/* ============================================================
   KidMantis — app.css
   Premium garden design system. Day/Night themes, seasons,
   reduced motion, WCAG-focused. Mobile-first from 320px.
   ============================================================ */

/* ---------- Baloo 2 (bundled, OFL-1.1) ---------- */
@font-face { font-family: "Baloo 2"; font-style: normal; font-weight: 400; font-display: swap; src: url("../assets/fonts/baloo-2-latin-400-normal.woff2") format("woff2"); }
@font-face { font-family: "Baloo 2"; font-style: normal; font-weight: 600; font-display: swap; src: url("../assets/fonts/baloo-2-latin-600-normal.woff2") format("woff2"); }
@font-face { font-family: "Baloo 2"; font-style: normal; font-weight: 700; font-display: swap; src: url("../assets/fonts/baloo-2-latin-700-normal.woff2") format("woff2"); }
@font-face { font-family: "Baloo 2"; font-style: normal; font-weight: 800; font-display: swap; src: url("../assets/fonts/baloo-2-latin-800-normal.woff2") format("woff2"); }

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  font-family: "Baloo 2", "Segoe UI Rounded", ui-rounded, -apple-system, "Segoe UI", Roboto, "Noto Sans", Arial, sans-serif;
  font-size: 17px; line-height: 1.5;
  color: var(--ink); background: var(--bg-solid);
  overflow-x: hidden;
  touch-action: manipulation;
}
img { max-width: 100%; }
button { font: inherit; }

/* ---------- Theme tokens ---------- */
:root {
  /* ---------- rc.130: THE PICTURE SIZE SCALE ----------
     There was no scale. Every mechanic invented its own and the range ran
     from 16 px to 96 px — a six-fold spread with nothing behind it. Three
     of those were defects a child would feel:

       · sorting bins drew their label at 22 px while the tokens sorted
         INTO them drew at 88 px. The target was the smallest picture on
         the screen, a quarter the width and a sixteenth the area of the
         thing in the child's hand.
       · dragMatch drew the same object at 34 px in the tray and 83 px in
         the grid — in a mechanic whose entire job is matching those two
         by eye.
       · 5,283 rounds (14.1%) drew a picture inside the prompt sentence at
         23 px, while the answers below drew at 88 px. In 2,970 of them the
         picture was part of what was being asked.

     THE FLOOR IS MEASURED, NOT CHOSEN. Rendering the library at each size
     and looking: flat marks and faces stay legible at 23 px, but photoreal
     subjects are mud at 23, colour-only at 34–40, and legible at 52 —
     every confusable pair tested (wolf/fox, lion/bear, dolphin/shark,
     moth/butterfly) separates cleanly there and not below.

     So: 52 px is the floor for anything photoreal, and --pic-inline is for
     flat marks only. A photoreal subject is never rendered inline. */
  /* The scale sets a FLOOR and makes comparisons consistent. It must never
     SHRINK a picture that was already fine — rc.130 first set this to
     clamp(72px,...) and qa37's guitar test caught it immediately: the
     sorting token fell 88px -> 72px and the guitar inside it went to
     28.1px wide, under the 34px minimum for a visible object. Answers keep
     the size they had. */
  --pic-lg: clamp(88px, 25vw, 112px);      /* a thing the child taps as an answer */
  --pic-md: clamp(52px, 15vw, 72px);       /* things compared as a group, and the two halves of a match */
  --pic-sm: clamp(52px, 13vw, 64px);       /* a label on a container — still above the floor */
  --pic-inline: clamp(30px, 1.9em, 40px);  /* a flat mark standing in for a word inside prose */
}

