:root {
  --sky: #48b6f6;
  --ink: #24304a;
  --accent: #ffcc33;
  /* numbers use a big, clean font; everything else is pixel art */
  --num-font: "Arial Rounded MT Bold", "Arial Black", "Trebuchet MS", system-ui, sans-serif;
  /* size of the HTML layer (HUD, overlays, on-screen controls): a touch screen is close, a phone is small */
  --ui: 1;
  --inset-l: max(18px, env(safe-area-inset-left));
  --inset-r: max(18px, env(safe-area-inset-right));
  --inset-b: max(18px, env(safe-area-inset-bottom));
}
:root.touch-mode { --ui: 0.85; }
@media (max-height: 500px) {
  :root, :root.touch-mode { --ui: 0.62; } /* a phone held sideways */
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  background: var(--sky);
  color: var(--ink);
  font-family: var(--num-font);
  user-select: none;
  -webkit-user-select: none;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  /* swipes belong to the game: no scrolling, rubber-banding or pinch zoom (input.js) */
  touch-action: none;
  overscroll-behavior: none;
}

[hidden] { display: none !important; }

button {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: inherit;
  cursor: pointer;
}
button:focus { outline: none; }

svg.px,
img.px {
  display: inline-block;
  max-width: 100%;
  height: auto;
  vertical-align: middle;
}
img.px { image-rendering: pixelated; object-fit: contain; } /* px.toImg: one image pixel per cell, never stretched */
/* button glyphs: pad badges or the keyboard keys that do the same, for the device used last (input.js) */
.kb-mode .pad-only,
html:not(.kb-mode) .kb-only { display: none; }
/* touch mode: the pad badges go, a hand (tap) stands for A, arrows only where the hub asks for a swipe */
.touch-only { display: none; }
.touch-mode svg.touch-only { display: inline-block; }
.touch-mode span.touch-only { display: inline-flex; align-items: center; gap: 8px; }
.touch-mode .pad-only { display: none; }

/* ---------- 8-bit frame: notched corners + chunky outline (--edge: its colour, --thick: its width, --step: the notch) ----------
   The outline (::before) and the shadow below it (::after) are the box's notched shape grown by --thick, drawn behind
   it. (Drop-shadow filters drew the same, but the GPU re-ran five of them per frame on every card while anything
   moved, which made the hub lag.) */
.px-frame {
  --edge: var(--ink);
  --thick: 3px;
  --step: 6px;
  position: relative;
  isolation: isolate; /* the outline stays behind this box, not behind whatever box this frame sits in */
  display: inline-block;
}
.px-frame::before,
.px-frame::after {
  content: '';
  position: absolute;
  inset: calc(-1 * var(--thick));
  z-index: -1;
  background: var(--edge);
  pointer-events: none;
}
.px-frame::after {
  z-index: -2;
  transform: translateY(5px);
  background: rgba(0, 0, 0, 0.18);
}
.px-box {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 10px 14px;
  background: #fff;
}
.px-box,
.px-frame::before,
.px-frame::after {
  clip-path: polygon(
    0 var(--step), var(--step) var(--step), var(--step) 0,
    calc(100% - var(--step)) 0, calc(100% - var(--step)) var(--step), 100% var(--step),
    100% calc(100% - var(--step)), calc(100% - var(--step)) calc(100% - var(--step)), calc(100% - var(--step)) 100%,
    var(--step) 100%, var(--step) calc(100% - var(--step)), 0 calc(100% - var(--step))
  );
}

