/* ==========================================================================
   Chord Garden — styles
   Two visual languages, one app:
   • Child screens: a flag garden. The answers are Eguchi-style colour flags
     planted on a hill (the method is taught with real flags); everything
     else — buttons, text, progress — is drawn in neutral white and garden
     ink, so the chord colours only ever mean chords. Grandstander for the
     playful display type, Nunito for labels. A night garden in dark mode.
   • Grown-up screens (body.adult, or any .adult overlay): calm surfaces,
     grouped lists and standard controls in Nunito, same ink accent.
   ========================================================================== */

/* Fonts are bundled locally (assets/fonts, precached by sw.js) so the app
   keeps its offline-first promise. Both are variable fonts (OFL 1.1). */
@font-face {
  font-family: 'Grandstander'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url(../assets/fonts/grandstander-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Grandstander'; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url(../assets/fonts/grandstander-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Nunito'; font-style: normal; font-weight: 200 1000; font-display: swap;
  src: url(../assets/fonts/nunito-latin.woff2) format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Nunito'; font-style: normal; font-weight: 200 1000; font-display: swap;
  src: url(../assets/fonts/nunito-latin-ext.woff2) format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ------------------------------------------------------------- Tokens --- */
:root {
  --font: 'Nunito', ui-rounded, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --display: 'Grandstander', 'Nunito', ui-rounded, system-ui, sans-serif;
  --sky: #CDE9F5;
  --cloud: rgba(255, 255, 255, .85);
  --hill-back: #B4DA93;
  --hill-front: #93C774;
  --grass: #7AB05C;
  --ink: #1F3A2E;
  --ink-soft: #35584A;
  --card: #FFFFFF;
  --card-shadow: 0 14px 34px -16px rgba(31, 58, 46, .35);
  --lip: rgba(31, 58, 46, .16);
  --pole: #9B6B43;
  --knob: #C9A26B;
  --mound: rgba(79, 125, 58, .45);
  --vine: #5E8F46;
  --vine-track: rgba(255, 255, 255, .8);
  --leaf: #6FA656;
  --soil: #9B7650;
  --soil-dark: #7A5B3D;
  --water: #BFE3F2;
  --water-ink: #4E8FAE;
  --glow: rgba(255, 255, 255, .9);
  --accent: var(--ink); /* focus rings and the few accents stay garden ink */
}

/* Grown-up tokens. Declared on a class (not :root) so they apply to the
   grown-up screens via body.adult AND to a grown-up overlay shown on top of
   a child screen, such as the "who is playing?" picker. */
.adult {
  --font: 'Nunito', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --bg: #F4F6F2;
  --surface: #FFFFFF;
  --card: var(--surface); /* the gear/lock icons punch their holes with --card */
  --ink: #1D2A23;
  --ink-soft: #4D5E55;
  --ink-muted: #6A7A71;
  --line: #E1E7DE;
  --fill: #EDF1EA;
  --fill-strong: #E0E7DB;
  --accent: #1F3A2E;
  --accent-soft: #E3ECE5;
  --on-accent: #FFFFFF;
  --good: #2A7A4B;
  --good-soft: #E2F1E7;
  --warn: #8A5A00;
  --warn-soft: #FBF0DE;
  --danger: #B8322A;
  --danger-soft: #FCEBEA;
  --raise: 0 1px 2px rgba(20, 32, 24, .05), 0 10px 30px -18px rgba(20, 32, 24, .25);
  font-family: var(--font);
  color: var(--ink);
}

/* Night garden */
@media (prefers-color-scheme: dark) {
  :root {
    --sky: #15233A;
    --cloud: rgba(255, 255, 255, .07);
    --hill-back: #1F3B2D;
    --hill-front: #274A34;
    --grass: #335C40;
    --ink: #EAF3EC;
    --ink-soft: #B5CBBE;
    --card: #203447;
    --card-shadow: 0 14px 34px -16px rgba(0, 0, 0, .7);
    --lip: rgba(0, 0, 0, .4);
    --pole: #8A6242;
    --knob: #B39266;
    --mound: rgba(0, 0, 0, .35);
    --vine: #86C27B;
    --vine-track: rgba(255, 255, 255, .16);
    --leaf: #8CC47E;
    --soil: #6E5236;
    --soil-dark: #4F3A26;
    --water: #8CC3DD;
    --water-ink: #D6ECF5;
    --glow: rgba(255, 255, 255, .16);
  }
  .adult {
    --bg: #121A16;
    --surface: #1B2620;
    --ink: #E6EEE8;
    --ink-soft: #A9BAB0;
    --ink-muted: #7E8F85;
    --line: #2C3A32;
    --fill: #243029;
    --fill-strong: #2E3B33;
    --accent: #BFE0C9;
    --accent-soft: #22362B;
    --on-accent: #121A16;
    --good: #6FD19A;
    --good-soft: #193226;
    --warn: #F0B45B;
    --warn-soft: #372B17;
    --danger: #FF8B7E;
    --danger-soft: #3B2220;
    --raise: 0 1px 2px rgba(0, 0, 0, .3), 0 10px 30px -18px rgba(0, 0, 0, .7);
  }
}

/* --------------------------------------------------------------- Base --- */
* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body { margin: 0; min-height: 100%; }

/* Only body carries a background, so it propagates to the whole canvas
   (including iOS overscroll) and switches cleanly with body.adult. */
body {
  font-family: var(--font);
  color: var(--ink);
  background: var(--sky);
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}
body.adult { background: var(--bg); }

/* The garden scenery (clouds + two hills, see index.html) sits fixed behind
   every child screen and is hidden for grown-ups. */
#scene { position: fixed; inset: 0; z-index: -1; pointer-events: none; }
body.adult #scene { display: none; }
.scene-clouds { position: absolute; top: 60px; left: 50%; width: 390px; height: 80px; transform: translateX(-50%); }
.scene-clouds ellipse { fill: var(--cloud); }
.scene-hills { position: absolute; left: 0; bottom: 0; width: 100%; height: 42vh; min-height: 260px; }
.hill-back { fill: var(--hill-back); }
.hill-front { fill: var(--hill-front); }
.grass { stroke: var(--grass); }

/* Past days' flowers (renderGarden in app.js). Must stay in sync with
   .scene-hills above — flowers are placed by percentages of THIS box,
   sampled against the hill's own SVG curve (backHillY in app.js), so the
   box the flowers sit in has to match the hills' box exactly. */
#garden { position: absolute; left: 0; bottom: 0; width: 100%; height: 42vh; min-height: 260px; }
.garden-flower { position: absolute; width: 34px; height: 51px; transform: translateX(-50%); }
.garden-flower svg { width: 100%; height: 100%; display: block; overflow: visible; }

button { font: inherit; color: inherit; cursor: pointer; border: none; background: none; padding: 0; }
button:focus-visible, [tabindex]:focus-visible, summary:focus-visible { outline: 3px solid var(--accent); outline-offset: 3px; }
button:disabled { cursor: default; }
@media (hover: hover) and (pointer: fine) {
  button:not(:disabled):hover { filter: brightness(1.03); }
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

#app {
  max-width: 560px;
  margin: 0 auto;
  padding: 16px 18px 24px;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
}
body.adult #app { max-width: 680px; }

.screen { display: flex; flex-direction: column; gap: 18px; flex: 1; animation: fade-in .3s ease; }
@keyframes fade-in { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }

/* ------------------------------------------------------ Child buttons --- */
/* White faces with a solid lip below that compresses when pressed, like a
   wooden toy. No chord colours: those are reserved for the flags. */
.toy-btn, .ghost-btn, .calm-stop, .listen-btn, .gear, .avatar-chip, .primary-btn, .mic-pill {
  transition: transform .1s ease, box-shadow .1s ease;
}
.toy-btn, .ghost-btn, .calm-stop, .listen-btn, .gear, .avatar-chip {
  background: var(--card); color: var(--ink);
  box-shadow: 0 4px 0 var(--lip);
}
.toy-btn:active, .ghost-btn:active, .calm-stop:active, .listen-btn:active, .gear:active, .avatar-chip:active {
  transform: translateY(3px); box-shadow: 0 1px 0 var(--lip);
}
.primary-btn {
  background: var(--ink); color: var(--card);
  font-weight: 800; font-size: 1.05rem; padding: 12px 26px; border-radius: 999px;
  box-shadow: 0 5px 0 var(--lip);
}
.primary-btn:active { transform: translateY(3px); box-shadow: 0 2px 0 var(--lip); }
.ghost-btn { font-weight: 800; font-size: 1.05rem; padding: 12px 28px; border-radius: 999px; color: var(--ink-soft); }

/* The big Play button: a round white disc with a thick ink rim and lip,
   labelled underneath. The label is inside the button so it's tappable. */
.big-start { display: inline-flex; flex-direction: column; align-items: center; gap: 10px; color: var(--ink); }
.play-disc {
  width: 132px; height: 132px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--card); border: 5px solid var(--ink); box-shadow: 0 8px 0 var(--ink);
  transition: transform .1s ease, box-shadow .1s ease;
}
.play-disc svg { width: 52px; height: 52px; color: var(--ink); margin-left: 6px; }
.big-start:active .play-disc { transform: translateY(6px); box-shadow: 0 2px 0 var(--ink); }
.big-start:disabled .play-disc { opacity: .7; }
.play-label { font-family: var(--display); font-weight: 700; font-size: 1.55rem; line-height: 1; }
.btn-ico { display: inline-flex; }
.btn-ico svg { width: 24px; height: 24px; }

.start-error {
  margin: 4px auto 0; max-width: 300px; text-align: center;
  background: var(--card); color: var(--ink-soft); font-weight: 700; font-size: .95rem;
  line-height: 1.4; padding: 12px 16px; border-radius: 18px; box-shadow: var(--card-shadow);
}

/* --------------------------------------------------------------- Home --- */
.home { gap: 12px; }
.home-top { display: flex; justify-content: space-between; align-items: center; }
.avatar-chip {
  display: inline-flex; align-items: center; gap: 8px;
  border-radius: 999px; padding: 5px 16px 5px 5px;
  font-weight: 800; font-size: 1.05rem;
}
.avatar-emoji, .avatar-emoji svg { width: 38px; height: 38px; display: block; }
.gear {
  width: 48px; height: 48px; border-radius: 50%;
  display: grid; place-items: center; color: var(--ink-soft);
}
.gear svg { width: 22px; height: 22px; }

.home-main {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 26px; text-align: center; padding: 4px 0 8px;
}
.brand-title {
  margin: 0; font-family: var(--display); font-weight: 800;
  font-size: clamp(2.4rem, 11vw, 3rem); line-height: 1; letter-spacing: -.01em; color: var(--ink);
}
.brand-sub { margin: 8px 0 0; color: var(--ink-soft); font-weight: 700; font-size: 1.15rem; }

/* Today's plant: grows a stage per Practice Set played today (Logic.plantStage)
   — a cadence nudge with no numbers, so a seed or a bud just reads "not yet".
   A soft glow pulses behind it so it reads as the thing to tend, not just
   scenery. */
.today-plant { position: relative; isolation: isolate; width: 64px; height: 96px; }
.today-plant svg { width: 100%; height: 100%; display: block; overflow: visible; }
.today-plant::before {
  content: ''; position: absolute; z-index: -1; left: 50%; top: 50%;
  width: 120px; height: 120px; margin: -66px 0 0 -60px; border-radius: 50%;
  background: radial-gradient(circle, var(--glow) 0%, transparent 68%);
  animation: today-glow 2.4s ease-in-out infinite;
}
@keyframes today-glow { 0%, 100% { opacity: .6; transform: scale(1); } 50% { opacity: 1; transform: scale(1.08); } }
@media (max-height: 700px) { .today-plant { width: 52px; height: 78px; } }
/* A small phone with its browser bars showing: no taller than the old
   five-daisies row, so Home fits the way it used to. */
@media (max-height: 640px) { .today-plant { width: 44px; height: 66px; } }
@keyframes pop { from { transform: scale(0); } to { transform: scale(1); } }

/* Today's flags, planted along the front hill; tapping one plays its chord. */
.home-flags { display: flex; flex-direction: column; align-items: center; gap: 12px; padding-bottom: 6px; }
.today-label { margin: 0; font-weight: 800; font-size: .95rem; color: var(--ink); }
.today-colors { display: flex; flex-wrap: wrap; justify-content: center; align-items: flex-end; gap: 10px 14px; }
.today-swatch { width: 54px; height: 82px; transition: transform .12s ease; animation: pop .4s ease backwards; transform-origin: 16% 100%; }
.today-swatch svg { width: 100%; height: 100%; display: block; overflow: visible; }
.today-swatch:active { transform: rotate(-6deg); }
.today-swatch:nth-child(2) { animation-delay: .05s; } .today-swatch:nth-child(3) { animation-delay: .1s; }
.today-swatch:nth-child(4) { animation-delay: .15s; } .today-swatch:nth-child(5) { animation-delay: .2s; }

/* ------------------------------------------------------------- Flags --- */
.flag-pole { fill: var(--pole); }
.flag-knob { fill: var(--knob); }
.flag-mound { fill: var(--mound); }
.flag-cloth { transform-box: fill-box; transform-origin: 0% 50%; }
@media (prefers-color-scheme: dark) {
  /* Keeps the black flag's edge visible against the night sky. */
  .flag-fabric { stroke: rgba(255, 255, 255, .28); stroke-width: 2; }
}
@keyframes flag-wave {
  0%, 100% { transform: none; }
  50% { transform: skewY(-7deg) scaleX(.93); }
}
/* A gentler cousin of flag-wave for the round-start flutter (see
   .answers.flutter below) — every flag plays it identically, so it never
   hints at the answer the way a bigger, per-flag wave would. */
@keyframes flag-flutter {
  0%, 100% { transform: none; }
  50% { transform: skewY(-4deg) scaleX(.96); }
}

/* ----------------------------------------------------------- Overlays --- */
.overlay-backdrop {
  position: fixed; inset: 0; z-index: 70; display: grid; place-items: center;
  background: rgba(16, 28, 22, .42); padding: 20px; animation: fade-in .15s ease;
}
@media (prefers-color-scheme: dark) { .overlay-backdrop { background: rgba(0, 0, 0, .6); } }
.dialog {
  width: 100%; max-width: 340px; background: var(--surface);
  border-radius: 16px; padding: 20px; box-shadow: 0 24px 60px -12px rgba(16, 28, 22, .4);
}
.dialog-title { margin: 0 0 6px; font-size: 1.0625rem; font-weight: 800; }
.dialog-body { margin: 0 0 18px; color: var(--ink-soft); font-size: .9375rem; line-height: 1.5; }
.dialog-actions { display: flex; gap: 8px; justify-content: flex-end; }
.dialog .g-list { margin: 4px 0 16px; }

/* ----------------------------------------------------------- Practice --- */
.practice { gap: 14px; min-height: 0; }
/* A round-to-round rebuild of the practice screen — see renderPractice. */
.practice.continuing { animation: none; }
.practice-top { display: flex; align-items: center; gap: 12px; }

/* The vine: grows along a wavy track toward the end of the set, sprouting a
   leaf for every round played, with the child's own mascot riding its tip.
   The wave is computed in JS (vinePoint in app.js) so the mascot and the
   leaves sit exactly on the line. Left padding is half the mascot's width,
   so it never hangs off the screen edge on round one. */
.vine { position: relative; flex: 1; min-width: 0; height: 48px; margin-left: 18px; }
.vine svg { position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible; }
.vine-track, .vine-grow { fill: none; stroke-width: 8; stroke-linecap: round; stroke-linejoin: round; }
.vine-track { stroke: var(--vine-track); }
.vine-grow { stroke: var(--vine); animation: vine-grow .6s ease-out both; }
/* The vine is redrawn each round; it grows from the previous length. */
@keyframes vine-grow { from { stroke-dasharray: var(--from, 0) 1000; } }
.vine-leaf {
  position: absolute; width: 14px; height: 8px; border-radius: 50%;
  background: var(--leaf); transform: translate(-50%, -50%) rotate(var(--tilt, -30deg));
}
.vine-leaf.new { animation: leaf-pop .35s ease .45s backwards; }
@keyframes leaf-pop { from { transform: translate(-50%, -50%) rotate(var(--tilt, -30deg)) scale(0); } }
/* Mascot faces occupy roughly y 20–91 of their 100px canvas; app.js places
   the box so the drawn chin (not the box edge) rests on the vine. */
.journey-mascot {
  position: absolute; left: 0; top: 0; width: 36px; height: 36px;
  transform: translateX(-50%);
  transition: left .6s cubic-bezier(.34, 1.56, .64, 1), top .6s ease;
  filter: drop-shadow(0 3px 0 var(--lip));
}
.journey-mascot svg { width: 36px; height: 36px; display: block; transition: transform .25s ease; }
.journey-mascot.happy { animation: jump .9s ease; }
@keyframes jump { 0%, 100% { transform: translate(-50%, 0) scale(1); } 30% { transform: translate(-50%, -20px) scale(1.12); } 60% { transform: translate(-50%, 0) scale(1.04); } }
/* Digital mode's only pre-chord cue (see roundCue in app.js — mic mode gets
   a card, digital doesn't): the mascot itself tilts as if listening, with
   two little sound-wave arcs pulsing off to its right. Only the inner svg
   tilts, not the outer element, so it doesn't fight the left/top position
   transition above. */
.journey-mascot.listening svg { transform: rotate(-12deg); }
/* The two arcs share a centre (right offsets differ by their radius
   difference), so they read as two waves rather than one thick one. */
.journey-mascot.listening::before, .journey-mascot.listening::after {
  content: ''; position: absolute; top: 50%; border-radius: 50%;
  border: 2px solid transparent; border-right-color: var(--ink);
  animation: mascot-waves .8s ease-in-out infinite alternate;
}
.journey-mascot.listening::before { width: 10px; height: 10px; margin-top: -5px; right: -3px; }
.journey-mascot.listening::after { width: 20px; height: 20px; margin-top: -10px; right: -8px; animation-delay: .15s; }
@keyframes mascot-waves { from { opacity: .35; } to { opacity: 1; } }

/* The watering can at the end of the vine: fills a little every round
   (--fill, set in JS by fillCan in app.js) and drops a bead of water into
   itself each time. transform-box/-origin so .can-water (a plain rect,
   see Sprites.icon('can')) scales up from its own bottom, like water
   rising, rather than from the SVG's origin. */
.vine-can { position: relative; flex: 0 0 auto; width: 44px; height: 37px; }
.vine-can > svg { width: 100%; height: 100%; display: block; overflow: visible; }
.vine-can .can-water { transform-box: fill-box; transform-origin: 50% 100%; transform: scaleY(var(--fill, 0)); transition: transform .45s ease .15s; }
.can-drop { position: absolute; left: 36%; top: -16px; width: 12px; height: 16px; opacity: 0; pointer-events: none; }
.can-drop svg { width: 100%; height: 100%; display: block; }
.vine-can.splash .can-drop { animation: can-drop .5s ease-in; }
@keyframes can-drop { 0% { opacity: 0; transform: translateY(-10px); } 25% { opacity: 1; } 100% { opacity: 0; transform: translateY(14px); } }

.calm-stop {
  font-weight: 800; font-size: 1rem; color: var(--ink-soft);
  padding: 10px 18px; border-radius: 999px; white-space: nowrap;
}

/* Measured microphone input, with an explicit paused state between listens. */
.mic-pill {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--card); color: var(--ink-soft); font-weight: 700; font-size: .85rem;
  padding: 8px 12px; border-radius: 999px; box-shadow: 0 3px 0 var(--lip);
  white-space: nowrap;
}
.mic-meter { width: 44px; height: 10px; }
.mic-pill-icon { display: inline-flex; color: var(--ink); }
.mic-pill-icon svg { width: 16px; height: 16px; }

