/* ==========================================================================
   Colour Safari — design system
   --------------------------------------------------------------------------
   One language throughout: soft painted-wood toys on paper.
   Every surface is either paper (flat, cream/mint) or painted wood (saturated,
   matte, chunky, with a physical bottom edge that compresses when pressed).
   Nothing is glassy, nothing glows, nothing is a gradient mesh.
   ========================================================================== */

/* ---------- tokens ---------- */
:root {
  /* ground + ink */
  --ground:      #EDF5EE;
  --ground-warm: #F8FBF4;
  --card:        #FFFFFF;
  --ink:         #33413A;
  --ink-soft:    #7A8B81;
  --line:        #E3EDE5;
  --line-strong: #D2E2D6;

  /* feedback */
  --good:      #43A047;
  --good-soft: #E8F5E9;
  --oops:      #E8A33D;
  --oops-soft: #FDF3E2;

  /* shape */
  --r-card: 30px;
  --r-block: 22px;
  --r-pill: 999px;

  /* depth — one consistent light source, straight above */
  --lift-1: 0 2px 6px rgba(38, 60, 45, .06);
  --lift-2: 0 8px 20px rgba(38, 60, 45, .08);
  --lift-3: 0 14px 34px rgba(38, 60, 45, .12);

  /* motion — snappy, weighted, never floaty */
  --ease-pop: cubic-bezier(.34, 1.56, .64, 1);
  --ease-out: cubic-bezier(.22, .61, .36, 1);
  --ease-in-out: cubic-bezier(.65, .05, .36, 1);

  --font: "Fredoka", ui-rounded, "SF Pro Rounded", "Segoe UI Variable Display",
          "Segoe UI", system-ui, -apple-system, sans-serif;

  --safe-t: env(safe-area-inset-top, 0px);
  --safe-b: env(safe-area-inset-bottom, 0px);
}

/* ---------- reset ---------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  overscroll-behavior: none;
}

body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--ground);
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: transparent;
  text-rendering: optimizeLegibility;
  /* A kid will mash the screen. Nothing should select, zoom, or bounce. */
  user-select: none;
  -webkit-user-select: none;
  touch-action: manipulation;
}

button { font: inherit; color: inherit; border: 0; background: none; cursor: pointer; }
img { display: block; max-width: 100%; }

/* ==========================================================================
   TOUCH-ACTION ON CONTROLS — this is what made the game feel dead
   --------------------------------------------------------------------------
   `touch-action: manipulation` on the body (above) only removes the
   double-tap-zoom delay. It still lets the browser claim a gesture as a PAN.

   Measured with real touch events (tools/probe-slop.py): when a finger lands,
   drifts about 30px and lifts — which is what a small child's finger does every
   time — the browser cancels the gesture and sends

       pointerdown -> pointermove -> pointercancel -> touchend

   with NO pointerup and NO click. The control never hears about it. To the
   child the button simply does not work.

   `touch-action: none` on the controls means the browser never starts a pan
   from them, so the gesture stays ours and always ends in pointerup.

   This is safe here because NOTHING in this app scrolls or pans: #app is a
   fixed, non-scrolling surface and every screen fits the viewport. There is no
   gesture to preserve.
   ========================================================================== */
button,
.block,
.level-card,
.icon-btn,
.btn,
.say {
  touch-action: none;
}

/* ==========================================================================
   THE MOBILE VIEWPORT HEIGHT — this is why the buttons were unreachable
   --------------------------------------------------------------------------
   A phone browser's visible area is NOT its screen height. Android Chrome shows
   a URL bar and a bottom toolbar; when they are visible the usable height can be
   150-200px less than the screen. There are four different "heights" in CSS and
   they disagree:

     vh   - the LARGEST possible viewport. Ignores the URL bar entirely, so it
            overflows the visible area whenever the bar is showing.
     dvh  - the DYNAMIC viewport, which resizes as the bar shows/hides. This is
            the one that matches what the user can actually see.
     svh  - the smallest (bar showing). Safe, but leaves a gap when the bar hides.
     lvh  - the largest. Same problem as vh.

   The layout below sizes against dvh so the answer blocks sit above the address
   bar. `svh` is the fallback for browsers without dvh; `vh` is the last resort.

   AND: the bottom safe area is added as padding. `viewport-fit=cover` in
   index.html lets the page paint under the Android navigation bar / iOS home
   indicator, so without this padding the bottom row of buttons sits underneath
   it and a tap there goes to the system, not the game.
   ========================================================================== */