.px-btn .px-box { padding: 12px 20px; gap: 14px; background: #eef3ff; }
.px-btn.primary .px-box { background: var(--accent); }
/* the thing under the mouse gets a thick black frame; the hub's cursor (card or grade tab) looks the same
   (hovering a card or tab moves the cursor there, so only one thing is ever framed).
   Only for a real pointer: on a touch screen the last tapped thing would keep the frame */
.hub-card.selected,
.hub-grade.cursor {
  --edge: #000;
  --thick: 6px;
}
@media (hover: hover) {
  .px-btn:hover { transform: translateY(-2px); }
  button.px-frame:not(.disabled):not(.hub-card):not(.hub-grade):hover {
    --edge: #000;
    --thick: 6px;
  }
  .hub-shoulder:hover { transform: translateY(-2px); }
  .hub-shoulder.off:hover { transform: none; }
}
.px-btn:active { transform: translateY(2px); }

/* ---------- hub ---------- */
.hub {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: clamp(12px, 3vh, 32px);
  /* room at the bottom for the control hints and sound buttons */
  padding: 16px 16px calc(88px + env(safe-area-inset-bottom));
}
/* touch: nothing to hint at (cards are tapped, tabs too), so the grid gets the room; no card is chosen before a tap */
:root.touch-mode .hub { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
:root.touch-mode .hub-hints { display: none; }
:root.touch-mode .hub-card.selected { --edge: var(--ink); --thick: 3px; z-index: auto; transform: none; }
:root.touch-mode .hub-card.selected .hub-icon { animation: none; }
.hub-title { position: relative; max-width: 92vw; margin: 0; }
.hub-title svg.px { max-height: 13vh; width: auto; }

/* ---------- grade tabs (Klasse 1-4) in a row, LB / RB flip through them ---------- */
.hub-tabs {
  position: relative;
  display: flex;
  align-items: center;
  gap: clamp(12px, 1.6vw, 22px);
}
.hub-grade-label { margin: 0 2px; }
.hub-shoulder { transition: transform 0.12s steps(2), opacity 0.12s steps(2); }
.hub-shoulder.off { opacity: 0.35; cursor: default; }
.hub-grade { transition: transform 0.12s steps(2); }
.hub-grade .px-box {
  width: clamp(48px, min(5.4vw, 8.5vh), 74px);
  height: clamp(48px, min(5.4vw, 8.5vh), 74px);
  padding: 0;
  background: #eef3ff;
}
.hub-grade b {
  font-size: clamp(32px, 3.6vw, 48px);
  line-height: 1;
  opacity: 0.55;
}
.hub-grade.selected { transform: scale(1.12); }
.hub-grade.selected .px-box { background: var(--accent); }
.hub-grade.selected b { opacity: 1; }

/* ---------- one grid page per grade, side by side; switching grades slides the track ----------
   hub.js sets --cols / --card / --gap per grid so all cards fit, and the view's height to the tallest grid */
.hub-view {
  position: relative;
  flex: none;
  align-self: stretch;
  overflow: hidden;
}
.hub-view.measure { flex: 1 1 0; min-height: 0; }
.hub-track {
  display: flex;
  height: 100%;
  transition: transform 0.3s steps(6);
}
.hub-track.instant { transition: none; }
.hub-page {
  flex: 0 0 100%;
  padding: 24px; /* room for the bigger selected card and its frame */
}
.hub-grid {
  display: grid;
  grid-template-columns: repeat(var(--cols, 5), var(--card, 160px));
  gap: var(--gap, 32px);
  justify-content: center;
  align-content: start;
}
.hub-card { position: relative; transition: transform 0.12s steps(2); }
.hub-card .px-box {
  flex-direction: column;
  gap: calc(var(--card, 160px) * 0.05);
  padding: 8px;
  width: var(--card, 160px);
  height: var(--card, 160px);
}
.hub-icon .px { width: calc(var(--card, 160px) * 0.56); max-height: calc(var(--card, 160px) * 0.58); }
.hub-card .px-box > .px { width: auto; height: max(12px, calc(var(--card, 160px) * 0.14)); }
.hub-card.selected { z-index: 1; transform: scale(1.08); }
.hub-card.selected .hub-icon { animation: px-bob 0.8s steps(2) infinite; }
.hub-card.disabled { opacity: 0.6; cursor: default; }
@keyframes px-bob {
  50% { transform: translateY(-6px); }
}

/* controls hint, bottom left (the sound buttons sit bottom right) */
.hub-hints {
  position: fixed;
  z-index: 1;
  left: var(--inset-l);
  bottom: var(--inset-b);
  display: flex;
  align-items: flex-end;
  gap: 16px;
}
.hub-hints .px-box { padding: 8px 12px; gap: 8px; }
.hub-pad.off { opacity: 0.45; animation: px-blink 1.2s steps(2) infinite; }
/* touch: cards are tapped and a swipe flips the grade, so only the hand with ← → stays */
.touch-mode .hub-keys,
.touch-mode .hub-go { display: none; }
@keyframes px-blink {
  50% { opacity: 0.15; }
}

.hub-clouds {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}
/* moved with transform, not left: the compositor slides them without repainting the hub every frame */
.hub-clouds .px {
  position: absolute;
  left: 0;
  animation: hub-drift 50s linear infinite;
  will-change: transform;
}
.hub-clouds .px:nth-child(1) { top: 10%; animation-duration: 56s; animation-delay: -12s; }
.hub-clouds .px:nth-child(2) { top: 64%; animation-duration: 40s; animation-delay: -28s; }
.hub-clouds .px:nth-child(3) { top: 84%; animation-duration: 66s; animation-delay: -44s; }
@keyframes hub-drift {
  from { transform: translateX(-200px); }
  to { transform: translateX(100vw); }
}

/* ---------- global voice / sound controls ---------- */
.audio-bar {
  position: fixed;
  z-index: 50;
  right: var(--inset-r);
  bottom: var(--inset-b);
  display: flex;
  align-items: flex-end;
  gap: 16px;
  zoom: var(--ui);
}
.audio-bar .px-box { padding: 8px 12px; gap: 8px; }
.audio-bar .off { opacity: 0.45; }
body:not(.in-game) .audio-pause { display: none; }

/* ---------- touch mode in a game: the child taps the scene; icon buttons for what the game polls sit bottom
   right, the number keys bottom centre while a number is typed, the sound bar (with pause) and the hint bottom left ---------- */
.touch-pad {
  position: fixed;
  z-index: 60;
  right: var(--inset-r);
  bottom: var(--inset-b);
  display: none;
  align-items: flex-end;
  gap: 14px;
  zoom: var(--ui);
}
html.touch-mode body.in-game .touch-pad { display: flex; }
.touch-btn,
.touch-key { touch-action: none; }
.touch-btn .px-box { padding: 12px; background: #eef3ff; }
.touch-btn.held,
.touch-key.held { transform: translateY(3px); }
.touch-btn.held .px-box { background: var(--accent); }
.touch-num {
  position: fixed;
  z-index: 60;
  left: 50%;
  bottom: var(--inset-b);
  transform: translateX(-50%);
  display: none;
  gap: 8px;
  zoom: var(--ui);
}
html.touch-mode body.in-game .touch-num.on { display: flex; }
.touch-key .px-box {
  width: clamp(42px, 5.6vw, 60px);
  height: clamp(42px, 5.6vw, 60px);
  padding: 0;
}
.touch-key b { font-size: clamp(24px, 3vw, 34px); line-height: 1; }
.touch-key.ok .px-box { background: var(--accent); }
.touch-key.held .px-box { background: #eef3ff; }
html.touch-mode body.in-game .audio-bar { right: auto; left: var(--inset-l); }
html.touch-mode body.in-game .touch-num.on ~ .audio-bar { bottom: calc(var(--inset-b) + 80px); }
/* touch: the child taps what it sees, so the control hints (in the game, on the intro panel, on buttons) go */
:root.touch-mode .gs-hint,
:root.touch-mode .md-hint,
:root.touch-mode .gs-controls,
:root.touch-mode .md-controls,
:root.touch-mode .px-btn svg.touch-only { display: none; }
.sound-hint { animation: hint-pulse 1s steps(2) infinite; }
@keyframes hint-pulse {
  50% { transform: scale(1.08); }
}

/* ---------- game container ---------- */
.game-root {
  position: fixed;
  inset: 0;
}
.game-root canvas { display: block; }

/* ---------- a phone held sideways (iPhone): the HTML layer is scaled by --ui (0.62), so the numbers below are
   in that scaled space; everything at the bottom fits in one row, the hub shows 7 × 3 cards ---------- */
@media (max-height: 500px) {
  .touch-key .px-box { width: 58px; height: 58px; } /* 36 px on screen: a finger still hits it */
  .touch-key b { font-size: 34px; }
  .touch-num { gap: 7px; }
  html.touch-mode body.in-game .touch-num.on ~ .audio-bar { bottom: var(--inset-b); } /* beside the keys, not above */
  .audio-bar .px-box { padding: 11px 15px; }
  .touch-btn .px-box { padding: 10px; }
  .hub { gap: 6px; padding: 6px 12px 8px; }
  .hub-title svg.px { max-height: 9vh; }
  .hub-tabs { gap: 10px; }
  .hub-grade .px-box { width: 40px; height: 40px; }
  .hub-grade b { font-size: 26px; }
  .hub-page { padding: 10px; }
  .hub-card .px-box { padding: 5px; }
}
/* a narrow phone (iPhone SE): the keys don't fit beside the pause / sound buttons; they move to the right edge when
   the game has no action buttons there, otherwise the sound bar goes above the keys */
@media (max-height: 500px) and (max-width: 720px) {
  html.touch-mode body.in-game .touch-pad:empty ~ .touch-num.on { left: auto; right: var(--inset-r); transform: none; }
  html.touch-mode body.in-game .touch-pad:not(:empty) ~ .touch-num.on ~ .audio-bar { bottom: calc(var(--inset-b) + 80px); }
}