.listen-wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: center; gap: 10px; min-height: 56px; }
.listen-btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--display); font-weight: 700; font-size: 1.3rem;
  padding: 12px 26px 12px 20px; border-radius: 999px;
}
.listen-icon { display: inline-flex; color: var(--ink); }
.listen-icon svg { width: 30px; height: 30px; }

/* The answer area takes whatever height is left. Flags are sized in JS
   (fitAnswers in app.js) to the largest that fits every active colour, so a
   few colours give big targets and many colours still fit without
   scrolling. The grid is absolutely placed so its own size can never feed
   back into the space it is measured from. */
.answers-wrap { position: relative; flex: 1 1 0; min-height: 220px; }
.answers {
  --tile-w: 112px; --tile-h: 170px;
  position: absolute; inset: 0; margin: auto; max-width: 100%;
  /* Rows fill from the bottom, so flags stand on the hill however few there are. */
  display: flex; flex-wrap: wrap; justify-content: center; align-content: flex-end; gap: 18px 10px;
  transition: opacity .25s ease;
}
.color-btn {
  width: var(--tile-w); height: var(--tile-h); flex: 0 0 auto; position: relative;
  transform-origin: 16% 100%;
}
.color-btn svg { width: 100%; height: 100%; display: block; overflow: visible; }
.color-btn:active { transform: rotate(-4deg) translateY(2px); }
.color-btn:focus-visible { outline-offset: 0; border-radius: 12px; }
/* Correct: the flag lifts and its cloth waves while the chord replays (the
   real reward — see playReward in audio.js). */