#app {
  position: fixed;
  left: 0;
  right: 0;
  top: 0;
  /* Fallback first, then the modern units. Order matters: the last supported
     declaration wins, so dvh is used wherever it exists. */
  height: 100vh;
  height: 100svh;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  /* Keep the whole game clear of the notch, the home indicator and the
     Android nav bar. */
  padding: var(--safe-t) 0 var(--safe-b);
  /* FLAT cream ground. One solid colour. No gradient, no blobs, no glass.
     The art carries the colour; the room stays out of its way. */
  background: #FBF7EE;
  overflow: hidden;
}

/* The tint machinery is gone. These rules are kept as inert no-ops so a stale
   cached index.html referencing #wash cannot render an unstyled block. */
#wash, #ambient { display: none; }

/* ==========================================================================
   SCREENS
   ========================================================================== */
.screen {
  position: absolute;
  /* inset:0 resolves against #app's PADDING box, so the safe-area padding on
     #app already keeps content clear of the notch and the nav bar. Adding it
     again here would double-count it. */
  inset: 0;
  display: none;
  flex-direction: column;
  z-index: 1;
  padding: 10px 16px 14px;
  /* LAST-RESORT SCROLL. #app is overflow:hidden and the screens fill it, so if
     a layout ever needs more room than the viewport has, the overflow is not
     merely below the fold — it is unreachable, because there is nothing to
     scroll. Allowing the screen itself to scroll means a control can never be
     stranded off the bottom on a short phone. It should never actually scroll;
     it is a safety net, not a layout. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
}
.screen.is-active { display: flex; }

/* ==========================================================================
   TOP BAR — level pill + bead progress
   ========================================================================== */
.topbar {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: none;
  padding: 2px 2px 12px;
}

.icon-btn {
  flex: none;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border-radius: 14px;
  background: var(--card);
  box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line);
  color: var(--ink-soft);
  transition: transform .12s var(--ease-pop), box-shadow .12s;
}
.icon-btn:active { transform: scale(.92); box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line-strong); }
.icon-btn svg { width: 21px; height: 21px; }

.level-pill {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  height: 42px;
  padding: 0 15px;
  border-radius: var(--r-pill);
  background: var(--card);
  box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: .1px;
  white-space: nowrap;
}
.level-pill b { font-weight: 600; color: var(--ink-soft); font-size: 13px; }

/* bead track — one bead per round, filled as you win.
   Three separate problems were fixed here, each found by measurement:
     1. With flex:none beads in a min-width:0 track, justify-content:flex-end
        packed them and the early ones spilled LEFT over the level pill's text
        (16.4px overlap at 360x640 on level 3, 56.4px at 320x568).
     2. Adding overflow:hidden stopped the spill but CLIPPED instead: the track
        was 13px tall while .is-now scales to 16.6px, so the current-round bead
        was cut top and bottom at EVERY viewport, and at 320x568 it was cut
        16.4px — entirely invisible, so the child could not see which round
        they were on.
     3. A scaled element keeps its layout box, so the transform must be paid for
        with track height, not hidden by overflow.
   Hence: a track tall enough for the scaled bead, overflow visible (the pill
   overlap is prevented by making the beads shrink, not by clipping), and beads
   that compress to fit. */
.beads {
  flex: 1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 6px;
  min-width: 0;
  height: 22px;              /* room for .is-now at scale(1.28) = 16.6px */
  overflow: visible;
}
.bead {
  flex: 0 1 13px;
  min-width: 5px;
  aspect-ratio: 1 / 1;
  height: auto;
  border-radius: 50%;
  background: #DCE9DF;
  box-shadow: inset 0 1.5px 2px rgba(40, 70, 50, .1);
  transition: background .3s var(--ease-out), transform .3s var(--ease-pop);
}
.bead.is-done {
  background: var(--good);
  box-shadow: inset 0 -1.5px 0 rgba(0, 0, 0, .16), 0 2px 5px rgba(67, 160, 71, .4);
  animation: beadPop .45s var(--ease-pop);
}
/* scale(1.15), not 1.28: 13px * 1.15 = 15px, comfortably inside the 22px track,
   and still reads clearly as "this is the round you are on". */