.app {
  /* Day (default) */
  --bg-solid: #eaf6e6;
  --sky-a: #bfe7ff; --sky-b: #e8f8e0; --sky-glow: #fff6c9;
  --ink: #2a333c; --ink-soft: #48545f; --ink-faint: #6a7681;
  --muted: #5c6873; --line: #d5e0d5; --wsoft: rgba(47, 158, 87, .14);
  --card: #ffffff; --card-edge: #cfe6cf; --card-soft: #f2faee;
  --accent: #2f9e57; --accent-ink: #ffffff; --accent-deep: #1d7a40;
  --accent2: #ef8bb1; --accent2-deep: #d05f8c;
  --gold: #e7a824; --gold-soft: #fdf3d7;
  --leaf: #3fae63; --coin: #e7a824;
  --danger: #c25543;
  --glow: 0 0 18px rgba(120, 220, 140, .55);
  --shadow: 0 6px 20px rgba(30, 70, 40, .16);
  --shadow-soft: 0 3px 10px rgba(30, 70, 40, .10);
  --focus: #7a3cc9;
  --btn-grad: linear-gradient(180deg, #4cc274, #2f9e57 60%, #268a4a);
  --btn2-grad: linear-gradient(180deg, #f6a9c8, #ef8bb1 60%, #e0759f);
  --stage-glow: radial-gradient(closest-side, rgba(255, 246, 180, .8), transparent);
  color: var(--ink);
  min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column;
  position: relative;
}
.app[data-theme="night"] {
  --bg-solid: #101a30;
  --sky-a: #16213f; --sky-b: #241d43; --sky-glow: #35406e;
  --ink: #eef1ff; --ink-soft: #c3cbea; --ink-faint: #93a0c8;
  --muted: #b6c0e4; --line: #3a4a76; --wsoft: rgba(255, 255, 255, .13);
  --card: #1c2846; --card-edge: #35436e; --card-soft: #223055;
  --accent: #46b877; --accent-ink: #06210f; --accent-deep: #5ecb8b;
  --accent2: #f19cc0; --accent2-deep: #f7b7d2;
  --gold: #f2c14e; --gold-soft: #3a3350;
  --danger: #ef8a76;
  --glow: 0 0 20px rgba(140, 240, 170, .35);
  --shadow: 0 6px 22px rgba(0, 0, 6, .5);
  --shadow-soft: 0 3px 10px rgba(0, 0, 6, .4);
  --focus: #ffd76a;
  --btn-grad: linear-gradient(180deg, #4cc274, #2f9e57 60%, #268a4a);
  --btn2-grad: linear-gradient(180deg, #f6a9c8, #ef8bb1 60%, #e0759f);
  --stage-glow: radial-gradient(closest-side, rgba(110, 130, 255, .25), transparent);
}

/* ---------- Sky / ambience / world scenery ---------- */
.sky {
  position: fixed; inset: 0; z-index: 0; pointer-events: none;
  /* drifting clouds, stars and particles must never widen the page */
  overflow: hidden;
  background: linear-gradient(180deg, var(--sky-a-w, var(--sky-a)), var(--sky-b-w, var(--sky-b)));
  transition: background 1.2s ease;
}
.app[data-theme="night"] .sky { background: linear-gradient(180deg, var(--sky-a), var(--sky-b)); }
.scenery-holder { position: absolute; left: 0; right: 0; bottom: 0; height: min(46vh, 420px); }
.scenery { width: 100%; height: 100%; display: block; }
.app[data-theme="night"] .scenery { filter: brightness(.38) saturate(.55); }
.app.high-contrast .scenery { opacity: .35; }
.wpart { position: absolute; bottom: -26px; opacity: 0; animation: wpart-rise linear infinite; }
@keyframes wpart-rise {
  0% { transform: translateY(0) rotate(0); opacity: 0; }
  12% { opacity: .8; }
  85% { opacity: .55; }
  100% { transform: translateY(-78vh) translateX(4vw) rotate(30deg); opacity: 0; }
}
.app.reduce-motion .wpart, .app.reduce-effects .wpart { display: none; }
.app.reduce-motion .wpart, .app.reduce-motion .screen { animation: none !important; }   /* rc.72 (PX KM-PX-02): nothing even nominally animating on Today under Reduce Motion */
.sky .orb {
  position: absolute; top: 6%; right: 8%; width: 90px; height: 90px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, #fff9dd, #ffd95e 65%, #f0b62a);
  box-shadow: 0 0 60px 22px rgba(255, 224, 130, .55);
}
.app[data-theme="night"] .sky .orb {
  background: radial-gradient(circle at 38% 34%, #ffffff, #dfe6ff 60%, #aab6e8);
  box-shadow: 0 0 44px 14px rgba(200, 214, 255, .35);
}
.sky .star { position: absolute; width: 3px; height: 3px; border-radius: 50%; background: #fff; opacity: 0; }
.app[data-theme="night"] .sky .star { opacity: .9; animation: twinkle 3.4s ease-in-out infinite; }
.sky .hill { position: absolute; bottom: -4vh; border-radius: 50% 50% 0 0; }
.sky .hill.h1 { left: -12%; width: 70%; height: 26vh; background: var(--hill1, #bfe3ae); }
.sky .hill.h2 { right: -14%; width: 76%; height: 20vh; background: var(--hill2, #a5d896); }
.app[data-theme="night"] .sky .hill.h1 { background: #1a2c4b; }
.app[data-theme="night"] .sky .hill.h2 { background: #152340; }
.sky .season { position: absolute; font-size: 20px; top: -30px; animation: fall linear infinite; opacity: .85; }
@keyframes fall { to { transform: translateY(115vh) rotate(200deg); } }
@keyframes twinkle { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.sky .firefly { position: absolute; width: 5px; height: 5px; border-radius: 50%; background: #ffe98a;
  box-shadow: 0 0 8px 3px rgba(255, 233, 138, .8); opacity: 0; }
.app[data-theme="night"] .sky .firefly { opacity: .95; animation: drift 7s ease-in-out infinite alternate; }
@keyframes drift { from { transform: translate(0, 0); } to { transform: translate(36px, -30px); } }

@media (prefers-reduced-motion: reduce) {
  .sky .season, .sky .star, .sky .firefly { animation: none !important; }
  * { animation-duration: .01s !important; transition-duration: .12s !important; }
}
.app.reduce-motion .sky .season, .app.reduce-motion .sky .star, .app.reduce-motion .sky .firefly { animation: none !important; }
.app.reduce-motion * { animation-duration: .01s !important; transition-duration: .12s !important; }
.app.reduce-effects .sky .season, .app.reduce-effects .sky .firefly { display: none; }
.app.reduce-effects .sky .orb { box-shadow: none; }

/* ---------- Layout ---------- */
.topbar {
  position: sticky; top: 0; z-index: 30;
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  padding: calc(6px + env(safe-area-inset-top)) max(10px, env(safe-area-inset-right)) 6px max(10px, env(safe-area-inset-left));
  background: color-mix(in srgb, var(--card) 82%, transparent);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--card-edge);
}
.top-status, .top-actions { display: flex; gap: 6px; align-items: center; flex: 0 0 auto; }
.main {
  position: relative; z-index: 5; flex: 1;
  width: 100%; max-width: 1060px; margin: 0 auto;
  padding: 12px max(12px, env(safe-area-inset-right)) 150px max(12px, env(safe-area-inset-left));
}
.main:focus { outline: none; }
.site-footer {
  /* rc.83 (CA-001): 4, not 5. `.main` is z-index 5 and the footer is its later
     sibling, so at 5 the footer won every tie and swallowed taps meant for a
     pinned control inside main. The footer overlaps nothing else, so sitting
     one layer below main costs nothing and stops it stealing hits. */
  position: relative; z-index: 4;
  display: flex; flex-wrap: wrap; gap: 2px 14px; align-items: center; justify-content: space-between;
  padding: 5px max(12px, env(safe-area-inset-right)) calc(5px + env(safe-area-inset-bottom)) max(12px, env(safe-area-inset-left));
  font-size: 11.5px; line-height: 1.5; color: var(--ink-faint);
  border-top: 1px solid var(--card-edge);
  background: color-mix(in srgb, var(--card) 70%, transparent);
}
.foot-brand { display: inline-flex; align-items: center; gap: 5px; font-weight: 600; }
.foot-brand img { width: 13px; height: 13px; }
.foot-links { display: flex; gap: 12px; align-items: center; }
.foot-links a { color: var(--ink-soft); text-decoration: underline;
  /* rc.150 QA-149-01: 17 px text links were the only controls under 24 px on any axis. Padding lifts the
     tap box to 29 px without moving the text; the row still fits 320 px (gap 12 px, three short words). */
  display: inline-flex; align-items: center; min-height: 24px; padding: 6px 2px; margin: -6px -2px; }

.skip-link {
  position: absolute; left: 8px; top: -60px; z-index: 100;
  background: var(--card); color: var(--ink); padding: 10px 14px; border-radius: 10px;
  transition: top .15s ease; box-shadow: var(--shadow);
}
.skip-link:focus { top: 8px; }

/* ---------- Buttons ---------- */
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 12px; }
.icon-btn {
  min-width: 48px; min-height: 48px; padding: 4px 8px;
  display: inline-flex; flex-direction: column; align-items: center; justify-content: center; gap: 0;
  border: 1px solid var(--card-edge); border-radius: 14px;
  background: var(--card); color: var(--ink); cursor: pointer;
  box-shadow: var(--shadow-soft);
}
.icon-btn:hover { box-shadow: var(--shadow); }
.icon-btn .ic { font-size: 20px; line-height: 1.1; }
.icon-btn .ic-label { font-size: 10.5px; font-weight: 700; color: var(--ink-soft); }
.icon-btn[aria-pressed="true"] { border-color: var(--accent); box-shadow: var(--glow); }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 56px; padding: 12px 22px;
  border: 0; border-radius: 18px; cursor: pointer;
  font-size: 18px; font-weight: 800; letter-spacing: .01em;
  color: var(--accent-ink); background: var(--btn-grad);
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35), 0 4px 0 var(--accent-deep), var(--shadow-soft);
  border: 2px solid color-mix(in srgb, var(--accent-deep) 70%, #000 8%);
  text-shadow: 0 1px 2px rgba(0, 40, 10, .25);
  transition: transform .08s ease, box-shadow .15s ease;
}
.app[data-theme="night"] .btn { color: #06210f; text-shadow: none; }
.app[data-theme="night"] .btn.ghost {
  background: linear-gradient(180deg, #2e4166, #24354f);
  color: #f2f6ff;
  border-color: rgba(150, 190, 255, .55);
  box-shadow: 0 0 12px rgba(120, 170, 255, .3), 0 3px 8px rgba(0, 0, 0, .35);
}
a.btn, a.btn:hover, a.btn:visited { text-decoration: none; }   /* a link dressed as a button reads as a button */
.btn:active { transform: translateY(2px); box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35), 0 2px 0 var(--accent-deep); }
.btn.glow { box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35), 0 4px 0 var(--accent-deep), var(--glow); }
.btn.alt { background: var(--btn2-grad); box-shadow: inset 0 2px 0 rgba(255, 255, 255, .4), 0 4px 0 var(--accent2-deep), var(--shadow-soft); border-color: var(--accent2-deep); color: #4a1029; text-shadow: none; }
.btn.ghost {
  background: var(--card); color: var(--ink); border: 2px solid var(--card-edge);
  box-shadow: var(--shadow-soft); text-shadow: none;
}
.btn.small { min-height: 44px; padding: 8px 16px; font-size: 15px; border-radius: 14px; }
.btn.big { min-height: 64px; font-size: 21px; padding: 14px 28px; }
.btn:disabled { opacity: .55; cursor: not-allowed; transform: none; }
.btn .em { font-size: 1.25em; }

.pill {
  display: inline-flex; align-items: center; gap: 5px;
  min-height: 36px; padding: 4px 12px; border-radius: 999px;
  background: var(--card); border: 1px solid var(--card-edge); font-weight: 800; font-size: 15px;
  box-shadow: var(--shadow-soft);
}
.pill-leaf b { color: var(--leaf); }
.pill-coin b { color: var(--coin); }
.pill.bump { animation: bump .5s ease; }
@keyframes bump { 30% { transform: scale(1.18); } }

/* ---------- Cards & screens ---------- */
.screen { animation: screen-in .35s ease; }
@keyframes screen-in { from { opacity: 0; transform: translateY(10px); } }
.card {
  position: relative;
  background: var(--card); border: 1px solid var(--card-edge); border-radius: 26px;
  box-shadow: 0 10px 26px rgba(30, 70, 40, .13), 0 2px 6px rgba(30, 70, 40, .08); padding: 16px;
  overflow: hidden;
}
.card::before {
  content: ""; position: absolute; inset: 0 0 auto 0; height: 42%;
  background: linear-gradient(180deg, rgba(255, 255, 255, .5), transparent);
  border-radius: 26px 26px 0 0; pointer-events: none;
}
.app[data-theme="night"] .card { box-shadow: 0 10px 26px rgba(0, 0, 8, .5); }
.app[data-theme="night"] .card::before { background: linear-gradient(180deg, rgba(255, 255, 255, .05), transparent); }
.card > * { position: relative; }
.card.soft { background: var(--card-soft); }
h1, h2, h3 { line-height: 1.2; margin: 0 0 8px; }
h1 { font-size: clamp(24px, 5.4vw, 34px); }
h2 { font-size: clamp(20px, 4.4vw, 26px); }
h3 { font-size: 18px; }
.center { text-align: center; }
.muted { color: var(--ink-faint); }
.row { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }
.row.spread { justify-content: space-between; }
.stack { display: flex; flex-direction: column; gap: 12px; }
.mt { margin-top: 14px; } .mb { margin-bottom: 14px; }

/* ---------- Home world grid — every world is a place ---------- */
.dest-grid { display: flex; flex-wrap: wrap; gap: 14px; }
/* tiles share each row equally and the LAST row stretches to fill —
   no dead space left at the end of the grid */
.dest-grid > .world-tile { flex: 1 1 152px; }
.world-tile {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 5px;
  min-height: 138px; padding: 16px 10px 13px;
  border-radius: 24px; border: 0; cursor: pointer;
  background: linear-gradient(160deg, var(--tile-a, #57b878), var(--tile-b, #2f8a52));
  box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35), inset 0 -3px 0 rgba(0, 0, 0, .18), 0 8px 18px rgba(20, 40, 25, .22);
  color: #fff; text-align: center; overflow: hidden;
  transition: transform .14s ease, box-shadow .2s ease;
  animation: tile-in .45s ease backwards;
}
.world-tile::after { /* shine sweep */
  content: ""; position: absolute; top: -60%; left: -80%; width: 55%; height: 220%;
  background: linear-gradient(105deg, transparent, rgba(255, 255, 255, .35), transparent);
  transform: rotate(12deg); transition: left .55s ease; pointer-events: none;
}
.world-tile:hover { transform: translateY(-4px) scale(1.02); box-shadow: inset 0 2px 0 rgba(255, 255, 255, .35), inset 0 -3px 0 rgba(0, 0, 0, .18), 0 14px 26px rgba(20, 40, 25, .3); }
.world-tile:hover::after { left: 120%; }
.world-tile:active { transform: translateY(0) scale(.99); }
.world-tile .w-em { font-size: 46px; line-height: 1.15; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, .3)); animation: em-float 3.4s ease-in-out infinite; }
.world-tile .w-name { font-weight: 800; font-size: 16px; text-shadow: 0 2px 3px rgba(0, 0, 0, .3); line-height: 1.15; }
.world-tile .w-sub { font-size: 12px; color: rgba(255, 255, 255, .85); font-weight: 600; text-shadow: 0 1px 2px rgba(0, 0, 0, .3); }
.world-tile .w-dom { position: absolute; top: 9px; right: 10px; font-size: 14px; filter: drop-shadow(0 1px 2px rgba(0, 0, 0, .3)); }
.world-tile .w-stars { position: absolute; top: 9px; left: 11px; font-size: 11.5px; color: #ffe28a; text-shadow: 0 1px 2px rgba(0, 0, 0, .4); }
@keyframes tile-in { from { opacity: 0; transform: translateY(16px) scale(.94); } }
@keyframes em-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.app.reduce-motion .world-tile { animation: none; }
.app.reduce-motion .world-tile .w-em { animation: none; }

/* ---------- Region list ---------- */
/* rc.102 — A WORLD GRID THAT ALWAYS FILLS ITS LAST ROW.

   `auto-fill minmax(230px, 1fr)` produced 1, 2, 3, 4, 5 or 6 columns
   depending on the window, so NO number of activities can fill the last row
   everywhere: thirty fills a 3-, 5- or 6-column screen and leaves a two-card
   hole at four, which is what the owner saw.

   The column count is deterministic now — 1, then 2, then 4 — so every world
   holding a multiple of four fills exactly, at every width. Four columns
   start at 1024px, where a card is still 236px wide, above the 230px the
   layout was designed around. */
.region-list { display: grid; grid-template-columns: 1fr; gap: 13px; }
@media (min-width: 600px) { .region-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 1024px) { .region-list { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.region-card {
  position: relative; display: flex; gap: 12px; align-items: center; text-align: left;
  padding: 12px 14px; border-radius: 22px; border: 0;
  background: var(--card); cursor: pointer; color: var(--ink);
  box-shadow: inset 0 0 0 2px var(--wsoft, var(--card-edge)), inset 0 -3px 0 rgba(0, 0, 0, .07), 0 6px 16px rgba(30, 60, 40, .14);
  transition: transform .13s ease, box-shadow .2s ease;
  animation: tile-in .4s ease backwards;
  /* no clipping: the pulsing glow lives OUTSIDE this box */
}
.region-card::before { content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 7px; border-radius: 26px 0 0 26px; background: linear-gradient(180deg, var(--wkey, var(--accent)), var(--wdeep, var(--accent-deep))); }
.region-card:hover { transform: translateY(-3px); box-shadow: inset 0 0 0 2px var(--wkey, var(--accent)), 0 12px 22px rgba(30, 60, 40, .2); }
.region-card .r-em {
  flex-shrink: 0; width: 54px; height: 54px; border-radius: 50%; font-size: 28px;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 34% 30%, #ffffff 0%, var(--wsoft, var(--card-soft)) 55%, var(--wsoft, var(--card-soft)) 100%);
  box-shadow: inset 0 0 0 2.5px var(--wkey, var(--accent));
}
.app[data-theme="night"] .region-card .r-em { background: radial-gradient(circle at 34% 30%, var(--card-soft), var(--card)); }
.region-card .r-name { font-weight: 800; font-size: 16px; color: var(--wdeep, var(--ink)); }
.app[data-theme="night"] .region-card .r-name { color: var(--ink); }
.region-card .r-sub { font-size: 13px; color: var(--ink-soft); }
.region-card .r-stars { margin-left: auto; font-size: 13px; color: var(--gold); white-space: nowrap; }
.app.reduce-motion .region-card { animation: none; }

/* ---------- Play screen ---------- */
.play-wrap { display: flex; flex-direction: column; gap: 10px; min-height: 0; }
/* The round header is PINNED. A child who has scrolled to the answers must
   still be able to see the way out; --topbar-h is measured live so it sits
   exactly under the sticky topbar at any width or notch. */
.play-head {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  position: sticky; top: calc(var(--topbar-h, 56px) + 6px); z-index: 12;
  padding: 7px; border-radius: 16px;
  background: color-mix(in srgb, var(--bg-solid) 96%, transparent);
  backdrop-filter: blur(8px);
  box-shadow: 0 6px 16px -9px rgba(20, 40, 28, .40);
}
/* the round's way out — a real button, named for where it goes */
.play-head .ph-back {
  flex-direction: row; gap: 6px; padding: 9px 15px; min-height: 46px; border-radius: 14px;
  background: var(--btn-grad); color: var(--accent-ink); border-color: transparent;
  box-shadow: 0 2px 0 rgba(0, 0, 0, .10), 0 6px 14px rgba(20, 40, 28, .18);
}
.play-head .ph-back .ic-label {
  display: inline !important; font-size: 14px; font-weight: 800;
  max-width: 44vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Home sits beside the world button in the pinned header. Icon only, so
   the row still fits Back + title + How on a 320px phone. */
.play-head .ph-home-ic { flex-direction: row; gap: 0; padding: 9px 11px; min-height: 46px; min-width: 46px; }
.play-head .ph-home-ic .ic { font-size: 19px; }
@media (hover: hover) { .play-head .ph-back:hover { filter: brightness(1.06); } }
@media (max-width: 470px) {
  /* one tidy row: Back · title · How — with the progress vine on its own
     line beneath, instead of the How button being pushed to a second row */
  .play-head { gap: 6px; }
  .play-head .ph-back { padding: 8px 12px; }
  /* On a phone the row holds three real controls — leave to the world,
     Home, and How. Squeezing the region name in beside them left it three
     characters wide, which is worse than useless, so it drops down and
     shares the progress line instead. Still two rows in total. */
  .play-head .ph-title {
    order: 9; flex: 1 1 auto; min-width: 0; font-size: 13.5px; align-self: center;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; display: block;
    color: var(--ink-soft);
  }
  /* Back + Home + title + How on one phone row: the world label yields a
     little so the region name keeps enough width to be worth reading. */
  .play-head .ph-back .ic-label { max-width: 30vw; }
  .play-head .ph-back { padding: 8px 10px; }
  .play-head .ph-home-ic { padding: 9px 8px; min-width: 44px; }
  .play-head { gap: 5px; }
  .play-head .spacer { display: block; flex: 1 1 auto; }
  /* a zero-height full-width break: everything ordered after it starts a
     new line, so the controls keep line one and the region name shares
     line two with the progress vine */
  .play-head::after { content: ""; flex: 1 0 100%; height: 0; order: 8; }
  .play-head .progress-dots { order: 10; flex: 0 0 auto; }
}
/* The title is the one flexible thing in this row: it shrinks and
   ellipsises so the buttons either side of it — the world exit, Home and
   How — always stay on one line. flex-basis 0 is what stops flex-wrap
   from breaking the row before it tries to shrink. */
.play-head .ph-title {
  font-weight: 800; font-size: 17px;
  flex: 1 1 0; min-width: 0;
  display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.play-head .spacer { flex: 1; }
/* progress vine: leaves sprout as the round advances */
.progress-dots { display: flex; gap: 3px; align-items: center; background: color-mix(in srgb, var(--card) 70%, transparent); padding: 3px 8px; border-radius: 999px; box-shadow: inset 0 0 0 1px var(--card-edge); }
.progress-dots .dot { font-size: 14px; line-height: 1; filter: grayscale(1); opacity: .4; transform: scale(.8); transition: all .3s ease; }
.progress-dots .dot::before { content: "🍃"; }
.progress-dots .dot.done { filter: none; opacity: 1; transform: scale(1); }
.progress-dots .dot.now { filter: none; opacity: 1; transform: scale(1.15); animation: leaf-pulse 1.2s ease-in-out infinite; }
.progress-dots .dot.now::before { content: "🌟"; }
@keyframes leaf-pulse { 50% { transform: scale(1.35) rotate(8deg); } }
.app.reduce-motion .progress-dots .dot.now { animation: none; }

/* completion stars slam in one by one */
.finish-stars { display: flex; gap: 8px; justify-content: center; font-size: 46px; min-height: 56px; }
.finish-stars .fstar { animation: star-slam .55s cubic-bezier(.2, 1.6, .4, 1) backwards; filter: drop-shadow(0 4px 8px rgba(200, 150, 0, .4)); }
.finish-stars .fstar.off { filter: grayscale(1) opacity(.35); animation: none; }
@keyframes star-slam { from { transform: scale(2.6) rotate(-18deg); opacity: 0; } }
.app.reduce-motion .finish-stars .fstar { animation: none; }

.prompt-card {
  background: var(--card); border: 0; border-radius: 24px;
  box-shadow: inset 0 0 0 2.5px var(--wsoft, var(--card-edge)), 0 0 0 1px var(--card-edge), 0 8px 22px rgba(30, 60, 40, .15), 0 0 24px var(--wsoft, transparent);
  padding: 14px 16px;
  display: flex; align-items: center; gap: 10px;
  border-top: 3px solid var(--wkey, var(--accent));
}
.prompt-card .p-text { font-size: clamp(18px, 4.5vw, 24px); font-weight: 800; flex: 1; line-height: 1.3; }
.prompt-card .p-say { flex-shrink: 0; }

.stimulus {
  display: flex; align-items: center; justify-content: center; flex-wrap: wrap; gap: 10px;
  min-height: 88px; padding: 14px 10px;
  border-radius: 22px;
  background: radial-gradient(ellipse at 50% 20%, color-mix(in srgb, #ffffff 65%, var(--card-soft)), var(--card-soft) 75%);
  border: 0;
  box-shadow: inset 0 3px 10px rgba(30, 60, 40, .1), inset 0 0 0 1.5px var(--card-edge);
  font-size: clamp(48px, 14vw, 92px); text-align: center; line-height: 1.15; letter-spacing: .08em;
  max-width: 100%; overflow-wrap: anywhere;
}
.app[data-theme="night"] .stimulus { background: radial-gradient(ellipse at 50% 20%, color-mix(in srgb, #ffffff 7%, var(--card-soft)), var(--card-soft) 75%); }
.stimulus > * { max-width: 100%; min-width: 0; }
/* rc.84 (CA-007): a countable stimulus is a row of separately named objects
   rather than one string, so it wraps like the string did and keeps the same
   size. Nothing here changes what a sighted child sees. */
.stim-countable { display: inline; }
.stim-countable > span { display: inline; }
/* rc.142 CA-RC141-038: Matching Marsh cards draw their group as separate,
   named pictures, wrapped inside the card. */
.dm-card .dm-countable { display: flex; flex-wrap: wrap; justify-content: center; gap: 2px; max-width: 100%; }
.dm-card .dm-countable > span { display: inline-flex; font-size: clamp(20px, 5.5vw, 28px); line-height: 1; }
.dm-card .dm-countable .pw-art { width: clamp(20px, 5.5vw, 28px); height: clamp(20px, 5.5vw, 28px); }
/* rc.144 CA-RC141-038: the countable group sits in the card wrapper; the
   button is a transparent hit layer over it, so drops land anywhere on the
   card and the objects stay outside the button for assistive technology. */
.dm-card-wrap { position: relative; padding-bottom: 34px; }
.dm-card-wrap .dm-card-hit { position: absolute; inset: 0; min-height: 0; padding: 0; background: transparent; border-color: transparent; box-shadow: none; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; }
.dm-card-wrap .dm-card-hit.target { border-color: var(--accent); }
.dm-card-wrap .dm-card-hit.dm-done { background: color-mix(in srgb, var(--gold-soft, #fff3c4) 70%, transparent); }
.dm-card-wrap .dm-card-hit .dm-placed { margin-bottom: 6px; }
.stimulus .stim-word { font-size: clamp(24px, 7vw, 40px); font-weight: 800; letter-spacing: .06em; overflow-wrap: anywhere; }
.stimulus .stim-note { font-size: 14px; color: var(--ink-faint); width: 100%; }

.choices { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); }
.choices.wide { grid-template-columns: 1fr; }
.choice-btn {
  min-height: 70px; padding: 10px 12px; border-radius: 20px;
  border: 2px solid var(--card-edge);
  background: linear-gradient(180deg, color-mix(in srgb, #ffffff 55%, var(--card)), var(--card) 55%);
  color: var(--ink);
  font-size: clamp(18px, 5vw, 26px); font-weight: 800; cursor: pointer;
  box-shadow: 0 4px 0 color-mix(in srgb, var(--wkey, var(--accent)) 35%, var(--card-edge)), 0 6px 14px rgba(30, 60, 40, .12);
  transition: transform .1s ease, box-shadow .15s ease, border-color .15s ease;
  display: flex; align-items: center; justify-content: center; gap: 10px; text-align: center;
  overflow-wrap: break-word; hyphens: none;
}
.app[data-theme="night"] .choice-btn { background: linear-gradient(180deg, color-mix(in srgb, #ffffff 9%, var(--card)), var(--card) 55%); }
.choice-btn .c-em { font-size: 1.5em; filter: drop-shadow(0 2px 3px rgba(0, 0, 0, .15)); }
/* rc.62 art pilot: drawn pictures size with the emoji they replace */
.pw-art { display: inline-block; width: 1.15em; height: 1.15em; vertical-align: -0.2em; }
.pw-art.pw-none { display: none; }   /* rc.158 CA-RC156 V02/V03: a withheld or failed picture draws nothing and leaves no gap */
.c-em.has-art { display: inline-flex; align-items: center; }
.stimulus .has-art { display: inline-flex; align-items: center; justify-content: center; }
.stimulus .pw-art.stim-art { width: 1.2em; height: 1.2em; vertical-align: middle; }
.choice-btn.em-only { min-height: 88px; }
.choice-btn.em-only .c-em { font-size: clamp(44px, 11vw, 64px); }
.choice-btn:hover { border-color: var(--wkey, var(--accent)); box-shadow: 0 4px 0 var(--wkey, var(--accent)), 0 8px 18px rgba(30, 60, 40, .18), 0 0 16px var(--wsoft, transparent); }
.choice-btn:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--wkey, var(--accent)); }
.choice-btn.correct { animation: correct-pop .5s ease; }
@keyframes correct-pop { 30% { transform: scale(1.07); } 60% { transform: scale(.98); } }
.app.reduce-motion .choice-btn.correct { animation: none; }
.choice-btn.correct { border-color: var(--leaf); background: color-mix(in srgb, var(--leaf) 18%, var(--card)); box-shadow: 0 0 0 3px color-mix(in srgb, var(--leaf) 60%, transparent), var(--shadow-soft); }
.choice-btn.incorrect { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, var(--card)); }
/* Ruled out: it must LOOK spent, so a child doesn't keep aiming at it.
   It stays tappable on purpose — a tap gets a shake and a word back
   rather than the silence that reads as a broken game. */
.choice-btn.out {
  cursor: default; filter: grayscale(.45); opacity: .62;
  box-shadow: none !important;
  position: relative; border-style: dashed;          /* rc.61 (4.6): "already tried", not "broken" */
}
.choice-btn.out .c-em { opacity: .6; }
/* the ghost mark: a small quiet tag in the corner, so a faded card reads as
   one the child has ALREADY TRIED — visibly different from a plain disabled
   card and from a broken one, at 320px, day and night */
.choice-btn.out::after {
  content: "tried"; position: absolute; top: 4px; right: 6px;
  font-size: 11px; line-height: 1; font-weight: 700; letter-spacing: .04em; text-transform: lowercase;
  padding: 3px 7px; border-radius: 999px;
  background: var(--card-edge); color: var(--ink-soft);
  pointer-events: none;
}
.choice-btn.out:hover { border-color: var(--danger); box-shadow: none; }
.choice-btn.out:active { transform: none; }
/* tapped again: a gentle wobble, never a violent shake */
@keyframes shakeOut {
  0%, 100% { transform: translateX(0) rotate(0); }
  25% { transform: translateX(-3px) rotate(-1.5deg); }
  50% { transform: translateX(3px) rotate(1.5deg); }
  75% { transform: translateX(-2px) rotate(-.8deg); }
}
.choice-btn.shake-out { animation: shakeOut .38s ease; }
.app.reduce-motion .choice-btn.shake-out { animation: none; }
@media (prefers-reduced-motion: reduce) { .choice-btn.shake-out { animation: none; } }
.choice-btn.dim { opacity: .45; }
.choice-btn.selected { border-color: var(--gold); box-shadow: 0 0 0 3px color-mix(in srgb, var(--gold) 55%, transparent); }
.choice-btn:disabled { cursor: default; }

/* The action row is a GRID, so every button in it lines up — same width,
   same height, same edges — instead of a ragged flex row whose widths are
   set by how long each label happens to be. */
.play-actions {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(148px, 1fr));
  gap: 10px; align-items: stretch;
}
.play-actions > .btn {
  width: 100%; min-height: 48px;
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* an odd one out fills its row rather than leaving a hole beside it */
.play-actions > .btn:last-child:nth-child(odd) { grid-column: 1 / -1; }
/* setting display on the buttons beats the [hidden] attribute, which would
   otherwise leave the un-offered Clear button sitting in the grid as an
   invisible, zero-height hole between two real controls */
.play-actions > .btn[hidden] { display: none; }
.play-actions .spacer { display: none; }
@media (min-width: 700px) {
  .play-actions { grid-template-columns: repeat(auto-fit, minmax(160px, 190px)); justify-content: start; }
  .play-actions > .btn:last-child:nth-child(odd) { grid-column: auto; }
}
/* The second exit, beside the help button. It names its world like the
   pinned one at the top, and truncates rather than wrapping the row. */
/* the grid sizes it now; the label ellipsises if a world name is long */
.play-actions .ph-exit { min-width: 0; }
/* Hint and Weetik & Beetik are help — they stay the filled green pair.
   Leaving is a different kind of action, so it keeps the row's rounded glow
   but wears the card colour instead of joining the greens. The day pass
   re-applies the button gradient through background-image, so day is
   matched explicitly rather than left to lose on specificity. */
.play-actions .ph-exit,
.app[data-theme="day"] .play-actions .ph-exit {
  background: var(--card); background-image: none; color: var(--ink);
}

.feedback-line { min-height: 30px; font-weight: 800; font-size: 17px; display: flex; align-items: center; gap: 8px; }
.feedback-line.good { color: var(--leaf); }
.feedback-line.try { color: var(--ink-soft); }

/* build-a-word slots */
.slot-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.slot {
  min-width: 54px; height: 60px; border-radius: 14px;
  border: 2px dashed var(--ink-faint); background: var(--card);
  display: flex; align-items: center; justify-content: center;
  font-size: 28px; font-weight: 800;
}
.slot.filled { border-style: solid; border-color: var(--accent); }
.token-tray { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; }
.token {
  min-width: 54px; min-height: 56px; padding: 6px 12px; border-radius: 14px;
  border: 2px solid var(--card-edge); background: var(--card); color: var(--ink);
  font-size: 26px; font-weight: 800; cursor: pointer; box-shadow: 0 3px 0 var(--card-edge);
}
.token:disabled { opacity: .35; }
.token:hover { border-color: var(--accent); }

/* number line */
.numline { display: flex; gap: 4px; justify-content: center; flex-wrap: wrap; padding: 8px 0; }
.numline button {
  min-width: 44px; min-height: 52px; border-radius: 12px; font-size: 19px; font-weight: 800;
  border: 2px solid var(--card-edge); background: var(--card); color: var(--ink); cursor: pointer;
}
.numline button.mark { border-color: var(--gold); background: var(--gold-soft); }
.numline button.picked { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 20%, var(--card)); }

/* counting objects */
.count-field { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; padding: 6px; font-size: 50px; }
.count-item { cursor: pointer; border: none; background: none; font-size: inherit; line-height: 1; padding: 4px; border-radius: 12px; transition: transform .12s ease, opacity .2s; }
.count-item.counted { transform: scale(.92); opacity: .5; }
.count-item:focus-visible { outline: 3px solid var(--focus); }

/* trace canvas */
.trace-box { position: relative; margin: 0 auto; max-width: 340px; width: 100%; }
.trace-box canvas { width: 100%; border-radius: 20px; border: 2px solid var(--card-edge); background: var(--card); touch-action: none; display: block; }
.trace-guide { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; font-size: 160px; color: color-mix(in srgb, var(--ink) 14%, transparent); font-weight: 800; }

/* rc.160 (replay finding 2): a map is drawn as rows and columns */
.stim-grid { display: inline-flex; flex-direction: column; gap: 6px; }
.stim-grid-row { display: flex; gap: 6px; justify-content: center; }
.stim-grid .sg-cell { width: calc(var(--pic-md) + 6px); height: calc(var(--pic-md) + 6px); display: flex; align-items: center; justify-content: center; border-radius: 12px; background: var(--card); border: 2px solid var(--card-edge); font-weight: 800; font-size: 24px; }
.stim-grid .sg-cell .pw-art { width: var(--pic-md); height: var(--pic-md); }
/* pattern tiles */
.pattern-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; font-size: 34px; align-items: center; }
.pattern-row .p-cell { width: calc(var(--pic-md) + 10px); height: calc(var(--pic-md) + 10px); display: flex; align-items: center; justify-content: center; border-radius: 14px; background: var(--card); border: 2px solid var(--card-edge); }
.pattern-row .p-cell.blank { border-style: dashed; color: var(--ink-faint); font-size: 22px; }
/* rc.160 (replay finding 3): a cell holding a group grows to fit it, and its pieces wrap instead of spilling */
.pattern-row .p-cell.multi { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); min-height: calc(var(--pic-md) + 10px); max-width: 140px; padding: 6px; }
.p-group { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; align-items: center; max-width: 126px; }
.p-group .p-piece { display: inline-flex; align-items: center; justify-content: center; font-size: 20px; line-height: 1; }
.p-group .p-art-sm { width: 24px; height: 24px; }
.choice-btn.multi { padding: 8px 10px; }
@media (max-width: 380px) { .pattern-row .p-cell.multi { max-width: 108px; } .p-group { max-width: 96px; } }
/* rc.159 (review LQ01): an ordered-row cell holds picture + words + position, and wraps on a phone */
.pattern-row .p-cell.seq-cell { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); max-width: 150px; min-height: calc(var(--pic-md) + 10px); padding: 6px 8px; flex-direction: column; gap: 3px; position: relative; font-size: 28px; }
.pattern-row .p-cell.seq-cell .seq-pic { display: inline-flex; align-items: center; justify-content: center; }
.pattern-row .p-cell.seq-cell .seq-label { font-size: 13px; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink); overflow-wrap: anywhere; }
.pattern-row .p-cell.seq-cell .seq-n { position: absolute; top: 2px; left: 6px; font-size: 10.5px; font-weight: 800; color: var(--ink-faint); }
@media (max-width: 380px) { .pattern-row .p-cell.seq-cell { max-width: 120px; } }
/* rc.160 (replay finding 3): a cell holding a group grows to fit it, and its pieces wrap instead of spilling */
.pattern-row .p-cell.multi { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); min-height: calc(var(--pic-md) + 10px); max-width: 140px; padding: 6px; }
.p-group { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; align-items: center; max-width: 126px; }
.p-group .p-piece { display: inline-flex; align-items: center; justify-content: center; font-size: 20px; line-height: 1; }
.p-group .p-art-sm { width: 24px; height: 24px; }
.choice-btn.multi { padding: 8px 10px; }
@media (max-width: 380px) { .pattern-row .p-cell.multi { max-width: 108px; } .p-group { max-width: 96px; } }
/* rc.159 (review LQ01): an ordered-row cell holds picture + words + position, and wraps on a phone */
.pattern-row .p-cell.seq-cell { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); max-width: 150px; min-height: calc(var(--pic-md) + 10px); padding: 6px 8px; flex-direction: column; gap: 3px; position: relative; font-size: 28px; }
.pattern-row .p-cell.seq-cell .seq-pic { display: inline-flex; align-items: center; justify-content: center; }
.pattern-row .p-cell.seq-cell .seq-label { font-size: 13px; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink); overflow-wrap: anywhere; }
.pattern-row .p-cell.seq-cell .seq-n { position: absolute; top: 2px; left: 6px; font-size: 10.5px; font-weight: 800; color: var(--ink-faint); }
@media (max-width: 380px) { .pattern-row .p-cell.seq-cell { max-width: 120px; } }
/* rc.160 (replay finding 3): a cell holding a group grows to fit it, and its pieces wrap instead of spilling */
.pattern-row .p-cell.multi { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); min-height: calc(var(--pic-md) + 10px); max-width: 140px; padding: 6px; }
.p-group { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; align-items: center; max-width: 126px; }
.p-group .p-piece { display: inline-flex; align-items: center; justify-content: center; font-size: 20px; line-height: 1; }
.p-group .p-art-sm { width: 24px; height: 24px; }
.choice-btn.multi { padding: 8px 10px; }
@media (max-width: 380px) { .pattern-row .p-cell.multi { max-width: 108px; } .p-group { max-width: 96px; } }
/* rc.159 (review LQ01): an ordered-row cell holds picture + words + position, and wraps on a phone */
.pattern-row .p-cell.seq-cell { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); max-width: 150px; min-height: calc(var(--pic-md) + 10px); padding: 6px 8px; flex-direction: column; gap: 3px; position: relative; font-size: 28px; }
.pattern-row .p-cell.seq-cell .seq-pic { display: inline-flex; align-items: center; justify-content: center; }
.pattern-row .p-cell.seq-cell .seq-label { font-size: 13px; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink); overflow-wrap: anywhere; }
.pattern-row .p-cell.seq-cell .seq-n { position: absolute; top: 2px; left: 6px; font-size: 10.5px; font-weight: 800; color: var(--ink-faint); }
@media (max-width: 380px) { .pattern-row .p-cell.seq-cell { max-width: 120px; } }
/* rc.160 (replay finding 3): a cell holding a group grows to fit it, and its pieces wrap instead of spilling */
.pattern-row .p-cell.multi { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); min-height: calc(var(--pic-md) + 10px); max-width: 140px; padding: 6px; }
.p-group { display: flex; flex-wrap: wrap; gap: 2px; justify-content: center; align-items: center; max-width: 126px; }
.p-group .p-piece { display: inline-flex; align-items: center; justify-content: center; font-size: 20px; line-height: 1; }
.p-group .p-art-sm { width: 24px; height: 24px; }
.choice-btn.multi { padding: 8px 10px; }
@media (max-width: 380px) { .pattern-row .p-cell.multi { max-width: 108px; } .p-group { max-width: 96px; } }
/* rc.159 (review LQ01): an ordered-row cell holds picture + words + position, and wraps on a phone */
.pattern-row .p-cell.seq-cell { width: auto; height: auto; min-width: calc(var(--pic-md) + 10px); max-width: 150px; min-height: calc(var(--pic-md) + 10px); padding: 6px 8px; flex-direction: column; gap: 3px; position: relative; font-size: 28px; }
.pattern-row .p-cell.seq-cell .seq-pic { display: inline-flex; align-items: center; justify-content: center; }
.pattern-row .p-cell.seq-cell .seq-label { font-size: 13px; font-weight: 800; line-height: 1.15; text-align: center; color: var(--ink); overflow-wrap: anywhere; }
.pattern-row .p-cell.seq-cell .seq-n { position: absolute; top: 2px; left: 6px; font-size: 10.5px; font-weight: 800; color: var(--ink-faint); }
@media (max-width: 380px) { .pattern-row .p-cell.seq-cell { max-width: 120px; } }
/* rc.113: a pattern cell that draws a real picture. Sized inside the 56px
   cell the glyph already used, so a pattern of pictures and letters still
   lines up as one row. */
.pattern-row .p-cell.has-art .pw-art { width: var(--pic-md); height: var(--pic-md); }
/* rc.118: the SAME tile inside an answer button. The pattern row and the
   options below it drew the same object two different ways — the row a
   picture, the button a glyph — so the button now carries a p-cell of its
   own, one size down because it sits inside a tappable target. */
.choice-btn .p-cell { width: calc(var(--pic-md) + 8px); height: calc(var(--pic-md) + 8px); display: flex; align-items: center; justify-content: center; }
.choice-btn .p-cell.has-art .pw-art { width: var(--pic-md); height: var(--pic-md); vertical-align: middle; }

/* memory grid */
.mem-grid { display: grid; gap: 10px; justify-content: center; grid-template-columns: repeat(var(--mem-cols, 4), minmax(56px, 76px)); }
.mem-card {
  aspect-ratio: 1; border-radius: 16px; border: 2px solid var(--card-edge);
  background: var(--btn-grad); cursor: pointer; font-size: 30px;
  display: flex; align-items: center; justify-content: center; color: transparent;
  transition: transform .25s ease, background .2s ease;
}
.mem-card.open { background: var(--card); color: var(--ink); transform: rotateY(180deg); font-size: 34px; }
.mem-card.matched { background: var(--gold-soft); color: var(--ink); border-color: var(--gold); cursor: default; }
/* rc.113: the cards now turn over onto real pictures. A face-down card hides
   its text with `color: transparent`, which an <img> would ignore completely —
   so the picture is hidden explicitly as well. The renderer already removes
   the face when a card flips back, and this is the second lock on it: a memory
   game that shows one card through its back is not a memory game. */
.mem-card .pw-art { width: 72%; height: 72%; }
.mem-card:not(.open):not(.matched) .pw-art { visibility: hidden; }
/* rc.142 CA-RC141-033: a labelled face — picture with its name under it. */
.mem-card .mem-face { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px; width: 100%; height: 100%; }
.mem-card .mem-face .pw-art { width: 58%; height: 58%; }
.mem-card .mem-face-label { font-size: clamp(10px, 2.6vw, 13px); font-weight: 700; line-height: 1.1; text-align: center; padding: 0 3px; overflow-wrap: anywhere; }
.mem-card:not(.open):not(.matched) .mem-face-label { visibility: hidden; }

/* sort bins */
.bin-row { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); }
.bin {
  min-height: 96px; border-radius: 18px; border: 2px dashed var(--ink-faint);
  background: var(--card-soft); padding: 8px; text-align: center;
}
.bin.target { border-color: var(--accent); box-shadow: var(--glow); }
.bin .bin-label { font-weight: 800; font-size: 15px; margin-bottom: 4px; display: flex; align-items: center; justify-content: center; gap: 5px; }
.bin .bin-items { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; font-size: 30px; }
/* rc.118: the bin's own mark, and the things dropped into it, now draw the
   bundled picture like the tokens they came from. The tally stays small —
   it is a record of what is already sorted, not the thing being looked at. */
.bin .bin-label { flex-wrap: wrap; }
/* rc.130: the bin label is what a child must recognise BEFORE they can
   sort into it. It was 22px against 88px tokens. The bin grid is
   minmax(130px), so --pic-sm fits with room for the placed items. */
.bin .bin-label .bin-em { font-size: 17px; line-height: 1; display: inline-flex; align-items: center; }
.bin .bin-label .bin-em .pw-art { width: var(--pic-sm); height: var(--pic-sm); vertical-align: middle; }
.bin .bin-items .has-art { display: inline-flex; align-items: center; }
.bin .bin-items .has-art .pw-art { width: calc(var(--pic-sm) * 0.72); height: calc(var(--pic-sm) * 0.72); vertical-align: middle; }

/* scenario/story */
.story-panel { font-size: clamp(17px, 4.2vw, 21px); line-height: 1.65; }
.story-panel .story-scene { font-size: 42px; text-align: center; margin: 6px 0; }

/* drawing studio */
.draw-tools { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; justify-content: center; }
.draw-tools .swatch { width: 44px; height: 44px; border-radius: 50%; border: 3px solid var(--card); box-shadow: 0 0 0 2px var(--card-edge); cursor: pointer; }
.draw-tools .swatch[aria-pressed="true"] { box-shadow: 0 0 0 3px var(--focus); }
.draw-box canvas { width: 100%; border-radius: 20px; border: 2px solid var(--card-edge); background: #fff; touch-action: none; display: block; }

/* ---------- Mascots ---------- */
.mascot-stage {
  position: fixed; right: 8px; bottom: 58px; z-index: 20; pointer-events: none;
  display: flex; align-items: flex-end; gap: 4px;
  padding: 0 4px;
}
.mascot { position: relative; transform-origin: bottom center; }
.mascot .m-idle { transform-origin: bottom center; }
.mascot img { display: block; width: auto; object-fit: contain; filter: drop-shadow(0 5px 10px rgba(0, 0, 0, .28)); transition: height .5s ease; }
.app[data-theme="night"] .mascot img { filter: drop-shadow(0 0 12px rgba(180, 255, 200, .4)) drop-shadow(0 5px 10px rgba(0, 0, 0, .5)); }
.mascot .m-burst { position: absolute; top: -16px; left: 50%; transform: translateX(-50%); font-size: 24px; opacity: 0; z-index: 2; }

/* emote bubble — small expression crops at native size, above the head */
.m-emote {
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%);
  background: var(--card); border: 2px solid var(--card-edge); border-radius: 16px;
  padding: 5px 7px 3px; box-shadow: var(--shadow-soft); z-index: 3; white-space: nowrap;
}
.m-emote::after {
  content: ""; position: absolute; top: 100%; left: 50%; transform: translateX(-50%);
  border: 7px solid transparent; border-top-color: var(--card-edge);
}
.m-emote img { display: block; width: auto; }
.m-emote.pop { animation: emote-pop .35s ease; }
@keyframes emote-pop { 0% { transform: translateX(-50%) scale(.4); opacity: 0; } 70% { transform: translateX(-50%) scale(1.1); } 100% { transform: translateX(-50%) scale(1); opacity: 1; } }
.app.reduce-motion .m-emote.pop { animation: none; }

/* always-on idle life — each in character */
.m-weetik .m-idle { animation: idle-weetik 1.5s ease-in-out infinite; }
.m-beetik .m-idle { animation: idle-beetik 4.2s ease-in-out infinite; }
@keyframes idle-weetik {
  0%, 100% { transform: translateY(0) rotate(0); }
  30% { transform: translateY(-5px) rotate(-1.5deg); }
  55% { transform: translateY(0) scale(1.02, .97); }
  75% { transform: translateY(-2px) rotate(1deg); }
}
@keyframes idle-beetik {
  0%, 100% { transform: rotate(0) scale(1); }
  35% { transform: rotate(-1.6deg) scale(1.015, .99); }
  70% { transform: rotate(1.2deg); }
}
.app.reduce-motion .m-weetik .m-idle, .app.reduce-motion .m-beetik .m-idle { animation: none; }

/* reactions & ambient moves */
.mascot.celebrate-w { animation: weetik-cheer .9s ease 2; }
.mascot.big-cheer-w { animation: weetik-big-cheer .85s ease 3; }
.mascot.celebrate-b { animation: beetik-nod 1.2s ease 1; }
.mascot.sad-support { animation: lean-in .8s ease 1; }
.mascot.hop { animation: weetik-hop .7s ease 1; }
.mascot.dash-w { animation: weetik-dash 1.5s ease 1; }
.mascot.wiggle-w { animation: weetik-wiggle .7s ease 1; }
.mascot.inspect { animation: beetik-inspect 1.5s ease 1; }
.mascot.burst .m-burst { animation: burst-pop 1s ease 1; }
@keyframes weetik-cheer {
  0% { transform: translateY(0); }
  20% { transform: translateY(-22px) rotate(-7deg); }
  45% { transform: translateY(0) scale(1.06, .9); }
  55% { transform: translateY(0) scale(1); }
  72% { transform: translateY(-14px) rotate(6deg); }
  100% { transform: translateY(0); }
}
@keyframes weetik-big-cheer {
  0% { transform: translateY(0); }
  22% { transform: translateY(-30px) rotate(-9deg) scale(1.05); }
  46% { transform: translateY(0) scale(1.1, .86); }
  56% { transform: translateY(0) scale(1); }
  74% { transform: translateY(-18px) rotate(8deg); }
  100% { transform: translateY(0); }
}
@keyframes weetik-hop { 30% { transform: translateY(-16px) rotate(-3deg); } 60% { transform: translateY(0) scale(1.05, .93); } 100% { transform: translateY(0); } }
@keyframes weetik-dash {
  0% { transform: translateX(0); }
  25% { transform: translateX(-30px) translateY(-10px) rotate(-5deg); }
  50% { transform: translateX(-44px) translateY(0); }
  75% { transform: translateX(-14px) translateY(-8px) rotate(4deg); }
  100% { transform: translateX(0); }
}
@keyframes weetik-wiggle { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-6deg); } 50% { transform: rotate(5deg); } 75% { transform: rotate(-3deg); } }
@keyframes beetik-nod { 0% { transform: rotate(0); } 30% { transform: rotate(-5deg) translateY(3px); } 60% { transform: rotate(3deg); } 100% { transform: rotate(0); } }
@keyframes beetik-inspect { 0% { transform: translateX(0); } 30% { transform: translateX(-9px) rotate(-5deg); } 70% { transform: translateX(6px) rotate(4deg); } 100% { transform: translateX(0); } }
@keyframes lean-in { 40% { transform: rotate(-4deg) translateX(-5px); } 100% { transform: none; } }
@keyframes burst-pop { 10% { opacity: 1; transform: translateX(-50%) translateY(-8px) scale(1.3); } 90% { opacity: 1; } 100% { opacity: 0; transform: translateX(-50%) translateY(-26px) scale(.8); } }
.app.reduce-motion .mascot { animation: none !important; }

/* ---------- center-stage celebrations ---------- */
.celebrate-layer {
  position: fixed; inset: 0; z-index: 55; pointer-events: none;
  display: flex; align-items: center; justify-content: center; gap: 26px;
  opacity: 0; transition: opacity .2s ease;
}
.celebrate-layer.show { opacity: 1; }
.cs-char { position: relative; transform-origin: bottom center; }
.cs-char img { display: block; width: auto; object-fit: contain; filter: drop-shadow(0 10px 20px rgba(0, 0, 0, .3)); }
.app[data-theme="night"] .cs-char img { filter: drop-shadow(0 0 18px rgba(180, 255, 200, .5)) drop-shadow(0 10px 20px rgba(0, 0, 0, .5)); }
.cs-w { animation: cs-leap-left .5s ease, cs-bounce .55s ease .5s infinite; }
.cs-b { animation: cs-leap-right .55s ease, cs-nod 1s ease .55s infinite; }
.cs-spark { position: absolute; font-size: 26px; animation: cs-spark 1s ease infinite; }
@keyframes cs-leap-left { from { transform: translate(-46vw, 30vh) scale(.5) rotate(-14deg); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cs-leap-right { from { transform: translate(46vw, 30vh) scale(.5) rotate(12deg); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes cs-bounce { 0%, 100% { transform: translateY(0); } 40% { transform: translateY(-26px) rotate(-4deg); } 70% { transform: translateY(0) scale(1.06, .92); } }
@keyframes cs-nod { 0%, 100% { transform: rotate(0); } 35% { transform: rotate(-4deg) translateY(3px); } 70% { transform: rotate(3deg); } }
@keyframes cs-spark { 0% { transform: translateY(0) scale(.7); opacity: 0; } 30% { opacity: 1; } 100% { transform: translateY(-42px) scale(1.25); opacity: 0; } }
.app.reduce-motion .cs-w, .app.reduce-motion .cs-b { animation: none; }
.app.reduce-motion .cs-spark { animation: none; opacity: .9; }

/* during rounds the stage steps back and content reserves room below */
.app.in-round .main { padding-bottom: 150px; }
/* An activity is a focused space. The site footer is app chrome — brand
   line, slogan, Privacy and Terms — and it has no business sitting under
   something a child is doing: a question, a drawing, a tune, a story, the
   rules of a game. .in-activity is set by the router for every one of
   those screens; .in-round stays as a belt-and-braces for anything that
   enters play mode without a matching route. Both links come straight
   back on every browsing screen. */
.app.in-activity .site-footer,
.app.in-round .site-footer { display: none; }
.app.in-round .mascot-stage { bottom: 52px; opacity: .96; }
/* On a phone the fixed bottom nav (rc.27) sits where Weetik & Beetik stand,
   so they were being covered. Lift the stage clear of the bar — in a round
   the bar is hidden, and the .app.in-round rule above still applies. */
@media (max-width: 599px) {
  .mascot-stage { bottom: calc(82px + env(safe-area-inset-bottom)); }
}

.m-pop { animation: idle-weetik 1.6s ease-in-out infinite; transform-origin: bottom center; filter: drop-shadow(0 5px 10px rgba(0,0,0,.25)); }
.app.reduce-motion .m-pop { animation: none; }

/* Welcome hero — the live duo */
.hero-duo { display: flex; justify-content: center; align-items: flex-end; gap: 10px; margin: 8px 0; min-height: 160px; }
.hero-duo img { display: block; width: auto; filter: drop-shadow(0 8px 16px rgba(0, 0, 0, .25)); transition: height .3s ease; }
.hero-char { transform-origin: bottom center; }
.hero-w { animation: idle-weetik 1.5s ease-in-out infinite, hero-hop 5s ease-in-out infinite; }
.hero-b { animation: idle-beetik 4.2s ease-in-out infinite; }
@keyframes hero-hop { 0%, 88%, 100% { transform: translateY(0); } 92% { transform: translateY(-18px) rotate(-4deg); } 96% { transform: translateY(0) scale(1.06, .92); } }
.app.reduce-motion .hero-w, .app.reduce-motion .hero-b { animation: none; }

/* ---------- Tree ---------- */
.tree-scene { position: relative; display: flex; flex-direction: column; align-items: center; padding: 12px 0 0; }
.tree-svg { width: min(320px, 78vw); height: auto; }
.tree-stage-label { font-weight: 800; font-size: 19px; margin-top: 4px; }
.growth-bar { width: min(320px, 78vw); height: 14px; border-radius: 999px; background: var(--card-edge); overflow: hidden; margin-top: 6px; }
.growth-bar > div { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--leaf), var(--gold)); transition: width .8s ease; }

/* ---------- Modal ---------- */
.modal-veil { position: fixed; inset: 0; z-index: 60; background: rgba(8, 20, 12, .55); display: flex; align-items: center; justify-content: center; padding: 14px; }
.modal {
  width: 100%; max-width: 520px; max-height: min(86vh, 86dvh); overflow: auto;
  background: var(--card); color: var(--ink); border-radius: 24px; border: 1px solid var(--card-edge);
  box-shadow: var(--shadow); padding: 18px;
}
.modal h2 { display: flex; align-items: center; gap: 8px; }
.modal .modal-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: flex-end; margin-top: 14px; }

/* ---------- Toast / caption ---------- */
.toast-zone { position: fixed; left: 50%; bottom: 84px; transform: translateX(-50%); z-index: 70; display: flex; flex-direction: column; gap: 8px; align-items: center; width: max-content; max-width: 92vw; pointer-events: none; }
.toast {
  background: var(--card); color: var(--ink); border: 1px solid var(--card-edge);
  border-radius: 16px; padding: 10px 18px; font-weight: 800; box-shadow: var(--shadow);
  display: flex; gap: 8px; align-items: center; animation: toast-in .3s ease;
  max-width: 92vw;
}
.toast.reward { border-color: var(--gold); box-shadow: 0 0 14px rgba(240, 200, 70, .5), var(--shadow-soft); }
@keyframes toast-in { from { opacity: 0; transform: translateY(10px); } }
.caption-bar {
  position: fixed; left: 50%; bottom: 46px; transform: translateX(-50%); z-index: 65;
  max-width: min(680px, 94vw); background: rgba(10, 22, 14, .88); color: #fff;
  padding: 8px 16px; border-radius: 14px; font-size: 16px; font-weight: 600; text-align: center;
}

/* ---------- Settings / parent ---------- */
.setting-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--card-edge); flex-wrap: wrap; }
.setting-row:last-child { border-bottom: 0; }
.setting-row label { font-weight: 700; }
.setting-row .hint { display: block; font-size: 13px; color: var(--ink-faint); font-weight: 400; }
input[type="range"] { width: 150px; accent-color: var(--accent); min-height: 44px; }
select, input[type="text"], input[type="number"] {
  font: inherit; padding: 10px 12px; border-radius: 12px; border: 2px solid var(--card-edge);
  background: var(--card); color: var(--ink); min-height: 48px; max-width: 100%;
}
.switch { position: relative; display: inline-block; width: 62px; height: 36px; flex-shrink: 0; }
.switch input { opacity: 0; width: 62px; height: 36px; margin: 0; cursor: pointer; position: absolute; z-index: 2; }
.switch .knob { position: absolute; inset: 0; border-radius: 999px; background: var(--card-edge); transition: background .2s; }
.switch .knob::after { content: ""; position: absolute; top: 4px; left: 4px; width: 28px; height: 28px; border-radius: 50%; background: #fff; transition: left .2s; box-shadow: 0 1px 4px rgba(0, 0, 0, .3); }
.switch input:checked + .knob { background: var(--accent); }
.switch input:checked + .knob::after { left: 30px; }
.switch input:focus-visible + .knob { outline: 3px solid var(--focus); outline-offset: 2px; }

/* profile chips */
.profile-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); gap: 12px; }
.profile-chip {
  display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 14px 8px;
  border-radius: 20px; border: 2px solid var(--card-edge); background: var(--card); cursor: pointer;
  font-weight: 800; color: var(--ink); box-shadow: var(--shadow-soft);
}
.profile-chip .pc-av { font-size: 44px; }
.profile-chip:hover { border-color: var(--accent); box-shadow: var(--glow); }

/* how-to-play */
.htp-step { display: flex; gap: 12px; align-items: flex-start; padding: 12px 0; border-bottom: 1px dashed var(--card-edge); }
.htp-step:last-child { border-bottom: 0; }
.htp-step .htp-num { flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; background: var(--accent); color: var(--accent-ink); display: flex; align-items: center; justify-content: center; font-weight: 800; }
.htp-demo { border: 2px solid var(--card-edge); border-radius: 18px; padding: 12px; background: var(--card-soft); margin-top: 8px; }
.htp-demo .demo-label { font-size: 12.5px; font-weight: 800; letter-spacing: .06em; text-transform: uppercase; color: var(--ink-faint); margin-bottom: 6px; }

/* shop */
.shop-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(130px, 1fr)); gap: 12px; }
.shop-item { text-align: center; padding: 12px 8px; border-radius: 18px; border: 2px solid var(--card-edge); background: var(--card); }
.shop-item .s-em { font-size: 40px; }
.shop-item .s-name { font-weight: 800; font-size: 14px; }
.shop-item .s-price { font-size: 14px; color: var(--ink-soft); margin: 4px 0; }
.shop-item.owned { border-color: var(--gold); background: var(--gold-soft); }
.app[data-theme="night"] .shop-item.owned { background: var(--card-soft); }

/* collection */
.badge-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 10px; }
.badge { text-align: center; padding: 10px 6px; border-radius: 16px; background: var(--card); border: 1px solid var(--card-edge); }
.badge .b-em { font-size: 34px; }
.badge .b-name { font-size: 12px; font-weight: 700; }
/* LOCKED IS A STATE, NOT A FADE (rc.46).
   Dimming the whole tile with opacity and greyscale dimmed the LABEL with
   it. On a pale day sky that left a wall of barely-readable world names —
   exactly the text a child needs most, because it tells them where to go.
   The tile now keeps its solid card and full-strength type; only the icon
   reads as not-yet-earned, and a dashed edge carries the "not yet". */
.badge.locked {
  opacity: 1; filter: none;
  background: var(--card);
  border-style: dashed;
  border-color: color-mix(in srgb, var(--ink-faint) 45%, transparent);
}
.badge.locked .b-em { opacity: .5; filter: grayscale(.85); }
.badge.locked .b-name { color: var(--ink-soft); }

/* A friend not met yet is a DOOR, not a sign with nothing behind it: the
   tile already names the world they hide in, so it goes there. */
.badge.badge-go {
  border: 1px dashed color-mix(in srgb, var(--ink-faint) 45%, transparent);
  font: inherit; color: inherit; width: 100%;
  cursor: pointer; -webkit-tap-highlight-color: transparent;
  transition: transform .14s ease, border-color .14s ease, box-shadow .14s ease;
}
.badge.badge-go .b-name { color: var(--ink); }
.badge.badge-go:active { transform: translateY(1px); }
.badge.badge-go:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
@media (hover: hover) {
  .badge.badge-go:hover {
    transform: translateY(-2px);
    border-style: solid; border-color: var(--accent);
    box-shadow: var(--shadow-soft);
  }
  .badge.badge-go:hover .b-em { opacity: 1; filter: none; }
}
.app.reduce-motion .badge.badge-go { transition: none; }

/* confetti */
.confetti { position: fixed; z-index: 80; top: -12px; font-size: 20px; pointer-events: none; animation: confetti-fall 1.6s ease-in forwards; }
@keyframes confetti-fall { to { transform: translateY(105vh) rotate(300deg); opacity: .6; } }
.app.reduce-motion .confetti, .app.reduce-effects .confetti { display: none; }

/* text sizing prefs */
.app.text-lg { font-size: 19px; }
.app.text-xl { font-size: 21px; }
.app.high-contrast { --card-edge: color-mix(in srgb, var(--ink) 55%, transparent); --ink-faint: var(--ink-soft); }

@media (max-width: 470px) {
  .icon-btn .ic-label { display: none; }
  .topbar { gap: 3px; padding-left: 5px; padding-right: 5px; }
  .topbar .icon-btn { min-width: 36px; min-height: 44px; padding: 2px; border-radius: 11px; }
  .topbar .icon-btn .ic { font-size: 17px; }
  .top-status, .top-actions { gap: 3px; }
  .pill { min-height: 30px; padding: 2px 6px; font-size: 12.5px; gap: 3px; }
  .main { padding-left: 8px; padding-right: 8px; }
  .choices { grid-template-columns: repeat(auto-fit, minmax(132px, 1fr)); }
}
@media (min-width: 760px) {
  .main { padding-top: 20px; }
}
@media print { .sky, .mascot-stage, .topbar, .toast-zone { display: none; } }

/* Play Together turn banner */
.turn-banner {
  text-align: center; font-weight: 800; font-size: 15.5px;
  padding: 8px 14px; border-radius: 999px; align-self: center;
  background: var(--card); box-shadow: inset 0 0 0 2px var(--card-edge), var(--shadow-soft);
}
.turn-banner.t1 { box-shadow: inset 0 0 0 2.5px #2e7c5c, var(--shadow-soft); }
.turn-banner.t2 { box-shadow: inset 0 0 0 2.5px #d94f5c, var(--shadow-soft); }

/* ---------- Toy House ---------- */
.toyhouse { position: relative; border-radius: 26px; overflow: hidden; box-shadow: var(--shadow); background: linear-gradient(180deg, #f8e8c8, #efd9ad); }
.app[data-theme="night"] .toyhouse { background: linear-gradient(180deg, #2a2f52, #232744); }
.th-wall { position: relative; padding: 18px 14px 0; min-height: 120px; }
.th-window { position: absolute; top: 16px; right: 18px; width: 74px; height: 74px; border-radius: 14px; border: 5px solid #a2652a;
  background: linear-gradient(180deg, var(--sky-a-w, #bfe7ff), var(--sky-b-w, #e8f8e0)); box-shadow: inset 0 0 0 2px rgba(255,255,255,.4); }
.app[data-theme="night"] .th-window { background: linear-gradient(180deg, #16213f, #241d43); }
.th-window::after { content: "☀️"; position: absolute; top: 6px; left: 8px; font-size: 18px; }
.app[data-theme="night"] .th-window::after { content: "🌙"; }
.th-shelf { display: flex; gap: 10px; flex-wrap: wrap; align-items: flex-end; min-height: 62px;
  border-bottom: 8px solid #a2652a; border-radius: 0 0 4px 4px; padding: 4px 10px 2px; margin: 6px 6px 12px; }
.app[data-theme="night"] .th-shelf { border-bottom-color: #6b4a26; }
.th-floor { position: relative; display: flex; gap: 14px; flex-wrap: wrap; align-items: flex-end; min-height: 84px;
  background: linear-gradient(180deg, #d9a45e, #c8924d); padding: 10px 16px 16px; }
.app[data-theme="night"] .th-floor { background: linear-gradient(180deg, #3a3560, #322c52); }
.th-rug { position: absolute; left: 50%; bottom: 8px; transform: translateX(-50%); width: 46%; height: 26px; border-radius: 50%;
  background: repeating-radial-gradient(ellipse at center, #ef8bb1 0 8px, #f6a9c8 8px 16px); opacity: .8; }
.th-garden { display: flex; gap: 12px; flex-wrap: wrap; align-items: flex-end;
  background: linear-gradient(180deg, #9fd489, #7bbd66); padding: 10px 16px 14px; min-height: 64px; }
.app[data-theme="night"] .th-garden { background: linear-gradient(180deg, #1e3b2f, #162c23); }
.th-toy { border: 0; background: none; font-size: 34px; line-height: 1.1; cursor: pointer; padding: 4px; border-radius: 12px;
  filter: drop-shadow(0 3px 4px rgba(0,0,0,.25)); transition: transform .12s ease; position: relative; z-index: 1; }
.th-toy:hover { transform: translateY(-4px) scale(1.1); }
.th-toy.boing { animation: th-boing .5s ease; }
@keyframes th-boing { 30% { transform: translateY(-14px) rotate(-8deg) scale(1.15); } 60% { transform: translateY(0) scale(1.05,.9); } }
.app.reduce-motion .th-toy.boing { animation: none; }
.th-empty { text-align: center; padding: 26px 14px; color: var(--ink-soft); font-weight: 600; }

/* daily gift banner */
.gift-banner { border: 2px dashed var(--gold); animation: gift-glow 2.4s ease-in-out infinite; }
@keyframes gift-glow { 50% { box-shadow: 0 0 18px rgba(240, 200, 70, .45); } }
.app.reduce-motion .gift-banner { animation: none; }

/* ---- Today: the warm welcome-back home ---- */
.today-eyebrow { font-size: 12.5px; font-weight: 800; letter-spacing: .04em; text-transform: uppercase; color: var(--accent, #2f9e57); }
.today-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
@media (max-width: 620px) { .today-grid { grid-template-columns: 1fr; } }
.today-panel { padding: 16px; }
.today-continue { justify-content: space-between; }
.today-fun-row {
  display: flex; align-items: center; gap: 10px; width: 100%; text-align: left;
  background: var(--card, #fff);
  background-image: linear-gradient(180deg, rgba(255,255,255,.55), rgba(0,0,0,.045));
  border: 1.5px solid var(--card-edge, #e2ece2); border-radius: 18px;
  padding: 11px 14px; cursor: pointer; color: var(--ink, #22302a);
  transition: transform .14s ease, box-shadow .14s ease, border-color .14s ease;
}
.app[data-theme="night"] .today-fun-row {
  background: #2b3d63; background-image: linear-gradient(180deg, rgba(255,255,255,.10), rgba(0,0,0,.16));
  border-color: #566ea6; color: var(--ink, #eaf0ff);
}
.today-fun-em { font-size: 24px; }
.today-fun-t { flex: 1; font-weight: 700; font-size: 14.5px; }
.today-fun-go { font-weight: 800; font-size: 13px; color: var(--accent, #2f9e57); white-space: nowrap; }
.today-quick { display: flex; flex-wrap: wrap; gap: 10px; }
/* Two to a row, always. The colour medallion widened the card's minimum
   content, which tipped the old 150px basis into a ragged 1 / 2 / 1
   layout on a phone. A half-width basis with min-width:0 keeps the tidy
   2-up grid and lets the names ellipsise instead of forcing a reflow. */
.today-quick > .today-qp-card { flex: 1 1 calc(50% - 5px); min-width: 0; }
.today-qp-card {
  display: flex; align-items: center; gap: 9px; text-align: left;
  background: var(--card, #fff);
  background-image: linear-gradient(180deg, rgba(255,255,255,.55), rgba(0,0,0,.045));
  border: 1.5px solid var(--card-edge, #e2ece2); border-top: 4px solid var(--qp-accent, #2f9e57);
  border-radius: 20px; padding: 12px 11px; cursor: pointer;
  transition: transform .14s ease, box-shadow .14s ease;
}
.app[data-theme="night"] .today-qp-card {
  background: #2b3d63; background-image: linear-gradient(180deg, rgba(255,255,255,.10), rgba(0,0,0,.16));
  border-color: #566ea6; border-top-color: var(--qp-accent, #2f9e57);
}
.today-qp-card .qp-em { font-size: 22px; line-height: 1; }
.today-qp-card .qp-body { display: flex; flex-direction: column; min-width: 0; }
.today-qp-card .qp-label { font-size: 11.5px; font-weight: 800; letter-spacing: .03em; text-transform: uppercase; color: var(--qp-accent, #2f9e57); }
.today-qp-card .qp-name { font-weight: 800; font-size: 15px; color: var(--ink, #22302a); overflow: hidden; white-space: normal; line-height: 1.55; }   /* rc.74 (design gate D-03): a long world name wraps to two lines instead of "Creation Mea…" */
.app[data-theme="night"] .today-qp-card .qp-name { color: var(--ink, #eaf2ea); }

/* story */
.story-chapter .story-panel { font-size: 16.5px; }
.story-locked { display: flex; gap: 12px; align-items: center; opacity: .65; padding: 12px 16px; }

/* records */
.rec-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 6px 18px; }
.rec-line { display: flex; gap: 8px; align-items: baseline; padding: 4px 0; }
.rec-line .rec-em { font-size: 18px; }
.rec-line .rec-label { color: var(--ink-soft); font-weight: 600; }
.rec-line .rec-val { margin-left: auto; font-weight: 800; }

/* living tree overlay */
.tree-scene { overflow: hidden; }
.tree-life { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.tl-flower { position: absolute; font-size: 16px; animation: tl-bloom .8s ease backwards; }
@keyframes tl-bloom { from { transform: scale(0); opacity: 0; } }
.tl-nest { position: absolute; font-size: 22px; }
.tl-butterfly { position: absolute; top: 30%; font-size: 18px; animation: tl-flutter 7s ease-in-out infinite; }
@keyframes tl-flutter {
  0%, 100% { transform: translate(0, 0) rotate(-6deg); }
  25% { transform: translate(26px, -22px) rotate(8deg); }
  50% { transform: translate(-12px, -38px) rotate(-8deg); }
  75% { transform: translate(20px, -12px) rotate(6deg); }
}
.app.reduce-motion .tl-butterfly { animation: none; }
.app.reduce-motion .tl-flower { animation: none; }

/* toy house fx */
.th-frame { position: absolute; top: 14px; left: 16px; border: 5px solid #a2652a; border-radius: 8px; background: #fff;
  padding: 2px; cursor: pointer; box-shadow: var(--shadow-soft); z-index: 1; }
.th-frame img { display: block; width: 74px; height: 52px; object-fit: cover; border-radius: 3px; }
.th-spin { animation: th-spin .9s ease; }
@keyframes th-spin { to { transform: rotate(360deg); } }
.th-launch { animation: th-launch 1.3s ease; }
@keyframes th-launch { 30% { transform: translateY(-70px) rotate(-4deg); } 60% { transform: translateY(-64px) rotate(3deg); } 100% { transform: translateY(0); } }
.th-sway { animation: th-sway 1.4s ease; }
@keyframes th-sway { 25% { transform: rotate(-12deg); } 60% { transform: rotate(10deg); } 100% { transform: rotate(0); } }
.th-rock { animation: th-rock 1.4s ease; }
@keyframes th-rock { 20% { transform: rotate(-14deg); } 45% { transform: rotate(12deg); } 70% { transform: rotate(-8deg); } 100% { transform: rotate(0); } }
.th-fish { position: absolute; left: -30px; font-size: 22px; animation: th-swim 2.4s linear forwards; pointer-events: none; }
@keyframes th-swim { to { transform: translateX(110vw); } }
.app.reduce-motion .th-spin, .app.reduce-motion .th-launch, .app.reduce-motion .th-sway, .app.reduce-motion .th-rock { animation: none; }
.app.reduce-motion .th-fish { display: none; }

/* Work it out — counters + scratch pad */
.calc-panel { background: var(--card-soft); border-radius: 20px; padding: 12px; box-shadow: inset 0 0 0 2px var(--card-edge); display: flex; flex-direction: column; gap: 10px; }
.calc-beads { display: flex; flex-direction: column; gap: 6px; min-height: 34px; }
.calc-frame { display: flex; gap: 4px; flex-wrap: wrap; padding: 4px 6px; border-radius: 10px; background: var(--card); box-shadow: inset 0 0 0 1.5px var(--card-edge); width: fit-content; max-width: 100%; }
.calc-bead { width: 26px; height: 26px; border-radius: 50%; border: 0; cursor: pointer;
  background: radial-gradient(circle at 35% 30%, #7db8f0, #2a6fc0); box-shadow: 0 2px 3px rgba(0,0,0,.25); }
.calc-bead:nth-child(5n) { margin-right: 8px; }
.calc-count { font-size: 20px; color: var(--accent-deep); }
.calc-canvas { width: 100%; max-width: 480px; border-radius: 14px; background: var(--card); box-shadow: inset 0 0 0 1.5px var(--card-edge); touch-action: none; display: block; }

/* ============================================================
   rc.6 — CELEBRATION SEQUENCER (ThinkMantis move-library port)
   Entrance → main → accent phases on the big duo; every move is a
   distinct whole-duo motion plus per-character accents. Tap skips.
   ============================================================ */
.celebrate-layer.km-party { pointer-events: auto; background: radial-gradient(ellipse at center, rgba(20, 40, 26, .18), rgba(8, 18, 11, .34)); }
.km-party-inner { display: flex; flex-direction: column; align-items: center; gap: 18px; }
.km-party .cs-duo { display: flex; align-items: flex-end; gap: 30px; position: relative; }
.km-party .cs-w, .km-party .cs-b { animation: none; }
.km-party .cs-w img { height: 210px; }
.km-party .cs-b img { height: 132px; }
@media (max-width: 480px) { .km-party .cs-w img { height: 160px; } .km-party .cs-b img { height: 101px; } }
.km-party-label {
  font-size: clamp(24px, 6vw, 40px); font-weight: 900; color: #fff; text-align: center;
  text-shadow: 0 2px 0 rgba(0,0,0,.25), 0 6px 24px rgba(0,0,0,.4);
  animation: km-label-pop .5s cubic-bezier(.2,1.6,.4,1) both .15s;
}
@keyframes km-label-pop { from { transform: scale(.4) translateY(20px); opacity: 0; } to { transform: none; opacity: 1; } }

/* ---- entrances (fire once) ---- */
.km-move-zoomin .cs-duo { animation: kmv-zoomin .8s cubic-bezier(.2,.9,.3,1) 1 both; }
@keyframes kmv-zoomin { 0% { transform: translateX(-92vw) scale(.7); } 78% { transform: translateX(3vw) scale(1.02); } 100% { transform: none; } }
.km-move-dropin .cs-duo { animation: kmv-dropin .85s cubic-bezier(.3,1.4,.5,1) 1 both; }
@keyframes kmv-dropin { 0% { transform: translateY(-88vh); } 62% { transform: translateY(0) scale(1.1,.86); } 80% { transform: translateY(-16px); } 100% { transform: none; } }
.km-move-popup .cs-duo { animation: kmv-popup .7s cubic-bezier(.2,1.7,.4,1) 1 both; }
@keyframes kmv-popup { 0% { transform: scale(0); } 70% { transform: scale(1.12); } 100% { transform: scale(1); } }
.km-move-bouncein .cs-duo { animation: kmv-bouncein .9s ease-out 1 both; }
@keyframes kmv-bouncein { 0% { transform: translateX(88vw) translateY(0); } 25% { transform: translateX(56vw) translateY(-60px); } 50% { transform: translateX(28vw) translateY(0); } 70% { transform: translateX(10vw) translateY(-34px); } 100% { transform: none; } }
.km-move-riseup .cs-duo { animation: kmv-riseup .85s cubic-bezier(.2,.9,.3,1.2) 1 both; }
@keyframes kmv-riseup { 0% { transform: translateY(70vh) scale(.8); opacity: 0; } 60% { opacity: 1; } 100% { transform: none; opacity: 1; } }
.km-move-swoosh .cs-duo { animation: kmv-swoosh .8s cubic-bezier(.3,.8,.3,1) 1 both; }
@keyframes kmv-swoosh { 0% { transform: translateX(92vw) rotate(9deg); } 70% { transform: translateX(-5vw) rotate(-4deg); } 100% { transform: none; } }
.km-move-leafswirl .cs-duo { animation: kmv-leafswirl 1s ease-in-out 1 both; }
@keyframes kmv-leafswirl { 0% { transform: rotate(-360deg) scale(.2) translateY(30vh); opacity: 0; } 55% { opacity: 1; } 100% { transform: none; opacity: 1; } }
.km-move-rollin .cs-duo { animation: kmv-rollin .9s cubic-bezier(.3,.7,.4,1) 1 both; }
@keyframes kmv-rollin { 0% { transform: translateX(-90vw) rotate(-540deg); } 85% { transform: translateX(2vw) rotate(6deg); } 100% { transform: none; } }

/* ---- dances (loop a few times; sprites flip cheer/fired in JS) ---- */
.km-move-twostep .cs-duo { animation: kmv-twostep .52s ease-in-out 4 both; }
@keyframes kmv-twostep { 0%,100% { transform: translateX(0); } 25% { transform: translateX(-18px) rotate(-5deg); } 50% { transform: translateY(-10px); } 75% { transform: translateX(18px) rotate(5deg); } }
.km-move-twostep .cs-w { animation: kmw-sway .5s ease-in-out infinite; }
.km-move-twostep .cs-b { animation: kmb-hop .55s ease-in-out infinite; }
.km-move-sidestep .cs-duo { animation: kmv-sidestep .7s ease-in-out 3 both; }
@keyframes kmv-sidestep { 0%,100% { transform: translateX(-26px); } 50% { transform: translateX(26px); } }
.km-move-sidestep .cs-w { animation: kmw-tilt .68s ease-in-out infinite; }
.km-move-sidestep .cs-b { animation: kmb-tilt .68s ease-in-out infinite reverse; }
.km-move-bouncegroove .cs-duo { animation: kmv-bouncegroove .48s ease-in-out 4 both; }
@keyframes kmv-bouncegroove { 0%,100% { transform: translateY(0) scale(1); } 45% { transform: translateY(-24px) scale(1.03,.97); } 70% { transform: translateY(0) scale(1.05,.93); } }
.km-move-bouncegroove .cs-b { animation: kmb-spinlite .95s linear infinite; }
.km-move-spingroove .cs-duo { animation: kmv-spingroove 1.1s ease-in-out 2 both; }
@keyframes kmv-spingroove { 0%,100% { transform: rotate(0); } 30% { transform: rotate(-9deg) translateY(-8px); } 60% { transform: rotate(9deg) translateY(-14px); } }
.km-move-spingroove .cs-w { animation: kmw-bob .55s ease-in-out infinite; }
.km-move-headbob .cs-duo { animation: kmv-headbob .66s ease-in-out 3 both; }
@keyframes kmv-headbob { 0%,100% { transform: translateY(0); } 30% { transform: translateY(-9px) rotate(-2deg); } 65% { transform: translateY(-3px) rotate(2deg); } }
.km-move-headbob .cs-w { animation: kmw-nodfast .33s ease-in-out infinite; }
.km-move-headbob .cs-b { animation: kmb-nodfast .33s ease-in-out infinite .16s; }
.km-move-hipsway .cs-duo { animation: kmv-hipsway .72s ease-in-out 3 both; }
@keyframes kmv-hipsway { 0%,100% { transform: rotate(-4deg) translateX(-10px); } 50% { transform: rotate(4deg) translateX(10px); } }
.km-move-hipsway .cs-w { animation: kmw-sway .7s ease-in-out infinite reverse; }
.km-move-clapstep .cs-duo { animation: kmv-clapstep .51s ease-in-out 4 both; }
@keyframes kmv-clapstep { 0%,100% { transform: translateY(0); } 35% { transform: translateY(-14px) scale(1.04); } 55% { transform: translateY(0) scale(.98); } 75% { transform: translateX(8px); } }
.km-move-clapstep .cs-b { animation: kmb-hop .48s ease-in-out infinite .1s; }
.km-move-bodywave .cs-duo { animation: kmv-bodywave .7s ease-in-out 3 both; }
@keyframes kmv-bodywave { 0%,100% { transform: skewX(0) translateY(0); } 25% { transform: skewX(-5deg) translateY(-6px); } 50% { transform: skewX(0) translateY(-12px); } 75% { transform: skewX(5deg) translateY(-6px); } }
.km-move-shimmy .cs-duo { animation: kmv-shimmy .475s ease-in-out 4 both; }
@keyframes kmv-shimmy { 0%,100% { transform: translateX(0) rotate(0); } 20% { transform: translateX(-8px) rotate(-3deg); } 40% { transform: translateX(8px) rotate(3deg); } 60% { transform: translateX(-6px) rotate(-2deg); } 80% { transform: translateX(6px) rotate(2deg); } }
.km-move-wiggledance .cs-duo { animation: kmv-wiggledance .5s ease-in-out 4 both; }
@keyframes kmv-wiggledance { 0%,100% { transform: rotate(0) scale(1); } 30% { transform: rotate(-6deg) scale(1.03); } 70% { transform: rotate(6deg) scale(1.03); } }
.km-move-wiggledance .cs-w { animation: kmw-bob .45s ease-in-out infinite; }
.km-move-wiggledance .cs-b { animation: kmb-hop .5s ease-in-out infinite .12s; }

/* ---- stunts ---- */
.km-move-frontflip .cs-duo { animation: kmv-frontflip 1.1s cubic-bezier(.35,.1,.3,1) 1 both; }
@keyframes kmv-frontflip { 0% { transform: translateY(0); } 20% { transform: translateY(14px) scale(1.06,.9); } 55% { transform: translateY(-150px) rotate(360deg); } 82% { transform: translateY(0) rotate(360deg) scale(1.1,.88); } 100% { transform: rotate(360deg); } }
.km-move-spinjump .cs-duo { animation: kmv-spinjump 1.15s cubic-bezier(.35,.1,.3,1) 1 both; }
@keyframes kmv-spinjump { 0% { transform: none; } 18% { transform: translateY(12px) scale(1.05,.9); } 58% { transform: translateY(-160px) rotate(-360deg) scale(.94); } 84% { transform: translateY(0) rotate(-360deg) scale(1.1,.9); } 100% { transform: rotate(-360deg); } }
.km-move-tuckjump .cs-duo { animation: kmv-tuckjump 1s ease-out 1 both; }
@keyframes kmv-tuckjump { 0% { transform: none; } 22% { transform: translateY(12px) scale(1.08,.86); } 55% { transform: translateY(-130px) scale(.82); } 80% { transform: translateY(0) scale(1.1,.88); } 100% { transform: none; } }
.km-move-trampoline .cs-duo { animation: kmv-trampoline .6s ease-in-out 3 both; }
@keyframes kmv-trampoline { 0%,100% { transform: translateY(0) scale(1.06,.9); } 45% { transform: translateY(-110px) scale(.96,1.05); } }
.km-move-trampoline .cs-b { animation: kmb-spinlite .62s linear infinite; }
.km-move-cartwheel .cs-duo { animation: kmv-cartwheel 1.2s cubic-bezier(.4,.1,.4,1) 1 both; }
@keyframes kmv-cartwheel { 0% { transform: translateX(-34vw); } 50% { transform: translateX(0) rotate(360deg); } 100% { transform: translateX(0) rotate(720deg); } }
.km-move-handspring .cs-duo { animation: kmv-handspring 1.15s ease-in-out 1 both; }
@keyframes kmv-handspring { 0% { transform: none; } 25% { transform: translateY(10px) rotate(-14deg); } 55% { transform: translateY(-120px) rotate(180deg); } 80% { transform: translateY(0) rotate(360deg) scale(1.08,.9); } 100% { transform: rotate(360deg); } }
.km-move-corkscrew .cs-duo { animation: kmv-corkscrew 1.25s cubic-bezier(.35,.1,.3,1) 1 both; }
@keyframes kmv-corkscrew { 0% { transform: none; } 20% { transform: translateY(12px) scale(1.06,.9); } 60% { transform: translateY(-150px) rotate(360deg) skewX(8deg); } 85% { transform: translateY(0) rotate(540deg) scale(1.08,.9); } 100% { transform: rotate(540deg); } }
.km-move-bounceflip .cs-duo { animation: kmv-bounceflip 1.4s ease-in-out 1 both; }
@keyframes kmv-bounceflip { 0% { transform: none; } 18% { transform: translateY(-56px); } 34% { transform: translateY(0) scale(1.08,.88); } 50% { transform: translateY(-90px) rotate(180deg); } 68% { transform: translateY(0) rotate(360deg) scale(1.1,.88); } 84% { transform: translateY(-26px) rotate(360deg); } 100% { transform: rotate(360deg); } }

/* ---- impacts (the two do it TO each other) ---- */
.km-move-highfive .cs-duo { animation: kmv-highfive 1s ease-in-out 1 both; }
@keyframes kmv-highfive { 0%,100% { transform: none; } 40% { transform: translateY(-24px); } 55% { transform: translateY(-30px) scale(1.05); } 70% { transform: translateY(0); } }
.km-move-highfive .cs-w { animation: kmw-reach 1s ease-in-out 1 both; }
.km-move-highfive .cs-b { animation: kmb-reach 1s ease-in-out 1 both; }
@keyframes kmw-reach { 0%,100% { transform: none; } 45% { transform: translateX(20px) rotate(8deg); } 60% { transform: translateX(14px); } }
@keyframes kmb-reach { 0%,100% { transform: none; } 45% { transform: translateX(-20px) rotate(-8deg) translateY(-16px); } 60% { transform: translateX(-14px); } }
.km-move-chestbump .cs-duo { animation: kmv-chestbump .54s ease-in-out 2 both; }
@keyframes kmv-chestbump { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-18px); } }
.km-move-chestbump .cs-w { animation: kmw-bumpr .54s cubic-bezier(.5,-.3,.3,1.4) 2 both; }
.km-move-chestbump .cs-b { animation: kmb-bumpl .54s cubic-bezier(.5,-.3,.3,1.4) 2 both; }
@keyframes kmw-bumpr { 0%,100% { transform: translateX(0); } 45% { transform: translateX(30px) scale(1.07); } 62% { transform: translateX(12px); } }
@keyframes kmb-bumpl { 0%,100% { transform: translateX(0); } 45% { transform: translateX(-30px) scale(1.07); } 62% { transform: translateX(-12px); } }
.km-move-fistpump .cs-duo { animation: kmv-fistpump .575s ease-out 2 both; }
@keyframes kmv-fistpump { 0%,100% { transform: translateY(0); } 34% { transform: translateY(-32px) scale(1.07); } 60% { transform: translateY(0); } }
.km-move-stompcheer .cs-duo { animation: kmv-stompcheer .55s ease-in-out 2 both; }
@keyframes kmv-stompcheer { 0%,100% { transform: translateY(0); } 30% { transform: translateY(-20px); } 55% { transform: translateY(0) scale(1.08,.9); } 70% { transform: translateY(-6px); } }
.km-move-stompcheer .cs-b { animation: kmb-hop .52s ease-in-out infinite .1s; }
.km-move-hipbump .cs-duo { animation: kmv-hipbump .54s ease-in-out 2 both; }
@keyframes kmv-hipbump { 0%,100% { transform: rotate(0); } 50% { transform: rotate(3deg) translateY(-8px); } }
.km-move-hipbump .cs-w { animation: kmw-hipr .54s ease-in-out 2 both; }
.km-move-hipbump .cs-b { animation: kmb-hipl .54s ease-in-out 2 both; }
@keyframes kmw-hipr { 0%,100% { transform: none; } 50% { transform: translateX(16px) rotate(7deg); } }
@keyframes kmb-hipl { 0%,100% { transform: none; } 50% { transform: translateX(-16px) rotate(-7deg); } }

/* ---- accents (short, characterful finishers) ---- */
.km-move-bow .cs-duo { animation: kmv-bow 1.1s ease-in-out 1 both; }
@keyframes kmv-bow { 0%,100% { transform: none; } 35% { transform: rotate(9deg) translateY(6px); } 65% { transform: rotate(9deg) translateY(6px); } }
.km-move-sparklehands .cs-duo { animation: kmv-sparklehands 1.2s ease-in-out 1 both; }
@keyframes kmv-sparklehands { 0%,100% { transform: none; } 30% { transform: translateY(-10px) scale(1.05); } 60% { transform: translateY(-6px) scale(1.05) rotate(-3deg); } 80% { transform: translateY(-6px) scale(1.05) rotate(3deg); } }
.km-move-hearthands .cs-duo { animation: kmv-hearthands 1.2s ease-in-out 1 both; }
@keyframes kmv-hearthands { 0%,100% { transform: none; } 40% { transform: scale(1.08); } 70% { transform: scale(1.04) translateY(-6px); } }
.km-move-victoryv .cs-duo { animation: kmv-victoryv 1.1s ease-out 1 both; }
@keyframes kmv-victoryv { 0% { transform: none; } 30% { transform: translateY(-22px) scale(1.06); } 55% { transform: translateY(0); } 75% { transform: translateY(-10px); } 100% { transform: none; } }
.km-move-crownpose .cs-duo { animation: kmv-crownpose 1.3s ease-in-out 1 both; }
@keyframes kmv-crownpose { 0%,100% { transform: none; } 30% { transform: translateY(-14px); } 60% { transform: translateY(-14px) rotate(-3deg); } 80% { transform: translateY(-14px) rotate(3deg); } }
.km-move-winkpose .cs-duo { animation: kmv-winkpose 1s ease-in-out 1 both; }
@keyframes kmv-winkpose { 0%,100% { transform: none; } 40% { transform: rotate(-5deg) scale(1.05); } 70% { transform: rotate(0) scale(1.02); } }
.km-move-confettipose .cs-duo { animation: kmv-confettipose 1.2s ease-in-out 1 both; }
@keyframes kmv-confettipose { 0%,100% { transform: none; } 25% { transform: translateY(-26px); } 45% { transform: translateY(0) scale(1.06,.94); } 65% { transform: translateY(-14px); } 85% { transform: translateY(0); } }

/* shared per-character accent layers */
@keyframes kmw-sway { 0%,100% { transform: rotate(-5deg); } 50% { transform: rotate(5deg); } }
@keyframes kmw-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-12px); } }
@keyframes kmw-tilt { 0%,100% { transform: rotate(-6deg) translateY(0); } 50% { transform: rotate(6deg) translateY(-8px); } }
@keyframes kmw-nodfast { 0%,100% { transform: rotate(0); } 50% { transform: rotate(-6deg) translateY(4px); } }
@keyframes kmb-hop { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-14px); } }
@keyframes kmb-tilt { 0%,100% { transform: rotate(-5deg); } 50% { transform: rotate(5deg); } }
@keyframes kmb-nodfast { 0%,100% { transform: rotate(0); } 50% { transform: rotate(5deg) translateY(3px); } }
@keyframes kmb-spinlite { from { transform: rotate(0); } to { transform: rotate(360deg); } }

.app.reduce-motion .km-party .cs-duo,
.app.reduce-motion .km-party .cs-w,
.app.reduce-motion .km-party .cs-b { animation: none !important; }

/* ---------- together antics (hub corner crew moments) ---------- */
.mascot.tg-bump-w { animation: km-tgw-bump 1.2s ease-in-out 1; }
.mascot.tg-bump-b { animation: km-tgb-bump 1.2s ease-in-out 1; }
@keyframes km-tgw-bump { 0%,100% { transform: none; } 40% { transform: translateX(26px) translateY(-10px); } 55% { transform: translateX(20px); } }
@keyframes km-tgb-bump { 0%,100% { transform: none; } 40% { transform: translateX(-14px) translateY(-12px); } 55% { transform: translateX(-8px); } }
.mascot.tg-look-w { animation: km-tgw-look 1.2s ease-in-out 1; }
.mascot.tg-look-b { animation: km-tgb-look 1.2s ease-in-out 1; }
@keyframes km-tgw-look { 0%,100% { transform: none; } 35% { transform: rotate(7deg) translateY(-4px); } 70% { transform: rotate(5deg); } }
@keyframes km-tgb-look { 0%,100% { transform: none; } 35% { transform: rotate(-6deg); } 70% { transform: rotate(-4deg) translateY(-3px); } }
.mascot.tg-nudge-w { animation: km-tgw-nudge 1.2s ease-in-out 1; }
.mascot.tg-nudge-b { animation: km-tgb-nudge 1.2s ease-in-out 1; }
@keyframes km-tgw-nudge { 0%,100% { transform: none; } 45% { transform: translateX(12px) rotate(4deg); } }
@keyframes km-tgb-nudge { 0%,100% { transform: none; } 55% { transform: translateX(-8px) rotate(-4deg) translateY(-5px); } }
.app.reduce-motion .mascot.tg-bump-w, .app.reduce-motion .mascot.tg-bump-b,
.app.reduce-motion .mascot.tg-look-w, .app.reduce-motion .mascot.tg-look-b,
.app.reduce-motion .mascot.tg-nudge-w, .app.reduce-motion .mascot.tg-nudge-b { animation: none; }

/* ---------- gibberish quips: their own little language ---------- */
.m-quip {
  position: absolute; bottom: calc(100% + 6px); left: 50%; transform: translateX(-50%) translateY(6px) scale(.8);
  background: var(--card, #fff); color: var(--ink, #2a333c); border: 2px solid var(--wkey, #2f9e57);
  border-radius: 14px 14px 14px 4px; padding: 4px 10px; font-size: 14px; font-weight: 800;
  white-space: nowrap; opacity: 0; transition: opacity .22s ease, transform .22s cubic-bezier(.2,1.5,.4,1);
  pointer-events: none; z-index: 4; box-shadow: var(--shadow-soft, 0 4px 12px rgba(0,0,0,.18));
}
.m-quip.q-b { border-radius: 14px 14px 4px 14px; }
.m-quip.show { opacity: 1; transform: translateX(-50%) translateY(0) scale(1); }
.km-party .m-quip { font-size: 17px; bottom: calc(100% + 10px); }
.app[data-theme="night"] .m-quip { background: #1c2b3f; color: #eef1ff; }

/* ---------- press compression: the moment of touch ---------- */
.km-press { transform: scale(.94) !important; transition: transform .08s ease !important; }
.app.reduce-motion .km-press { transform: none !important; }

/* ---------- panel-enter spring ---------- */
.km-enter { animation: km-enter .42s cubic-bezier(.2,1.2,.4,1) 1 both; }
@keyframes km-enter { from { transform: translateY(14px) scale(.985); opacity: .4; } to { transform: none; opacity: 1; } }
.app.reduce-motion .km-enter { animation: none; }

/* ============================================================
   rc.6 — DRAG AND DROP
   Real dragging with a ghost that follows the finger; tapping
   still works everywhere (pick up, then tap the target), so
   little hands and switch users are never locked out.
   ============================================================ */
.km-ghost {
  position: fixed; z-index: 90; pointer-events: none; margin: 0;
  transform: translate(-50%, -55%) scale(1.08) rotate(-2deg);
  box-shadow: 0 14px 30px rgba(0, 0, 0, .3) !important; opacity: .95;
}
.drag-src.dragging { opacity: .35; }
.drop-ready { outline: 3px dashed var(--wkey, #2f9e57); outline-offset: 3px; }
.drop-hot { outline: 4px solid var(--gold, #e0a51f); outline-offset: 3px; transform: scale(1.04); transition: transform .12s ease; }
.drag-snapback { animation: km-snapback .3s ease 1; }
@keyframes km-snapback { from { transform: scale(1.06) rotate(2deg); } to { transform: none; } }
.token, .dm-chip { touch-action: none; }

/* dragMatch: target cards + a tray of chips to carry onto them */
.dm-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 10px; }
.dm-card {
  border: 2.5px solid var(--line, #c9d6c9); border-radius: 16px; background: var(--card, #fff);
  padding: 10px 8px 12px; text-align: center; min-height: 96px; cursor: pointer;
  display: flex; flex-direction: column; align-items: center; gap: 4px; position: relative;
}
.dm-card .dm-em { font-size: clamp(40px, 9vw, 56px); line-height: 1.1; }
.dm-card .dm-lbl { font-weight: 800; font-size: 15px; }
.dm-card.dm-done { border-color: var(--leaf, #3fae63); background: rgba(63, 174, 99, .1); }
.dm-card .dm-placed { font-size: 22px; font-weight: 800; min-height: 26px; display: flex; align-items: center; gap: 4px; }
/* rc.118: the confirmation line used to glue the chip's emoji into a string.
   It now holds the same drawn picture the chip carried, at tally size. */
.dm-card .dm-placed .dm-placed-em.has-art { display: inline-flex; align-items: center; line-height: 1; }
.dm-card .dm-placed .dm-placed-em.has-art .pw-art { width: calc(var(--pic-sm) * 0.72); height: calc(var(--pic-sm) * 0.72); vertical-align: middle; }
.dm-tray { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin-top: 12px; }
.dm-chip {
  border: 2.5px solid var(--wkey, #2f9e57); border-radius: 999px; background: var(--card, #fff);
  padding: 10px 16px; font-size: clamp(18px, 5vw, 26px); font-weight: 800; cursor: grab;
  min-height: 52px; display: inline-flex; align-items: center; gap: 6px; color: var(--ink, #2a333c);
}
/* rc.105: dragMatch draws real art instead of the device emoji.
   rc.106 (owner: "Images must be full. Head is cut off") — THE FIRST VERSION
   OF THIS RULE CROPPED THE ANIMAL. `.dm-card .dm-em` sets line-height 1.1
   while `.pw-art` is 1.15em tall and sits on `vertical-align: -0.2em`, so the
   picture was both taller than its line box and pushed down inside it: the
   top quarter — a kangaroo's head — was clipped away. An emoji glyph tolerates
   that because a glyph has built-in padding; a cut-out photo has none, and its
   subject reaches the edge of the frame by design.
   So the picture is sized explicitly here and taken off the text baseline
   entirely, rather than inheriting a line box meant for a character. */
.dm-card .dm-em.has-art,
.dm-chip .dm-em.has-art { display: inline-flex; align-items: center; justify-content: center; line-height: 1; }
/* rc.112 (owner, of the Animal Atlas continent cards: "Lion is not full") —
   THE PICTURE WAS HALF ITS CARD.

   Measured before the change: the drop-zone card is 176 x 169 on a desktop
   and the animal inside it was 86 x 86 — 49% of the card's width, 51% of its
   height. On a 390px phone it was worse: 58px of a 182px card, 32%. The card
   is not clipping anything (360 pictures measured across three viewports, no
   clip anywhere) and the lion's own artwork is complete down to the claws —
   both checked before touching this. The picture was simply small, sitting in
   the top half of a card that then looked mostly empty.

   The gap under the label is NOT dead space and is deliberately kept: it is
   `.dm-placed`, the slot that holds the animal once a child drops it there.
   Reclaiming it would make every card jump in height at the moment of the
   drop, which is the one moment the child is watching.

   So the picture grows into the space it already had. `object-fit: contain`
   is unchanged, so a wide subject still shows whole — it just shows bigger. */
/* rc.130: THE CHIP AND THE CARD ARE THE SAME SIZE. The mechanic is
   "find the card that goes with this chip" and they were drawn at 34px
   and 83px — a 2.4x difference the child has to rescale mentally before
   they can even start. Both are now --pic-md: the card comes down, the
   chip comes up, and the tray stays compact enough not to push the grid
   off a 320px screen. */
.dm-card .dm-em.has-art .pw-art { width: var(--pic-lg); height: var(--pic-lg); vertical-align: middle; }
.dm-chip .dm-em.has-art .pw-art { width: var(--pic-lg); height: var(--pic-lg); vertical-align: middle; }
.dm-chip.selected { border-color: var(--gold, #e0a51f); box-shadow: 0 0 0 4px rgba(224, 165, 31, .25); }
.dm-chip:disabled { opacity: .3; cursor: default; }
.app[data-theme="night"] .dm-card, .app[data-theme="night"] .dm-chip { background: #182740; color: #eef1ff; }

/* ============================================================
   rc.7 — ROBOT GARDEN (coding), PEEK (memory), COLOR OF JOY
   ============================================================ */
.rp-grid {
  display: grid; gap: 6px; max-width: min(88vw, 340px); margin: 0 auto;
  background: var(--wsoft, rgba(47,158,87,.12)); padding: 10px; border-radius: 16px;
}
.rp-cell {
  aspect-ratio: 1; border-radius: 10px; background: var(--card, #fff);
  border: 2px solid var(--line, #c9d6c9); display: flex; align-items: center; justify-content: center;
  font-size: clamp(22px, 7vw, 34px); position: relative;
}
.app[data-theme="night"] .rp-cell { background: #182740; border-color: #2b3f5e; }
.rp-cell.rp-wall { background: var(--wsoft, rgba(0,0,0,.08)); }
.rp-cell.rp-goal { border-color: var(--gold, #e0a51f); box-shadow: 0 0 0 3px rgba(224, 165, 31, .25); }
.rp-bot { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: clamp(24px, 8vw, 38px); transition: transform .15s ease; z-index: 2; }
.rp-bot.rp-bump { animation: rp-bump .4s ease; }
@keyframes rp-bump { 0%,100% { transform: none; } 40% { transform: translateX(-6px) rotate(-8deg); } 70% { transform: translateX(4px) rotate(5deg); } }
.rp-bot.rp-win { animation: rp-win .5s ease; }
@keyframes rp-win { 0%,100% { transform: none; } 50% { transform: translateY(-14px) scale(1.2); } }
.rp-program { display: flex; gap: 6px; justify-content: center; flex-wrap: wrap; margin: 12px 0 6px; }
.rp-slot {
  min-width: 46px; min-height: 46px; border-radius: 12px; font-size: 22px;
  border: 2.5px dashed var(--line, #c9d6c9); background: var(--card, #fff); color: var(--muted, #7d8a7d);
}
.rp-slot.filled { border-style: solid; border-color: var(--wkey, #2f9e57); }
.rp-cmds { display: flex; gap: 10px; justify-content: center; margin-bottom: 8px; }
.rp-cmd {
  min-width: 58px; min-height: 58px; border-radius: 16px; font-size: 28px; cursor: grab;
  border: 2.5px solid var(--wkey, #2f9e57); background: var(--card, #fff); box-shadow: var(--shadow-soft, 0 4px 12px rgba(0,0,0,.14));
}
.app[data-theme="night"] .rp-slot, .app[data-theme="night"] .rp-cmd { background: #182740; color: #eef1ff; }

.peek-scene {
  display: flex; gap: 12px; justify-content: center; flex-wrap: wrap;
  background: var(--card, #fff); border: 2.5px solid var(--wkey, #2f9e57);
  border-radius: 18px; padding: 18px 12px; min-height: 92px; align-items: center;
}
.app[data-theme="night"] .peek-scene { background: #182740; }
.peek-em { font-size: clamp(40px, 10vw, 60px); line-height: 1.1; }
/* rc.113: the flash scene now draws real pictures. Same sizing as the glyph it
   replaces, so a scene of six mixed items stays one row of one size — a
   picture larger than its neighbours in a memory flash would be a cue the
   round did not intend to give. */
.peek-em.has-art { display: inline-flex; align-items: center; justify-content: center; line-height: 1; }
.peek-em.has-art .pw-art { width: var(--pic-md); height: var(--pic-md); vertical-align: middle; }
.peek-bar { height: 8px; border-radius: 99px; background: var(--wsoft, rgba(47,158,87,.15)); overflow: hidden; margin-top: 8px; }
.peek-fill { display: block; height: 100%; width: 100%; border-radius: 99px; background: var(--wkey, #2f9e57); animation: peek-drain linear forwards; transform-origin: left; }
@keyframes peek-drain { from { transform: scaleX(1); } to { transform: scaleX(0); } }
.app.reduce-motion .peek-fill { animation-duration: 0.01ms !important; opacity: .4; }

.joy-grid { display: flex; flex-wrap: wrap; gap: 10px; }
/* swatches share each row and the last row stretches — never ragged */
.joy-grid > .joy-swatch { flex: 1 1 128px; }
.joy-swatch {
  display: flex; align-items: center; gap: 8px; padding: 10px 12px; border-radius: 14px;
  border: 2.5px solid var(--line, #c9d6c9); background: var(--card, #fff); cursor: pointer;
  font-weight: 800; color: var(--ink, #2a333c); min-height: 52px; text-align: left;
}
.joy-swatch .joy-dot { width: 26px; height: 26px; border-radius: 50%; flex: 0 0 auto; box-shadow: inset 0 0 0 2px rgba(255,255,255,.5), 0 2px 6px rgba(0,0,0,.18); }
.joy-swatch .joy-name { font-size: 14px; }
.joy-swatch.selected { border-color: var(--gold, #e0a51f); box-shadow: 0 0 0 4px rgba(224, 165, 31, .22); }
.app[data-theme="night"] .joy-swatch { background: #182740; color: #eef1ff; }

/* ============================================================
   rc.8 — Parent Progress Report, Wonder Letter, new toy motion
   ============================================================ */
.rep-row { display: grid; grid-template-columns: 130px 1fr; gap: 4px 12px; align-items: center; padding: 7px 0; border-bottom: 1px dashed var(--line, #d5e0d5); }
.rep-row:last-child { border-bottom: 0; }
.rep-name { font-weight: 800; font-size: 14.5px; }
.rep-bar { height: 14px; border-radius: 99px; background: var(--card-edge); box-shadow: inset 0 0 0 1px var(--line); overflow: hidden; }
.rep-bar span { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, #8a5cf0, #2f9e57 55%, #e0a51f); min-width: 8px; }
.rep-nums { grid-column: 2; font-size: 12.5px; color: var(--ink-soft); }
@media (max-width: 470px) { .rep-row { grid-template-columns: 1fr; } .rep-nums { grid-column: 1; } }

.letter-card { border: 3px solid var(--gold, #e0a51f); background: linear-gradient(170deg, #fffdf4, #fff6da); font-size: 16.5px; line-height: 1.55; }
.app[data-theme="night"] .letter-card { background: linear-gradient(170deg, #1d2b45, #16233a); }
.letter-open { font-weight: 800; font-size: 19px; }
.letter-sign { font-weight: 800; text-align: right; }

.th-toy.th-drive { animation: th-drive 1.5s ease-in-out 1; }
@keyframes th-drive { 0% { transform: translateX(0); } 40% { transform: translateX(46px) rotate(8deg); } 60% { transform: translateX(46px); } 100% { transform: translateX(0); } }
.app.reduce-motion .th-toy.th-drive { animation: none; }

/* printing: reports & letters come out clean on paper */
@media print {
  .play-actions, .btn, button, .site-footer, .gift-banner { display: none !important; }
  .rep-screen .card, .wonder-letter .card { box-shadow: none; border: 1px solid #999; }
  .rep-bar span { background: #444 !important; -webkit-print-color-adjust: exact; }
  body { background: #fff !important; }
}

/* ============================================================
   rc.8 — LIVING SCENERY, SURPRISE CAMEOS, GLOW & HOVER, QUICK-NAV
   ============================================================ */
/* the world is alive: gears turn, plants sway, flags flutter, waves
   drift — and everything quickens for a beat on a right answer */
.scenery .an-spin { animation: scn-spin 16s linear infinite; transform-box: fill-box; transform-origin: center; }
.scenery .an-sway { animation: scn-sway 5.5s ease-in-out infinite; transform-box: fill-box; transform-origin: bottom center; }
.scenery .an-flutter { animation: scn-flutter 2.2s ease-in-out infinite; transform-box: fill-box; transform-origin: left center; }
.scenery .an-drift { animation: scn-drift 7s ease-in-out infinite; }
.scenery g:nth-of-type(2n) .an-sway, .scenery .an-sway:nth-of-type(2n) { animation-delay: -2.6s; }
@keyframes scn-spin { to { transform: rotate(360deg); } }
@keyframes scn-sway { 0%, 100% { transform: rotate(-2.2deg); } 50% { transform: rotate(2.2deg); } }
@keyframes scn-flutter { 0%, 100% { transform: skewY(0) scaleX(1); } 50% { transform: skewY(-6deg) scaleX(.92); } }
@keyframes scn-drift { 0%, 100% { transform: translateX(0); } 50% { transform: translateX(-5px); } }
.sky-quicken .an-spin { animation-duration: 3.5s; }
.sky-quicken .an-sway { animation-duration: 1.6s; }
.sky-quicken .an-flutter { animation-duration: .8s; }
.app.reduce-motion .scenery *, .app.reduce-effects .scenery * { animation: none !important; }

/* surprise cameos: a friendly visitor drifts across, low and gentle */
.km-cameo {
  position: fixed; left: -60px; z-index: 14; pointer-events: none;
  font-size: 34px; animation: cameo-walk linear forwards;
  filter: drop-shadow(0 3px 6px rgba(0,0,0,.2));
}
.km-cameo.fly { animation-name: cameo-fly; font-size: 30px; }
@keyframes cameo-walk {
  0% { transform: translateX(0) translateY(0); }
  25% { transform: translateX(28vw) translateY(-6px); }
  50% { transform: translateX(55vw) translateY(0); }
  75% { transform: translateX(82vw) translateY(-6px); }
  100% { transform: translateX(110vw) translateY(0); }
}
@keyframes cameo-fly {
  0% { transform: translateX(0) translateY(0) rotate(4deg); }
  30% { transform: translateX(34vw) translateY(-9vh) rotate(-5deg); }
  60% { transform: translateX(68vw) translateY(-3vh) rotate(5deg); }
  100% { transform: translateX(112vw) translateY(-12vh) rotate(-4deg); }
}
.app.reduce-motion .km-cameo, .app.reduce-effects .km-cameo { display: none; }

/* every button GLOWS — steadily, visibly, and each in its OWN color
   (the position-color language: violet/azure/emerald/amber/pink/teal).
   Color is decorative and positional, never meaningful — the words and
   pictures always carry the answer. Hover lifts and brightens. */

.choices .choice-btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.choices .choice-btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.choices .choice-btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.choices .choice-btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.choices .choice-btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.choices .choice-btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.token-tray .token:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-tray .dm-chip:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.dm-grid .dm-card:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-cmds .rp-cmd:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.bin-row .bin:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
/* Game cards in every world. Each carries ONE position colour, declared
   once here as --pos, and the ring, the bloom, the medallion and the spine
   are all lit from it — so a card reads as a single glowing object rather
   than an outlined box. (owner directive: round and glowing) */
.region-list .region-card:nth-of-type(6n+1) { --pos: 138,92,246; }
.region-list .region-card:nth-of-type(6n+2) { --pos: 47,157,224; }
.region-list .region-card:nth-of-type(6n+3) { --pos: 16,185,129; }
.region-list .region-card:nth-of-type(6n+4) { --pos: 232,160,19; }
.region-list .region-card:nth-of-type(6n+5) { --pos: 239,93,168; }
.region-list .region-card:nth-of-type(6n+6) { --pos: 10,165,165; }

/* NIGHT — the card lifts off the dark sky: a fill a shade brighter than the
   ground, a firm ring, and a two-stage bloom (tight + wide) so the colour
   actually spills into the dark instead of stopping at the border. */
.region-list .region-card {
  border-radius: 26px;
  /* the dome: lit along the crown, shading away under the bottom edge */
  background-image:
    linear-gradient(180deg, rgba(255,255,255,.20), rgba(255,255,255,.05) 30%, rgba(0,0,0,.10) 70%, rgba(0,0,0,.24)),
    linear-gradient(180deg, rgba(var(--pos, 138,92,246), .22), rgba(var(--pos, 138,92,246), .06) 55%, transparent);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.30),                       /* top lip */
    inset 0 -12px 18px -10px rgba(0,0,0,.60),                  /* underside */
    0 0 0 2.5px rgba(var(--pos, 138,92,246), .88),             /* rim */
    0 6px 0 -1px rgba(var(--pos, 138,92,246), .40),            /* its thickness */
    0 12px 22px rgba(6, 12, 26, .48);                          /* cast on the ground */
}
/* the medallion wears the card's colour, not the world's */
.region-list .region-card .r-em {
  background: radial-gradient(circle at 34% 28%, rgba(var(--pos, 138,92,246), .30), rgba(var(--pos, 138,92,246), .10) 62%, transparent);
  box-shadow: inset 0 0 0 2.5px rgba(var(--pos, 138,92,246), .95), 0 0 16px rgba(var(--pos, 138,92,246), .40);
}
/* the spine down the left edge, same colour, so the card has one identity */
.region-list .region-card::before {
  background: linear-gradient(180deg, rgba(var(--pos, 138,92,246), 1), rgba(var(--pos, 138,92,246), .45));
}
/* DAY — same object, sunlit: a tinted wash and a soft coloured shadow.
   Night's neon bloom is wrong in daylight, so it is replaced, not reused. */
.app[data-theme="day"] .region-list .region-card {
  background-image:
    linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,255,255,.62) 40%, rgba(0,0,0,.045) 78%, rgba(0,0,0,.10)),
    linear-gradient(180deg, rgba(var(--pos, 138,92,246), .16), rgba(var(--pos, 138,92,246), .05));
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.95),
    inset 0 -12px 16px -12px rgba(86,74,44,.45),
    0 0 0 2px rgba(var(--pos, 138,92,246), .72),
    0 6px 0 -1px rgba(var(--pos, 138,92,246), .30),
    0 12px 20px rgba(86, 74, 44, .20);
}
.app[data-theme="day"] .region-list .region-card .r-em {
  background: radial-gradient(circle at 34% 28%, #ffffff, rgba(var(--pos, 138,92,246), .18) 70%, rgba(var(--pos, 138,92,246), .10));
  box-shadow: inset 0 0 0 2.5px rgba(var(--pos, 138,92,246), .85), 0 3px 8px rgba(var(--pos, 138,92,246), .28);
}
.app.reduce-effects .region-list .region-card { box-shadow: 0 0 0 2px rgba(var(--pos, 138,92,246), .7), var(--shadow-soft) !important; }
.dest-grid .world-tile:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.dest-grid .world-tile:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.dest-grid .world-tile:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.dest-grid .world-tile:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.dest-grid .world-tile:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.dest-grid .world-tile:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.joy-grid .joy-swatch:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.topbar .icon-btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.play-actions .btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.modal-actions .btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.row > .btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.rp-program .rp-slot:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }

/* Today hub rows/cards join the position-colour glow language */
.today-panel .today-fun-row:nth-of-type(6n+1) { --pos: 138,92,246; }
.today-panel .today-fun-row:nth-of-type(6n+2) { --pos: 47,157,224; }
.today-panel .today-fun-row:nth-of-type(6n+3) { --pos: 16,185,129; }
.today-panel .today-fun-row:nth-of-type(6n+4) { --pos: 232,160,19; }
.today-panel .today-fun-row:nth-of-type(6n+5) { --pos: 239,93,168; }
.today-panel .today-fun-row:nth-of-type(6n+6) { --pos: 10,165,165; }
.today-quick .today-qp-card:nth-of-type(6n+1) { --pos: 138,92,246; }
.today-quick .today-qp-card:nth-of-type(6n+2) { --pos: 47,157,224; }
.today-quick .today-qp-card:nth-of-type(6n+3) { --pos: 16,185,129; }
.today-quick .today-qp-card:nth-of-type(6n+4) { --pos: 232,160,19; }
.today-quick .today-qp-card:nth-of-type(6n+5) { --pos: 239,93,168; }
.today-quick .today-qp-card:nth-of-type(6n+6) { --pos: 10,165,165; }

/* ============================================================
   RAISED CARDS + A BREATHING GLOW (rc.48)
   A ring around a flat panel still reads flat, however bright it is.
   These now read as PHYSICAL objects: a domed face (light along the top
   lip, shade tucked under the bottom edge) sitting on a hard, unblurred
   colour edge — the thickness of the thing — with the cast shadow below
   it. Behind each one, a coloured glow breathes in and out.

   The pulse is deliberately SLOW — a ~3.4s breath, under 0.3 Hz. This is
   a children's app: WCAG 2.3.1 caps flashing at 3 per second and a fast
   strobe is both a photosensitivity risk and a distraction from the
   question on screen. It stops entirely for reduced motion and effects.
   ============================================================ */
@keyframes bumpGlow {
  0%, 100% { opacity: .40; transform: scale(.985); }
  50%      { opacity: 1;   transform: scale(1.02); }
}
.region-card, .today-fun-row, .today-qp-card, .card.today-act { position: relative; }
.card.today-act { overflow: visible; }          /* the glow sits outside */
.region-card::after, .today-fun-row::after, .today-qp-card::after, .card.today-act::after {
  content: ""; position: absolute; inset: 3px; z-index: -1;
  border-radius: inherit; pointer-events: none;
  box-shadow: 0 0 20px 5px rgba(var(--pos, 138,92,246), .60),
              0 0 44px 14px rgba(var(--pos, 138,92,246), .28);
  animation: bumpGlow 3.4s ease-in-out infinite;
  will-change: opacity, transform;
}
.app[data-theme="day"] .region-card::after,
.app[data-theme="day"] .today-fun-row::after,
.app[data-theme="day"] .today-qp-card::after,
.app[data-theme="day"] .card.today-act::after {
  box-shadow: 0 0 18px 4px rgba(var(--pos, 138,92,246), .58),
              0 0 38px 12px rgba(var(--pos, 138,92,246), .30);
}
/* they breathe out of step — a row pulsing in unison reads as a warning
   light, not a garden */
.region-list .region-card:nth-of-type(6n+1)::after, .today-fun-row:nth-of-type(6n+1)::after,
.today-qp-card:nth-of-type(6n+1)::after { animation-delay: -.2s; }
.region-list .region-card:nth-of-type(6n+2)::after, .today-fun-row:nth-of-type(6n+2)::after,
.today-qp-card:nth-of-type(6n+2)::after { animation-delay: -.9s; }
.region-list .region-card:nth-of-type(6n+3)::after, .today-fun-row:nth-of-type(6n+3)::after,
.today-qp-card:nth-of-type(6n+3)::after { animation-delay: -1.6s; }
.region-list .region-card:nth-of-type(6n+4)::after, .today-fun-row:nth-of-type(6n+4)::after,
.today-qp-card:nth-of-type(6n+4)::after { animation-delay: -2.3s; }
.region-list .region-card:nth-of-type(6n+5)::after, .today-fun-row:nth-of-type(6n+5)::after,
.today-qp-card:nth-of-type(6n+5)::after { animation-delay: -2.9s; }
.region-list .region-card:nth-of-type(6n+6)::after, .today-fun-row:nth-of-type(6n+6)::after,
.today-qp-card:nth-of-type(6n+6)::after { animation-delay: -1.2s; }
.app.reduce-motion .region-card::after, .app.reduce-motion .today-fun-row::after,
.app.reduce-motion .today-qp-card::after, .app.reduce-motion .card.today-act::after,
.app.reduce-effects .region-card::after, .app.reduce-effects .today-fun-row::after,
.app.reduce-effects .today-qp-card::after, .app.reduce-effects .card.today-act::after {
  animation: none; opacity: .7; transform: none;
}
@media (prefers-reduced-motion: reduce) {
  .region-card::after, .today-fun-row::after, .today-qp-card::after, .card.today-act::after {
    animation: none !important; opacity: .7; transform: none;
  }
}

/* ============================================================
   THE LIT-CARD RECIPE (rc.44)
   Every card in the six-colour system — Today's tasks, the quick-play
   tiles and the four whole-card actions — is drawn the same way as a
   world's game cards: one --pos colour above, and here the ring, the
   bloom and the FILL are all lit from it.
   Day was the broken half. A white card on a pale sky with a coloured
   outline and a neon bloom that daylight swallows is not an object, it
   is a box: the ring was the only thing visible, so the cards read flat.
   Day now gets a tinted wash and a coloured shadow instead of neon.
   ============================================================ */
.today-fun-row, .today-qp-card, .card.today-act {
  background-image:
    linear-gradient(180deg, rgba(255,255,255,.20), rgba(255,255,255,.05) 30%, rgba(0,0,0,.10) 70%, rgba(0,0,0,.24)),
    linear-gradient(180deg, rgba(var(--pos, 138,92,246), .21), rgba(var(--pos, 138,92,246), .06) 55%, transparent);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.30),
    inset 0 -12px 18px -10px rgba(0,0,0,.58),
    0 0 0 2.5px rgba(var(--pos, 138,92,246), .86),
    0 6px 0 -1px rgba(var(--pos, 138,92,246), .38),
    0 12px 20px rgba(6, 12, 26, .42);
}
/* Night sets its own card background further up the sheet and outranks the
   base rule above, so the tint is restated here at night's specificity —
   otherwise night keeps a flat grey fill and only the ring is coloured. */
.app[data-theme="night"] .today-fun-row,
.app[data-theme="night"] .today-qp-card,
.app[data-theme="night"] .card.today-act {
  background-image: linear-gradient(180deg, rgba(var(--pos, 138,92,246), .17), rgba(var(--pos, 138,92,246), .05) 48%, transparent 78%);
  /* night's generic .card shadow outranks the shared recipe, so the dome
     is restated at that same depth */
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.30),
    inset 0 -12px 18px -10px rgba(0,0,0,.58),
    0 0 0 2.5px rgba(var(--pos, 138,92,246), .86),
    0 6px 0 -1px rgba(var(--pos, 138,92,246), .38),
    0 12px 20px rgba(6, 12, 26, .42);
}
.app[data-theme="day"] .today-fun-row,
.app[data-theme="day"] .today-qp-card,
.app[data-theme="day"] .card.today-act {
  background-image:
    linear-gradient(180deg, rgba(255,255,255,.98), rgba(255,255,255,.62) 40%, rgba(0,0,0,.045) 78%, rgba(0,0,0,.10)),
    linear-gradient(180deg, rgba(var(--pos, 138,92,246), .16), rgba(var(--pos, 138,92,246), .05));
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.95),
    inset 0 -12px 16px -12px rgba(86,74,44,.45),
    0 0 0 2px rgba(var(--pos, 138,92,246), .70),
    0 6px 0 -1px rgba(var(--pos, 138,92,246), .28),
    0 12px 20px rgba(86, 74, 44, .20);
}
/* the icon medallion wears the same colour as the card it sits on */
.today-fun-row .today-fun-em, .today-qp-card .qp-em {
  flex: 0 0 auto; width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: radial-gradient(circle at 34% 28%, rgba(var(--pos, 138,92,246), .26), rgba(var(--pos, 138,92,246), .08) 64%, transparent);
  box-shadow: inset 0 0 0 2px rgba(var(--pos, 138,92,246), .85);
}
.app[data-theme="day"] .today-fun-row .today-fun-em,
.app[data-theme="day"] .today-qp-card .qp-em {
  background: radial-gradient(circle at 34% 28%, #ffffff, rgba(var(--pos, 138,92,246), .18) 70%, rgba(var(--pos, 138,92,246), .10));
  box-shadow: inset 0 0 0 2px rgba(var(--pos, 138,92,246), .78), 0 3px 8px rgba(var(--pos, 138,92,246), .24);
}
.app.reduce-effects .today-fun-row,
.app.reduce-effects .today-qp-card,
.app.reduce-effects .card.today-act {
  box-shadow: 0 0 0 2px rgba(var(--pos, 138,92,246), .7), var(--shadow-soft) !important;
}
@media (hover: hover) {
  .today-fun-row:hover, .today-qp-card:hover, .card.today-act:hover {
    transform: translateY(-2px);
    box-shadow:
      0 0 0 3px rgba(var(--pos, 138,92,246), 1),
      0 0 28px rgba(var(--pos, 138,92,246), .68),
      0 0 56px rgba(var(--pos, 138,92,246), .30),
      0 12px 22px rgba(6, 12, 26, .40);
  }
  .app[data-theme="day"] .today-fun-row:hover,
  .app[data-theme="day"] .today-qp-card:hover,
  .app[data-theme="day"] .card.today-act:hover {
    box-shadow:
      0 0 0 2.5px rgba(var(--pos, 138,92,246), .85),
      0 12px 24px rgba(var(--pos, 138,92,246), .36),
      0 3px 8px rgba(86, 74, 44, .14);
  }
}

@media (hover: hover) {
}


@media (hover: hover) {
  .choices .choice-btn:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .choices .choice-btn:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .choices .choice-btn:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .choices .choice-btn:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .choices .choice-btn:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .choices .choice-btn:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .token-tray .token:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-tray .dm-chip:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dm-grid .dm-card:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-cmds .rp-cmd:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .bin-row .bin:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .dest-grid .world-tile:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .joy-grid .joy-swatch:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .topbar .icon-btn:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .play-actions .btn:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .modal-actions .btn:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .row > .btn:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+1):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(138,92,246,.9), 0 0 26px rgba(138,92,246,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+2):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(47,157,224,.9), 0 0 26px rgba(47,157,224,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+3):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(16,185,129,.9), 0 0 26px rgba(16,185,129,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+4):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(232,160,19,.9), 0 0 26px rgba(232,160,19,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+5):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(239,93,168,.9), 0 0 26px rgba(239,93,168,.7), 0 10px 18px rgba(20,40,28,.18); }
  .rp-program .rp-slot:nth-of-type(6n+6):hover { transform: translateY(-2px); box-shadow: 0 0 0 3px rgba(10,165,165,.9), 0 0 26px rgba(10,165,165,.7), 0 10px 18px rgba(20,40,28,.18); }
  .world-tile:hover { transform: translateY(-4px) scale(1.02); }
  .btn:hover { transform: translateY(-2px); filter: brightness(1.06); }
}
/* big primary buttons keep their 3D press base and add an accent glow */
.btn.big, .btn.glow { box-shadow: inset 0 2px 0 rgba(255,255,255,.35), 0 4px 0 var(--accent-deep), 0 0 20px rgba(63,174,99,.55), var(--shadow-soft); }
.world-tile { box-shadow: 0 0 14px rgba(255,255,255,.25), 0 10px 20px rgba(20,40,28,.18); }
.app[data-theme="night"] .choices .choice-btn, .app[data-theme="night"] .token-tray .token,
.app[data-theme="night"] .dm-tray .dm-chip, .app[data-theme="night"] .rp-cmds .rp-cmd { filter: brightness(1.02); }
.app.reduce-effects .choices .choice-btn, .app.reduce-effects .token-tray .token,
.app.reduce-effects .dm-tray .dm-chip, .app.reduce-effects .dm-grid .dm-card,
.app.reduce-effects .topbar .icon-btn { box-shadow: var(--shadow-soft) !important; }
.app.reduce-motion .btn:hover, .app.reduce-motion .icon-btn:hover, .app.reduce-motion .world-tile:hover { transform: none; }


/* ============================================================
   DAYLIGHT PASS — the day theme, art-directed.
   Day was a flat two-stop wash: pale cards on a pale ground, one
   value throughout, and night's neon glow rings burning in
   sunlight. This gives day a real sky (warm sun wash, cool
   overhead, warm meadow haze at the horizon), light that falls
   from above onto every surface, warm shadows instead of cold
   grey-green, and colour rings that read as tinted shadow rather
   than neon. NIGHT IS UNTOUCHED — every rule here is day-scoped.
   ============================================================ */
.app[data-theme="day"] {
  --ink: #223028;                       /* deeper, warmer — was #2a333c */
  --ink-soft: #41544a;
  --ink-faint: #64776b;
  --card-edge: #dbead9;
  --shadow: 0 10px 26px rgba(86, 74, 44, .13), 0 2px 6px rgba(86, 74, 44, .07);
  --shadow-soft: 0 4px 12px rgba(86, 74, 44, .09);
}
/* the sky: sun wash top-right, clear overhead, warm haze at the horizon */
.app[data-theme="day"] .sky {
  background:
    /* the sun's own wash, centred on the orb */
    radial-gradient(58% 40% at 89% 8%, rgba(255, 246, 206, .92), rgba(255, 246, 206, 0) 62%),
    /* warm light lying along the horizon — cream, never a fixed hue, so it
       lights every world's palette instead of muddying it */
    radial-gradient(130% 38% at 50% 100%, rgba(255, 251, 236, .60), rgba(255, 251, 236, 0) 74%),
    linear-gradient(180deg,
      var(--sky-a-w, var(--sky-a)) 0%,
      color-mix(in srgb, var(--sky-a-w, var(--sky-a)) 52%, #ffffff) 46%,
      var(--sky-b-w, var(--sky-b)) 100%);
}
/* a sun that actually glows, and sits behind the content */
.app[data-theme="day"] .sky .orb {
  width: 104px; height: 104px; top: 5%; right: 7%;
  background: radial-gradient(circle at 36% 34%, #fffdf2, #ffe98a 52%, #ffcf4d 78%, #f7b73a);
  box-shadow: 0 0 70px 30px rgba(255, 222, 130, .48), 0 0 160px 70px rgba(255, 233, 170, .30);
}
/* clouds — day only. Three soft lobes, drifting slowly left to right.
   Transform-only animation, so it costs nothing on a phone. */
.cloud { display: none; }
.app[data-theme="day"] .cloud {
  display: block; position: absolute; left: 0;
  width: 7.4em; height: 2.1em; border-radius: 999px;
  background: #ffffff; opacity: .62;
  animation-name: cloudDrift; animation-timing-function: linear; animation-iteration-count: infinite;
  will-change: transform;
}
.app[data-theme="day"] .cloud::before,
.app[data-theme="day"] .cloud::after {
  content: ""; position: absolute; background: #ffffff; border-radius: 50%;
}
.app[data-theme="day"] .cloud::before { width: 3.2em; height: 3.2em; left: 1.1em; top: -1.5em; }
.app[data-theme="day"] .cloud::after  { width: 2.3em; height: 2.3em; left: 3.9em; top: -1em; }
@keyframes cloudDrift { from { transform: translateX(-30vw); } to { transform: translateX(130vw); } }
.app.reduce-motion .cloud, .app.reduce-effects .cloud { animation: none; opacity: .48; }
@media (prefers-reduced-motion: reduce) { .cloud { animation: none !important; } }

/* light falls from above: a soft sheen on every raised surface */
.app[data-theme="day"] .card,
.app[data-theme="day"] .region-card,
.app[data-theme="day"] .world-tile,
.app[data-theme="day"] .today-act {
  background-image: linear-gradient(180deg, rgba(255, 255, 255, .92), rgba(255, 255, 255, 0) 46%);
  background-color: var(--card);
}
.app[data-theme="day"] .prompt-card { background-image: linear-gradient(180deg, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 40%); }
/* colour rings: in daylight a ring reads best as a tinted shadow, not neon.
   Night keeps its full glow — these overrides are day-only. */
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2px rgba(138,92,246,.55), 0 6px 14px rgba(138,92,246,.22), 0 2px 4px rgba(86,74,44,.10); }
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2px rgba(47,157,224,.55),  0 6px 14px rgba(47,157,224,.22),  0 2px 4px rgba(86,74,44,.10); }
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2px rgba(16,185,129,.55),  0 6px 14px rgba(16,185,129,.22),  0 2px 4px rgba(86,74,44,.10); }
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2px rgba(232,160,19,.55),  0 6px 14px rgba(232,160,19,.22),  0 2px 4px rgba(86,74,44,.10); }
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2px rgba(239,93,168,.55),  0 6px 14px rgba(239,93,168,.22),  0 2px 4px rgba(86,74,44,.10); }
.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2px rgba(10,165,165,.55),  0 6px 14px rgba(10,165,165,.22),  0 2px 4px rgba(86,74,44,.10); }
/* primary buttons catch the sun */
.app[data-theme="day"] .btn {
  background-image: linear-gradient(180deg, rgba(255,255,255,.34), rgba(255,255,255,0) 52%), var(--btn-grad);
  box-shadow: 0 2px 0 rgba(0,0,0,.10), 0 8px 18px rgba(86,74,44,.16);
}
/* the growth ladder reads as a lit row of stepping stones, not flat chips */
.app[data-theme="day"] .stage-chip { background-image: linear-gradient(180deg, #ffffff, rgba(255,255,255,0) 60%); }

/* ---- Tap an animal, hear it ---------------------------------------
   Anything with a synthesized call gets a gentle affordance: a pointer,
   a soft ring on hover, and a gentle bounce when it answers. It is never
   a hard-edged button — the picture stays a picture. */
.has-call { cursor: pointer; border-radius: 16px; transition: transform .16s ease, filter .16s ease; }
.has-call:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
@media (hover: hover) { .has-call:hover { transform: scale(1.06); filter: brightness(1.05); } }
.has-call.call-pop { animation: callPop .34s cubic-bezier(.2,1.4,.4,1); }
@keyframes callPop { 0% { transform: scale(1); } 40% { transform: scale(1.18) rotate(-4deg); } 100% { transform: scale(1); } }
.app.reduce-motion .has-call.call-pop { animation: none; }

/* ---- Today: whole-card controls -----------------------------------
   The gift banner, the Keep-going panel, My House and the shop nudge are
   each ONE big tappable card rather than a small chip at the end of a row
   — a 5-year-old aims at the card, not the button. Soft, rounded, each
   with its own glow colour, lifting on hover and pressing on tap. */
.today-act {
  display: flex; width: 100%; text-align: left;
  font: inherit; color: inherit;
  border: 1px solid var(--card-edge);
  border-radius: 20px;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  transition: transform .16s ease, box-shadow .16s ease, filter .16s ease;
}
.today-act.stack { display: flex; flex-direction: column; }
/* pressed: the bump squashes onto the ground — its thickness collapses */
.today-act:active, .today-fun-row:active, .today-qp-card:active, .region-card:active {
  transform: translateY(4px);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.22),
    inset 0 -6px 12px -8px rgba(0,0,0,.5),
    0 0 0 2.5px rgba(var(--pos, 138,92,246), .9),
    0 1px 0 -1px rgba(var(--pos, 138,92,246), .4),
    0 3px 8px rgba(6, 12, 26, .35);
}
.today-act .today-act-text { min-width: 0; }
.today-act .muted { color: var(--muted); }
.today-cta {
  flex: 0 0 auto; align-self: center;
  padding: 9px 16px; border-radius: 999px;
  background: var(--btn-grad); color: var(--accent-ink);
  font-weight: 800; font-size: 14px; white-space: nowrap;
  box-shadow: 0 2px 0 rgba(0, 0, 0, .10);
}
.today-cta-big { align-self: stretch; text-align: center; padding: 14px 20px; font-size: 19px; border-radius: 18px; }
@media (hover: hover) {
  .today-act:hover { transform: translateY(-2px); }
  .today-act:hover .today-cta { filter: brightness(1.06); }
}
/* one distinct colour per card, matching the six-colour system */
.today-act.act-amber { --pos: 232,160,19; }
.today-act.act-teal { --pos: 10,165,165; }
.today-act.act-pink { --pos: 239,93,168; }
.today-act.act-violet { --pos: 138,92,246; }
@media (hover: hover) {
  .region-list .region-card:hover {
    transform: translateY(-3px);
    box-shadow:
      0 0 0 3px rgba(var(--pos, 138,92,246), 1),
      0 0 30px rgba(var(--pos, 138,92,246), .70),
      0 0 62px rgba(var(--pos, 138,92,246), .34),
      0 14px 26px rgba(6, 12, 26, .46);
  }
  .app[data-theme="day"] .region-list .region-card:hover {
    box-shadow:
      0 0 0 2.5px rgba(var(--pos, 138,92,246), .85),
      0 12px 24px rgba(var(--pos, 138,92,246), .34),
      0 3px 8px rgba(86, 74, 44, .14);
  }
}
.app.reduce-effects .card.today-act { box-shadow: var(--shadow-soft) !important; }
.app.reduce-motion .today-act { transition: none; }
@media (max-width: 480px) {
  .today-act { border-radius: 18px; }
  .today-cta { padding: 8px 13px; font-size: 13px; }
}

/* ---- Phone bottom navigation (<600px) ----------------------------
   Under 600px the topbar has no room for the quick-nav, which left a
   phone with no way to reach Today / Worlds / Tree / My House /
   Collection / Shop. Those six live in a thumb-reachable bottom bar
   instead — same routing, same per-position glow colours, big targets.
   Hidden at 600px+ (the topbar nav takes over) and during a round (the
   Leave button is the round's one safe exit). */
.bottom-nav { display: none; }
@media (max-width: 599px) {
  .bottom-nav {
    display: flex; gap: 4px; justify-content: space-between; align-items: stretch;
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 28;
    padding: 7px max(6px, env(safe-area-inset-left)) calc(7px + env(safe-area-inset-bottom)) max(6px, env(safe-area-inset-right));
    background: color-mix(in srgb, var(--card) 92%, transparent);
    -webkit-backdrop-filter: saturate(150%) blur(10px);
    backdrop-filter: saturate(150%) blur(10px);
    border-top: 1px solid var(--card-edge);
    box-shadow: 0 -6px 20px rgba(20, 40, 28, .10);
  }
  .bottom-nav[hidden] { display: none; }
  .app.in-round .bottom-nav { display: none; }
  .bottom-nav .icon-btn {
    flex: 1 1 0; min-width: 0; min-height: 52px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 1px;
    padding: 4px 2px; border-radius: 14px;
  }
  .bottom-nav .icon-btn .ic { font-size: 20px; line-height: 1; }
  .bottom-nav .icon-btn .ic-label {
    display: block; font-size: 9.5px; font-weight: 800; line-height: 1.45;
    max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  }
  /* the fixed bar must never cover the end of a screen or the footer */
  .main { padding-bottom: 96px; }
  .site-footer { padding-bottom: calc(78px + env(safe-area-inset-bottom)); }
}
/* rc.84 (CA-111): the rc.83 fix PINNED this bar to the bottom of the phone
   viewport so the first-run control could never be below the fold. That
   solved CA-001's real complaint — the fixed nav sitting on top of the
   control — and then created a new one: an 85px fixed bar over a 568px
   screen covers the step-3 heading and four of the six seeds, and steals
   their taps. The re-audit found it at one text size; it reproduces at six
   viewport/text combinations.

   The pin is removed. The occluder CA-001 was actually about is the NAV, and
   `hideNav` still removes that on every first-run screen. With the nav gone,
   the control sits where a form's submit belongs — directly after the last
   step, in reading order, covering nothing. A control below the fold at the
   end of a form longer than the screen is ordinary; a control underneath
   fixed chrome is not, and that is the part that was broken.

   The lesson worth keeping: qa32 asked only "is the CTA reachable?" and never
   "does the CTA cover anything?". A one-directional gate passed a defect its
   own fix introduced. It now asks both. */
.onb-cta { display: flex; justify-content: center; padding: 4px 0 0; }
.onb-cta .btn { width: min(420px, 100%); justify-content: center; }

/* same six-colour position glow the topbar uses, so the bar reads as part
   of the same family rather than a grey system chrome */
.bottom-nav .icon-btn:nth-of-type(6n+1) { box-shadow: 0 0 0 2.5px rgba(138,92,246,.65), 0 0 16px rgba(138,92,246,.45), 0 4px 10px rgba(20,40,28,.12); }
.bottom-nav .icon-btn:nth-of-type(6n+2) { box-shadow: 0 0 0 2.5px rgba(47,157,224,.65), 0 0 16px rgba(47,157,224,.45), 0 4px 10px rgba(20,40,28,.12); }
.bottom-nav .icon-btn:nth-of-type(6n+3) { box-shadow: 0 0 0 2.5px rgba(16,185,129,.65), 0 0 16px rgba(16,185,129,.45), 0 4px 10px rgba(20,40,28,.12); }
.bottom-nav .icon-btn:nth-of-type(6n+4) { box-shadow: 0 0 0 2.5px rgba(232,160,19,.65), 0 0 16px rgba(232,160,19,.45), 0 4px 10px rgba(20,40,28,.12); }
.bottom-nav .icon-btn:nth-of-type(6n+5) { box-shadow: 0 0 0 2.5px rgba(239,93,168,.65), 0 0 16px rgba(239,93,168,.45), 0 4px 10px rgba(20,40,28,.12); }
.bottom-nav .icon-btn:nth-of-type(6n+6) { box-shadow: 0 0 0 2.5px rgba(10,165,165,.65), 0 0 16px rgba(10,165,165,.45), 0 4px 10px rgba(20,40,28,.12); }
.app.reduce-effects .bottom-nav .icon-btn { box-shadow: var(--shadow-soft) !important; }

/* quick-nav: the topbar is never empty off the home page (≥600px).
   The nav is the bar's centrepiece: it takes the space left between the
   brand/status cluster and the actions and centres its buttons in it. */
.top-nav { display: none; gap: 6px; margin: 0; }
@media (min-width: 600px) {
  .top-nav {
    display: flex; flex: 1 1 auto; min-width: 0;
    /* auto margins centre the group when there is room and keep every
       button reachable (never clipped) when the bar gets tight */
    justify-content: flex-start;
    overflow-x: auto; overscroll-behavior-x: contain;
    scrollbar-width: none; -ms-overflow-style: none;
    padding: 6px 4px; margin: -6px 0;      /* room for the button glow rings */
  }
  .top-nav::-webkit-scrollbar { display: none; }
  .top-nav > :first-child { margin-left: auto; }
  .top-nav > :last-child { margin-right: auto; }
}
/* Wide screens: pin the nav to the true centre of the bar. Only where the
   side clusters can never reach the centred group. */
@media (min-width: 1080px) {
  .top-nav {
    position: absolute; left: 50%; transform: translateX(-50%);
    flex: 0 0 auto; max-width: calc(100% - 620px);
  }
  .topbar .top-status { margin-right: auto; }   /* left cluster stays packed left */
}

/* rc.9 — story reading panel + caption safety */
.stimulus .stim-read {
  display: block; width: 100%; text-align: left;
  font-size: clamp(16.5px, 4.2vw, 19.5px); line-height: 1.7; font-weight: 500;
  letter-spacing: normal; color: var(--ink);
  background: var(--card); border: 2px solid var(--card-edge, #dfe8df);
  border-radius: 16px; padding: 16px 18px; box-shadow: var(--shadow-soft);
}
.caption-bar { max-height: 24vh; overflow: hidden; line-height: 1.45; }

/* rc.10 — one-time introduction */
.celebrate-layer.km-intro { background: rgba(8, 16, 10, .74); backdrop-filter: blur(3px); }
.km-intro .km-party-inner { gap: 26px; padding: 0 16px; }
.intro-bubble {
  max-width: min(520px, 88vw); background: var(--card, #fff); color: var(--ink, #2a333c);
  border-radius: 22px; padding: 16px 20px; font-size: clamp(18px, 4.8vw, 23px); font-weight: 800;
  text-align: center; line-height: 1.45; box-shadow: 0 10px 30px rgba(0,0,0,.3);
  border: 3px solid var(--wkey, #2f9e57); position: relative; min-height: 64px;
  display: flex; align-items: center; justify-content: center;
  animation: km-label-pop .4s cubic-bezier(.2,1.5,.4,1) both;
}
.intro-bubble.from-w { border-color: #2f9e57; }
.intro-bubble.from-b { border-color: #e0468f; }
.intro-bubble.from-w::after, .intro-bubble.from-b::after {
  content: ""; position: absolute; bottom: -14px; border: 8px solid transparent; border-top-color: inherit;
}
.intro-bubble.from-w::after { left: 30%; border-top-color: #2f9e57; }
.intro-bubble.from-b::after { right: 30%; border-top-color: #e0468f; }
.app[data-theme="night"] .intro-bubble { background: #1c2b3f; color: #eef1ff; }
.km-intro .cs-duo.intro-hop { animation: kmv-popup .45s cubic-bezier(.2,1.5,.4,1) 1; }
.intro-hint { color: #fff; font-weight: 800; font-size: 14px; opacity: .85; text-shadow: 0 1px 3px rgba(0,0,0,.4); }
.intro-skip { pointer-events: auto; }
.app.reduce-motion .km-intro .cs-duo.intro-hop, .app.reduce-motion .intro-bubble { animation: none; }

/* rc.10 — balloons, delivery flight, premium swatches, ages badge */
.th-balloon { position: absolute; bottom: 8px; font-size: 26px; animation: th-balloon 2.4s ease-out forwards; pointer-events: none; }
@keyframes th-balloon { 0% { transform: translateY(0); opacity: 1; } 100% { transform: translateY(-170px) translateX(12px); opacity: 0; } }
.km-deliver { position: fixed; z-index: 95; font-size: 34px; pointer-events: none; filter: drop-shadow(0 4px 8px rgba(0,0,0,.25)); }
/* big cross-screen delivery — the bought item travels home, large */
.km-deliver-big {
  position: fixed; z-index: 96; font-size: 96px; line-height: 1; pointer-events: none;
  filter: drop-shadow(0 12px 16px rgba(0,0,0,.30)); will-change: transform, opacity;
  transform: translate(-50%,-50%);
}
@media (max-width: 460px) { .km-deliver-big { font-size: 84px; } }   /* rc.68: hero-sized departure on phones (was 62px) */
.km-deliver-mark {
  position: fixed; z-index: 94; font-size: 26px; pointer-events: none;
  transform: translate(-50%,-50%); animation: km-mark .9s ease-out forwards;
}
@keyframes km-mark {
  0% { opacity: 0; transform: translate(-50%,-50%) scale(.5); }
  30% { opacity: .75; }
  100% { opacity: 0; transform: translate(-50%,-50%) translateY(16px) scale(1.15); }
}
.km-deliver-track { position: fixed; left: 0; width: 100%; height: 0; z-index: 93; pointer-events: none; }
.km-deliver-track.track-drive { border-top: 3px dashed rgba(120,120,120,.26); }
.km-deliver-track.track-sail { border-top: 4px solid rgba(90,150,220,.20); }
.km-deliver-puff {
  position: fixed; z-index: 97; font-size: 34px; pointer-events: none;
  transform: translate(-50%,-50%); animation: km-puff .72s ease-out forwards;
}
@keyframes km-puff {
  0% { opacity: 0; transform: translate(-50%,-50%) scale(.4); }
  40% { opacity: 1; transform: translate(-50%,-50%) scale(1.1); }
  100% { opacity: 0; transform: translate(-50%,-90%) scale(1.45); }
}
.icon-btn.nav-arrived { filter: drop-shadow(0 0 11px rgba(255,206,90,.95)); }
.app.reduce-motion .km-deliver-big, .app.reduce-motion .km-deliver-mark,
.app.reduce-motion .km-deliver-track { display: none; }
.joy-swatch.locked { opacity: .72; border-style: dashed; }
.joy-swatch.locked .joy-name::after { content: " · Shop"; font-size: 11px; color: var(--muted, #7d8a7d); }
.ages-badge {
  align-self: center; font-size: 11.5px; font-weight: 800; color: var(--ink-faint, #66756b);
  border: 1.5px solid var(--card-edge, #dfe8df); border-radius: 999px; padding: 3px 9px;
  background: var(--card, #fff); white-space: nowrap; margin-left: 4px;
}
@media (max-width: 1179px) { .ages-badge { display: none; } }
.app.reduce-motion .km-deliver, .app.reduce-motion .th-balloon { display: none; }

/* topbar labels need real room — icon-only until 900px */
@media (max-width: 899px) {
  .topbar .icon-btn .ic-label { display: none; }
  .topbar .icon-btn { min-width: 40px; padding: 3px; }
  .top-nav { gap: 4px; }
}

/* rc.10 — answer reveal (two-attempt rule) */
.choice-btn.revealed { animation: km-reveal 1s ease 2; box-shadow: 0 0 0 3px var(--leaf, #3fae63), 0 0 22px rgba(63, 174, 99, .6) !important; }
@keyframes km-reveal { 0%,100% { transform: scale(1); } 50% { transform: scale(1.06); } }
input.revealed { border-color: var(--leaf, #3fae63) !important; box-shadow: 0 0 14px rgba(63, 174, 99, .5); font-weight: 800; }
.app.reduce-motion .choice-btn.revealed { animation: none; }

/* ============================================================
   rc.13 — WORLD OPENING celebration (balloons, birds, petals)
   ============================================================ */
.km-worldopen { position: fixed; inset: 0; z-index: 60; pointer-events: none; overflow: hidden; transition: opacity .25s ease; }
.km-worldopen.wo-out { opacity: 0; }
/* the scrim: the one thing in the layer that takes the tap. Light, so the
   world still shows through; enough that the card reads as "a moment", not
   as a stray card lying on top of the region list. */
.wo-scrim { position: absolute; inset: 0; pointer-events: auto; border: 0; margin: 0; padding: 0; cursor: pointer;
  background: rgba(12, 28, 20, .22); animation: wo-scrim-in .3s ease both; -webkit-tap-highlight-color: transparent; }
.wo-scrim:focus-visible { outline: 4px solid #fff; outline-offset: -8px; }
@keyframes wo-scrim-in { from { opacity: 0; } to { opacity: 1; } }
.app[data-theme="night"] ~ .km-worldopen .wo-scrim, body:has(.app[data-theme="night"]) .wo-scrim { background: rgba(2, 8, 20, .34); }
.wo-balloon { position: absolute; bottom: -60px; width: 34px; height: 42px; border-radius: 50% 50% 48% 48%;
  background: radial-gradient(circle at 34% 30%, #fff8, var(--bc, #ff6b8b) 62%); box-shadow: 0 4px 10px rgba(0,0,0,.14);
  animation: wo-rise 3.4s ease-in forwards; }
.wo-balloon::after { content: ""; position: absolute; left: 50%; bottom: -46px; width: 1.5px; height: 46px; background: rgba(120,120,120,.5); transform: translateX(-50%); }
@keyframes wo-rise { 0% { transform: translateY(0) scale(.7); opacity: 0; } 12% { opacity: 1; } 100% { transform: translateY(-118vh) translateX(14px) scale(1); opacity: 0; } }
.wo-bird { position: absolute; font-size: 30px; will-change: transform; filter: drop-shadow(0 3px 4px rgba(0,0,0,.12)); }
.wo-bird.ltr { left: -8%; animation: wo-fly-ltr 3s ease-in-out forwards; }
.wo-bird.rtl { right: -8%; animation: wo-fly-rtl 3s ease-in-out forwards; transform: scaleX(-1); }
@keyframes wo-fly-ltr { 0% { left: -8%; } 100% { left: 108%; } }
@keyframes wo-fly-rtl { 0% { right: -8%; } 100% { right: 108%; } }
.wo-bird.ltr, .wo-bird.rtl { animation-name: wo-fly-ltr, wo-flap; animation-duration: 3s, .32s; animation-timing-function: ease-in-out, ease-in-out; animation-iteration-count: 1, infinite; animation-fill-mode: forwards, none; }
.wo-bird.rtl { animation-name: wo-fly-rtl, wo-flap; }
@keyframes wo-flap { 0%,100% { transform: translateY(0) scaleX(var(--fx,1)); } 50% { transform: translateY(-10px) scaleX(var(--fx,1)); } }
.wo-bird.rtl { --fx: -1; }
.wo-petal { position: absolute; top: -6%; animation: wo-drift 3s linear forwards; }
@keyframes wo-drift { 0% { transform: translateY(-10vh) rotate(0); opacity: 0; } 10% { opacity: 1; } 100% { transform: translateY(112vh) rotate(200deg); opacity: 0; } }
.wo-banner { position: absolute; left: 50%; top: 20%; transform: translate(-50%, -50%); text-align: center;
  background: rgba(255,255,255,.94); border-radius: 22px; padding: 12px 22px; box-shadow: 0 12px 34px rgba(20,40,28,.24);
  border: 3px solid var(--wkey, #2f9e57); animation: wo-pop .5s cubic-bezier(.2,1.6,.4,1) both, wo-fade .6s ease 2.5s forwards;
  display: flex; flex-direction: column; align-items: center; gap: 2px; max-width: 86vw; }
.wo-banner.big { top: 34%; padding: 18px 30px; }
.wo-banner .wo-em { font-size: 44px; }
.wo-banner.big .wo-em { font-size: 60px; animation: wo-em-bob 1.1s ease-in-out infinite; }
.wo-banner .wo-title { font-weight: 800; font-size: clamp(18px, 5vw, 26px); color: var(--wdeep, #1c6b3f); }
.wo-banner .wo-sub { font-size: 14px; color: var(--ink-soft, #6b7a6b); font-weight: 700; }
.app[data-theme="night"] .wo-banner { background: #1c2b3f; }
.app[data-theme="night"] .wo-banner .wo-title { color: #bfe9cf; }
@keyframes wo-pop { 0% { transform: translate(-50%,-50%) scale(.6); opacity: 0; } 100% { transform: translate(-50%,-50%) scale(1); opacity: 1; } }
@keyframes wo-fade { to { opacity: 0; transform: translate(-50%,-58%) scale(.96); } }
@keyframes wo-em-bob { 0%,100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-8px) rotate(4deg); } }
.app.reduce-motion .km-worldopen, .app.reduce-effects .km-worldopen { display: none; }

/* ============================================================
   rc.13 — 3D DOLLHOUSE. A gently-tilted, floating cutaway home
   whose rooms transform from empty to alive as items are owned.
   Pure CSS, GPU-friendly (transform/opacity only), mobile-first.
   ============================================================ */
.house3d { perspective: 1100px; margin: 6px 0 10px; }
.house3d-inner {
  transform-style: preserve-3d;
  transform: rotateX(5deg);
  animation: h3-float 6s ease-in-out infinite;
  will-change: transform;
}
@keyframes h3-float { 0%,100% { transform: rotateX(5deg) translateY(0); } 50% { transform: rotateX(5deg) translateY(-6px); } }
.app.reduce-motion .house3d-inner, .app.reduce-effects .house3d-inner { animation: none; }

/* roof */
.h3-roof {
  position: relative; height: 42px; margin: 0 auto -6px; width: 96%;
  background: linear-gradient(180deg, var(--roof1, #d9694e), var(--roof2, #b64a34));
  clip-path: polygon(6% 100%, 0 100%, 14% 0, 86% 0, 100% 100%, 94% 100%);
  box-shadow: 0 6px 12px rgba(20,20,30,.16); z-index: 3; transform: translateZ(18px);
  display: flex; align-items: flex-end; justify-content: center;
}
.h3-nameplate {
  margin-bottom: 4px; font-size: 12.5px; font-weight: 800; color: #fff;
  background: rgba(0,0,0,.22); border-radius: 999px; padding: 2px 12px; white-space: nowrap;
  text-shadow: 0 1px 2px rgba(0,0,0,.3);
}
.h3-chimney { position: absolute; right: 18%; top: -14px; width: 16px; height: 22px; background: linear-gradient(180deg, #8a5a3c, #6d4227); border-radius: 3px 3px 0 0; }
.h3-smoke { position: absolute; left: 3px; top: -8px; width: 9px; height: 9px; border-radius: 50%; background: rgba(230,230,235,.75); animation: h3-smoke 2.4s ease-out infinite; }
@keyframes h3-smoke { 0% { transform: translateY(0) scale(.6); opacity: .8; } 100% { transform: translateY(-30px) translateX(-8px) scale(1.5); opacity: 0; } }
.app.reduce-motion .h3-smoke { display: none; }

/* body */
.h3-body {
  border-radius: 4px 4px 18px 18px; overflow: hidden; position: relative; z-index: 2;
  background: linear-gradient(180deg, var(--wallc, #f3e2c2), var(--wallc2, #e9d3a8));
  box-shadow: var(--shadow), inset 0 0 0 3px rgba(255,255,255,.35);
  padding: 8px; display: flex; flex-direction: column; gap: 8px;
}
.app[data-theme="night"] .h3-body { background: linear-gradient(180deg, #2c3157, #242946); }
.house-rooms { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.room {
  position: relative; min-height: 108px; border-radius: 12px; padding: 6px 8px 8px;
  background: linear-gradient(180deg, #fffdf8 0%, #fff 55%, #efe7db 100%);
  box-shadow: inset 0 -14px 16px -12px rgba(80,60,30,.28), inset 0 0 0 1.5px rgba(160,140,100,.28);
  overflow: hidden; transition: box-shadow .3s ease, transform .2s ease;
}
.app[data-theme="night"] .room { background: linear-gradient(180deg, #333a63 0%, #2c3157 60%, #262a4d 100%); box-shadow: inset 0 -14px 16px -12px rgba(0,0,0,.4), inset 0 0 0 1.5px rgba(150,170,220,.25); }
.room .room-label { font-size: 11.5px; font-weight: 800; color: #8a7250; margin-bottom: 2px; letter-spacing: .2px; }
.app[data-theme="night"] .room .room-label { color: #9fb0dd; }
.room-stage { position: relative; display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: center; gap: 8px; min-height: 112px; }
.room.empty { filter: saturate(.6); }
.room.empty .room-stage { align-items: center; }
.room-hint {
  font-size: 11.5px; color: #a99878; font-weight: 700; text-align: center; line-height: 1.3;
  border: 1.5px dashed rgba(150,130,90,.5); border-radius: 10px; padding: 8px 6px; width: 92%;
}
.app[data-theme="night"] .room-hint { color: #8fa0cc; border-color: rgba(150,170,220,.4); }
.room.furnished { box-shadow: inset 0 -14px 16px -12px rgba(255,190,80,.4), inset 0 0 0 1.5px rgba(255,200,110,.55), 0 0 16px rgba(255,205,120,.28); }
.room.furnished .room-label { color: #b07a2a; }
.room-item { font-size: 46px; }
.room-item.room-centre { font-size: 68px; filter: drop-shadow(0 4px 6px rgba(0,0,0,.18)); }
/* living & celestial things quietly animate on their own (home + shop) */
.idle-wrap { display: inline-flex; transform-origin: bottom center; }
.idle-swim { animation: idle-swim 3.2s ease-in-out infinite; }
@keyframes idle-swim { 0%,100% { transform: translateX(0) rotate(-3deg); } 50% { transform: translateX(6px) rotate(3deg); } }
.idle-fly { animation: idle-fly 2.4s ease-in-out infinite; }
@keyframes idle-fly { 0%,100% { transform: translateY(0) rotate(-4deg); } 50% { transform: translateY(-8px) rotate(4deg); } }
.idle-hop { animation: idle-hop 1.7s ease-in-out infinite; }
@keyframes idle-hop { 0%,58%,100% { transform: translateY(0); } 30% { transform: translateY(-10px); } }
.idle-bob { animation: idle-bob 2.8s ease-in-out infinite; }
@keyframes idle-bob { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-5px); } }
.idle-sway { animation: idle-sway 3.8s ease-in-out infinite; transform-origin: bottom center; }
@keyframes idle-sway { 0%,100% { transform: rotate(-5deg); } 50% { transform: rotate(5deg); } }
.idle-twinkle { animation: idle-twinkle 1.9s ease-in-out infinite; }
@keyframes idle-twinkle { 0%,100% { transform: scale(1); opacity: .85; } 50% { transform: scale(1.18); opacity: 1; filter: drop-shadow(0 0 6px rgba(255,230,120,.9)); } }
.idle-glow { animation: idle-glow 3s ease-in-out infinite; }
@keyframes idle-glow { 0%,100% { filter: drop-shadow(0 0 2px rgba(255,240,180,.5)); } 50% { filter: drop-shadow(0 0 9px rgba(255,240,180,.95)); } }
.idle-spin-slow { animation: idle-spin-slow 9s linear infinite; }
@keyframes idle-spin-slow { to { transform: rotate(360deg); } }
.app.reduce-motion .idle-swim, .app.reduce-motion .idle-fly, .app.reduce-motion .idle-hop,
.app.reduce-motion .idle-bob, .app.reduce-motion .idle-sway, .app.reduce-motion .idle-twinkle,
.app.reduce-motion .idle-glow, .app.reduce-motion .idle-spin-slow,
.app.reduce-effects .idle-swim, .app.reduce-effects .idle-fly, .app.reduce-effects .idle-hop,
.app.reduce-effects .idle-bob, .app.reduce-effects .idle-sway, .app.reduce-effects .idle-twinkle,
.app.reduce-effects .idle-glow, .app.reduce-effects .idle-spin-slow { animation: none !important; }
.room-more { display: block; margin: 6px auto 0; font-size: 12px; font-weight: 800; color: #b07a2a; background: rgba(255,255,255,.55); border: 1.5px solid rgba(176,122,42,.45); border-radius: 999px; padding: 6px 10px; min-height: 32px; cursor: pointer; }
.app[data-theme="night"] .room-more { background: rgba(255,255,255,.08); color: #ffd867; border-color: rgba(255,216,103,.45); }
.room .room-extra { display: none; }                 /* the seventh toy onward waits behind "+N more" */
.room.open .room-extra { display: inline-flex; }
.room.open .room-stage { max-height: 260px; overflow-y: auto; align-items: flex-start; align-content: flex-start; padding-bottom: 4px; }
/* lit-window glow for furnished rooms */
.room.furnished::before { content: ""; position: absolute; top: 6px; right: 8px; width: 14px; height: 14px; border-radius: 3px; background: radial-gradient(circle, #fff2b0, #ffd867); box-shadow: 0 0 10px #ffd867; opacity: .9; }

/* garden strip runs full width along the bottom */
.room-garden { grid-column: 1 / -1; min-height: 96px;
  background: linear-gradient(180deg, #eaf6e6 0%, #d8efce 60%, #b6dfa0 100%); }
.app[data-theme="night"] .room-garden { background: linear-gradient(180deg, #1f3b2f 0%, #1a3327 60%, #14281f 100%); }
.room-garden .room-stage { min-height: 104px; }
.garden-tree { transition: font-size .4s ease, transform .3s ease; transform-origin: bottom center; align-self: flex-end; line-height: 1; }
.garden-tree.tree-wonder { filter: drop-shadow(0 0 9px rgba(120,220,150,.65)); animation: h3-float 5s ease-in-out infinite; }
.garden-tree-label { align-self: flex-end; font-size: 10.5px; font-weight: 700; color: #5f8a52; margin-left: 4px; margin-bottom: 4px; }
.app[data-theme="night"] .garden-tree-label { color: #8fc79a; }

/* the Wonder Villa — a lovely luxury home, given from the very start */
.house3d.tier-villa { --roof1:#c8873f; --roof2:#9a5f28; --wallc:#fff7e6; --wallc2:#f4e6be; }
.house3d.tier-villa .h3-body { box-shadow: var(--shadow), inset 0 0 0 3px rgba(255,255,255,.55); }
.house3d.tier-villa .h3-nameplate { background: rgba(120,90,10,.32); }
.house3d.tier-villa .h3-roof { box-shadow: 0 7px 18px rgba(150,110,20,.30); }

/* ---- Today: plant growth-level ladder + daily task rows ---- */
.stage-ladder { display: flex; gap: 8px; overflow-x: auto; padding: 2px 2px 6px; -webkit-overflow-scrolling: touch; }
.stage-chip {
  /* grow to share the row evenly (no ragged gap at the end), but never
     shrink below 84px — so on a phone the ladder scrolls instead */
  flex: 1 0 84px; display: flex; flex-direction: column; align-items: center; gap: 2px;
  min-width: 84px; padding: 9px 10px; border-radius: 16px;
  border: 1.5px solid var(--card-edge, #e2ece2); background: var(--card, #fff);
  background-image: linear-gradient(180deg, rgba(255,255,255,.5), rgba(0,0,0,.04));
}
.stage-chip .sc-em { font-size: 24px; line-height: 1; }
.stage-chip .sc-name { font-size: 11.5px; font-weight: 800; text-align: center; color: var(--ink, #22302a); }
.stage-chip .sc-at { font-size: 11px; font-weight: 700; color: var(--ink-faint, #7d8a7d); }
.stage-chip.stage-cur { border-color: var(--accent, #2f9e57); box-shadow: 0 0 0 2.5px rgba(47,158,87,.5), 0 0 16px rgba(47,158,87,.35); }
.stage-chip.stage-cur .sc-at { color: var(--accent, #2f9e57); }
.stage-chip.stage-done { opacity: .95; }
.stage-chip.stage-done .sc-at { color: var(--accent, #2f9e57); }
.stage-chip.stage-next { opacity: .62; }
.app[data-theme="night"] .stage-chip { background: #2b3d63; background-image: linear-gradient(180deg, rgba(255,255,255,.10), rgba(0,0,0,.16)); border-color: #566ea6; }
.app[data-theme="night"] .stage-chip .sc-name { color: #eaf0ff; }
.app[data-theme="night"] .stage-chip .sc-at { color: #b6c0e4; }
.task-bar { display: block; height: 7px; border-radius: 999px; background: var(--card-edge, #e2ece2); overflow: hidden; margin-top: 5px; }
.task-bar > span { display: block; height: 100%; border-radius: 999px; background: linear-gradient(90deg, #7c5cf0, #2f9e57, #e8a013); transition: width .35s ease; }
.app[data-theme="night"] .task-bar { background: rgba(255,255,255,.16); }
.today-fun-row.task-done .today-fun-t { opacity: .8; }
.today-fun-row.task-done .today-fun-go { color: var(--accent, #2f9e57); }

/* ---- Parent progress report: hero, level card, milestone tiles ---- */
.rep-hero { padding: 6px 0 2px; }
.rep-hero-title { font-size: clamp(26px, 5vw, 40px); line-height: 1.1; margin: 2px 0 4px; }
.rep-level .rep-seed { font-size: 40px; line-height: 1; }
.rep-level .rep-big { font-size: clamp(22px, 4vw, 30px); font-weight: 900; line-height: 1.15; color: var(--ink, #22302a); }
.app[data-theme="night"] .rep-level .rep-big { color: var(--ink, #eaf2ea); }
.rep-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; }
.rep-tile {
  border: 1.5px solid var(--card-edge, #e2ece2); border-top: 4px solid var(--rt-accent, #2f9e57);
  border-radius: 18px; padding: 12px 14px; background: var(--card, #fff);
  background-image: linear-gradient(180deg, rgba(255,255,255,.5), rgba(0,0,0,.04));
}
.app[data-theme="night"] .rep-tile { background: #2b3d63; background-image: linear-gradient(180deg, rgba(255,255,255,.10), rgba(0,0,0,.16)); border-color: #566ea6; }
.rep-tile-1 { --rt-accent: #8a5cf6; } .rep-tile-2 { --rt-accent: #2f9de0; }
.rep-tile-3 { --rt-accent: #10b981; } .rep-tile-4 { --rt-accent: #e8a013; }
.rep-tile .rt-big { font-size: 26px; font-weight: 900; color: var(--rt-accent, #2f9e57); line-height: 1.1; }
.rep-tile .rt-lab { font-size: 12.5px; font-weight: 700; color: var(--ink-soft, #5c6873); margin-top: 2px; }
.app[data-theme="night"] .rep-tile .rt-lab { color: #b6c0e4; }

/* ---- brand: Switik mark beside the KidMantis name (top-left) ---- */
/* the logo is the way home — a real control, not a label */
.brand {
  display: inline-flex; align-items: center; gap: 8px; padding: 4px 8px; min-width: 0;
  background: none; border: 0; border-radius: 14px; cursor: pointer; font: inherit; color: inherit;
  -webkit-tap-highlight-color: transparent;
  transition: transform .16s ease, background .16s ease;
}
.brand:active { transform: scale(.97); }
.brand:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; }
@media (hover: hover) { .brand:hover { background: var(--wsoft); transform: translateY(-1px); } }
.brand-mark { display: block; width: 28px; height: 28px; flex: 0 0 auto; }
.brand-name { font-weight: 900; font-size: 17px; letter-spacing: -.01em; color: var(--ink, #22302a); white-space: nowrap; }
.app[data-theme="night"] .brand-name { color: var(--ink, #eaf2ea); }
@media (max-width: 899px) { .brand-name { display: none; } }

/* Switik's brand lockup in the footer of every page (rc.65, Slogan spec Part 2):
   "Switik · Screen time worth it" as live text, the slogan coloured from the
   same tokens as the mark. On LIGHT surfaces the word colours are the icon
   hues darkened with ink until they pass 4.5:1 on the card; in night mode the
   card is dark and the icon colours pass as they are. The lockup sits on a
   solid card pill, so its contrast never depends on what the sky is doing. */
.app { --sw-word-a: color-mix(in srgb, var(--sw-gold) 52%, #000); --sw-word-b: color-mix(in srgb, var(--sw-green) 52%, #000); }
.app[data-theme="night"] { --sw-word-a: var(--sw-gold); --sw-word-b: var(--sw-green); }
.foot-lockup { display: inline-flex; align-items: center; gap: 5px; padding: 2px 10px; border-radius: 999px; background: var(--card); border: 1px solid var(--card-edge); font-size: 11.5px; white-space: nowrap; color: var(--ink); }
.foot-lockup b { font-weight: 900; letter-spacing: -.01em; }
@media (max-width: 480px) { .foot-lockup { font-size: 11px; } }
/* plain text links in cards follow the theme (rc.65: the browser's default
   blue failed contrast on the night card — flagged while eyeballing the lockup) */
.card a:not(.btn) { color: var(--accent-deep); text-decoration: underline; }
/* the same lockup as a closing line on the parent surfaces */
.brand-close { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 6px; font-size: 15px; color: var(--ink); }
.brand-close img { width: 22px; height: 22px; }
.brand-close b { font-weight: 900; }
.brand-close .sw-slogan { font-size: 15px; }

/* ---- Switik studio splash: its CSS is INLINE in index.html <head>
   (rc.61, cold-start): the splash must paint before this stylesheet has
   arrived, so on a slow connection the child sees the mark at once instead
   of a blank screen while 180 KB of CSS and the game scripts download. ---- */

/* ============================================================
   GROWN-UPS SURFACE — a calm, professional admin area for
   parents. The playful garden chrome, drifting particles and
   rainbow button glow all belong to the child's side of the
   app; here we use quiet neutrals, clear hierarchy and space.
   ============================================================ */
.app.in-parent #sky, .app.in-parent .confetti,
.app.in-parent .mascot-stage { display: none !important; }
/* rc.86 (premium pass): the rc.70 rule above hid #sky, but the SEASONAL
   layer was added afterwards in its own fixed container and was never
   added to it. So petals, pollen and snow went on drifting across the
   grown-ups area — translucent discs crossing the sentence about where
   a child's data is stored, and over the Backup & Restore card. The
   celebration layer is here for the same reason: nothing on a parent's
   document should be moving while they read it. */
.app.in-parent .scenery-holder,
.app.in-parent .wpart,
.app.in-parent .celebrate-layer { display: none !important; }
/* The seasonal layer is a <canvas> appended to document.body — OUTSIDE
   #app — so no `.app.in-parent …` selector can ever reach it. That is
   why the rc.70 rule above, which has hidden #sky correctly since it
   was written, never stopped the petals and pollen drifting across the
   grown-ups area: they were never in #sky to begin with. Matched from
   the body instead, keyed on the class #app carries. */
body:has(#app.in-parent) .km-seasons { display: none !important; }
.app.in-parent { background: #f6f7f9; }
.app[data-theme="night"].in-parent { background: #10141c; }

/* rc.70 (owner): the grown-ups area gets REAL buttons — depth, a soft glow
   at rest, a brighter glow + lift on hover and keyboard focus — while the
   child-facing bounce/celebration animations stay off in here. Palette is the
   area's own calm indigo, not the garden green, so it still reads as the
   parents' surface. */
.app.in-parent .card, .app.in-parent .icon-btn, .app.in-parent .setting-row { animation: none !important; }
.app.in-parent .main .icon-btn { box-shadow: none !important; }
.app.in-parent .main .btn {
  --gb: #3b5bdb; --gb-deep: #2f4bb8; --gb-glow: rgba(59, 91, 219, .30);
  position: relative; background-color: var(--gb); background-image: linear-gradient(180deg, #5b7cff, var(--gb) 62%, #3450c8);
  border: 1px solid var(--gb-deep); color: #fff; text-shadow: 0 1px 1px rgba(10, 20, 60, .35);
  border-radius: 12px; font-weight: 700; animation: none;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .35), 0 3px 0 var(--gb-deep), 0 0 14px var(--gb-glow);
  transition: transform .12s ease, box-shadow .18s ease, filter .18s ease;
}
.app.in-parent .main .btn.alt { background-color: var(--gb); background-image: linear-gradient(180deg, #5b7cff, var(--gb) 62%, #3450c8); border-color: var(--gb-deep); color: #fff; }
.app.in-parent .main .btn.has-cap .btn-cap { opacity: .96; }
.app.in-parent .main .btn:hover, .app.in-parent .main .btn:focus-visible {
  transform: translateY(-1px); filter: brightness(1.06);
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, .4), 0 4px 0 var(--gb-deep), 0 0 0 3px rgba(59, 91, 219, .22), 0 0 26px rgba(59, 91, 219, .55);
}
.app.in-parent .main .btn:active { transform: translateY(2px); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .3), 0 1px 0 var(--gb-deep), 0 0 12px var(--gb-glow); }
.app.in-parent .main .btn:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.app.in-parent .main .btn.ghost {
  background: #fff; background-image: linear-gradient(180deg, #ffffff, #f3f5fb); color: #1f2a5c; text-shadow: none; border: 1px solid #c3cbe6;
  box-shadow: inset 0 1px 0 #fff, 0 3px 0 #c3cbe6, 0 0 12px rgba(59, 91, 219, .14);
}
.app.in-parent .main .btn.ghost:hover, .app.in-parent .main .btn.ghost:focus-visible {
  box-shadow: inset 0 1px 0 #fff, 0 4px 0 #c3cbe6, 0 0 0 3px rgba(59, 91, 219, .18), 0 0 22px rgba(59, 91, 219, .38); filter: none;
}
.app.in-parent .main .btn.ghost:active { box-shadow: inset 0 1px 0 #fff, 0 1px 0 #c3cbe6, 0 0 10px rgba(59, 91, 219, .14); }
.app.in-parent .main .btn.ghost:focus-visible { outline-color: #3b5bdb; }
.app[data-theme="night"].in-parent .main .btn, .app[data-theme="night"].in-parent .main .btn.alt { --gb: #3f5fe0; --gb-deep: #2f4bb8; --gb-glow: rgba(110, 140, 255, .34); background-color: var(--gb); background-image: linear-gradient(180deg, #5b7cff, var(--gb) 62%, #3450c8); border-color: #4a63d6; }
.app[data-theme="night"].in-parent .main .btn.ghost { background: #1a2130; background-image: linear-gradient(180deg, #212a3d, #1a2130); color: #e7ecf5; border-color: #3a4760; box-shadow: inset 0 1px 0 rgba(255,255,255,.06), 0 3px 0 #0f141e, 0 0 12px rgba(110, 140, 255, .18); }
.app[data-theme="night"].in-parent .main .btn.ghost:hover, .app[data-theme="night"].in-parent .main .btn.ghost:focus-visible { box-shadow: inset 0 1px 0 rgba(255,255,255,.08), 0 4px 0 #0f141e, 0 0 0 3px rgba(110, 140, 255, .25), 0 0 22px rgba(110, 140, 255, .45); }
@media (prefers-reduced-motion: reduce) {
  .app.in-parent .main .btn, .app.in-parent .main .btn:hover, .app.in-parent .main .btn:focus-visible { transition: none; transform: none; }
}

/* cards: flat, generous, hairline-separated */
.app.in-parent .main .card {
  background: #fff; border: 1px solid #e4e8ee; border-radius: 14px;
  box-shadow: 0 1px 2px rgba(16,24,40,.04); padding: 22px 24px;
}
.app[data-theme="night"].in-parent .main .card { background: #161c27; border-color: #2a3444; box-shadow: none; }
.app.in-parent .main h1 { font-size: 26px; letter-spacing: -.01em; }
.app.in-parent .main h2 { font-size: 16px; font-weight: 800; letter-spacing: .01em; margin: 0 0 4px; }
.app.in-parent .main p { line-height: 1.6; }
.app.in-parent .main .muted { color: #667085; }
.app[data-theme="night"].in-parent .main .muted { color: #98a4b8; }
.app.in-parent .setting-row {
  border-bottom: 1px solid #eef1f5; padding: 13px 0; margin: 0;
}
.app[data-theme="night"].in-parent .setting-row { border-bottom-color: #262f3d; }
.app.in-parent .setting-row:last-child { border-bottom: 0; }
.app.in-parent .setting-row label { font-weight: 650; }
.app.in-parent .setting-row .hint { color: #667085; font-weight: 400; }
.app[data-theme="night"].in-parent .setting-row .hint { color: #8d99ad; }

/* the rewards explainer reads as a document, not a game card */
.app.in-parent .rewards-doc p { margin: 0 0 12px; max-width: 68ch; }
.app.in-parent .rewards-doc p:last-child { margin-bottom: 0; }
.app.in-parent .rewards-doc .doc-lead {
  font-size: 13px; font-weight: 800; text-transform: uppercase; letter-spacing: .06em;
  color: #667085; margin: 0 0 10px;
}
.app[data-theme="night"].in-parent .rewards-doc .doc-lead { color: #8d99ad; }
.app.in-parent .rewards-doc .doc-rule { height: 1px; background: #eef1f5; margin: 16px 0; border: 0; }
.app[data-theme="night"].in-parent .rewards-doc .doc-rule { background: #262f3d; }

/* ============================================================
   MENAGERIE (rc.51) — the milestone animal cameos.
   A creature crosses the garden, moves the way that animal moves,
   and calls in its own voice. It NEVER takes a tap: the layer is
   inert, so a child can carry on regardless. Rare by design; the
   whole value is in how seldom it happens.
   ============================================================ */
.menagerie{position:fixed;inset:0;z-index:60;pointer-events:none;overflow:hidden}
.mg-act{
  position:absolute;bottom:16vh;left:0;width:min(196px,44vw);height:min(140px,32vw);
  will-change:transform;pointer-events:none;
}
.mg-act svg{width:100%;height:100%;overflow:visible;display:block}
.mg-em{font-size:min(76px,17vw);line-height:1;text-align:center;
  filter:drop-shadow(0 6px 10px rgba(0,0,0,.35))}
.mg-shadow{position:absolute;left:50%;bottom:-4px;width:64%;height:14px;translate:-50% 0;
  background:radial-gradient(ellipse at center,rgba(0,0,0,.34),transparent 70%);filter:blur(1px)}
.app[data-theme="night"] .mg-shadow{background:radial-gradient(ellipse at center,rgba(0,0,0,.55),transparent 70%)}
.rig-flyer .mg-shadow,.rig-flutter .mg-shadow,.rig-swim .mg-shadow{display:none}
/* the cameo says who it is, once, quietly */
.mg-name{
  position:absolute;left:50%;bottom:9vh;translate:-50% 0;
  font-weight:800;font-size:15px;color:var(--ink);
  background:color-mix(in srgb,var(--card) 88%,transparent);
  border:1px solid var(--card-edge);border-radius:999px;padding:7px 14px;
  box-shadow:var(--shadow-soft);animation:mgName 3.2s ease both;
}
@keyframes mgName{0%{opacity:0;transform:translateY(8px)}14%,74%{opacity:1;transform:none}100%{opacity:0}}

/* ---- gaits ---------------------------------------------------------
   Legs out of phase with a suspension beat, knees folding under the
   body, and a ground shadow that tightens on each footfall. Motion is
   what makes an animal read as alive — not detail. */
@keyframes mgStrideA{0%{transform:rotate(-32deg)}25%{transform:rotate(10deg)}
  50%{transform:rotate(30deg)}75%{transform:rotate(2deg)}100%{transform:rotate(-32deg)}}
@keyframes mgStrideB{0%{transform:rotate(26deg)}25%{transform:rotate(-6deg)}
  50%{transform:rotate(-30deg)}75%{transform:rotate(4deg)}100%{transform:rotate(26deg)}}
@keyframes mgKnee{0%,100%{transform:rotate(34deg)}40%{transform:rotate(2deg)}70%{transform:rotate(46deg)}}
@keyframes mgBob{0%,100%{transform:translateY(0) scaleY(1)}
  22%{transform:translateY(-9px) scaleY(1.03)}
  52%{transform:translateY(1px) scaleY(.965) scaleX(1.03)}
  78%{transform:translateY(-6px) scaleY(1.02)}}
@keyframes mgSwish{0%,100%{transform:rotate(-9deg)}50%{transform:rotate(11deg)}}
@keyframes mgNeck{0%,100%{transform:rotate(2.5deg)}50%{transform:rotate(-3deg)}}
@keyframes mgBlink{0%,96%,100%{transform:scaleY(1)}98%{transform:scaleY(.08)}}
@keyframes mgFlap{0%,100%{transform:rotate(-42deg) scaleY(1)}50%{transform:rotate(36deg) scaleY(.82)}}
@keyframes mgFlapFar{0%,100%{transform:rotate(-34deg) scaleY(1)}50%{transform:rotate(30deg) scaleY(.86)}}
@keyframes mgFin{0%,100%{transform:rotate(-14deg)}50%{transform:rotate(16deg)}}
@keyframes mgShadow{0%,100%{transform:translate(-50%,0) scale(1,1);opacity:.55}
  22%{transform:translate(-50%,0) scale(.82,1);opacity:.32}
  52%{transform:translate(-50%,0) scale(1.12,1);opacity:.62}}

.mg-act svg .lg,.mg-act svg .lg .lo,.mg-act svg .tail,.mg-act svg .mane,.mg-act svg .neck,
.mg-act svg .wingnear,.mg-act svg .wingfar,.mg-act svg .tailf,.mg-act svg .pec{transform-box:view-box}
.mg-act svg .eye{transform-box:fill-box;transform-origin:center;animation:mgBlink 5.5s linear infinite}

.go-run .lg-a{animation:mgStrideA .34s linear infinite}
.go-run .lg-b{animation:mgStrideB .34s linear infinite}
.go-run .lg-c{animation:mgStrideB .34s linear infinite;animation-delay:-.09s}
.go-run .lg-d{animation:mgStrideA .34s linear infinite;animation-delay:-.09s}
.go-run .lg .lo{animation:mgKnee .34s linear infinite}
.go-run svg{animation:mgBob .34s ease-in-out infinite}
.go-run .tail{animation:mgSwish .5s ease-in-out infinite}
.go-run .neck{animation:mgNeck .68s ease-in-out infinite}
.go-run .mg-shadow{animation:mgShadow .34s linear infinite}
/* a crawler is quicker and lower — same rig, different tempo */
.go-crawl .lg-a,.go-crawl .lg-d{animation:mgStrideA .2s linear infinite}
.go-crawl .lg-b,.go-crawl .lg-c{animation:mgStrideB .2s linear infinite}
.go-crawl svg{animation:mgBob .2s ease-in-out infinite}
.go-fly .wingnear{animation:mgFlap .26s ease-in-out infinite}
.go-fly .wingfar{animation:mgFlapFar .26s ease-in-out infinite}
.go-fly .tailf{animation:mgSwish .52s ease-in-out infinite}
/* a butterfly beats far faster and less evenly than a bird */
.go-flutter .wingnear{animation:mgFlap .13s ease-in-out infinite}
.go-flutter .wingfar{animation:mgFlapFar .13s ease-in-out infinite}
.go-swim .pec{animation:mgFin .5s ease-in-out infinite}

.app.reduce-motion .mg-act *,.app.reduce-motion .mg-name{animation:none !important}
@media (prefers-reduced-motion: reduce){ .mg-act *,.mg-name{animation:none !important} }
.app.reduce-effects .menagerie{display:none}

/* Grown-ups → Sound check readout (rc.53) */
.sound-check{
  margin:0;padding:12px 14px;border-radius:14px;
  background:color-mix(in srgb,var(--ink) 6%,var(--card));border:1px solid var(--card-edge);
  font:500 12.5px/1.6 ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:var(--ink);
  white-space:pre-wrap;word-break:break-word;
}

/* ============================================================
   rc.57 — ROUND 2, PARENT TRUST (grownups.js)
   ============================================================ */
/* 2.1 the promise */
.promise-link { font-weight: 800; color: var(--accent-deep); text-decoration: none; border-bottom: 2px solid color-mix(in srgb, var(--accent) 40%, transparent); }
.promise-link:hover, .promise-link:focus-visible { border-bottom-color: var(--accent); }
/* rc.64 — the promise as a button that cannot be missed: full width, tall,
   grown-up gold, three facts on its face, arrow. Distinct from the child's
   green Start button so a parent finds it and a child isn't pulled into it. */
.promise-cta {
  display: flex; align-items: center; gap: 12px; width: 100%; max-width: 440px; min-height: 64px;
  margin: 6px auto 0; padding: 12px 14px 12px 16px; border-radius: 18px; text-decoration: none; text-align: left;
  background: linear-gradient(180deg, #fff7dd, var(--gold-soft)); color: #6b4a08;
  border: 2px solid color-mix(in srgb, var(--gold) 70%, #fff); box-shadow: 0 4px 0 color-mix(in srgb, var(--gold) 60%, #b07a2a), 0 8px 18px rgba(176, 122, 42, .22);
  transition: transform .1s ease, box-shadow .15s ease;
}
.promise-cta:hover, .promise-cta:focus-visible { box-shadow: 0 4px 0 var(--gold), 0 10px 22px rgba(176, 122, 42, .3), 0 0 0 3px color-mix(in srgb, var(--gold) 45%, transparent); outline: none; }
.promise-cta:active { transform: translateY(3px); box-shadow: 0 1px 0 var(--gold); }
.promise-cta .pc-ic { font-size: 30px; line-height: 1; flex-shrink: 0; }
.promise-cta .pc-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.promise-cta .pc-title { font-weight: 800; font-size: 17px; line-height: 1.2; }
.promise-cta .pc-sub { font-size: 12.5px; font-weight: 600; color: #8a6412; line-height: 1.3; }
.promise-cta .pc-arrow { font-size: 30px; font-weight: 800; line-height: 1; color: #b07a2a; flex-shrink: 0; }
.app[data-theme="night"] .promise-cta { background: linear-gradient(180deg, #3a3150, #2e2742); color: #ffe8a8; border-color: rgba(244, 183, 64, .6); box-shadow: 0 4px 0 #7a5a12, 0 8px 18px rgba(0, 0, 0, .35); }
.app[data-theme="night"] .promise-cta .pc-sub { color: #e6c877; }
.app[data-theme="night"] .promise-cta .pc-arrow { color: #F4B740; }
@media (max-width: 340px) { .promise-cta .pc-title { font-size: 16px; } .promise-cta .pc-sub { font-size: 12px; } }

/* rc.80 (KM-PX-10) — the welcome-screen restore line. Deliberately QUIET:
   it is a grown-up's errand on a child's screen, so it must be findable
   without competing with "Start growing". Text-weight, not a slab.
   Line-height 1.45: Baloo 2's glyph box clips descenders below that. */
.restore-hint {
  min-height: 44px; margin: 2px auto 0; padding: 10px 14px; border-radius: 14px;
  font-size: 14px; line-height: 1.45; font-weight: 700; color: var(--ink-soft, #6b6250);
  background: transparent; border: 1.5px dashed color-mix(in srgb, var(--ink-soft, #6b6250) 32%, transparent);
  box-shadow: none;
}
.restore-hint:hover, .restore-hint:focus-visible { border-style: solid; border-color: color-mix(in srgb, var(--gold) 70%, transparent); color: #6b4a08; outline: none; }
.app[data-theme="night"] .restore-hint { color: #c9c2b2; border-color: rgba(255, 255, 255, .22); }
.app[data-theme="night"] .restore-hint:hover, .app[data-theme="night"] .restore-hint:focus-visible { color: #ffe8a8; border-color: rgba(244, 183, 64, .6); }

/* rc.80 — the welcome screen in portrait is unchanged: both wrappers are
   `display: contents`, so their children are laid out by .stack exactly as
   they were before rc.80. The landscape rule below is the only place they
   become boxes. */
.welcome > .w-hero, .welcome > .w-actions { display: contents; }

/* rc.64 — the shop/house cue: a calm dot (and a soft breath of glow) on the
   Shop and House nav entries while something new is affordable. Reduced
   effects keeps the dot, drops the glow. Silent, no bounce, no number. */
.icon-btn { position: relative; }
.icon-btn .new-dot { position: absolute; top: 5px; right: 6px; width: 10px; height: 10px; border-radius: 50%; background: var(--gold); border: 2px solid var(--card); box-shadow: 0 0 0 0 rgba(244, 183, 64, .55); animation: new-breathe 2.6s ease-in-out infinite; }
@keyframes new-breathe { 0%, 100% { box-shadow: 0 0 0 0 rgba(244, 183, 64, .55); } 50% { box-shadow: 0 0 0 5px rgba(244, 183, 64, 0); } }
.app.reduce-effects .icon-btn .new-dot, .app.reduce-motion .icon-btn .new-dot { animation: none; box-shadow: none; }
.promise-lede { margin: 0; font-size: 16px; line-height: 1.55; max-width: 62ch; }
.promise-list { display: grid; gap: 10px; }
.promise-item { display: grid; grid-template-columns: 40px 1fr; gap: 10px; align-items: start;
  padding: 12px 14px; border-radius: 16px; background: color-mix(in srgb, var(--accent) 6%, var(--card)); border: 1px solid var(--card-edge); }
.promise-em { font-size: 26px; line-height: 1; padding-top: 2px; text-align: center; }
.promise-claim { font-weight: 800; font-size: 16px; line-height: 1.3; }
.promise-proof { margin: 4px 0 0; color: var(--ink-soft); font-size: 14px; line-height: 1.5; }
.promise-card h2 { font-size: 18px; }
/* 2.2 arrival summary */
.arrival-card { border-color: color-mix(in srgb, var(--accent) 45%, var(--card-edge)); background: color-mix(in srgb, var(--accent) 5%, var(--card)); }
.chip { display: inline-block; padding: 4px 10px; border-radius: 999px; font-size: 13px; font-weight: 700;
  background: color-mix(in srgb, var(--accent) 14%, var(--card)); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--card-edge)); color: var(--ink); }
.ask-card { display: grid; grid-template-columns: 34px 1fr; gap: 10px; align-items: start; padding: 12px 14px; border-radius: 16px;
  background: var(--gold-soft); border: 1px solid color-mix(in srgb, var(--gold) 55%, var(--card-edge)); }
.ask-em { font-size: 24px; line-height: 1; padding-top: 2px; }
.ask-card p { line-height: 1.5; }
/* 2.4 backup */
.nudge-card { border-color: color-mix(in srgb, var(--gold) 60%, var(--card-edge)); background: var(--gold-soft); }
.profile-block { padding: 8px 0; border-bottom: 1px solid var(--card-edge); }
.profile-block:last-child { border-bottom: 0; }
.profile-block .setting-row { flex-wrap: wrap; gap: 8px; }
.backup-status { display: block; font-size: 12.5px; }
.backup-status.ok { color: var(--accent-deep); }
.backup-status.warn { color: #b8651a; font-weight: 800; }
.app[data-theme="night"] .backup-status.warn { color: #f2b56a; }
/* 2.3 the garden gets sleepy — atmosphere only, never a lock */
.app.sleepy #sky { filter: saturate(.78) brightness(.82); transition: filter 2.4s ease; }
.app.sleepy #sky::after { content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(58, 42, 96, .34), rgba(214, 120, 80, .18) 55%, rgba(30, 24, 60, .30)); animation: sleepy-in 2.4s ease both; }
@keyframes sleepy-in { from { opacity: 0; } to { opacity: 1; } }
.app.sleepy .main { transition: filter 2s ease; }
.mascot-stage.sleepy .mascot { animation: sleepy-bob 4.2s ease-in-out infinite !important; }
.mascot-stage.sleepy .mascot::after { content: "z z"; position: absolute; right: -10px; top: -6px; font-weight: 900; font-size: 14px; color: var(--ink-soft);
  letter-spacing: 3px; animation: sleepy-z 3.2s ease-in-out infinite; pointer-events: none; }
@keyframes sleepy-bob { 0%, 100% { transform: translateY(0) scale(1, 1); } 50% { transform: translateY(2px) scale(1.01, .985); } }
@keyframes sleepy-z { 0% { opacity: 0; transform: translateY(6px); } 30% { opacity: .9; } 100% { opacity: 0; transform: translateY(-16px); } }
.app.reduce-motion .mascot-stage.sleepy .mascot, .app.reduce-motion .mascot-stage.sleepy .mascot::after { animation: none !important; }
/* the goodnight scene */
.goodnight { position: fixed; inset: 0; z-index: 90; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px; padding: 24px;
  background: radial-gradient(ellipse at 50% 30%, #2b3a6b, #131a33 70%); color: #eef1ff; text-align: center; animation: sleepy-in .9s ease both; }
.gn-sky { position: absolute; inset: 0; pointer-events: none; }
.gn-moon { position: absolute; right: 12%; top: 9%; font-size: 54px; animation: gn-float 6s ease-in-out infinite; }
.gn-star { position: absolute; color: #ffe9a8; font-size: 16px; animation: gn-twinkle 2.6s ease-in-out infinite; }
.gn-star.s1 { left: 14%; top: 16%; } .gn-star.s2 { left: 30%; top: 8%; animation-delay: .8s; } .gn-star.s3 { right: 30%; top: 20%; animation-delay: 1.5s; }
@keyframes gn-float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } }
@keyframes gn-twinkle { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }
.gn-duo { display: flex; align-items: flex-end; gap: 18px; }
.gn-duo img { height: min(140px, 28vw); filter: drop-shadow(0 0 14px rgba(180, 255, 200, .35)); animation: sleepy-bob 4.2s ease-in-out infinite; }
.gn-tree { font-size: 64px; filter: drop-shadow(0 0 22px rgba(255, 230, 150, .75)); animation: gn-glow 3.5s ease-in-out infinite; }
@keyframes gn-glow { 0%, 100% { filter: drop-shadow(0 0 14px rgba(255, 230, 150, .5)); } 50% { filter: drop-shadow(0 0 30px rgba(255, 230, 150, .95)); } }
.gn-title { margin: 0; font-size: clamp(26px, 6vw, 38px); }
.gn-line { margin: 0; max-width: 40ch; font-size: 16px; line-height: 1.5; color: #d6dcf5; }
.goodnight .btn.ghost { color: #d6dcf5; border-color: rgba(255, 255, 255, .3); background: transparent; }
.app.reduce-motion ~ .goodnight *, .goodnight.calm * { animation: none !important; }
@media (prefers-reduced-motion: reduce) { .goodnight *, .mascot-stage.sleepy .mascot, .mascot-stage.sleepy .mascot::after, .app.sleepy #sky::after { animation: none !important; } }

/* ============================================================
   rc.58 — ROUND 3, FEATURES THAT BIND CHILD AND PARENT (family.js)
   ============================================================ */
/* 3.1 sprouts */
.sprout-card { --pos: 16,185,129; display: grid !important; grid-template-columns: 1fr; gap: 8px; text-align: left; }
.sprout-card .row { gap: 8px; }
.sprout-card h2 { font-size: 20px; }
/* 3.2 grown-up & me */
.gm-intro { border-color: color-mix(in srgb, var(--gold) 55%, var(--card-edge)); }
.gm-card .r-sub { color: var(--accent-deep); font-weight: 700; }
.turn-banner.t2 { background: color-mix(in srgb, var(--gold) 26%, var(--card)); }
/* 3.4 read-along */
.ra-live .ra-word { border-radius: 6px; padding: 0 2px; margin: 0 -2px; transition: background .12s ease, color .12s ease; }
.ra-word.ra-on { background: var(--gold); color: #1d1a0e; font-weight: 800; }
.ra-word.ra-sent { background: color-mix(in srgb, var(--gold) 38%, transparent); }
.app[data-theme="night"] .ra-word.ra-on { background: #f2c14e; color: #1d1a0e; }
.app[data-theme="night"] .ra-word.ra-sent { background: color-mix(in srgb, #f2c14e 34%, transparent); color: var(--ink); }
/* 3.5 recap */
.recap-card { display: grid; gap: 8px; padding: 12px 14px; border-radius: 16px; background: var(--card); border: 1px solid var(--card-edge); color: var(--ink); text-align: left; max-width: 46ch; }
.goodnight .recap-card { background: rgba(255, 255, 255, .08); border-color: rgba(255, 255, 255, .18); color: #eef1ff; }
.goodnight .recap-card .today-eyebrow { color: #ffe9a8; }
.recap-list { display: grid; gap: 6px; }
.recap-line { display: grid; grid-template-columns: 30px 1fr; gap: 8px; align-items: start; font-size: 15px; line-height: 1.4; }
.recap-em { font-size: 22px; line-height: 1; }
/* 3.3 printables — on screen */
.print-screen .printable { background: #fff; color: #1a1a1a; border-radius: 16px; padding: 22px; border: 1px solid #d8d8d8; box-shadow: 0 8px 24px rgba(0,0,0,.08); }
.print-bar { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: space-between; }
.certificate .cert-frame { border: 6px double #2f6b3f; border-radius: 12px; padding: 24px 18px; text-align: center; display: grid; gap: 8px; justify-items: center; }
.cert-brand { font-size: 12px; letter-spacing: .12em; text-transform: uppercase; color: #555; }
.cert-eyebrow { font-size: 14px; letter-spacing: .2em; font-weight: 800; color: #2f6b3f; }
.cert-mark { font-size: 64px; line-height: 1; }
.cert-name { font-size: clamp(30px, 8vw, 46px); font-weight: 900; color: #1a1a1a; }
.cert-line { margin: 0; font-size: 18px; max-width: 40ch; }
.cert-line.small { font-size: 14px; color: #444; }
.pr-duo { display: flex; gap: 18px; align-items: flex-end; }
.pr-duo img { height: 96px; }
.cert-foot { display: flex; justify-content: space-between; width: 100%; font-size: 13px; color: #444; border-top: 1px solid #ccc; padding-top: 8px; margin-top: 6px; }
.coloring .col-title { font-size: 28px; font-weight: 900; text-align: center; }
.coloring .col-sub { text-align: center; color: #444; margin-bottom: 8px; }
.col-art { width: min(100%, 520px); margin: 0 auto; }
.col-art svg, .col-scene svg { width: 100%; height: auto; display: block; }
.col-scene { border: 2px solid #222; border-radius: 12px; overflow: hidden; margin-top: 10px; aspect-ratio: 640 / 230; }
.col-scene svg { height: 100%; }
/* outline rendering: every fill becomes white with a dark stroke */
.coloring .col-art svg *, .coloring .col-scene svg * { fill: #fff !important; stroke: #222 !important; stroke-width: 1.4px; opacity: 1 !important; }
.coloring .col-art svg [fill="none"] { fill: none !important; }
.col-foot { text-align: center; font-size: 12px; color: #555; margin-top: 12px; }
.gallery .gal-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; }
.gal-item { margin: 0; border: 1px solid #ccc; border-radius: 10px; padding: 8px; background: #fff; break-inside: avoid; }
.gal-item img { width: 100%; border-radius: 6px; display: block; }
.gal-item figcaption { font-size: 12px; color: #444; margin-top: 6px; text-align: center; }
/* 3.3 printables — on paper: only the sheet prints, day colours forced, A4 and Letter */
@media print {
  @page { margin: 12mm; }
  html, body { background: #fff !important; }
  body * { visibility: hidden !important; }
  .printable, .printable * { visibility: visible !important; }
  .printable { position: absolute !important; left: 0; top: 0; width: 100%; margin: 0; padding: 0 !important; border: 0 !important; box-shadow: none !important; border-radius: 0 !important; background: #fff !important; color: #111 !important; }
  .no-print, .topbar, .bottom-nav, .site-footer, .sky, .mascot-stage, .toast-zone, .caption-bar, #modal-root, .splash { display: none !important; }
  .certificate .cert-frame { min-height: 160mm; }
  .cert-line, .cert-name, .cert-eyebrow, .col-title, .col-sub { color: #111 !important; }
  .cert-eyebrow { color: #2f6b3f !important; }
  .gal-item { page-break-inside: avoid; }
}

/* rc.68 (New Requirements item 1): grown-ups buttons carry a VISIBLE one-line
   caption of what they do — a second line inside the button, on every device
   (rc.72, owner: the caption must never be hidden; the rc.70 hover-only
   tooltip on mouse devices is gone). Ink on the button's own surface passes
   AA on both themes; long captions wrap, never overflow. Hover / focus still
   brighten the glow (see the Grown-ups button rules). */
.btn.has-cap { flex-direction: column; align-items: flex-start; text-align: left; gap: 2px; padding-top: 9px; padding-bottom: 9px; max-width: 100%; position: relative; }
.btn.has-cap .btn-cap { display: block; font-size: 12px; font-weight: 500; line-height: 1.25; letter-spacing: 0; text-transform: none; white-space: normal; opacity: .88; max-width: 100%; }
.center .btn.has-cap { align-items: center; text-align: center; }

/* rc.69 — the realistic illustration library (assets/art/*.webp, transparent 192px).
   Picture words: the image fills the same 1.15em / 1.2em slot the drawn symbol
   used. Shop / collection / house / delivery: a square image sized to its slot,
   never the sole carrier of meaning — every tile keeps its name and aria. */
.pw-img { object-fit: contain; display: inline-block; vertical-align: middle; }
.shop-img { display: block; object-fit: contain; width: 100%; height: 100%; }
.shop-item .s-em .s-img { width: 92px; height: 92px; margin: 0 auto; }
.badge .b-em .b-img { width: 52px; height: 52px; margin: 0 auto; }
.th-toy .th-img { display: block; }
.km-deliver-big .big-img { width: 150px; height: 150px; filter: none; }

/* ============================================================
   rc.72 — TAP REACTIONS (js/react.js). Transform/opacity only, on the
   picture itself (library image, drawn svg, or emoji). One class per
   kind; the JS adds it for the length of the move and removes it after.
   Reduce Motion / Reduced effects: .rx-pulse — a soft glow held ~0.5 s,
   no keyframes (the global reduce-motion rule clamps animations anyway).
   ============================================================ */
.rx { display: inline-block; transform-origin: 50% 88%; will-change: transform; backface-visibility: hidden; }
img.rx, svg.rx { display: block; }
.rx-wired { cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
.rx-wired:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; border-radius: 12px; }
.rx-pulse { transition: filter .12s ease, box-shadow .12s ease; filter: brightness(1.12) drop-shadow(0 0 10px rgba(63, 174, 99, .75)); }
@keyframes rxHop { 0% { transform: none } 25% { transform: scaleX(1.12) scaleY(.86) } 50% { transform: translateY(-22%) scaleX(.94) scaleY(1.08) rotate(-4deg) } 75% { transform: translateY(0) scaleX(1.08) scaleY(.92) } 100% { transform: none } }
@keyframes rxSkitter { 0% { transform: none } 20% { transform: scaleX(1.1) scaleY(.88) } 45% { transform: translateY(-14%) rotate(6deg) } 65% { transform: translateY(0) scaleX(1.06) scaleY(.94) } 80% { transform: translateY(-7%) rotate(-4deg) } 100% { transform: none } }
@keyframes rxStomp { 0% { transform: none } 30% { transform: translateY(-9%) scaleY(1.04) } 45% { transform: translateY(2%) scaleX(1.1) scaleY(.92) } 60% { transform: translateX(-4%) } 75% { transform: translateX(4%) } 100% { transform: none } }
@keyframes rxFlutter { 0% { transform: none } 10% { transform: rotate(-8deg) translateY(-4%) } 20% { transform: rotate(8deg) translateY(-10%) } 30% { transform: rotate(-8deg) translateY(-17%) } 40% { transform: rotate(8deg) translateY(-22%) } 55% { transform: rotate(0) translateY(-26%) } 80% { transform: translateY(-7%) rotate(3deg) } 100% { transform: none } }
@keyframes rxBuzz { 0% { transform: none } 10% { transform: translate(3%, -3%) rotate(3deg) } 20% { transform: translate(-3%, -6%) rotate(-3deg) } 30% { transform: translate(4%, -9%) rotate(3deg) } 40% { transform: translate(-4%, -7%) rotate(-3deg) } 50% { transform: translate(3%, -11%) } 70% { transform: translate(-2%, -4%) } 100% { transform: none } }
@keyframes rxSwim { 0% { transform: none } 20% { transform: translateX(-8%) rotate(-6deg) } 45% { transform: translateX(8%) translateY(-6%) rotate(6deg) } 70% { transform: translateX(-4%) translateY(-3%) rotate(-3deg) } 100% { transform: none } }
@keyframes rxBounce { 0% { transform: none } 20% { transform: translateY(-30%) } 40% { transform: translateY(0) scaleX(1.15) scaleY(.85) } 55% { transform: translateY(-14%) } 70% { transform: translateY(0) scaleX(1.08) scaleY(.92) } 82% { transform: translateY(-5%) } 100% { transform: none } }
@keyframes rxBite { 0% { transform: none } 30% { transform: scale(.9) rotate(-6deg) } 45% { transform: scale(.86) rotate(4deg) } 70% { transform: scale(1.06) } 100% { transform: none } }
@keyframes rxShake { 0% { transform: none } 15% { transform: rotate(-7deg) scale(1.04) } 30% { transform: rotate(7deg) } 45% { transform: rotate(-5deg) scale(1.03) } 60% { transform: rotate(5deg) } 75% { transform: rotate(-2deg) } 100% { transform: none } }
@keyframes rxStrum { 0% { transform: none } 20% { transform: rotate(-10deg) translateY(-4%) } 45% { transform: rotate(6deg) } 65% { transform: rotate(-3deg) } 100% { transform: none } }
@keyframes rxFlip { 0% { transform: none } 40% { transform: perspective(300px) rotateY(-35deg) translateY(-5%) } 70% { transform: perspective(300px) rotateY(18deg) } 100% { transform: none } }
@keyframes rxJiggle { 0% { transform: none } 15% { transform: rotate(14deg) } 30% { transform: rotate(-12deg) } 45% { transform: rotate(10deg) } 60% { transform: rotate(-6deg) } 75% { transform: rotate(3deg) } 100% { transform: none } }
@keyframes rxSwoop { 0% { transform: none } 30% { transform: translate(-18%, -22%) rotate(-14deg) } 60% { transform: translate(16%, -32%) rotate(10deg) } 85% { transform: translate(3%, -8%) rotate(-3deg) } 100% { transform: none } }
@keyframes rxFloat { 0% { transform: none } 50% { transform: translateY(-20%) rotate(4deg) } 75% { transform: translateY(-12%) rotate(-3deg) } 100% { transform: none } }
@keyframes rxDrive { 0% { transform: none } 12% { transform: translate(-2%, 1%) } 24% { transform: translate(2%, -1%) } 36% { transform: translate(-2%, 1%) } 48% { transform: translateX(2%) } 62% { transform: translateX(18%) skewX(-6deg) } 100% { transform: none } }
@keyframes rxWobble { 0% { transform: none } 20% { transform: rotate(-6deg) scale(1.04) } 45% { transform: rotate(5deg) } 70% { transform: rotate(-3deg) } 100% { transform: none } }
@keyframes rxTwinkle { 0% { transform: none; filter: none } 30% { transform: scale(1.14) rotate(-6deg); filter: brightness(1.25) drop-shadow(0 0 8px rgba(255, 220, 120, .9)) } 60% { transform: scale(1.06) rotate(5deg); filter: brightness(1.15) drop-shadow(0 0 5px rgba(255, 220, 120, .6)) } 100% { transform: none; filter: none } }
@keyframes rxGrow { 0% { transform: none } 30% { transform: scaleX(1.08) scaleY(.9) } 60% { transform: scaleX(.94) scaleY(1.16) translateY(-4%) } 80% { transform: scaleX(1.03) scaleY(.97) } 100% { transform: none } }
@keyframes rxSpin { 0% { transform: none } 100% { transform: rotate(360deg) } }
@keyframes rxLaunch { 0% { transform: none } 15% { transform: translateX(-2%) } 30% { transform: translateX(2%) } 45% { transform: translateY(-4%) scaleY(1.04) } 75% { transform: translateY(-40%) scale(.9) } 100% { transform: none } }
@keyframes rxLap { 0% { transform: none } 30% { transform: translateX(calc(var(--rxd, 1) * 120%)) scale(.7) } 50% { transform: translate(calc(var(--rxd, 1) * 120%), -60%) scale(.6) scaleX(calc(var(--rxd, 1) * -.6)) } 75% { transform: translate(calc(var(--rxd, 1) * -12%), -60%) scale(.8) scaleX(calc(var(--rxd, 1) * -.8)) } 90% { transform: translateX(calc(var(--rxd, 1) * -6%)) scale(1) } 100% { transform: none } }
@keyframes rxFlight { 0% { transform: none } 25% { transform: translate(calc(var(--rxd, 1) * 50%), -60%) rotate(12deg) } 50% { transform: translate(0, -100%) rotate(0) scaleX(-1) } 75% { transform: translate(calc(var(--rxd, 1) * -50%), -60%) rotate(-12deg) scaleX(-1) } 100% { transform: none } }
.rx-hop { animation: rxHop .62s cubic-bezier(.3, .9, .4, 1.1); }
.rx-skitter { animation: rxSkitter .55s ease; }
.rx-stomp { animation: rxStomp .7s ease; }
.rx-flutter { animation: rxFlutter .7s ease; }
.rx-buzz { animation: rxBuzz .6s linear; }
.rx-swim { animation: rxSwim .7s ease-in-out; }
.rx-bounce { animation: rxBounce .7s ease; }
.rx-bite { animation: rxBite .55s ease; }
.rx-shake { animation: rxShake .5s ease; }
.rx-strum { animation: rxStrum .5s ease; }
.rx-flip { animation: rxFlip .6s ease; }
.rx-jiggle { animation: rxJiggle .5s ease; }
.rx-swoop { animation: rxSwoop .7s ease; }
.rx-float { animation: rxFloat .7s ease-in-out; }
.rx-drive { animation: rxDrive .7s ease; }
.rx-wobble { animation: rxWobble .55s ease; }
.rx-twinkle { animation: rxTwinkle .7s ease; }
.rx-grow { animation: rxGrow .65s ease; }
.rx-spin { animation: rxSpin .7s ease-in-out; }
.rx-launch { animation: rxLaunch .7s ease; }
.rx-lap { animation: rxLap 1.6s ease-in-out; position: relative; z-index: 3; }
.rx-flight { animation: rxFlight 1.4s ease-in-out; position: relative; z-index: 3; }
.shop-item, .th-toy, .badge, .stimulus { overflow: visible; }   /* the flight / lap may leave the tile for a moment */

/* rc.72 (DEV-02): the smallest / shortest phones (≤ 600px tall, e.g. 320×568) — reclaim
   ~30px of vertical room inside a round from spacing only, so the last answer control
   sits inside the first screen. Touch targets, type sizes and content are untouched. */
@media (max-height: 600px) {
  .app.in-round .main { padding-top: 6px; }
  .app.in-round .main > .stack, .app.in-round .play-wrap.stack { gap: 8px; }
  .app.in-round .prompt-card { padding: 9px 14px; }
  .app.in-round .stimulus { padding: 8px 10px; min-height: 72px; }
  .app.in-round .play-head { margin-bottom: 0; }
  .app.in-round .choice-grid { gap: 8px; }
}

/* rc.74 — design gate (render-fidelity review of rc.73):
   D-01 the smallest / shortest phones (≤ 600px tall): the mascot pair covered the
        home screen's My Home / Shop buttons and a round's help row — scale the stage
        down so the buttons stay readable (taps already pass through the stage).
   D-02 desktop (≥ 1000px): the mascots sat on top of the last shop tiles / next-world
        tiles. The play column is now centred with a fixed maximum width and the
        mascots stand in the right margin at a smaller size — a centred column instead
        of a stretched layout, as the developer mandate requires. Tablets unchanged. */
@media (max-height: 600px) {
  .mascot-stage { transform: scale(.62); transform-origin: 100% 100%; }
}
@media (min-width: 1000px) {
  .main { max-width: 820px; }
  .mascot-stage { transform: scale(.7); transform-origin: 100% 100%; right: 6px; }
}
@media (max-width: 340px) {
  .bottom-nav .icon-btn .ic-label { font-size: 8.5px; letter-spacing: -.01em; }   /* rc.74 D-04: "Collection" fits at 320px */
}


/* ============================================================
   rc.78 — audit + external PX corrections
   AUD-01/02  Baloo 2's glyph box is taller than its em box, so a line-height
              under ~1.3 clipped the descenders of every bottom-nav label
              ("Today", "My House", "Shop") and every two-line quick-play name.
              Fixed at the two rules above by giving the line room; no size,
              colour or spacing change.
   KM-PX-06   LANDSCAPE: the answers sat below the fold on every short, wide
              viewport (740x360: all three off-screen). A short-and-wide screen
              has no height to spare and plenty of width, so the picture and the
              answers sit SIDE BY SIDE instead of stacked. Portrait is untouched.
   KM-PX-07   Touch targets below the 44px floor on small phones.
   ============================================================ */
@media (max-height: 460px) and (orientation: landscape) {
  .app.in-round .main { padding-top: 4px; padding-bottom: 12px; }
  .app.in-round .play-wrap {
    display: grid; gap: 6px 14px;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.1fr);
    grid-template-areas: "head head" "prompt prompt" "stim answers" "feed feed" "acts acts";
    align-items: start;
  }
  .app.in-round .play-wrap > .play-head     { grid-area: head; margin-bottom: 0; }
  .app.in-round .play-wrap > .prompt-card   { grid-area: prompt; padding: 7px 12px; }
  .app.in-round .play-wrap > .stimulus      { grid-area: stim; min-height: 0; padding: 6px 8px; align-self: stretch; }
  .app.in-round .play-wrap > .stack,
  .app.in-round .play-wrap > .choices       { grid-area: answers; }
  .app.in-round .play-wrap > .feedback-line { grid-area: feed; }
  .app.in-round .play-wrap > .play-actions  { grid-area: acts; }
  /* the picture may shrink, the answers may not */
  .app.in-round .stimulus img, .app.in-round .stimulus .pw-art { max-height: 30vh; }
  .app.in-round .choices { gap: 7px; }
  .app.in-round .choice-btn { min-height: 46px; padding: 8px 12px; }
  /* the mascots stay out of a landscape round entirely — there is no room */
  .app.in-round .mascot-stage { display: none; }

  /* rc.80 (KM-PX-10 + the same fold defect KM-PX-06 fixed for rounds) — on a
     short, wide screen the welcome screen stacked to 840px against a 390px
     viewport, putting "Start growing" itself 91px below the fold in rc.79.
     A landscape screen has no height and plenty of width, so the pair and
     the title take the left, and everything a hand touches takes the right. */
  .screen.welcome {
    display: grid; grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: 6px 18px; align-items: center; justify-items: stretch; padding-top: 4px;
  }
  .welcome > .w-hero, .welcome > .w-actions { display: flex; flex-direction: column; }
  .welcome > .w-hero { gap: 2px; align-items: center; justify-content: center; }
  .welcome > .w-actions { gap: 8px; justify-content: center; }
  .welcome .hero-duo { min-height: 0; margin: 0; }
  /* both scaled by the same 0.58, so the pair keeps its designed size
     relationship — Weetik leads, Beetik is the smaller buddy */
  .welcome .hero-w img { height: 104px !important; }       /* inline 180 */
  .welcome .hero-b img { height: 66px !important; }        /* inline 114 */
  .welcome h1 { font-size: 26px; line-height: 1.25; margin: 0; }
  .welcome > .w-hero > .muted { font-size: 12.5px; line-height: 1.45; margin: 0; }
  .welcome .promise-cta { min-height: 54px; margin: 0 auto; padding: 8px 12px; }
  .welcome .promise-cta .pc-ic, .welcome .promise-cta .pc-arrow { font-size: 24px; }
  .welcome .promise-cta .pc-title { font-size: 15px; }
  .welcome .promise-cta .pc-sub { font-size: 11.5px; }
  .welcome .restore-hint { margin: 0 auto; padding: 8px 12px; }
  .welcome .btn.big.glow { margin: 0 auto; }
  .welcome .profile-grid { justify-content: center; }
  .welcome > .w-actions > .muted { font-size: 11.5px !important; line-height: 1.45; }
}
/* KM-PX-07 — nothing a child taps falls under 44x44. These have to out-rank the
   earlier `.topbar .icon-btn { min-width: 40px }` inside its own media block, so
   they carry the same specificity and come later in the sheet. */
.topbar .icon-btn { min-width: 44px; min-height: 44px; }   /* these were 40 wide */
.play-head .icon-btn, .play-head .ph-back { min-width: 44px; min-height: 44px; }
.brand { min-height: 44px; }   /* was 44x36 — height is the deficient axis; a min-width here would push the 320px topbar into overflow */
/* deliberately NOT a blanket `.icon-btn` floor: the bottom-nav buttons are 52px by
   design and a global 44px min-height SHRINKS them, which moves the nav and lets it
   cover the last region name (caught by qa17). Never lower a target to raise a floor. */

/* ---- the grown-up PIN (rc.86) ----
   Four dots and a keypad, built on the token layer. rc.85's fields were
   painted rgba(0,0,0,.28) — a value meant for the dark game surface,
   which on the white modal rendered as a grey slab indistinguishable
   from a disabled control. That is the defect the owner reported as
   "PIN is not saving". There is an input-surface token now. */
.pinpad { display: flex; flex-direction: column; align-items: center; gap: var(--s-4); }
.pinpad-real {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
.pin-dots { display: flex; gap: var(--s-3); }
.pin-dot {
  width: 52px; height: 60px; border-radius: var(--r-control);
  background: var(--field-bg); border: 2px solid var(--field-edge);
  box-shadow: var(--e-press);
  display: block; position: relative;
  transition: border-color .14s ease, background .14s ease, transform .14s ease;
}
.pin-dot.on::after {
  content: ""; position: absolute; inset: 0; margin: auto;
  width: 16px; height: 16px; border-radius: var(--r-pill); background: var(--ink);
}
.pin-dot.on { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, var(--field-bg)); }
.pinpad-real:focus-visible ~ .pin-dots .pin-dot:not(.on):first-of-type,
.pinpad:focus-within .pin-dots .pin-dot:not(.on):first-of-type { border-color: var(--field-edge-focus); }
.pin-dots.wrong { animation: pinShake .36s ease; }
@keyframes pinShake { 0%,100% { transform: translateX(0) } 20% { transform: translateX(-7px) } 45% { transform: translateX(6px) } 70% { transform: translateX(-3px) } }
.app.reduce-motion .pin-dots.wrong { animation: none; }
.app.reduce-motion .pin-dot { transition: none; }

.pin-keys { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--s-2); width: min(100%, 268px); }
.pin-key {
  min-height: 56px; font-size: var(--t-xl); font-weight: 800;
  border-radius: var(--r-control); cursor: pointer;
  background: var(--card); color: var(--ink);
  border: 2px solid var(--card-edge); box-shadow: var(--e-1);
}
.pin-key:hover, .pin-key:focus-visible { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 8%, var(--card)); }
.pin-key:active { box-shadow: var(--e-press); transform: translateY(1px); }
.pin-key.ghost { background: none; border: 0; box-shadow: none; pointer-events: none; }
.pin-key.wipe { font-size: var(--t-lg); }
.app.reduce-motion .pin-key:active { transform: none; }

.pin-step { font-size: var(--t-md); font-weight: 700; text-align: center; margin: 0 0 var(--s-1); }
.pin-stage { display: flex; justify-content: center; }
.pin-note { font-size: var(--t-sm); color: var(--ink-faint); line-height: 1.55; margin: var(--s-4) 0 0; }
.gate-msg { margin: var(--s-2) 0 0; font-size: var(--t-base); min-height: 22px; text-align: center; font-weight: 700; }

/* press-and-hold: adult friction, with a fill a grown-up can see */
.hold-btn { position: relative; overflow: hidden; min-height: 52px; min-width: 232px; }
.hold-fill {
  position: absolute; left: 0; top: 0; bottom: 0; width: 0%;
  background: color-mix(in srgb, #ffffff 34%, transparent); pointer-events: none;
}
.hold-label { position: relative; }
.hold-btn.holding { box-shadow: var(--e-press); }


/* ============================================================
   rc.85 — MOBILE, TABLET AND DESKTOP  (owner: "designed should be for
   mobile, web and tablet; current design looks like it is designed for
   tablet only")

   What was actually wrong: the layout was correct and overflow-free on
   phones, but it STOPPED adapting above 1000px. `.main` was pinned at
   820px, so a 1280 or 1680 screen showed a narrow tablet column floating
   in the middle with the play area no bigger than on an iPad — and the
   pictures a child has to recognise stayed at their phone size no matter
   how much room there was. The column now keeps growing in deliberate
   steps, and the things a child looks AT grow with it.

   Deliberately NOT done: letting the column run full-bleed. A reading and
   tapping surface wider than about 1200px is worse, not better — the eye
   loses the line and the choice buttons drift apart. Wider screens get a
   bigger column and bigger art, not an infinite one.
   ============================================================ */

/* ---- the picture tokens a child sorts ----
   The task in a sorting round is to recognise the picture, so the picture
   is the one thing that must never be small. Sized from the viewport, with
   a floor that is already generous on a 320px phone. */
.token-pic { min-width: clamp(76px, 20vw, 108px); min-height: clamp(76px, 20vw, 108px); padding: 8px; }
.token-pic .tok-em { display: block; font-size: clamp(40px, 11vw, 60px); line-height: 1.05; }
.token-pic.has-art .tok-em { display: flex; align-items: center; justify-content: center; }
.token-pic .tok-art { width: clamp(52px, 14vw, 78px); height: clamp(52px, 14vw, 78px); display: block; }
.token-pic .tok-label { display: block; font-size: clamp(12px, 3.2vw, 15px); font-weight: 700; margin-top: 2px; }
/* rc.142 CA-RC141-036: every sorting token now prints its name, so a long
   phrase ("people chatting right next to you") must wrap inside the chip
   instead of stretching it across the tray. */
.token-pic { max-width: clamp(118px, 34vw, 176px); white-space: normal; }
.token-pic .tok-label { line-height: 1.15; word-break: normal; overflow-wrap: anywhere; margin-left: auto; margin-right: auto; }
.token-tray { gap: 10px; }

/* ---- tablet: the column and the type both step up ---- */
@media (min-width: 700px) {
  .main { padding-left: max(20px, env(safe-area-inset-left)); padding-right: max(20px, env(safe-area-inset-right)); }
  .token-tray { gap: 14px; }
}

/* ---- laptop and desktop: keep growing, in steps ----
   These override the rc.74 D-02 rule (`.main { max-width: 820px }` at
   ≥1000px), which is the rule that made every large screen look like a
   tablet. The mascot margin still has room at each step: the stage is
   ~180px wide at its .7 scale and sits in the right gutter, so the column
   maximum is always at least 300px short of the viewport. */
@media (min-width: 1100px) {
  .main { max-width: 960px; }
  .stimulus { min-height: 110px; font-size: clamp(56px, 7vw, 104px); }
  .choice-btn { min-height: 80px; font-size: 1.05em; }
  .choice-btn.em-only { min-height: 104px; }
  .choice-btn.em-only .c-em { font-size: 74px; }
  .token-pic { min-width: 116px; min-height: 116px; }
  .token-pic .tok-art { width: 86px; height: 86px; }
  .token-pic .tok-em { font-size: 66px; }
}
@media (min-width: 1500px) {
  .main { max-width: 1120px; }
  .stimulus { min-height: 128px; }
  .token-pic { min-width: 128px; min-height: 128px; }
  .token-pic .tok-art { width: 96px; height: 96px; }
  .token-pic .tok-em { font-size: 74px; }
  .mascot-stage { transform: scale(.85); transform-origin: 100% 100%; }
}

/* ---- short landscape (a phone turned sideways, a small laptop) ----
   Height, not width, is the scarce axis here: shrink the vertical rhythm
   rather than the tap targets, which stay at their 44px floor. */
@media (max-height: 560px) and (min-width: 700px) {
  .main { padding-top: 8px; padding-bottom: 96px; }
  .stimulus { min-height: 72px; padding: 8px 10px; font-size: clamp(40px, 8vh, 64px); }
  .token-pic { min-width: 84px; min-height: 84px; }
  .token-pic .tok-art { width: 58px; height: 58px; }
  .token-pic .tok-em { font-size: 46px; }
}

/* ============================================================
   rc.86 — THE DESIGN SYSTEM  (premium audit P0)

   The audit's finding was that this file had no system: 122 distinct
   box-shadows, 70 font-sizes, 27 radii, 93 paddings and ~425 literal
   colour values against 42 tokens. Premium feel is mostly consistency,
   and nothing can be consistent when nothing is shared.

   These are the shared values. Scales are theme-independent; surfaces
   and elevation have a value per theme, because a shadow tuned for a
   white card is wrong on a dark one — which is exactly how the PIN
   field ended up painted with a dark wash on a white modal. There was
   no input-surface token to reach for, so one exists now.

   Adoption is progressive and deliberately NOT a blind rewrite of
   216 KB: every surface this round touches is built on these, and the
   global elements (buttons, cards, fields) are converted. What is not
   yet converted is recorded in the round's report with a count, rather
   than claimed.
   ============================================================ */
.app {
  /* ---- type: 9 steps ---- */
  --t-xs: 12px; --t-sm: 13.5px; --t-base: 15px; --t-md: 17px; --t-lg: 19px;
  --t-xl: 22px; --t-2xl: 26px; --t-3xl: 32px; --t-4xl: 40px;

  /* ---- radius: 5 steps ---- */
  --r-chip: 10px; --r-control: 14px; --r-card: 20px; --r-panel: 26px; --r-pill: 999px;

  /* ---- space: one 4pt scale ---- */
  --s-1: 4px; --s-2: 8px; --s-3: 12px; --s-4: 16px; --s-5: 20px;
  --s-6: 24px; --s-7: 32px; --s-8: 40px;

  /* ---- elevation: 6 steps, two layers each (contact + ambient),
          tinted with the surface's own hue rather than neutral grey ---- */
  --e-0: none;
  --e-1: 0 1px 1px rgba(30, 70, 40, .07), 0 2px 5px rgba(30, 70, 40, .07);
  --e-2: 0 1px 2px rgba(30, 70, 40, .08), 0 4px 12px rgba(30, 70, 40, .10);
  --e-3: 0 2px 4px rgba(30, 70, 40, .10), 0 10px 24px rgba(30, 70, 40, .14);
  --e-4: 0 4px 8px rgba(30, 70, 40, .12), 0 18px 38px rgba(30, 70, 40, .18);
  --e-5: 0 8px 16px rgba(30, 70, 40, .16), 0 30px 64px rgba(30, 70, 40, .26);
  --e-press: inset 0 2px 5px rgba(30, 70, 40, .18);

  /* ---- the input surface the audit found missing ---- */
  --field-bg: #f5f9f4; --field-edge: #b6cdb6; --field-edge-focus: var(--accent);
  --field-ink: var(--ink); --field-hint: var(--ink-faint);
  --field-disabled-bg: #e7ebe7; --field-disabled-ink: #9aa69a;
}
.app[data-theme="night"] {
  --e-1: 0 1px 1px rgba(0, 0, 0, .28), 0 2px 6px rgba(0, 0, 0, .30);
  --e-2: 0 1px 2px rgba(0, 0, 0, .32), 0 5px 14px rgba(0, 0, 0, .36);
  --e-3: 0 2px 5px rgba(0, 0, 0, .36), 0 12px 28px rgba(0, 0, 0, .44);
  --e-4: 0 4px 10px rgba(0, 0, 0, .40), 0 20px 44px rgba(0, 0, 0, .50);
  --e-5: 0 10px 20px rgba(0, 0, 0, .46), 0 34px 72px rgba(0, 0, 0, .58);
  --e-press: inset 0 2px 6px rgba(0, 0, 0, .45);

  --field-bg: #16203a; --field-edge: #465a92; --field-edge-focus: var(--accent-deep);
  --field-disabled-bg: #1a2238; --field-disabled-ink: #6b779c;
}

/* ---- fields: one definition, both themes, and an enabled field can
        never be mistaken for a disabled one (the rc.85 PIN defect) ---- */
.field, .pin-input, .rec-input {
  width: 100%; box-sizing: border-box;
  font: inherit; font-size: var(--t-md);
  min-height: 48px; padding: var(--s-3) var(--s-4);
  border-radius: var(--r-control);
  background: var(--field-bg);
  border: 2px solid var(--field-edge);
  color: var(--field-ink);
  box-shadow: var(--e-press);
  transition: border-color .12s ease, box-shadow .12s ease;
}
.field::placeholder, .pin-input::placeholder { color: var(--field-hint); }
.field:focus-visible, .pin-input:focus-visible, .rec-input:focus-visible {
  outline: 3px solid var(--focus); outline-offset: 2px;
  border-color: var(--field-edge-focus);
}
.field:disabled, .pin-input:disabled {
  background: var(--field-disabled-bg); color: var(--field-disabled-ink);
  border-style: dashed; box-shadow: none; cursor: not-allowed;
}
.app.reduce-motion .field, .app.reduce-motion .pin-input { transition: none; }

/* ---- button hierarchy: primary / tonal / text.
        Before this the product had one shape for everything, so nothing
        directed the eye. Colour and elevation now rank the actions. ---- */
/* `.app[data-theme="day"] .btn` (line ~1843) paints a gloss gradient at
   specificity (0,3,0), which beat a bare `.btn.is-tonal` (0,2,0) and left
   every "secondary" button still looking primary. The hierarchy classes
   are scoped to `.app` so they tie on specificity and win on order. */
.app .btn.is-primary { box-shadow: var(--e-2); }
.app .btn.is-tonal {
  background: color-mix(in srgb, var(--accent) 14%, var(--card));
  background-image: none;
  color: var(--ink); border-color: color-mix(in srgb, var(--accent) 34%, var(--card-edge));
  box-shadow: var(--e-1); text-shadow: none;
}
.app .btn.is-tonal:hover, .app .btn.is-tonal:focus-visible {
  background: color-mix(in srgb, var(--accent) 22%, var(--card));
}
.app .btn.is-text {
  background: none; background-image: none; border-color: transparent;
  box-shadow: none !important; color: var(--ink-soft); text-shadow: none;
  text-decoration: underline; text-underline-offset: 3px;
}
.app .btn.is-text:active { transform: none; box-shadow: none !important; }
.app .btn.is-text:hover, .app .btn.is-text:focus-visible { color: var(--ink); background: var(--wsoft); }

/* ------------------------------------------------------------
   The grown-ups surface has its own button skin at line ~2375:
   `.app.in-parent .main .btn` is FOUR classes — (0,4,0) — so it
   beat every hierarchy class above and painted primary, tonal and
   text identically. That is the premium audit's finding in one
   selector: a surface-level skin written before a hierarchy
   existed, silently outranking it.

   The fix is not a specificity arms race. The parent skin's blue
   IS this surface's primary, so it stays exactly as it is and the
   other two tiers are restated at the same weight — the ranking
   that already governs the rest of the app, expressed in the one
   place that had opted out of it.
   ------------------------------------------------------------ */
.app.in-parent .main .btn.is-tonal {
  background-color: color-mix(in srgb, var(--gb) 12%, var(--card));
  background-image: none;
  color: var(--ink); text-shadow: none;
  border: 1px solid color-mix(in srgb, var(--gb) 38%, var(--card-edge));
  box-shadow: var(--e-1);
}
.app.in-parent .main .btn.is-tonal:hover, .app.in-parent .main .btn.is-tonal:focus-visible {
  background-color: color-mix(in srgb, var(--gb) 20%, var(--card));
  box-shadow: var(--e-2); filter: none;
}
.app.in-parent .main .btn.is-tonal:active { box-shadow: var(--e-press); transform: translateY(1px); }
.app.in-parent .main .btn.is-text {
  background: none; background-image: none; border-color: transparent;
  box-shadow: none; color: var(--gb); text-shadow: none;
  text-decoration: underline; text-underline-offset: 3px;
}
.app.in-parent .main .btn.is-text:hover, .app.in-parent .main .btn.is-text:focus-visible {
  background: color-mix(in srgb, var(--gb) 8%, transparent); box-shadow: none; filter: none;
}
.app.in-parent .main .btn.is-text:active { transform: none; box-shadow: none; }

/* ---- the destructive tier ----
   One class, used only where a tap removes something a family cannot
   get back by tapping again: Replace and restore, Delete profile,
   Erase all data. It is deliberately NOT red-on-white alarm styling —
   a parent doing a legitimate restore should not feel warned off — but
   it must never be mistaken for the Cancel beside it, which was the
   defect this replaces: both buttons in the restore confirmation were
   painted the same primary, so the safe choice and the destructive one
   were visually identical. */
.app .btn.is-danger, .app.in-parent .main .btn.is-danger {
  background-color: var(--danger); background-image: none;
  color: #fff; text-shadow: none;
  border: 1px solid color-mix(in srgb, var(--danger) 72%, #000);
  box-shadow: var(--e-2);
}
.app .btn.is-danger:hover, .app .btn.is-danger:focus-visible,
.app.in-parent .main .btn.is-danger:hover, .app.in-parent .main .btn.is-danger:focus-visible {
  background-color: color-mix(in srgb, var(--danger) 88%, #000);
  box-shadow: var(--e-3); filter: none; transform: translateY(-1px);
}
.app .btn.is-danger:active, .app.in-parent .main .btn.is-danger:active {
  box-shadow: var(--e-press); transform: translateY(1px);
}

/* ============================================================
   rc.86 — BACKUP & RESTORE PAGE  (#/backup)

   Built on the rc.86 token layer above: no literal colours, no
   literal radii, no literal shadows, no new type sizes. If this
   block needed a value the system doesn't have, that was the
   signal the system was wrong — not the licence to hard-code.
   ============================================================ */

/* ---- the link card in the Grown-ups area ---- */
.app .backup-cta {
  display: flex; align-items: center; gap: var(--s-3);
  padding: var(--s-4); border-radius: var(--r-card);
  background: var(--card); border: 1px solid var(--card-edge);
  box-shadow: var(--e-2); text-decoration: none; color: inherit;
  min-height: 64px;
}
.app .backup-cta:active { box-shadow: var(--e-press); transform: translateY(1px); }
.app .backup-cta.is-fresh { border-color: var(--gold); box-shadow: var(--e-3); }
.backup-cta .bc-ic { font-size: var(--t-2xl); line-height: 1; flex: 0 0 auto; }
.backup-cta .bc-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1 1 auto; }
.backup-cta .bc-title { font-size: var(--t-lg); font-weight: 700; }
.backup-cta .bc-sub { font-size: var(--t-sm); color: var(--muted); }
.backup-cta .bc-arrow { font-size: var(--t-2xl); color: var(--muted); flex: 0 0 auto; }

/* ---- WHY ---- */
.why-card .why-lead { font-size: var(--t-xl); font-weight: 700; margin: 0; }
.why-loss {
  border-left: 4px solid var(--gold); padding: var(--s-3) var(--s-3) var(--s-3) var(--s-4);
  background: var(--card-soft); border-radius: 0 var(--r-control) var(--r-control) 0;
}
.why-loss ul.tight { margin: 0; padding-left: 1.2em; }
.why-loss ul.tight li { margin: 0 0 4px; }
.warn-line {
  border-left: 4px solid var(--gold); padding: var(--s-3);
  background: var(--card-soft); border-radius: 0 var(--r-control) var(--r-control) 0;
  margin: 0;
}

/* ---- the step diagrams ----
   A numbered list that LOOKS like a flow. The arrows are drawn by
   CSS on the gaps, never as characters in the text, so a screen
   reader hears four steps and not four steps and three arrows. */
.step-flow {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--s-5); grid-template-columns: 1fr;
}
.step-cell {
  position: relative; display: flex; align-items: flex-start; gap: var(--s-3);
  padding: var(--s-3); border-radius: var(--r-control);
  background: var(--field-bg); border: 1px solid var(--field-edge);
}
.step-cell .step-n {
  flex: 0 0 auto; width: 26px; height: 26px; border-radius: var(--r-pill);
  display: grid; place-items: center; font-size: var(--t-sm); font-weight: 700;
  background: var(--ink); color: var(--card);
}
.step-cell .step-t { font-size: var(--t-base); line-height: 1.35; }
/* the connector: a short vertical run with a chevron, in the gap below */
.step-cell:not(:last-child)::after {
  content: "▼"; position: absolute; left: calc(var(--s-3) + 13px);
  bottom: calc(var(--s-5) * -1); transform: translate(-50%, 2px);
  font-size: 11px; color: var(--muted); line-height: var(--s-5);
}
/* wide enough for a row: the flow turns horizontal and the chevron with it */
@media (min-width: 700px) {
  .step-flow { grid-auto-flow: column; grid-auto-columns: 1fr; align-items: stretch; }
  .step-cell { flex-direction: column; }
  .step-cell:not(:last-child)::after {
    content: "▶"; left: auto; right: calc(var(--s-5) * -1); bottom: auto;
    top: 50%; transform: translate(50%, -50%);
  }
}

/* ---- the screenshots ---- */
.help-shot { margin: 0; }
.help-shot img {
  display: block; width: 100%; height: auto; max-width: 100%;
  border-radius: var(--r-control); border: 1px solid var(--card-edge);
  box-shadow: var(--e-1); background: var(--field-bg);
}
.help-shot figcaption {
  font-size: var(--t-sm); color: var(--muted);
  margin-top: var(--s-2); line-height: 1.35;
}

/* ---- undo ---- */
.undo-card { border: 1px solid var(--gold); box-shadow: var(--e-2); }

/* the backup filename, shown so a grown-up can recognise it in Files */
.app code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: .92em; background: var(--field-bg); border: 1px solid var(--field-edge);
  border-radius: var(--r-chip); padding: 1px 5px; overflow-wrap: anywhere;
}

/* ============================================================
   rc.86 — CA-301: EDUCATIONAL IMAGE SIZE IN SCORED CONTEXTS

   The locked criterion: a child must identify the ordinary object
   "without zooming, guessing, or relying on the accompanying word or
   spoken answer."

   THE DEFECT, exactly. A picture on a labelled choice card was sized
   in `em` of the CARD's font. That font is `clamp(18px, 5vw, 26px)`,
   so on a 320 px phone it resolves to 18 px; `.c-em` took 1.5em of
   that (27 px) and `.pw-art` took 1.15em of THAT — 31.05 px, the
   number the audit measured. A 192 px drawing was being shown at 31 px
   because it had been chained to a text size two multiplications away.

   And a box is not what a child sees. Art sits inside its box at its
   own aspect ratio, so the guitar — 70x168 of a 192 canvas — painted
   11.3 x 27.2 px. That is a smudge. The word beside it was doing all
   the identifying, which is precisely what the criterion forbids.

   THE FIX. A picture in a scored context is sized as a PICTURE: an
   absolute box that answers to the viewport, never to the length of
   the word next to it. Three sizes, one rule behind them — the
   smaller the surrounding furniture, the more of the card the picture
   is allowed to take.

   Paired with the asset pass that reframed 21 educational drawings to
   fill 94% of their canvas (they wasted up to 29% on transparent
   margin), the guitar goes from 11.3 x 27.2 px to roughly 30 x 72 px
   on the same phone.

   Labelled cards STACK the picture above the word from here on. Side
   by side, a 68 px picture and a word cannot both be honest in a
   120 px grid cell; stacked, both are full size and the column count
   is unchanged.
   ============================================================ */

/* the picture's own box — independent of the label's type size */
.choices .choice-btn { flex-direction: column; gap: 6px; padding: 10px 8px; }
.choices .choice-btn .c-em.has-art,
.choices .choice-btn .c-em {
  font-size: 1em;                       /* stop inheriting the label's scale */
  display: flex; align-items: center; justify-content: center;
  /* 88 px is not a taste decision. The narrowest drawing in the set is
     the guitar, 75 x 180 of its 192 canvas, so it paints 39% of its
     box's width. For its neck and waist to survive at ~34 px across —
     the floor below which the shape stops being a guitar on a phone —
     the box has to be 34 / 0.39 = 88. Every scored picture gets that
     same box, whatever its own shape, because the child does not know
     in advance which one they are being shown. */
  width: clamp(88px, 25vw, 124px); height: clamp(88px, 25vw, 124px);
  flex: 0 0 auto;
}
.choices .choice-btn .c-em .pw-art,
.choices .choice-btn .c-em.has-art .pw-art {
  width: 100%; height: 100%; vertical-align: middle;
}
/* an emoji has no alpha box to normalize, so it is sized to fill the
   same square rather than left at the old text scale */
.choices .choice-btn .c-em:not(.has-art) { font-size: clamp(70px, 20vw, 100px); line-height: 1; }

/* picture-only: the whole card is the picture */
.choices .choice-btn.em-only { min-height: 118px; }
.choices .choice-btn.em-only .c-em,
.choices .choice-btn.em-only .c-em.has-art {
  width: clamp(96px, 27vw, 148px); height: clamp(96px, 27vw, 148px);
}
.choices .choice-btn.em-only .c-em:not(.has-art) { font-size: clamp(76px, 21vw, 116px); }

/* sorting tokens — scored, so they answer to the same rule */
.token-tray .token { min-height: 104px; min-width: 104px; padding: 8px; }
.token-tray .token .pw-art { width: var(--pic-lg); height: var(--pic-lg); }

/* the stimulus is the question itself and was already the largest
   picture on screen; it is raised in step so the answer cards never
   out-size the prompt they answer */
.stimulus .pw-art, .stimulus .pw-art.stim-art {
  width: clamp(104px, 29vw, 168px); height: clamp(104px, 29vw, 168px);
  vertical-align: middle;
}

/* The grid asked for 120 px columns when the picture was 31 px wide.
   A stacked card with a ~68 px picture needs a little more, or two
   columns of it crush the word onto three lines at 320 px. */
.choices { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
@media (max-width: 359px) { .choices { grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); } }

/* ============================================================
   rc.86 — THE REWARD SHOP TILE
   Owner: "The items in the shop also need a more premium design look."

   The art was already good. What was wrong was everything around it:
   a flat white rectangle with `box-shadow: none`, an object floating on
   it with no ground, the price set smaller than the name, and a green
   Unlock button repeated 198 times down the page.

   Nothing here adds an asset or a kilobyte of image. It is the card
   language the rest of the product already uses — a lit dome with a top
   lip, thickness and a cast shadow — finally applied to the one surface
   that never got it, plus a ground shadow under the object and a price
   that carries the weight a price should.

   `--cat` is set per section, so the wash, the chip tint and the cast
   shadow all carry the category's hue. Colour is never the only signal:
   every state also differs in weight, fill and wording.
   ============================================================ */
.shop-grid {
  grid-template-columns: repeat(auto-fill, minmax(146px, 1fr));
  /* `content-visibility: auto` was here for the 198 domed, shadowed tiles.
     MEASURED and REMOVED, because the spec asked for 60 fps to be measured
     rather than assumed and the measurement said no: at 4x CPU throttle the
     median frame time was 33.2 ms with it and 33.3 ms without — identical,
     because the cost is the throttle, not the shadows. What it did change
     was real: `contain-intrinsic-size` under-estimated the tile height, so
     the page reported 13,595 px instead of 22,163 and the scrollbar moved
     under the child's thumb as they scrolled; and skipped tiles drop out of
     `innerText`, which quietly hid two thirds of the catalogue from anything
     reading the page as text. An optimisation with no measured benefit and
     two real costs is not an optimisation. */
}
.app .shop-item {
  --cat: #3b8bd6;
  position: relative;
  display: flex; flex-direction: column; align-items: center; gap: var(--s-2);
  width: 100%; text-align: center;
  padding: var(--s-3) var(--s-2) var(--s-3);
  border-radius: var(--r-card);
  border: 1px solid color-mix(in srgb, var(--cat) 34%, var(--card-edge));
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, #ffffff 78%, var(--cat) 12%), transparent 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--cat) 11%, var(--card)), var(--card) 62%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    inset 0 -10px 14px -12px color-mix(in srgb, var(--cat) 45%, transparent),
    0 1px 2px color-mix(in srgb, var(--cat) 14%, transparent),
    0 6px 16px color-mix(in srgb, var(--cat) 18%, transparent);
  font: inherit; color: var(--ink); cursor: pointer;
  transition: transform .12s ease, box-shadow .18s ease;
}
.app[data-theme="night"] .shop-item {
  border-color: color-mix(in srgb, var(--cat) 40%, var(--card-edge));
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, #ffffff 10%, var(--card)), transparent 62%),
    linear-gradient(180deg, color-mix(in srgb, var(--cat) 12%, var(--card)), var(--card) 58%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .10),
    inset 0 -10px 14px -12px rgba(0, 0, 0, .5),
    0 2px 6px rgba(0, 0, 0, .35), 0 10px 22px rgba(0, 0, 0, .28);
}
.app .shop-item:hover, .app .shop-item:focus-visible {
  transform: translateY(-2px);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .9),
    inset 0 -10px 14px -12px color-mix(in srgb, var(--cat) 45%, transparent),
    0 3px 6px color-mix(in srgb, var(--cat) 20%, transparent),
    0 14px 30px color-mix(in srgb, var(--cat) 26%, transparent);
}
.app .shop-item:focus-visible { outline: 3px solid var(--cat); outline-offset: 3px; }
.app .shop-item:active { transform: translateY(1px); box-shadow: var(--e-press); }

/* the ground. An object with a shadow under it is somewhere; without
   one it is a sticker on a page. This is the cheapest change here and
   it does the most work. */
.shop-item .s-stage {
  position: relative; display: grid; place-items: center;
  width: 100%; min-height: 104px; padding-bottom: 6px;
}
.shop-item .s-stage::after {
  content: ""; position: absolute; left: 50%; bottom: 2px;
  width: 58%; height: 11px; transform: translateX(-50%);
  border-radius: 50%;
  background: radial-gradient(ellipse at 50% 50%,
              color-mix(in srgb, var(--cat) 52%, transparent), transparent 74%);
  pointer-events: none;
}
.shop-item .s-em { font-size: 54px; line-height: 1; position: relative; z-index: 1; }
.shop-item .s-em img, .shop-item .s-em .s-img, .shop-item .s-em svg {
  width: clamp(86px, 24vw, 108px); height: clamp(86px, 24vw, 108px);
  object-fit: contain; display: block;
}
.shop-item .s-name {
  font-weight: 800; font-size: var(--t-sm); line-height: 1.2;
  overflow-wrap: break-word; hyphens: none;
}

/* the price, as a chip with weight — in the currency's own colour */
.shop-item .s-chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 11px; border-radius: var(--r-pill);
  font-size: var(--t-base); font-weight: 800; line-height: 1.25;
  border: 1.5px solid transparent; white-space: nowrap;
}
.shop-item .s-chip .s-cur { font-size: 1.05em; }
/* affordable: filled and warm */
.shop-item .s-chip.is-ready {
  background: color-mix(in srgb, var(--gold) 22%, var(--card));
  border-color: color-mix(in srgb, var(--gold) 55%, var(--card-edge));
  color: var(--ink);
}
/* not yet: outlined, quieter — NEVER greyed out, never a padlock, and
   nothing on the tile counts down or says what the child cannot have */
.shop-item .s-chip.is-soon {
  background: transparent;
  border-color: color-mix(in srgb, var(--ink-faint) 42%, transparent);
  color: var(--ink-soft);
}
.app .shop-item.soon { box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .8),
    0 1px 2px color-mix(in srgb, var(--cat) 8%, transparent),
    0 4px 10px color-mix(in srgb, var(--cat) 10%, transparent); }
/* owned: a reward, not a disabled control — full strength, gold edge */
.app .shop-item.owned {
  cursor: default;
  border-color: var(--gold);
  background:
    radial-gradient(120% 80% at 50% 0%, color-mix(in srgb, #ffffff 85%, var(--gold) 10%), transparent 62%),
    linear-gradient(180deg, var(--gold-soft), var(--card) 62%);
}
.app .shop-item.owned:hover { transform: none; }
.shop-item .s-chip.is-owned {
  background: color-mix(in srgb, var(--gold) 30%, var(--card));
  border-color: var(--gold); color: var(--ink);
  font-size: var(--t-xs); padding: 4px 10px;
}
.app[data-theme="night"] .shop-item.owned {
  background: linear-gradient(180deg, color-mix(in srgb, var(--gold) 16%, var(--card)), var(--card) 62%);
}
/* reduced motion: no lift, no depression — the states still read,
   because none of them was ever carried by the movement */
.app.reduce-motion .shop-item,
.app.reduce-motion .shop-item:hover,
.app.reduce-motion .shop-item:active { transform: none; transition: none; }
@media (prefers-reduced-motion: reduce) {
  .shop-item, .shop-item:hover, .shop-item:active { transform: none; transition: none; }
}
@media (max-width: 359px) { .shop-grid { grid-template-columns: repeat(2, 1fr); } }

/* ============================================================
   rc.86 — PREMIUM PASS, P1: THE RAINBOW HALO IS A CHILD'S DEVICE

   The build deals a coloured ring to buttons, tiles and chips by their
   DOM index — `:nth-of-type(6n+1)` through `6n+6`, six hues, applied to
   `.dest-grid .world-tile`, `.joy-grid .joy-swatch`, `.topbar .icon-btn`,
   `.play-actions .btn`, `.modal-actions .btn`, `.row > .btn` and
   `.choices .choice-btn`.

   On a child's screen it is one of the nicest things in the product: a
   row of destinations that each glow a different colour. Nothing here
   touches that.

   On a GROWN-UP's screen it is the single biggest reason the parent
   area does not look considered. A parent reading about their child's
   data sees the back button ringed purple, the theme button blue, the
   moon green and the grown-ups button gold — six accent colours on
   chrome, dealt by position rather than by meaning, with a Cancel
   button in a confirmation dialog glowing pink because it happens to
   be second in the DOM. Colour that carries no meaning is noise, and
   on the surface where a parent is being asked to trust the product it
   reads as unfinished.

   So the halo is scoped OUT of the grown-ups surface, and out of any
   dialog opened from it. Everything a parent sees there falls back to
   the elevation scale and the button hierarchy — the system the
   premium audit found missing and the rc.86 token layer added.
   ============================================================ */
/* The `:nth-of-type(n)` here is deliberate and matches every element.
   The rules being overridden are themselves written with
   `:nth-of-type(6n+N)`, and the topbar's are theme-scoped on top of
   that — `.app[data-theme="day"] .topbar .icon-btn:nth-of-type(6n+1)`
   is five classes. Repeating the pseudo-class puts these at the same
   weight, where being later in the file decides it. The alternative
   was `!important`, and the premium audit counted 61 of those already;
   adding more would be treating the symptom. */
/* The rc.70 grown-ups button — "depth, a soft glow at rest" — keeps its
   THICKNESS. Only the randomly-dealt hue goes. An early version of this
   rule replaced the whole shadow with a flat elevation step and took the
   solid bottom edge with it, which is what made these read as real
   buttons rather than tinted rectangles; qa26's depth check caught it at
   1 of 19. The edge is the surface's own indigo, not a colour dealt by
   DOM position. */
.app.in-parent .main .row > .btn:nth-of-type(n),
.app.in-parent .main .play-actions .btn:nth-of-type(n) {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .35),
    0 3px 0 var(--gb-deep, #2f4bb8),
    0 6px 14px rgba(30, 60, 40, .16);
}
.app.in-parent .topbar .icon-btn:nth-of-type(n),
.modal-veil.on-parent .modal-actions .btn:nth-of-type(n) {
  box-shadow: var(--e-1);
}
/* Hover and keyboard focus must still ANSWER. Flattening the halo at rest
   flattened the response with it — qa26 caught a grown-ups surface where
   nothing brightened on hover and nothing answered the keyboard, which is
   worse than the noise it replaced. The rest state stays calm; the
   response is a lift in elevation plus the surface's own indigo ring, so
   it reads as one system rather than as a returning rainbow. */
.app.in-parent .topbar .icon-btn:nth-of-type(n):hover,
.app.in-parent .topbar .icon-btn:nth-of-type(n):focus-visible,
.modal-veil.on-parent .modal-actions .btn:nth-of-type(n):hover,
.modal-veil.on-parent .modal-actions .btn:nth-of-type(n):focus-visible {
  box-shadow: var(--e-3), 0 0 0 3px color-mix(in srgb, var(--gb, #3b5bdb) 26%, transparent);
}
.app.in-parent .main .row > .btn:nth-of-type(n):hover,
.app.in-parent .main .row > .btn:nth-of-type(n):focus-visible,
.app.in-parent .main .play-actions .btn:nth-of-type(n):hover,
.app.in-parent .main .play-actions .btn:nth-of-type(n):focus-visible {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .42),
    0 4px 0 var(--gb-deep, #2f4bb8),
    0 0 0 3px rgba(59, 91, 219, .24),
    0 10px 26px rgba(59, 91, 219, .30);
  filter: brightness(1.06);
}
.app.in-parent .main .row > .btn:nth-of-type(n):active,
.app.in-parent .main .play-actions .btn:nth-of-type(n):active,
.app.in-parent .topbar .icon-btn:nth-of-type(n):active {
  box-shadow: var(--e-press);
}
/* the hierarchy classes must still win inside a parent dialog */
.modal-veil.on-parent .modal-actions .btn.is-primary:nth-of-type(n) { box-shadow: var(--e-2); }
.modal-veil.on-parent .modal-actions .btn.is-tonal:nth-of-type(n)   { box-shadow: var(--e-1); }
.modal-veil.on-parent .modal-actions .btn.is-text:nth-of-type(n)    { box-shadow: none; }
.modal-veil.on-parent .modal-actions .btn.is-danger:nth-of-type(n)  { box-shadow: var(--e-2); }
.modal-veil.on-parent .modal-actions .btn:nth-of-type(n):active     { box-shadow: var(--e-press); }

/* The grown-ups surface is a document, not a playground: one calm
   card treatment, one elevation, no per-card accent. */
.app.in-parent .main .card {
  box-shadow: var(--e-1);
  border: 1px solid var(--card-edge);
}
.app.in-parent .main .card:hover { box-shadow: var(--e-1); }

/* ============================================================
   rc.87 — MY HOUSE, BUILT LIKE A HOUSE
   Owner: "My House should look premium like a real house."

   What was wrong, measured rather than felt: five white rectangles in a
   grid, each with a DASHED BOX in the middle saying "Add a bed to make
   it cozy". A dashed rounded box with grey text is the universal shape
   of a file-upload field. The screen a child is told is *their home*
   was a form.

   Underneath, the rc.13 dollhouse was all still there — roof, chimney,
   walls, a 5° tilt — but every part of it had been flattened into one
   gradient, so none of it read. Nothing here adds an asset or a
   kilobyte of image; it is the same structure, given the surfaces it
   was always supposed to have.

   THE ONE IDEA. A room is two surfaces — a back WALL and a FLOOR —
   meeting at a horizon, with a skirting board along the join. That is
   what makes a bed look like it is standing IN a bedroom instead of
   pasted onto a card, and it is the single change that does the most
   here. Everything else is materials: wallpaper, floorboards, kitchen
   tile, asphalt, grass.
   ============================================================ */

/* ---------- the shell ---------- */
.house3d { perspective: 1400px; margin: 10px 0 14px; }
.house3d-inner { transform: rotateX(4deg); }

/* ---------- roof ---------- */
.h3-roofwrap { position: relative; z-index: 3; margin-bottom: -10px; }
.app .h3-roof {
  /* A shallow triangle in one flat colour reads as a banner, which is
     what the first pass gave. A roof needs PITCH and COURSES: it is
     taller now, and the shingle rows are strong enough to survive the
     downsample instead of being a polite 10%-black hairline. */
  position: relative; height: 74px; width: 100%; margin: 0;
  clip-path: polygon(50% 0, 100% 100%, 0 100%);
  background:
    /* the vertical seams between tiles in a course */
    repeating-linear-gradient(90deg,
      rgba(0,0,0,.09) 0 1px, rgba(0,0,0,0) 1px 22px),
    /* the courses themselves: a dark lip and a lit top on each row */
    repeating-linear-gradient(180deg,
      rgba(255,255,255,.14) 0 2px,
      rgba(0,0,0,0) 2px 11px,
      rgba(0,0,0,.22) 11px 14px),
    linear-gradient(180deg,
      color-mix(in srgb, var(--roof1, #d9694e) 80%, #fff) 0%,
      var(--roof1, #d9694e) 40%,
      var(--roof2, #b64a34) 100%);
  box-shadow: none;
  display: block;
}
/* the ridge cap sits along the apex */
.h3-roof .h3-ridge {
  position: absolute; left: 50%; top: 0; transform: translateX(-50%);
  width: 34px; height: 11px; border-radius: 7px 7px 2px 2px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--roof1, #d9694e) 55%, #fff),
    color-mix(in srgb, var(--roof2, #b64a34) 85%, #000));
  box-shadow: 0 2px 3px rgba(0,0,0,.22);
}
/* eaves: the roof overhangs the wall and drops a shadow onto it */
.h3-eave {
  position: relative; height: 12px; width: 100%; margin: -2px 0 0;
  border-radius: 4px;
  background: linear-gradient(180deg,
    var(--roof2, #b64a34),
    color-mix(in srgb, var(--roof2, #b64a34) 70%, #000));
  box-shadow: 0 8px 14px -6px rgba(40, 20, 10, .45);
}
.h3-chimney {
  position: absolute; right: 22%; top: 2px; z-index: -1;
  width: 18px; height: 34px; border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, #9a6746, #7a4a2c);
  box-shadow: inset -3px 0 0 rgba(0,0,0,.18);
}
.h3-chimney::after {                       /* the cap */
  content: ""; position: absolute; left: -3px; top: -4px;
  width: 24px; height: 6px; border-radius: 2px;
  background: linear-gradient(180deg, #b07d59, #8a5a3c);
}
.h3-smoke { left: 4px; top: -10px; }

/* ---------- walls ---------- */
.app .h3-body {
  border-radius: 3px 3px 20px 20px;
  padding: 14px 12px 12px;
  background:
    /* plaster, lit from above-left */
    radial-gradient(120% 70% at 20% 0%, rgba(255,255,255,.55), transparent 60%),
    linear-gradient(180deg, var(--wallc, #f3e2c2), var(--wallc2, #e9d3a8));
  /* wall THICKNESS: a bright inner lip and a dark outer edge */
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.65),
    inset 0 0 0 1px rgba(120, 90, 50, .22),
    inset 0 -14px 20px -16px rgba(90, 60, 25, .45),
    0 2px 4px rgba(60, 40, 20, .12),
    0 18px 38px rgba(60, 40, 20, .22);
}
.app[data-theme="night"] .h3-body {
  background:
    radial-gradient(120% 70% at 20% 0%, rgba(255,255,255,.10), transparent 60%),
    linear-gradient(180deg, #2c3157, #242946);
  box-shadow:
    inset 0 2px 0 rgba(255,255,255,.10),
    inset 0 0 0 1px rgba(150,170,220,.22),
    0 18px 38px rgba(0,0,0,.42);
}
/* the house's name, on the wall like a plaque rather than on the roof */
.h3-plate {
  display: block; width: fit-content; margin: 0 auto 10px;
  font-size: var(--t-sm); font-weight: 800; letter-spacing: .2px;
  color: #6b5330; background: rgba(255,255,255,.62);
  border: 1px solid rgba(140,110,60,.30); border-radius: var(--r-pill);
  padding: 3px 14px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,.9), 0 1px 2px rgba(80,60,30,.14);
}
.app[data-theme="night"] .h3-plate {
  color: #e6ecff; background: rgba(255,255,255,.08); border-color: rgba(150,170,220,.3);
  box-shadow: none;
}

/* ---------- a room: back wall + floor ---------- */
.house-rooms { gap: 10px; }
.app .room {
  min-height: 132px; border-radius: var(--r-control); padding: 0;
  overflow: hidden; position: relative; background: none;
  /* a real recess: the room is set INTO the wall */
  box-shadow:
    inset 0 2px 5px rgba(60, 40, 20, .30),
    inset 0 0 0 1px rgba(120, 90, 50, .22),
    0 1px 0 rgba(255,255,255,.55);
  filter: none;
}
.app .room.empty { filter: none; }        /* an empty room is still a room */
.room-shell { position: absolute; inset: 0; z-index: 0; }
.room-wall {
  position: absolute; left: 0; right: 0; top: 0; height: 58%;
  background:
    linear-gradient(180deg, rgba(0,0,0,.07), rgba(0,0,0,0) 45%),
    linear-gradient(180deg, var(--w1, #fbf3e4), var(--w2, #f2e6d0));
}
.room-floor {
  position: absolute; left: 0; right: 0; top: 58%; bottom: 0;
  background: linear-gradient(180deg, var(--f1, #e3cda6), var(--f2, #cfae7e));
}
/* the skirting board — the line that makes the two surfaces read as a corner */
.room-floor::before {
  content: ""; position: absolute; left: 0; right: 0; top: 0; height: 5px;
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--f1, #e3cda6) 55%, #fff),
    color-mix(in srgb, var(--f2, #cfae7e) 80%, #000));
  box-shadow: 0 3px 6px -2px rgba(60,40,20,.35);
}
/* a window in the back wall, dark until the room is lived in */
.room-window {
  position: absolute; right: 10px; top: 16%; width: 40px; height: 30px;
  border-radius: 3px; display: grid; grid-template-columns: 1fr 1fr;
  background: linear-gradient(180deg, #b9cbd8, #8fa8bb);
  box-shadow: inset 0 0 0 2.5px rgba(255,255,255,.85), 0 1px 3px rgba(60,40,20,.28);
  overflow: hidden; transition: background .5s ease, box-shadow .5s ease;
}
.room-window i { border-right: 2px solid rgba(255,255,255,.75); }
.room-window i:last-child { border-right: 0; }
.room.furnished .room-window {
  background: linear-gradient(180deg, #ffe9a8, #ffcf63);
  box-shadow: inset 0 0 0 2.5px rgba(255,255,255,.9), 0 0 14px rgba(255,200,90,.65);
}
.app[data-theme="night"] .room-window { background: linear-gradient(180deg, #2a3350, #1d2440); }
.app[data-theme="night"] .room.furnished .room-window {
  background: linear-gradient(180deg, #ffe08a, #ffbe45);
  box-shadow: inset 0 0 0 2.5px rgba(255,255,255,.55), 0 0 18px rgba(255,190,70,.75);
}

/* the label sits on the wall, small and out of the way */
.app .room .room-label {
  position: relative; z-index: 2; margin: 0;
  padding: 6px 9px 0; font-size: var(--t-xs); font-weight: 800;
  color: color-mix(in srgb, var(--w2, #f2e6d0) 30%, #6b5330);
  text-shadow: 0 1px 0 rgba(255,255,255,.6);
}
.app[data-theme="night"] .room .room-label { color: #9fb0dd; text-shadow: none; }

/* Things stand ON the floor, not floating in the middle of the box.
   `align-items: flex-end` alone was not enough: a room with three items
   wraps into three flex ROWS, and each row baselines within itself, so
   only the bottom row touched the floor and the rest hung in the wall.
   `align-content: flex-end` packs the wrapped rows down onto the floor,
   and the size caps below keep a phone room to one or two rows so the
   centrepiece is the thing standing in the middle of its own room. */
.app .room-stage {
  position: relative; z-index: 2;
  min-height: 96px; padding: 0 8px 10px;
  align-items: flex-end; align-content: flex-end; gap: 4px 6px;
}
/* The picture fills the button and the BUTTON is sized by an inline
   font-size, so capping the image changes nothing — the cap has to be on
   the font-size itself. Three objects at 68–100px cannot share a 190px
   room, which is why they were stacking into three rows. */
.app .room-item { line-height: 0; }

/* ---- a phone gets FULL-WIDTH rooms ----
   Two rooms side by side on a 430px phone leaves each about 190px wide,
   and three pieces of furniture at 70–100px cannot stand side by side in
   190px — so they wrapped into three rows and hung in the wall. Shrinking
   the furniture to fit was the wrong trade: this is the screen where a
   child looks at the things they earned.

   Full-width rooms are also simply more house-like. The cutaway becomes a
   taller building read floor by floor, each room wide enough for its
   furniture to stand in a line on its own floor. Two columns return as
   soon as there is room for them. */
@media (max-width: 559px) {
  .house-rooms { grid-template-columns: 1fr; }
  .app .room { min-height: 138px; }
  .app .room-stage { min-height: 104px; }
}
.room-item { filter: drop-shadow(0 6px 5px rgba(60, 40, 20, .28)); }
.room-item.room-centre { filter: drop-shadow(0 9px 8px rgba(60, 40, 20, .32)); }

/* the empty invitation: no dashed field, no border at all */
.app .room-hint {
  border: 0; background: none; padding: 0; width: auto;
  display: flex; flex-direction: column; align-items: center; gap: 2px;
  align-self: center; margin-bottom: 6px;
}
.room-hint .rh-em { font-size: 34px; opacity: .28; filter: grayscale(.5); line-height: 1; margin-bottom: 2px; }
.room-hint .rh-t {
  font-size: var(--t-xs); font-weight: 700; text-align: center; line-height: 1.3;
  color: color-mix(in srgb, var(--f2, #cfae7e) 40%, #5a4527);
  /* the line lands across the wall/floor join, so it carries its own
     soft plate rather than relying on whichever surface it falls on */
  background: color-mix(in srgb, var(--f1, #e3cda6) 55%, #fff);
  border-radius: var(--r-pill); padding: 3px 10px;
  box-shadow: 0 1px 2px rgba(60,40,20,.14);
}
.app[data-theme="night"] .room-hint .rh-t { color: #b9c6ea; background: rgba(255,255,255,.07); box-shadow: none; }

/* furnished no longer needs a gold outline — the lit window says it */
.app .room.furnished {
  box-shadow:
    inset 0 2px 5px rgba(60, 40, 20, .30),
    inset 0 0 0 1px rgba(160, 120, 60, .30),
    0 1px 0 rgba(255,255,255,.55);
}
.room.furnished::before { display: none; }   /* the old corner dot */

/* ---------- materials, per room ---------- */
.room-bedroom  { --w1:#fdeef1; --w2:#f6dee4; --f1:#dcb98d; --f2:#c39a67; }
.room-kitchen  { --w1:#eef7f6; --w2:#dcece9; --f1:#e6e3dc; --f2:#cbc6bc; }
.room-living   { --w1:#f7f1e4; --w2:#ede3cf; --f1:#dcb98d; --f2:#c39a67; }
.room-driveway { --w1:#dfeaf5; --w2:#cbdcee; --f1:#b9b7b4; --f2:#96938f; }
.room-garden   { --w1:#dcefff; --w2:#c6e4fb; --f1:#9fd27f; --f2:#71b855; }
.app[data-theme="night"] .room {
  --w1:#333a63; --w2:#2b3157; --f1:#2a2f4e; --f2:#20253f;
}
.app[data-theme="night"] .room-garden { --f1:#28513c; --f2:#1c3b2c; }

/* floorboards in the rooms that have wood */
.room-bedroom .room-floor, .room-living .room-floor {
  background-image:
    repeating-linear-gradient(90deg, rgba(90,60,25,.13) 0 1px, rgba(0,0,0,0) 1px 26px),
    linear-gradient(180deg, var(--f1), var(--f2));
}
/* kitchen tile */
.room-kitchen .room-floor {
  background-image:
    repeating-linear-gradient(90deg, rgba(90,90,90,.16) 0 1px, rgba(0,0,0,0) 1px 22px),
    repeating-linear-gradient(180deg, rgba(90,90,90,.16) 0 1px, rgba(0,0,0,0) 1px 16px),
    linear-gradient(180deg, var(--f1), var(--f2));
}
.room-kitchen .room-wall {          /* splashback tiles */
  background-image:
    repeating-linear-gradient(90deg, rgba(70,110,110,.10) 0 1px, rgba(0,0,0,0) 1px 20px),
    repeating-linear-gradient(180deg, rgba(70,110,110,.10) 0 1px, rgba(0,0,0,0) 1px 14px),
    linear-gradient(180deg, var(--w1), var(--w2));
}
/* the driveway is outside: open sky above, an asphalt apron below */
.room-driveway .room-floor::after {
  content: ""; position: absolute; left: 12%; right: 12%; top: 46%; height: 3px;
  border-radius: 2px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,.72) 0 14px, rgba(255,255,255,0) 14px 28px);
}
/* the garden: grass blades along the horizon, and a fence on the wall */
.room-garden .room-floor::after {
  content: ""; position: absolute; left: 0; right: 0; top: -5px; height: 9px;
  background: repeating-linear-gradient(90deg,
    color-mix(in srgb, var(--f1) 70%, #2f7a34) 0 2px, rgba(0,0,0,0) 2px 7px);
  opacity: .55;
}
.room-garden .room-wall::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 22px;
  background:
    repeating-linear-gradient(90deg, rgba(150,110,70,.55) 0 4px, rgba(0,0,0,0) 4px 20px),
    linear-gradient(180deg, rgba(0,0,0,0) 0 40%, rgba(150,110,70,.5) 40% 46%, rgba(0,0,0,0) 46%);
}
.app .room-garden { min-height: 124px; }
.room-garden .room-stage { min-height: 92px; }
.garden-tree { filter: drop-shadow(0 7px 6px rgba(30, 70, 40, .35)); }

/* narrow phones: the rooms stack rather than crush */


/* rc.87 — a bundled landmark illustration used as a question's stimulus */
/* rc.123 (owner: "This image and many others are not blended. This breaks the
   premium design") — THE PICTURE WAS WEARING A CARD NOBODY ASKED FOR.
   This rule gave the bundled landmark illustrations an opaque `--card`
   background, a corner radius and their own drop shadow, INSIDE a stimulus
   panel that already has a surface. The artwork is a transparent cut-out, so
   all three were pure decoration: a white rounded rectangle around a castle,
   pasted onto a green page like a sticker.

   It is also the only rule in this stylesheet that does it. Every other
   picture in the game — `.pw-art` in choice buttons, sorting tokens, memory
   cards, pattern cells, the peek scene, drag chips and cards — sits directly
   on the surface it belongs to and carries no plate, no radius and no shadow
   of its own. Twelve landmark stimuli were the exception, which is exactly
   why they looked pasted on rather than part of the screen.

   The plate is gone. Sizing stays; the radius goes with the plate, because a
   corner radius on a cut-out rounds nothing. */
.stim-art-img {
  display: block; width: clamp(104px, 30vw, 172px); height: auto;
}
.stimulus .stim-art-img + .stim-word { font-size: var(--t-lg); margin-top: var(--s-2); }

/* rc.123 — the stimulus row and the prompt, drawn from the art library.
   A ROW is its own line of picture cells, sized like the pattern tiles so a
   3x3 map reads at a glance on a 320px phone. An INLINE picture inside a
   sentence takes the text's own size, which is what `.pw-art` was built for,
   so a photoreal apple mid-sentence sits on the baseline like a word. */
.stim-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; }
.stim-row .sw-cell { display: inline-flex; align-items: center; justify-content: center; }
.stim-lines { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }   /* rc.159: one picture row per line, left-aligned so bar lengths compare */
.stim-lines .stim-line { justify-content: flex-start; flex-wrap: nowrap; }
.stim-lines .stim-line.stim-row .sw-cell .pw-art { width: calc(var(--pic-md) * 0.72); height: calc(var(--pic-md) * 0.72); }
.stim-row .sw-cell .pw-art { width: var(--pic-md); height: var(--pic-md); vertical-align: middle; }
.stim-row .sw-gap { font-weight: 800; color: var(--ink-faint); padding: 0 2px; }
/* rc.130: a sentence that had a run of pictures lifted out of it becomes
   a small stack — text, row, text — centred in the prompt card. */
.sw-blocks { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.sw-blocks .sw-line { display: block; }
.sw-blocks .stim-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 6px; }
.sw-inline { display: inline-flex; align-items: center; vertical-align: -0.22em; }
/* rc.130 measured 23px: a flat mark survives it, a photoreal subject does
   not. The note that used to sit here claimed a photoreal subject never
   renders inline because ui.js promotes it to a row — it does not, and
   26,328 prompt patterns were still drawing photographs at text size.
   rc.131 (CA-126-001): the predicate picks the SIZE rather than moving the
   picture, so the sentence stays whole and the subject clears the floor. */
.sw-inline .pw-art { width: var(--pic-inline); height: var(--pic-inline); }
.sw-inline.is-photo { vertical-align: -0.34em; }
.sw-inline.is-photo .pw-art { width: var(--pic-sm); height: var(--pic-sm); }
/* a line carrying one gets the room for it rather than clipping it */
.sw-line:has(.sw-inline.is-photo), .sw-sentence:has(.sw-inline.is-photo) { line-height: 1.75; }
/* rc.130: the landmark photographs in dragMatch had their own size rule
   and sat at 42px — below the measured floor, and out of step with the
   chip art beside them now that chip and card match. */
.dm-chip-art { width: var(--pic-lg); height: var(--pic-lg); border-radius: 8px; display: block; flex: 0 0 auto; }

/* ============================================================
   rc.92 — PARENT GATE AND RECOVERABLE DATA DIRECTIVE V1.0
   The recovery code has to be TRANSCRIBABLE: a grown-up reads it off a
   phone and writes it on paper, so it gets a monospace face, real letter
   spacing and a size that survives a 320px screen.
   ============================================================ */
.rec-code {
  display: flex; justify-content: center; margin: 10px 0 4px;
}
.rec-code code {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: clamp(20px, 6.4vw, 28px);
  font-weight: 700;
  letter-spacing: .12em;
  padding: 12px 16px;
  border-radius: var(--r-md, 12px);
  background: var(--surface-2, #f2efe6);
  border: 2px dashed var(--line, #cfc6b0);
  color: var(--ink, #23301f);
  user-select: all;
  word-break: break-all;
  text-align: center;
}
.rec-tick {
  display: flex; align-items: flex-start; gap: 10px;
  margin: 10px 0 0; padding: 10px 12px;
  border-radius: var(--r-md, 12px);
  background: var(--surface-2, #f2efe6);
  cursor: pointer; line-height: 1.35;
}
.rec-tick input { width: 22px; height: 22px; flex: 0 0 auto; margin-top: 1px; }
.rec-input {
  display: block; width: 100%; box-sizing: border-box;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 20px; letter-spacing: .1em; text-align: center; text-transform: uppercase;
  padding: 12px 10px; margin: 8px 0;
  border-radius: var(--r-md, 12px);
  border: 2px solid var(--line, #cfc6b0);
  background: var(--surface, #fff);
  color: var(--ink, #23301f);
}
.rec-input:focus-visible { outline: 3px solid var(--focus, #2a7d5f); outline-offset: 2px; }

/* rc.101: a quiet divider between the two ways back into the grown-ups area */
.soft-rule { border: 0; border-top: 1px solid var(--card-edge); margin: 12px 0 4px; opacity: .7; }

/* rc.111 → rc.113: A FLAG NEEDED AN EDGE, AND NOW IT HAS ONE AT SOURCE.

   rc.111 measured that seven of the twelve flags lost their outline on the
   white day card — 100% of Japan's silhouette sat within 1.6:1 of it, and the
   flag rendered as a red disc floating in the button. The mitigation here was
   an alpha-following drop-shadow, with a note that deleting it would be the
   whole change once an edge was baked in.

   The RC113 patch bakes a 2px #223028 border into all twelve. Checked at the
   three sizes the app actually draws them — 58, 86 and 122px — the border
   carries every flag on white AND on navy on its own, and the drop-shadow on
   top of it reads as a second, muddier ring. So it is deleted, as promised,
   rather than left in because it is already written. */


/* rc.113: the scenario buttons put their emoji inside an element instead of
   inside the label string, so it can be a real picture. Left-aligned rows of
   text with a picture in front — the picture gets a fixed box so the text
   lines up down the column. */
.choice-btn .sc-em { flex: 0 0 auto; display: inline-flex; align-items: center; margin-right: 2px; }
/* rc.130: a scenario answer is a thing the child taps; 30px was below
   the legibility floor for a photoreal subject. */
.choice-btn .sc-em .pw-art { width: var(--pic-md); height: var(--pic-md); }

/* rc.113: things to count are now drawn pictures. The counting field sizes its
   items by font-size, so the picture takes the same em box the glyph had and a
   row of five stays a row of five. */
.count-item .pw-art { width: 1.1em; height: 1.1em; vertical-align: middle; }

/* rc.116: the countdown is held while the flash scene's pictures load, so the
   bar must not appear to be running during the wait. It sits full and still. */
.peek-bar.peek-wait .peek-fill { animation: none; width: 100%; }

/* rc.145 CA-RC141-007: Rhyme Writer word bank */
.word-bank { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; padding: 0; margin: 0 0 12px; }
.word-bank li { margin: 0; }
.word-bank .bank-word { font-size: 20px; min-height: 44px; padding: 6px 16px; border-radius: 999px; letter-spacing: .02em; }