.color-btn.correct { animation: flag-lift .9s ease; }
.color-btn.correct .flag-cloth { animation: flag-wave .45s ease-in-out 2; }
@keyframes flag-lift { 0%, 100% { transform: translateY(0); } 35% { transform: translateY(-16px); } }
/* Every wrong tap: a gentle wobble on its pole, never a "wrong" mark. */
.color-btn.nudge { animation: flag-wobble .5s ease; }
@keyframes flag-wobble { 0%, 100% { transform: rotate(0); } 25% { transform: rotate(-5deg); } 50% { transform: rotate(4deg); } 75% { transform: rotate(-2deg); } }

/* Locked until the chord has actually sounded, so an eager tap can't land
   before there's anything to listen to. Only mic mode also dims the flags
   (`.dim`) — that's a grown-up's wait, since the mic hasn't heard anything
   yet; digital mode's wait is a beat, so the flags stay at full colour and
   the mascot (`.journey-mascot.listening`, above) carries the cue instead. */
.answers.waiting { pointer-events: none; }
.answers.waiting.dim { opacity: .4; }

/* Once the chord sounds in digital mode, every flag flutters identically —
   never staggered, so it never hints at the answer — as a wordless "the
   chord is here, your turn" (see flutterFlags in app.js). It skips flags
   already mid reward/reveal animation so it never fights those. */