.bead.is-now { background: #C4DCCB; transform: scale(1.15); }
@keyframes beadPop {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.55); }
  100% { transform: scale(1); }
}

/* ==========================================================================
   PICTURE CARD
   ========================================================================== */
/* The card is SQUARE, matching the square illustration canvases, so the art
   sits edge to edge with no dead white inside the card. A taller card was
   tried and rejected: the square art then letterboxes and the white card shows
   a band of empty space above and below the subject, which reads as a mistake.
   Leftover vertical slack belongs on the background, where it reads as air.
   The dvh term keeps the card from crowding the rest on a short phone. */
.card {
  position: relative;
  flex: 0 1 auto;
  width: min(100%, 430px, calc(100dvh - 300px));
  aspect-ratio: 1 / 1;
  max-height: 100%;
  min-height: 0;
  margin: auto auto;          /* splits leftover slack evenly above and below */
  display: grid;
  place-items: center;
  border-radius: var(--r-card);
  background: var(--card);
  box-shadow: var(--lift-2), inset 0 0 0 1.5px var(--line);
  overflow: hidden;
  padding: 16px;
}
/* A flat white card. No inner gradient — the wash behind it is flat too, so a
   gradient here would be the only soft thing on screen and would read as glass. */
.card::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background: #FFFFFF;
  border-radius: inherit;
}

.card img {
  position: relative;
  z-index: 1;
  max-width: 100%;
  max-height: 100%;
  width: auto;
  height: auto;
  object-fit: contain;
  /* Drop shadow tuned to the cutout so the object sits ON the card, not in it. */
  filter: drop-shadow(0 10px 16px rgba(38, 60, 45, .16));
}
/* Each new picture arrives as a fresh card being laid down — a short settle
   with a touch of rotation, so the round change is felt rather than blinked. */
.card.is-enter img { animation: tileIn .5s var(--ease-pop) both; }
@keyframes tileIn {
  0%   { opacity: 0; transform: scale(.86) rotate(-2.5deg); }
  62%  { opacity: 1; transform: scale(1.025) rotate(.7deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}

/* ==========================================================================
   PROMPT LINE
   ========================================================================== */
.prompt {
  flex: none;
  padding: 16px 6px 12px;
  text-align: center;
}
/* Replay-the-voice: lives INSIDE the question line, as a small speaker icon,
   so it can never be mistaken for a colour choice. A child can always ask
   again — that is the whole point of a naming game. */
.prompt .q {
  font-size: clamp(21px, 6.4vw, 27px);
  font-weight: 600;
  letter-spacing: -.2px;
  line-height: 1.15;
  margin: 0;
}
.prompt .say {
  display: inline-grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin-left: 7px;
  vertical-align: -7px;
  border-radius: 50%;
  background: var(--card);
  box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line);
  color: var(--ink-soft);
  transition: transform .12s var(--ease-pop), color .2s, box-shadow .2s;
}
.prompt .say:active { transform: scale(.88); }
.prompt .say svg { width: 18px; height: 18px; }
.prompt .say.is-speaking {
  color: var(--good);
  box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--good);
}

/* ==========================================================================
   ANSWER BLOCKS — the choice
   --------------------------------------------------------------------------
   THE BLOCKS ARE DELIBERATELY COLOURLESS.

   This is the single most important rule in the game. If a block were painted
   its own colour, a child could answer by matching the picture to the block and
   would never read the name — the game would silently become the visual-matching
   game it is supposed to replace. The name is the only cue, so it is the only
   thing on the block.

   The colour is revealed ON the block only AFTER a correct answer, which is the
   teaching moment: the child sees the name they chose and the colour it means,
   together, with the voice saying it aloud.

   All blocks are also the same SHAPE, for the same reason: a differing
   silhouette would let a child answer by shape and never learn the colour.
   ========================================================================== */