.answers.flutter .color-btn:not(.correct):not(.reveal) .flag-cloth { animation: flag-flutter .5s ease-in-out 2; }

/* Reveal on a wrong tap: dim everything except the correct flag, which
   lifts, waves and glows while the chord replays alongside it. The glowing
   flag itself stays tappable (unlike every other flag here) — tapping it is
   how the child confirms and moves on (see onAnswer's `revealing` branch). */
.answers.reveal .color-btn { opacity: .3; pointer-events: none; transition: opacity .3s ease; }
.answers.reveal .color-btn.reveal { opacity: 1; pointer-events: auto; cursor: pointer; animation: reveal-lift 1s ease-in-out infinite; filter: drop-shadow(0 0 14px rgba(255, 255, 255, .9)); }
.answers.reveal .color-btn.reveal .flag-cloth { animation: flag-wave 1s ease-in-out infinite; }
@keyframes reveal-lift { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
/* Confirmed: the endless reveal bob/wave stop and the flag gets one lift +
   wave instead, same as a correct answer — the glow (filter, above) stays
   so it still reads as "yes, this one". */
.answers.reveal .color-btn.reveal.confirmed { animation: flag-lift .9s ease; }
.answers.reveal .color-btn.reveal.confirmed .flag-cloth { animation: flag-wave .45s ease-in-out 2; }

/* Real-piano mode's round-start card, centred over the flags while
   session.cueing is true — instructions for the grown-up, since the child
   can't read yet. Digital mode renders no .round-cue at all (see roundCue
   in app.js): the chord itself is the cue there. Never takes taps, even
   while fading out. */
.round-cue {
  position: absolute; top: 50%; left: 50%; z-index: 5;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--card); color: var(--ink);
  border-radius: 28px; padding: 20px 32px; box-shadow: 0 6px 0 var(--lip), var(--card-shadow);
  pointer-events: none; text-align: center; max-width: 86%;
  transform: translate(-50%, -50%);
  opacity: 1; transition: opacity .25s ease;
  animation: round-cue-pulse 1s ease-in-out infinite;
}
.round-cue.hidden { opacity: 0; }
.round-cue-icon { display: inline-flex; }
.round-cue-icon svg { width: 52px; height: 52px; }
.round-cue-label { font-family: var(--display); font-weight: 700; font-size: 1.5rem; color: var(--ink); }
.round-cue-sub { color: var(--ink-soft); font-size: .95rem; font-weight: 700; }
@keyframes round-cue-pulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1); }
  50% { transform: translate(-50%, -50%) scale(1.06); }
}
/* Real-piano waiting can last a while; a slower pulse reads as "still
   listening", not "hurry up". The heard state is a brief static beat. */
.round-cue.mic-wait { animation-duration: 2.2s; }
.round-cue.mic-heard { animation: none; }

/* Real-piano retry (never scored): a plain card over the flags. */
.mic-retry {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 6;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  background: var(--card); color: var(--ink-soft); font-weight: 700; font-size: 1rem; line-height: 1.45;
  border-radius: 24px; padding: 20px 22px; box-shadow: var(--card-shadow);
  width: min(320px, 92%); text-align: center;
}
.mic-retry p { margin: 0; }
.mic-retry-actions { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }
.mic-retry .ghost-btn { box-shadow: inset 0 0 0 2px var(--lip); }

/* -------------------------------------------------------- Celebration --- */
.celebrate { align-items: center; justify-content: center; text-align: center; gap: 16px; }
.cele-mascot { animation: cele-jump 1.1s ease infinite; filter: drop-shadow(0 6px 0 var(--lip)); }
.cele-mascot svg { width: 150px; height: 150px; display: block; }
@keyframes cele-jump { 0%, 100% { transform: translateY(0) scale(1); } 30% { transform: translateY(-20px) scale(1.06); } 60% { transform: translateY(0) scale(1.02); } }
.cele-title { font-family: var(--display); font-size: clamp(2.4rem, 10vw, 2.9rem); font-weight: 800; margin: 4px 0 0; color: var(--ink); line-height: 1.05; }

/* The watering prompt, under the title — hidden (not removed) once tapped,
   so the title/garden below it never jump up to fill the gap. */
.cele-hint { margin: 0; color: var(--ink-soft); font-weight: 800; font-size: 1.1rem; }
.cele-hint.hidden { visibility: hidden; }

/* The can + plant scene shown after a set that scored anything (see
   watering in renderCelebration, js/app.js). Fixed-size stage so the can,
   the pour drops and the plant can all be laid out at absolute pixel spots. */
.cele-garden { position: relative; width: 340px; max-width: 100%; height: 260px; }

/* The can bounces at rest, with a pulsing ring inviting a tap; both stop
   and the can tilts to pour once tapped (.watering, set by water() in
   app.js). */
.water-can { position: absolute; left: 4px; top: 0; width: 120px; height: 101px; transform-origin: 50% 80%; animation: can-bounce 1.3s ease-in-out infinite; }
.water-can svg { width: 100%; height: 100%; display: block; overflow: visible; }
.water-can::before { content: ''; position: absolute; inset: -14px; border-radius: 50%; border: 4px solid var(--card); animation: ring-ping 1.6s ease-out infinite; pointer-events: none; }
@keyframes can-bounce { 0%, 100% { transform: translateY(0) rotate(0); } 40% { transform: translateY(-10px) rotate(-4deg); } 70% { transform: translateY(0) rotate(2deg); } }
@keyframes ring-ping { 0% { transform: scale(.85); opacity: .95; } 100% { transform: scale(1.2); opacity: 0; } }
.cele-garden.watering .water-can { animation: can-tilt .5s ease-out both; }
@keyframes can-tilt { to { transform: rotate(32deg); } }
.cele-garden.watering .water-can::before { display: none; }

/* Three drops poised at the can's spout; they only actually fall once
   .watering is added. */
.pour-drop { position: absolute; top: 64px; width: 14px; height: 18px; opacity: 0; pointer-events: none; }
.pour-drop svg { width: 100%; height: 100%; display: block; }
.pour-drop.d1 { left: 118px; }
.pour-drop.d2 { left: 132px; animation-delay: .35s; }
.pour-drop.d3 { left: 146px; animation-delay: .6s; }
.cele-garden.watering .pour-drop { animation: pour-drop 1s ease-in infinite; }
@keyframes pour-drop { 0% { opacity: 0; transform: translateY(0); } 15% { opacity: 1; } 100% { opacity: 0; transform: translateY(48px); } }

/* Today's plant, growing in place: starts at watering.before, then swaps to
   watering.after and replays a pop once the tap has actually landed (see
   water() in app.js) — the growth itself is the reward, not a sticker. */
.cele-plant { position: absolute; left: 50%; bottom: 0; width: 120px; height: 180px; transform: translateX(-50%); }
.cele-plant svg { width: 100%; height: 100%; display: block; overflow: visible; }
.cele-plant.grow svg { transform-origin: 50% 100%; animation: grow-pop .7s cubic-bezier(.34, 1.56, .64, 1) both; }
@keyframes grow-pop { 0% { transform: scale(.6); opacity: .4; } 60% { transform: scale(1.08); opacity: 1; } 100% { transform: scale(1); } }

/* A bloom (the 5th set of the day) also twinkles a few sparkles around it. */
.cele-sparkle { position: absolute; width: 22px; height: 22px; color: var(--card); opacity: 0; filter: drop-shadow(0 0 1px var(--ink-soft)); }
.cele-sparkle svg { width: 100%; height: 100%; }
.cele-sparkle.s1 { left: 100px; top: 92px; }
.cele-sparkle.s2 { left: 222px; top: 100px; animation-delay: .35s; }
.cele-sparkle.s3 { left: 104px; top: 160px; animation-delay: .7s; }
.cele-sparkle.s4 { left: 226px; top: 150px; animation-delay: 1.05s; }
.cele-garden.bloomed .cele-sparkle { animation: twinkle 1.4s ease-in-out infinite; }
@keyframes twinkle { 0%, 100% { transform: scale(.6); opacity: .35; } 50% { transform: scale(1.1); opacity: 1; } }

/* In the garden the mascot stands small, off to the side — the plant is the
   star here. The plain (no-watering) celebration below keeps the big
   bouncing .cele-mascot instead. */
.cele-garden .cele-mascot { position: absolute; right: 0; bottom: 0; }
.cele-garden .cele-mascot svg { width: 84px; height: 84px; }