.blocks {
  flex: none;
  display: grid;
  gap: 10px;
  grid-template-columns: repeat(var(--n, 4), 1fr);
  padding: 2px 0 6px;
}

.block {
  position: relative;
  height: clamp(64px, 15.5vw, 82px);
  border-radius: var(--r-block);
  /* FLAT face. One solid colour — no gradient, no sheen.
     White against the cream ground so the blocks read clearly as separate
     objects; the same tone as the card, which is the only other white thing. */
  background: var(--block-face, #FFFFFF);
  /* A solid darker bottom edge makes it feel like a real object you press down.
     This is the ONLY depth: a hard offset edge, no soft gloss. */
  box-shadow: 0 5px 0 var(--block-edge, #E8E0CE);
  transition: transform .13s var(--ease-pop), box-shadow .13s var(--ease-out),
              background-color .34s var(--ease-out), filter .3s var(--ease-out),
              opacity .3s var(--ease-out);
  will-change: transform;
}

/* The colour name is the only thing on the block. */
.block .name {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  padding: 0 4px;
  line-height: 1;
  font-size: clamp(14px, 4vw, 18px);
  font-weight: 600;
  letter-spacing: -.2px;
  color: var(--ink);
  pointer-events: none;
  transition: color .28s var(--ease-out);
}

.block:active,
.block.is-press {
  transform: translateY(5px);
  box-shadow: 0 0 0 var(--block-edge, #E0DACB);
}

/* a block already guessed wrong: faded out, sunk, not tappable */
.block.is-dead {
  filter: grayscale(1);
  opacity: .34;
  transform: translateY(5px);
  box-shadow: 0 0 0 var(--block-edge, #E0DACB);
  pointer-events: none;
}

/* THE REVEAL — a correct answer fills the block with the colour it names.
   FLAT fill, matching the cel-shaded art. One solid colour and a hard bottom
   edge; no gradient and no white sheen. */
.block.is-correct {
  background: var(--c);
  box-shadow: 0 5px 0 var(--cd);
  animation: blockWin .62s var(--ease-pop);
  z-index: 2;
}
.block.is-correct .name { color: var(--ink-on, #fff); }
@keyframes blockWin {
  0%   { transform: translateY(5px) scale(1); }
  30%  { transform: translateY(-14px) scale(1.11, .9); }
  55%  { transform: translateY(0) scale(.94, 1.08); }
  75%  { transform: translateY(-4px) scale(1.03, .98); }
  100% { transform: translateY(0) scale(1); }
}

/* a wrong tap — a wobble, never a punishment */
.block.is-wrong { animation: blockWobble .5s var(--ease-in-out); }
@keyframes blockWobble {
  0%, 100% { transform: translateX(0) rotate(0); }
  15% { transform: translateX(-7px) rotate(-2.5deg); }
  32% { transform: translateX(6px) rotate(2deg); }
  50% { transform: translateX(-4px) rotate(-1.4deg); }
  70% { transform: translateX(3px) rotate(1deg); }
  88% { transform: translateX(-1.5px) rotate(-.4deg); }
}

/* ==========================================================================
   FEEDBACK — a big friendly mark, then gone
   ========================================================================== */
.mark {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  pointer-events: none;
  z-index: 20;
  opacity: 0;
}
.mark.is-on { animation: markShow 1.15s var(--ease-out) forwards; }
@keyframes markShow {
  0%   { opacity: 0; }
  14%  { opacity: 1; }
  72%  { opacity: 1; }
  100% { opacity: 0; }
}
.mark .disc {
  width: min(58vw, 240px);
  aspect-ratio: 1;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--card);
  box-shadow: var(--lift-3), inset 0 0 0 8px var(--good-soft);
  animation: discPop .5s var(--ease-pop);
}
.mark.is-oops .disc { box-shadow: var(--lift-3), inset 0 0 0 8px var(--oops-soft); }
@keyframes discPop {
  0%   { transform: scale(.4) rotate(-12deg); }
  60%  { transform: scale(1.06) rotate(3deg); }
  100% { transform: scale(1) rotate(0); }
}
.mark svg { width: 46%; height: 46%; }
.mark .tick { stroke: var(--good); }
.mark .oops { stroke: var(--oops); }

/* ==========================================================================
   HOME / MENU
   ========================================================================== */
.home {
  flex: 1;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  gap: 6px;
  padding: 8px 6px 0;
}

.logo {
  font-size: clamp(38px, 12.5vw, 56px);
  font-weight: 700;
  line-height: .98;
  letter-spacing: -1.5px;
  margin: 0 0 4px;
}
.logo span { display: block; }
.logo .l1 { color: #E4574C; }
.logo .l2 { color: #3A80D2; }
.logo .l3 { color: #F2BE2E; }
.logo .l4 { color: #4CAF62; }

.tagline {
  font-size: 16px;
  color: var(--ink-soft);
  margin: 6px 0 0;
  max-width: 27ch;
  line-height: 1.4;
}

/* the four-block emblem under the title */
.emblem {
  display: flex;
  gap: 9px;
  margin: 20px 0 24px;
}
.emblem i {
  width: 40px;
  height: 40px;
  border-radius: 13px;
  background: var(--c);
  box-shadow: 0 4px 0 var(--cd);
  animation: emblemBob 2.6s var(--ease-in-out) infinite;
}
.emblem i:nth-child(1) { animation-delay: 0s; }
.emblem i:nth-child(2) { animation-delay: .13s; }
.emblem i:nth-child(3) { animation-delay: .26s; }
.emblem i:nth-child(4) { animation-delay: .39s; }
@keyframes emblemBob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-7px); }
}

/* level picker */
.levels {
  width: 100%;
  max-width: 420px;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.level-card {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  padding: 15px 18px;
  border-radius: 22px;
  background: var(--card);
  box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line);
  text-align: left;
  transition: transform .14s var(--ease-pop), box-shadow .14s;
}
.level-card:active { transform: scale(.975); box-shadow: var(--lift-1), inset 0 0 0 1.5px var(--line-strong); }

.level-card .num {
  flex: none;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border-radius: 15px;
  font-size: 21px;
  font-weight: 600;
  color: #fff;
  background: var(--c);
  box-shadow: 0 4px 0 var(--cd);
}
.level-card .meta { flex: 1; min-width: 0; }
/* display:block is required — these are <span>s, so without it the title and
   subtitle run together on one line ("Warm UpThree easy colours").
   Found in a real browser by game-engine. */
.level-card .t { display: block; font-size: 17.5px; font-weight: 600; letter-spacing: -.2px; }
.level-card .s { display: block; font-size: 13.5px; color: var(--ink-soft); margin-top: 2px; }

/* little row of swatches showing the level's colours */
.level-card .swatches { display: flex; gap: 4px; margin-top: 7px; }
.level-card .swatches i {
  width: 13px; height: 13px; border-radius: 5px;
  background: var(--c);
  box-shadow: inset 0 1.5px 0 rgba(255,255,255,.5), 0 2px 0 var(--cd);
}

.level-card .chev { flex: none; color: var(--line-strong); }
.level-card .chev svg { width: 20px; height: 20px; display: block; }

/* ==========================================================================
   RESULTS
   ========================================================================== */
.results {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 4px;
  padding: 0 8px;
}
.results .trophy {
  width: min(46vw, 190px);
  aspect-ratio: 1;
  margin-bottom: 6px;
  animation: trophyIn .8s var(--ease-pop) both;
}
@keyframes trophyIn {
  0%   { transform: scale(.3) rotate(-18deg); opacity: 0; }
  65%  { transform: scale(1.08) rotate(4deg); opacity: 1; }
  100% { transform: scale(1) rotate(0); }
}
.results h2 {
  font-size: clamp(30px, 9.5vw, 40px);
  font-weight: 700;
  letter-spacing: -1px;
  margin: 0;
}
.results .score {
  font-size: 17px;
  color: var(--ink-soft);
  margin: 6px 0 0;
}
.results .score b { color: var(--good); font-weight: 600; }

/* the colours collected this level, as a little shelf of blocks */
.shelf {
  display: flex;
  gap: 9px;
  margin: 22px 0 26px;
  flex-wrap: wrap;
  justify-content: center;
}
.shelf i {
  width: 42px; height: 42px; border-radius: 14px;
  background: var(--c);
  box-shadow: 0 4px 0 var(--cd);
  animation: shelfIn .5s var(--ease-pop) both;
}
@keyframes shelfIn {
  from { transform: scale(.3) translateY(14px); opacity: 0; }
  to   { transform: scale(1) translateY(0); opacity: 1; }
}

/* ==========================================================================
   BUTTONS
   ========================================================================== */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  height: 60px;
  padding: 0 34px;
  border-radius: 20px;
  font-size: 18px;
  font-weight: 600;
  letter-spacing: -.2px;
  /* nowrap is required: at 360x640 "Play again" otherwise broke onto two lines
     inside a fixed 60px box and read as a broken label beside one-line "Menu". */
  white-space: nowrap;
  color: #fff;
  background: var(--good);
  box-shadow: 0 6px 0 #2E7A33;
  transition: transform .13s var(--ease-pop), box-shadow .13s;
}
.btn:active {
  transform: translateY(6px);
  box-shadow: 0 0 0 #2E7A33;
}
.btn.ghost {
  background: var(--card);
  color: var(--ink-soft);
  box-shadow: 0 4px 0 var(--line-strong);
}
.btn.ghost:active { box-shadow: 0 0 0 var(--line-strong); }
.btn svg { width: 21px; height: 21px; }

.result-actions {
  display: flex;
  gap: 12px;
  align-items: center;
}

/* ==========================================================================
   CONFETTI
   ========================================================================== */
#confetti {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 30;
}

/* ==========================================================================
   SIZING — keep it beautiful on a short phone and on a tablet
   ========================================================================== */
@media (max-height: 700px) {
  .prompt { padding: 11px 6px 8px; }
  .prompt .q { font-size: clamp(19px, 5.6vw, 23px); }
  .block { height: clamp(56px, 13.5vw, 70px); }
  .prompt .say { width: 30px; height: 30px; margin-left: 5px; vertical-align: -6px; }
  .emblem { margin: 12px 0 16px; }
  .emblem i { width: 34px; height: 34px; }
  .level-card { padding: 12px 16px; }
  .level-card .num { width: 40px; height: 40px; font-size: 19px; }
}

@media (min-width: 620px) {
  .screen { padding-left: 26px; padding-right: 26px; }
  .card { padding: 22px; }
  .block { height: 88px; }
  .blocks { gap: 14px; }
}

/* Landscape phones: shrink the card, keep everything on one screen. */
@media (orientation: landscape) and (max-height: 560px) {
  .screen { padding-top: calc(var(--safe-t) + 6px); }
  .topbar { padding-bottom: 7px; }
  .card { max-height: 46vh; }
  .prompt { padding: 7px 6px 5px; }
  .prompt .q { font-size: 19px; }
  .prompt .say { width: 28px; height: 28px; margin-left: 4px; vertical-align: -5px; }
  .block { height: 54px; }
}

/* ==========================================================================
   ACCESSIBILITY
   ========================================================================== */
:focus-visible {
  outline: 3px solid #3A80D2;
  outline-offset: 3px;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  #ambient { display: none; }
  .emblem i { animation: none; }
}

/* Utility */
.sr-only {  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* ==========================================================================
   BUILD STAMP — visible on purpose
   --------------------------------------------------------------------------
   A phone caches CSS and JS hard. A stale build is invisible from the outside:
   the old page loads perfectly and simply behaves like the old page, which
   makes "is the fix live?" unanswerable by looking. This prints the build tag
   in the corner of the menu so the answer is one glance away.
   ========================================================================== */
.build-stamp {
  margin: 18px 0 0;
  text-align: center;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .6px;
  text-transform: uppercase;
  color: var(--ink-faint, #A9B3AC);
  user-select: text;
  -webkit-user-select: text;
}