/* Actions wait (invisible, not removed, so nothing jumps) until the child's
   own tap has watered the plant — see water()'s reasoning in app.js. */
.cele-actions { display: flex; flex-direction: column; gap: 16px; align-items: center; margin-top: 10px; transition: opacity .4s ease; }
.cele-actions.waiting { visibility: hidden; opacity: 0; }

/* The watering celebration stands its garden on the front hill: the title
   goes to the top and the actions get exactly the room between the hill's
   ridge and the bottom of the screen. The ridge is 65.4% of the hills'
   height up from the bottom (index.html's .hill-front at the centre, y 117.5
   of 340) and the hills are max(42vh, 260px) tall (.scene-hills), so these
   numbers must stay in sync with both. 44px = the 16px .celebrate gap +
   #app's 24px bottom padding + 4px to settle the plant's soil into the grass. */
.celebrate-garden { justify-content: flex-end; }
.cele-top { margin-bottom: auto; padding-top: 24px; display: flex; flex-direction: column; align-items: center; gap: 12px; }
.celebrate-garden .cele-actions {
  flex-direction: row; justify-content: center; gap: 24px; margin-top: 0;
  height: calc(max(42vh, 260px) * .654 - 44px);
}
.celebrate-garden .cele-actions .play-disc { width: 104px; height: 104px; }
.celebrate-garden .cele-actions .play-disc svg { width: 42px; height: 42px; }
/* Short screens leave less hill below the ridge: a smaller disc and label
   keep Play again inside it instead of spilling off the bottom. */
@media (max-height: 640px) {
  .celebrate-garden .cele-top { padding-top: 0; gap: 6px; }
  .celebrate-garden .cele-title { font-size: 2.1rem; }
  .celebrate-garden .cele-garden { height: 230px; }
  .celebrate-garden .cele-actions .play-disc { width: 84px; height: 84px; }
  .celebrate-garden .cele-actions .play-disc svg { width: 34px; height: 34px; }
  .celebrate-garden .cele-actions .play-label { font-size: 1.25rem; }
}

/* ----------------------------------------------------------- Confetti --- */
/* Petals, circles and little stars in the colours just practised. */
#confetti { position: fixed; inset: 0; pointer-events: none; z-index: 50; overflow: hidden; }
.confetti-bit {
  position: absolute; top: -24px; width: 10px; height: 14px; border-radius: 3px;
  animation: fall var(--dur, 2.2s) cubic-bezier(.25, .6, .55, 1) forwards;
}
.confetti-bit.circle { width: 11px; height: 11px; border-radius: 50%; }
.confetti-bit.petal { width: 12px; height: 16px; border-radius: 50% 0 50% 0; }
.confetti-bit.star {
  width: 16px; height: 16px; border-radius: 0;
  clip-path: polygon(50% 0, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
}
@keyframes fall { to { transform: translate(var(--drift, 0), 105vh) rotate(var(--spin, 540deg)); opacity: .3; } }
@keyframes nudge { 0%, 100% { transform: translateX(0); } 20% { transform: translateX(-8px); } 40% { transform: translateX(8px); } 60% { transform: translateX(-6px); } 80% { transform: translateX(6px); } }

/* ================================================= Grown-up screens === */
.adult .screen { gap: 16px; }

.back-link {
  display: inline-flex; align-items: center; gap: 2px;
  color: var(--ink-soft); font-weight: 600; font-size: .9375rem;
  padding: 8px 10px 8px 2px; border-radius: 8px; justify-self: start;
}
.back-link svg { width: 20px; height: 20px; }
.back-link:active { color: var(--ink); }

/* Buttons */
.adult .primary-btn, .adult .ghost-btn, .secondary-btn, .danger-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 44px; padding: 0 18px; border-radius: 10px;
  font-size: .9375rem; font-weight: 700; box-shadow: none; transform: none;
  transition: background-color .12s ease;
}
.adult .primary-btn { background: var(--accent); color: var(--on-accent); }
.adult .primary-btn:active { background: color-mix(in srgb, var(--accent) 85%, #000); }
.adult .ghost-btn, .secondary-btn { background: var(--fill); color: var(--ink); }
.adult .ghost-btn:active, .secondary-btn:active { background: var(--fill-strong); }
.danger-btn { background: var(--danger); color: #fff; }
@media (prefers-color-scheme: dark) { .danger-btn { color: #121A16; } }
.btn-swatch { width: 14px; height: 14px; border-radius: 4px; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); }
.secondary-btn svg { width: 18px; height: 18px; }

/* PIN gate and the real-piano priming card */
.gate { align-items: stretch; }
.gate-center { flex: 1; display: flex; align-items: center; justify-content: center; padding-bottom: 40px; }
.gate-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 20px;
  padding: 28px 24px 24px; box-shadow: var(--raise);
  text-align: center; width: 100%; max-width: 360px;
}
.gate-card p { line-height: 1.5; }
.gate-lock { color: var(--accent); display: inline-flex; }
.gate-lock svg { width: 34px; height: 34px; }
.gate-actions { display: flex; flex-direction: column; gap: 10px; align-items: stretch; margin-top: 18px; }
.pin-msg { font-weight: 700; font-size: 1.125rem; margin: 10px 0 4px; }
.pin-hint { color: var(--ink-muted); font-size: .8125rem; margin: 0 0 18px; }
.pin-dots { display: flex; gap: 14px; justify-content: center; margin: 0 0 22px; }
.pin-dots.shake { animation: nudge .4s ease; }
.pin-dot { width: 12px; height: 12px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--ink-muted); transition: background-color .1s; }
.pin-dot.filled { background: var(--ink); box-shadow: none; }
.pin-pad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.pin-key {
  height: 58px; border-radius: 14px; background: var(--fill); color: var(--ink);
  font-size: 1.375rem; font-weight: 600; font-variant-numeric: tabular-nums;
  display: grid; place-items: center; transition: background-color .1s ease;
}
.pin-key:active { background: var(--fill-strong); }
.pin-key.pin-back { background: none; color: var(--ink-soft); }
.pin-key svg { width: 26px; height: 26px; }

/* Header + tabs */
.g-head { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; gap: 8px; min-height: 44px; }
.g-head h2 { margin: 0; font-size: 1.0625rem; font-weight: 700; text-align: center; }
.g-child { justify-self: end; display: inline-flex; align-items: center; gap: 8px; font-weight: 600; font-size: .875rem; color: var(--ink-soft); }
.g-child-ava, .g-child-ava svg { width: 28px; height: 28px; display: block; }

.segmented {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px;
  background: var(--fill); padding: 3px; border-radius: 10px;
}
.seg {
  min-height: 36px; padding: 6px 4px; border-radius: 8px;
  color: var(--ink-soft); font-size: .875rem; font-weight: 600; font-variant-numeric: tabular-nums;
  transition: background-color .12s ease, color .12s ease;
}
.seg.sel { background: var(--surface); color: var(--ink); box-shadow: 0 1px 2px rgba(20, 32, 24, .1), 0 0 0 .5px rgba(20, 32, 24, .06); }
@media (prefers-color-scheme: dark) { .seg.sel { background: var(--fill-strong); } }

/* Grouped sections: a small sentence-case title, a card of rows, and an
   optional caption underneath — the standard settings-list pattern. */
.g-body { display: flex; flex-direction: column; gap: 22px; padding-bottom: 12px; }
.g-section { display: flex; flex-direction: column; gap: 8px; }
.g-section-title { margin: 0 4px; font-size: .8125rem; font-weight: 700; color: var(--ink-soft); }
.g-caption { margin: 0 4px; font-size: .8125rem; line-height: 1.45; color: var(--ink-muted); }
.g-card { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; overflow: hidden; }
.g-card.pad { padding: 16px; }
.g-list > * + * { border-top: 1px solid var(--line); }
.g-row {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 11px 14px; min-height: 54px; text-align: left; color: var(--ink);
}
button.g-row { transition: background-color .12s ease; }
button.g-row:active { background: var(--fill); }
@media (hover: hover) and (pointer: fine) { button.g-row:not(:disabled):hover { background: var(--fill); filter: none; } }
.g-row.stack { flex-direction: column; align-items: stretch; gap: 10px; padding: 14px; }
.g-row-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.g-row-title { font-size: .9375rem; font-weight: 600; }
.g-row-sub { font-size: .8125rem; color: var(--ink-muted); }
.about-status.bad { color: var(--danger); } /* "Couldn't check" in Settings → About */
.g-row-end { margin-left: auto; display: flex; align-items: center; gap: 12px; color: var(--ink-soft); font-size: .875rem; font-variant-numeric: tabular-nums; }
.g-row[aria-disabled="true"] { cursor: default; }

.swatch { width: 30px; height: 30px; border-radius: 9px; flex-shrink: 0; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1); }
.swatch.sm { width: 14px; height: 14px; border-radius: 4px; }
@media (prefers-color-scheme: dark) { .swatch, .btn-swatch { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .18); } }
/* A small planted flag standing in for a colour in grown-up lists. */
.row-flag { width: 22px; height: 34px; flex-shrink: 0; display: inline-flex; }
.row-flag svg { width: 100%; height: 100%; display: block; overflow: visible; }

.badge {
  display: inline-block; padding: 2px 8px; border-radius: 999px;
  background: var(--accent-soft); color: var(--accent); font-size: .75rem; font-weight: 700;
}
.badge.muted { background: var(--fill); color: var(--ink-soft); }

/* Tick-box indicator for toggling a colour on/off. */
.check {
  width: 24px; height: 24px; border-radius: 50%; flex-shrink: 0;
  display: grid; place-items: center; color: var(--on-accent);
  box-shadow: inset 0 0 0 1.5px var(--fill-strong);
}
.check svg { width: 14px; height: 14px; opacity: 0; }
.check.on { background: var(--accent); box-shadow: none; }
.check.on svg { opacity: 1; }
.check.locked { opacity: .45; }

/* Disclosure for longer explanations kept out of the way by default. */
.g-details { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; }
.g-details summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: 8px;
  padding: 14px; font-size: .9375rem; font-weight: 600; border-radius: 14px;
}
.g-details summary::-webkit-details-marker { display: none; }
.g-details summary .btn-ico { margin-left: auto; color: var(--ink-muted); transition: transform .15s ease; }
.g-details summary svg { width: 18px; height: 18px; }
.g-details[open] summary .btn-ico { transform: rotate(180deg); }
.g-section > .g-details { margin-top: 4px; }
.g-details-body { padding: 0 14px 14px; color: var(--ink-soft); font-size: .875rem; line-height: 1.55; }
.g-details-body p { margin: 0 0 8px; }
.g-details-body p:last-child { margin-bottom: 0; }

/* Colours tab: readiness */
.readiness { display: grid; grid-template-columns: auto 1fr; gap: 2px 12px; padding: 16px; border-radius: 14px; }
.readiness.ready { background: var(--good-soft); }
.readiness.notyet { background: var(--warn-soft); }
.r-icon {
  grid-row: span 2; width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center; background: var(--surface);
}
.readiness.ready .r-icon { color: var(--good); }
.readiness.notyet .r-icon { color: var(--warn); }
.r-icon svg { width: 20px; height: 20px; }
.r-title { font-weight: 700; font-size: .9375rem; align-self: end; }
.r-sub { font-size: .875rem; line-height: 1.45; color: var(--ink-soft); }
.r-pips { grid-column: 2; display: flex; flex-wrap: wrap; gap: 6px; margin-top: 12px; }
.r-pip {
  width: 22px; height: 22px; border-radius: 50%; display: grid; place-items: center;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .12); opacity: .3;
}
.r-pip.ok { opacity: 1; }
.r-pip svg { width: 12px; height: 12px; }
.r-actions { grid-column: 2; margin-top: 14px; }

/* Progress tab */
.stat-tiles { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.stat-tile { background: var(--surface); border: 1px solid var(--line); border-radius: 14px; padding: 14px; }
.stat-label { font-size: .8125rem; color: var(--ink-soft); }
.stat-value { font-size: 1.75rem; font-weight: 700; letter-spacing: -.02em; margin-top: 2px; }
.stat-note { font-size: .8125rem; color: var(--ink-muted); }

.chart { position: relative; padding: 16px 16px 12px; }
.chart-head { margin-bottom: 14px; }
.chart-title { font-size: .9375rem; font-weight: 700; }
.chart-sub { font-size: .8125rem; color: var(--ink-muted); margin-top: 2px; }
.chart-plot { position: relative; height: 132px; margin-left: 36px; }
.chart-grid { position: absolute; left: 0; right: 0; height: 1px; background: var(--line); }
.chart-ylabel {
  position: absolute; right: calc(100% + 8px); transform: translateY(-50%);
  font-size: .6875rem; color: var(--ink-muted); font-variant-numeric: tabular-nums; white-space: nowrap;
}
.chart-goal { position: absolute; left: 0; right: 0; height: 1px; background: var(--ink-muted); opacity: .55; }
.chart-cols { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(var(--days), 1fr); }
.chart-col { position: relative; display: flex; align-items: flex-end; justify-content: center; outline-offset: -2px; border-radius: 6px; }
.chart-col:hover, .chart-col:focus-visible { background: color-mix(in srgb, var(--fill) 70%, transparent); }
.chart-bar { width: min(62%, 18px); background: var(--accent); border-radius: 4px 4px 0 0; min-height: 2px; }
.chart-x { display: grid; grid-template-columns: repeat(var(--days), 1fr); margin: 6px 0 0 36px; }
.chart-x span { text-align: center; font-size: .6875rem; color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.chart-x span.today { color: var(--ink); font-weight: 700; }
.chart-tip {
  position: absolute; z-index: 3; pointer-events: none; transform: translate(-50%, -100%);
  background: var(--ink); color: var(--surface); border-radius: 8px; padding: 6px 9px;
  font-size: .75rem; line-height: 1.35; white-space: nowrap; box-shadow: var(--raise);
}
.chart-tip strong { display: block; font-weight: 700; }
.chart-empty { font-size: .875rem; color: var(--ink-muted); padding: 28px 0 20px; text-align: center; }

.acc-grid { display: grid; grid-template-columns: max-content 1fr max-content; align-items: center; gap: 12px 12px; padding: 16px; }
.acc-row { display: contents; }
.acc-name { display: inline-flex; align-items: center; gap: 8px; font-size: .9375rem; font-weight: 600; }
.acc-track { height: 8px; border-radius: 999px; background: var(--fill); overflow: hidden; }
.acc-fill { height: 100%; border-radius: 999px; transition: width .5s ease; box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .08); }
@media (prefers-color-scheme: dark) { .acc-fill { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28); } }
.acc-nums { text-align: right; font-variant-numeric: tabular-nums; line-height: 1.25; }
.acc-pct { font-size: .9375rem; font-weight: 700; }
.acc-life { font-size: .75rem; color: var(--ink-muted); }

/* Sets per day: a column of five dots per day, one filled per set played. */
.sets-grid { display: grid; grid-template-columns: repeat(var(--days), minmax(0, 1fr)); align-items: end; padding: 16px 12px 8px; }
.sets-col { display: flex; flex-direction: column-reverse; align-items: center; gap: 3px; }
.sets-dot { width: 9px; height: 9px; border-radius: 50%; box-shadow: inset 0 0 0 1.5px var(--fill-strong); }
.sets-dot.on { background: var(--accent); box-shadow: none; }
.sets-x { display: flex; justify-content: space-between; padding: 0 12px 14px; font-size: .75rem; color: var(--ink-muted); }
.sets-x .today { color: var(--ink); font-weight: 700; }

.s-day { padding: 10px 14px 6px; font-size: .75rem; font-weight: 700; color: var(--ink-soft); background: var(--fill); }
.g-list > .s-day + * { border-top: none; }
.s-row { display: grid; grid-template-columns: 3.5rem 1fr auto; align-items: center; gap: 10px; padding: 11px 14px; font-size: .875rem; }
.s-time { color: var(--ink-muted); font-variant-numeric: tabular-nums; }
.s-main { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.s-pct { font-weight: 700; font-variant-numeric: tabular-nums; }

.cf-row { display: flex; align-items: center; gap: 8px; padding: 11px 14px; font-size: .875rem; }
.cf-label { font-weight: 600; }
.cf-as { color: var(--ink-muted); }
.cf-count { margin-left: auto; font-weight: 700; color: var(--ink-soft); font-variant-numeric: tabular-nums; }

/* Children + settings */
.avatar-row, .avatar-row svg { width: 40px; height: 40px; display: block; flex-shrink: 0; }
.row-remove { color: var(--danger); font-size: .875rem; font-weight: 600; padding: 8px 14px; align-self: stretch; }
.row-remove:active { background: var(--danger-soft); }
.profile-item { display: flex; align-items: stretch; }
.profile-item .g-row { flex: 1; min-width: 0; }

.text-input {
  width: 100%; height: 44px; padding: 0 12px; border-radius: 10px;
  border: 1px solid var(--line); background: var(--surface); color: var(--ink);
  font: inherit; font-size: 1rem;
}
.text-input:focus { outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.input-row { display: flex; gap: 8px; align-items: center; }
.input-row .text-input { flex: 1; }
.pin-input { max-width: 120px; text-align: center; letter-spacing: 6px; font-variant-numeric: tabular-nums; }
.form-msg { min-height: 1.2em; margin: 0; font-size: .8125rem; color: var(--ink-muted); }
.form-msg.bad { color: var(--danger); }
.form-msg:empty { display: none; }

.form-stack { display: flex; flex-direction: column; gap: 14px; }
.avatar-picker { display: flex; flex-wrap: wrap; gap: 8px; }
.avatar-opt {
  width: 52px; height: 52px; border-radius: 12px; display: grid; place-items: center;
  background: var(--fill); box-shadow: inset 0 0 0 2px transparent; transition: box-shadow .12s ease;
}
.avatar-opt svg { width: 40px; height: 40px; display: block; }
.avatar-opt.sel { background: var(--accent-soft); box-shadow: inset 0 0 0 2px var(--accent); }

.switch {
  position: relative; width: 50px; height: 30px; border-radius: 999px; flex-shrink: 0;
  background: var(--fill-strong); transition: background-color .15s ease;
}
.switch::after {
  content: ''; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%;
  background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, .25); transition: transform .15s ease;
}
.switch[aria-checked="true"] { background: var(--good); }
.switch[aria-checked="true"]::after { transform: translateX(20px); }

.danger-row { color: var(--danger); font-weight: 600; justify-content: center; }
.about { margin: 0 4px; font-size: .8125rem; line-height: 1.55; color: var(--ink-muted); }
.about p { margin: 0 0 6px; }

/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
