/* ===== FONTS (self-hosted Nunito, SIL OFL 1.1 — see fonts/LICENSE.txt) ===== */
@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/nunito-400.woff2') format('woff2');
}

@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url('fonts/nunito-700.woff2') format('woff2');
}

@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 800;
    font-display: swap;
    src: url('fonts/nunito-800.woff2') format('woff2');
}

@font-face {
    font-family: 'Nunito';
    font-style: normal;
    font-weight: 900;
    font-display: swap;
    src: url('fonts/nunito-900.woff2') format('woff2');
}

/* ===== RESET & BASE ===== */
* { margin: 0; padding: 0; box-sizing: border-box; }

/* Visually-hidden but screen-reader-available (labels, live prompts). */
.sr-only {
    position: absolute !important;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

:root {
    --bg: #FFF8F0;
    --text: #333;
    --radius: 20px;
    --safe-bottom: env(safe-area-inset-bottom, 0px);
}

body {
    font-family: 'Nunito', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    height: 100vh;
    height: 100dvh;
    overflow: hidden;
    transition: background 0.4s ease;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
}

#app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    height: 100dvh;
    position: relative;
}

/* ===== TOOLBAR ===== */
#toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 16px;
    padding-top: max(8px, env(safe-area-inset-top, 0px));
    z-index: 100;
    position: relative;
    flex-shrink: 0;
}

#app-title {
    font-size: 26px;
    font-weight: 900;
    background: linear-gradient(135deg, #FF6B6B, #FFE66D, #4ECDC4, #45B7D1, #7B68EE);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.tool-btn {
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 12px;
    background: rgba(0, 0, 0, 0.06);
    font-size: 22px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.15s;
}

.tool-btn:active { transform: scale(0.88); }

/* ===== MODES ===== */
.mode {
    display: none;
    flex: 1;
    flex-direction: column;
    overflow: hidden;
    min-height: 0;
}

.mode.active { display: flex; }

/* ===== HOME ===== */
/* Centered via auto margins (not justify-content: center) so that when the
   content is taller than the viewport it stays scrollable from the very top
   instead of clipping the title above scroll position 0. */
#mode-home {
    padding-bottom: var(--safe-bottom);
    overflow-y: auto;
}

.home-title {
    text-align: center;
    font-size: 34px;
    font-weight: 900;
    margin: auto 0 16px;
    color: #333;
    flex-shrink: 0;
}

.mode-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 12px;
    padding: 0 18px 20px;
    max-width: 420px;
    margin: 0 auto auto;
    width: 100%;
}

.mode-card {
    border: none;
    border-radius: var(--radius);
    padding: 18px 10px;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);
    transition: transform 0.2s;
    font-family: inherit;
}

/* No entrance animation — the picker is just there, ready to tap on load. */

.mode-card:active { transform: scale(0.94); }

/* Gentle lift on devices that actually hover (desktop) — never on touch, and
   never under reduced-motion. Gives the home grid + hubs a little life. */
@media (hover: hover) {
    .mode-card, .piano-hub-card, .read-hub-card, .math-hub-card,
    .toggle-btn, .play-btn { transition: transform 0.15s ease; }
    .mode-card:hover, .piano-hub-card:hover, .read-hub-card:hover,
    .math-hub-card:hover { transform: translateY(-3px) scale(1.02); }
    .toggle-btn:hover, .play-btn:hover { transform: translateY(-1px) scale(1.03); }
}
@media (prefers-reduced-motion: reduce) {
    .mode-card:hover, .piano-hub-card:hover, .read-hub-card:hover,
    .math-hub-card:hover, .toggle-btn:hover, .play-btn:hover { transform: none; }
}

.card-icon { font-size: 32px; line-height: 1.1; }
.card-label { font-size: 18px; font-weight: 900; color: white; }
.card-desc { font-size: 11px; font-weight: 700; color: rgba(255, 255, 255, 0.85); }

.card-abc { background: linear-gradient(135deg, #FF6B6B, #FF8E53); }
.card-123 { background: linear-gradient(135deg, #4ECDC4, #2ECC71); }
.card-free { background: linear-gradient(135deg, #7B68EE, #9B59B6); }
.card-game { background: linear-gradient(135deg, #45B7D1, #6C9CE3); }
.card-match { background: linear-gradient(135deg, #FFB347, #FFCC33); }
.card-count { background: linear-gradient(135deg, #FF85A1, #E07CC1); }
/* The paired (2-column) cards. Trace It + Spelling share a row. */
.card-trace { background: linear-gradient(135deg, #34D399, #10B981); }
.card-spell { background: linear-gradient(135deg, #F6A5C0, #C86DD7); }
/* Piano bookends the grid full-width so the middle cards pair up cleanly
   2-per-row and the music room gets featured. */
.card-piano { background: linear-gradient(135deg, #8E7CF0, #5B4BD6); grid-column: 1 / -1; }
/* Reading bookends the grid full-width too (a warm garden green) — featured. */
.card-read { background: linear-gradient(135deg, #7FBF6E, #4F9D5B); grid-column: 1 / -1; }
/* Math: a warm tangerine, distinct from green Reading / purple Piano. */
.card-math { background: linear-gradient(135deg, #F2A65A, #E8772E); grid-column: 1 / -1; }

/* ===== EXPLORER (ABC & 123) ===== */
.explorer-container {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 2px;
    padding: 0 20px;
    min-height: 0;
    overflow-y: auto;
}

.explorer-emoji {
    font-size: 60px; /* fallback for browsers without clamp() */
    font-size: clamp(48px, 12vmin, 90px);
    line-height: 1.1;
    cursor: pointer;
}

.explorer-char {
    font-size: 170px; /* fallback for browsers without clamp() */
    font-size: clamp(120px, 38vmin, 280px);
    font-weight: 900;
    line-height: 1;
    cursor: pointer;
    transition: color 0.3s;
    /* Subtle lift so even the lightest palette color reads crisply */
    text-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}

.explorer-word {
    font-size: 22px;
    font-weight: 800;
    color: #64748b;
    margin-top: 2px;
}

.case-btn {
    margin-top: 6px;
    padding: 6px 20px;
    border: 2px solid #e2e8f0;
    border-radius: 12px;
    background: white;
    font-family: inherit;
    font-size: 16px;
    font-weight: 800;
    color: #64748b;
    cursor: pointer;
    transition: transform 0.15s;
}

.case-btn:active { transform: scale(0.92); background: #f1f5f9; }

/* Count dots — colored circles in ten-frame grid */
.count-dots {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    margin-top: 8px;
}

.dot-group {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
}

.count-dot {
    margin: 3px; /* flex-gap fallback for old Safari */
    border-radius: 50%;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12), inset 0 1px 2px rgba(255, 255, 255, 0.3);
    animation: dot-pop 0.3s ease-out backwards;
}

.dots-sep {
    width: 80%;
    max-width: 140px;
    height: 3px;
    background: rgba(0, 0, 0, 0.08);
    border-radius: 2px;
    margin: 2px 0;
}

@keyframes dot-pop {
    from { transform: scale(0); opacity: 0; }
    60% { transform: scale(1.25); }
    to { transform: scale(1); opacity: 1; }
}

/* Explorer navigation */
.explorer-nav {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 14px;
    padding-bottom: max(18px, var(--safe-bottom));
    flex-shrink: 0;
}

.nav-arrow {
    width: 52px;
    height: 52px;
    border: none;
    border-radius: 14px;
    background: #2563eb;
    color: white;
    font-size: 20px;
    font-weight: 900;
    cursor: pointer;
    flex-shrink: 0;
    font-family: inherit;
    transition: transform 0.15s;
    display: flex;
    align-items: center;
    justify-content: center;
}

.nav-arrow:active { transform: scale(0.88); background: #1d4ed8; }
.nav-arrow:disabled { background: #cbd5e1; cursor: default; transform: none; opacity: 0.5; }

.quick-strip {
    display: flex;
    gap: 6px;
    overflow-x: auto;
    flex: 1;
    padding: 3px 2px;
    scrollbar-width: none;
    -ms-overflow-style: none;
    scroll-behavior: smooth;
}

.quick-strip::-webkit-scrollbar { display: none; }

.strip-item {
    min-width: 44px; /* touch-target floor: the strip scrolls, so big costs nothing */
    height: 44px;
    border: 2px solid #e2e8f0;
    border-radius: 9px;
    background: white;
    font-family: inherit;
    font-size: 15px;
    font-weight: 800;
    color: #64748b;
    cursor: pointer;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.15s, background 0.2s;
}

.strip-item.active {
    color: white;
    border-color: transparent;
    transform: scale(1.12);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.strip-item:active { transform: scale(0.88); }

/* Visible keyboard focus (drawn only on keyboard nav, never on touch/mouse) */
.strip-item:focus-visible,
.nav-arrow:focus-visible {
    outline: 4px solid #2563eb;
    outline-offset: 3px;
}

/* ===== FREE PLAY ===== */
#mode-freeplay {
    position: relative;
    background: #1a1a2e !important;
}

#freeplay-char-display {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    z-index: 1;
    gap: 4px;
}

#freeplay-char {
    font-size: 220px;
    font-weight: 900;
    color: white;
    text-shadow: 0 0 60px rgba(255, 255, 255, 0.3);
    transition: color 0.15s;
    line-height: 1;
}

#freeplay-word {
    font-size: 26px;
    font-weight: 800;
    color: rgba(255, 255, 255, 0.7);
    transition: color 0.3s;
}

#freeplay-hint {
    position: absolute;
    bottom: 70px;
    left: 0; right: 0;
    text-align: center;
    z-index: 2;
    pointer-events: none;
    transition: opacity 0.5s;
}
/* A wordless invite a pre-reader understands: a softly bobbing finger. */
.fp-hint-finger {
    display: inline-block;
    font-size: 52px;
    filter: drop-shadow(0 4px 10px rgba(0, 0, 0, 0.35));
    animation: fp-finger-bob 1.4s ease-in-out infinite;
}
@keyframes fp-finger-bob {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-12px); }
}
@media (prefers-reduced-motion: reduce) {
    .fp-hint-finger { animation: none; }
}

#draw-canvas {
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    z-index: 3;
    cursor: crosshair;
    touch-action: none;
}

.clear-btn {
    position: absolute;
    bottom: max(20px, var(--safe-bottom));
    right: 20px;
    z-index: 4;
    background: rgba(255, 255, 255, 0.12) !important;
}

body.dark-mode #toolbar { color: white; }
body.dark-mode .tool-btn { background: rgba(255, 255, 255, 0.1); }
body.dark-mode #app-title {
    -webkit-text-fill-color: rgba(255, 255, 255, 0.9);
    background: none;
}

/* ===== TRACE IT ===== */
#mode-trace {
    align-items: stretch;
}

#trace-stage {
    position: relative;
    flex: 1;
    min-height: 0;
    margin: 0 4px;
}

#trace-canvas {
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    cursor: crosshair;
    touch-action: none;
}

#trace-hint {
    position: absolute;
    bottom: 8px;
    left: 0; right: 0;
    text-align: center;
    font-size: 16px;
    font-weight: 700;
    color: #94a3b8;
    pointer-events: none;
    transition: opacity 0.5s;
}

/* Rainbow meter — the wordless "3 Perfects in a row = 🌈" progress story.
   Dim stars fill in per Perfect; at 2/3 the last empty star breathes ("one
   more!"); while the brush is HELD the chip becomes a gently-pulsing 🌈. */
#trace-rainbow-meter {
    position: absolute; top: 10px; left: 12px; z-index: 5;
    display: flex; align-items: center; gap: 5px;
    background: rgba(255,255,255,0.8); border-radius: 999px; padding: 5px 11px;
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    pointer-events: none;
}
.trm-slot { font-size: 16px; line-height: 1; opacity: 0.2; filter: grayscale(1); transition: opacity 0.2s, filter 0.2s; }
.trm-slot.filled { opacity: 1; filter: none; }
.trm-slot.pop { animation: trmPop 0.5s ease; }
.trm-slot.next-up { animation: trmNext 1.3s ease-in-out infinite; }
@keyframes trmPop { 0% { transform: scale(0.2); } 60% { transform: scale(1.5); } 100% { transform: scale(1); } }
@keyframes trmNext { 0%, 100% { opacity: 0.2; } 50% { opacity: 0.65; } }
.trm-bow { display: none; font-size: 20px; line-height: 1; }
#trace-rainbow-meter.unlocked { background: linear-gradient(90deg, rgba(255,220,220,0.9), rgba(255,246,200,0.9), rgba(214,245,214,0.9), rgba(214,230,255,0.9)); }
#trace-rainbow-meter.unlocked .trm-slot { display: none; }
#trace-rainbow-meter.unlocked .trm-bow { display: block; animation: trmBow 1.6s ease-in-out infinite; }
@keyframes trmBow { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.15); } }

/* Unlock beat: the letter the kid JUST painted spins through the whole rainbow. */
#trace-canvas.rainbow-spin { animation: traceHueSpin 1.7s ease-in-out; }
@keyframes traceHueSpin { from { filter: hue-rotate(0deg); } to { filter: hue-rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
    .trm-slot.pop, .trm-slot.next-up, #trace-rainbow-meter.unlocked .trm-bow { animation: none; }
    .trm-slot.next-up { opacity: 0.5; } /* the "one more!" cue survives, just static */
    #trace-canvas.rainbow-spin { animation: none; }
}

.trace-nav .trace-clear {
    font-size: 22px;
    background: #f59e0b;
}
.trace-nav .trace-clear:active { background: #d97706; }

/* The ⭐ mastery mark on a completed glyph's strip chip */
.strip-item.traced { position: relative; }
.strip-item.traced::after {
    content: '⭐';
    position: absolute;
    top: -7px;
    right: -5px;
    font-size: 13px;
    line-height: 1;
    pointer-events: none;
    filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.25));
}
/* A 🌟 Perfect finish reads differently from an ordinary ⭐ done. */
.strip-item.traced-perfect::after { content: '🌟'; }

/* ===== BUBBLE POP ===== */
#mode-game { position: relative; }

#game-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 12px;
    z-index: 10;
    position: relative;
    flex-shrink: 0;
    gap: 6px;
}

#game-left-stats, #game-right-stats {
    display: flex;
    flex-direction: column;
    gap: 0;
}

#game-score-display {
    font-size: 22px;
    font-weight: 900;
    color: #FF8E53;
    white-space: nowrap;
}

#game-best {
    font-size: 11px;
    font-weight: 700;
    color: #94a3b8;
}

#game-streak {
    font-size: 20px;
    font-weight: 900;
    color: #FF6B6B;
    text-align: right;
}

#game-mode-toggle {
    display: flex;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 10px;
    padding: 3px;
    flex-shrink: 0;
}

.toggle-btn {
    padding: 10px 14px;
    min-height: 40px; /* touch-target floor */
    border: none;
    border-radius: 8px;
    background: transparent;
    font-family: inherit;
    font-size: 13px;
    font-weight: 800;
    color: #94a3b8;
    cursor: pointer;
    transition: all 0.2s;
}

.toggle-btn.active {
    background: white;
    color: #333;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

#game-prompt {
    font-size: 18px;
    font-weight: 800;
    color: #333;
    white-space: nowrap;
    text-align: right;
}

/* White pill chip: the target stays legible whatever its palette color */
#game-target {
    font-size: 26px;
    font-weight: 900;
    display: inline-block;
    background: white;
    padding: 0 12px;
    border-radius: 999px;
    min-width: 44px;
    text-align: center;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.12);
}

#game-area {
    flex: 1;
    position: relative;
    overflow: hidden;
    touch-action: none;
}

.bubble {
    position: absolute;
    top: 0;
    left: 0;
    border-radius: 50%;
    border: none;
    color: white;
    font-weight: 900;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow:
        0 6px 20px rgba(0, 0, 0, 0.15),
        inset 0 -5px 12px rgba(0, 0, 0, 0.12),
        inset 0 5px 12px rgba(255, 255, 255, 0.3);
    /* Motion is JS-driven (gameTick physics) so breeze lines can deflect it */
    will-change: transform;
    font-family: 'Nunito', sans-serif;
    touch-action: manipulation;
    transition: box-shadow 0.2s;
    /* Legibility insurance: white glyph stays readable on any bubble color */
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45);
}

.bubble::after {
    content: '';
    position: absolute;
    top: 14%;
    left: 18%;
    width: 24%;
    height: 18%;
    background: rgba(255, 255, 255, 0.4);
    border-radius: 50%;
    transform: rotate(-30deg);
}

.bubble.popped {
    animation: pop-burst 0.35s ease-out forwards !important;
    pointer-events: none;
}

/* Wordless goal: huge faded ghost of the target letter behind the bubbles */
#game-ghost {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 46vmin;
    font-weight: 900;
    line-height: 1;
    opacity: 0.14;
    pointer-events: none;
    -webkit-user-select: none;
    user-select: none;
}

/* 'both' mode shows two glyphs ("Aa") — shrink so the pair still fits */
#game-ghost.two-char { font-size: 30vmin; }

#game-ghost.ghost-in { animation: ghost-in 0.4s ease-out; }

/* Breeze lines the kid draws; bubbles bounce off them. Input is handled on
   #game-area itself, so the canvas stays a pure display layer. */
#game-lines {
    position: absolute;
    top: 0;
    left: 0;
    pointer-events: none;
}

/* Transform-only (no opacity keyframes) so the watermark never flashes solid */
@keyframes ghost-in {
    from { transform: translate(-50%, -50%) scale(0.4); }
    to { transform: translate(-50%, -50%) scale(1); }
}

/* ===== MATCH UP ===== */
#mode-match { position: relative; }

#match-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 14px;
    flex-shrink: 0;
    gap: 6px;
}

#match-info {
    font-size: 20px;
    font-weight: 900;
    color: #FFB347;
}

/* Parent-facing print, demoted to its own quiet line under the header */
#match-moves {
    font-size: 12px;
    font-weight: 700;
    color: #94a3b8;
    text-align: center;
    flex-shrink: 0;
    padding: 0 14px;
}

#match-pair-toggle {
    display: flex;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 10px;
    padding: 3px;
    flex-shrink: 0;
}

#match-diff {
    display: flex;
    background: rgba(0, 0, 0, 0.06);
    border-radius: 10px;
    padding: 3px;
}

.diff-btn {
    padding: 10px 12px;
    min-height: 40px; /* touch-target floor */
    border: none;
    border-radius: 8px;
    background: transparent;
    font-family: inherit;
    font-size: 12px;
    font-weight: 800;
    color: #94a3b8;
    cursor: pointer;
    transition: all 0.2s;
}

.diff-btn.active {
    background: white;
    color: #333;
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.1);
}

#match-grid {
    display: grid;
    gap: 10px;
    padding: 10px 14px;
    flex: 1;
    align-content: center;
    justify-items: center;
    overflow: hidden; /* a tight Hard board never scrolls the section */
}

#match-grid.easy { grid-template-columns: repeat(3, 1fr); }
#match-grid.medium { grid-template-columns: repeat(4, 1fr); }
#match-grid.hard { grid-template-columns: repeat(4, 1fr); }

.match-card {
    /* Cards are real <button>s (keyboard playable) — reset button chrome */
    border: none;
    background: transparent;
    padding: 0;
    font-family: inherit;
    width: 100%;
    max-width: 100px;
    perspective: 600px;
    cursor: pointer;
}

.match-card:focus-visible {
    outline: 4px solid #2563eb;
    outline-offset: 3px;
    border-radius: 16px;
}

/* Square cards without aspect-ratio (iOS 12-14): padding-bottom spacer on the
   inner wrapper; the card faces are absolutely positioned so they fill it. */
.match-card-inner {
    width: 100%;
    height: 0;
    padding-bottom: 100%;
    position: relative;
    transform-style: preserve-3d;
    transition: transform 0.45s ease;
    border-radius: 16px;
}

@supports (aspect-ratio: 1) {
    .match-card { aspect-ratio: 1; }
    .match-card-inner { height: 100%; padding-bottom: 0; }
}

.match-card.flipped .match-card-inner,
.match-card.matched .match-card-inner {
    transform: rotateY(180deg);
}

.match-card-front,
.match-card-back {
    position: absolute;
    width: 100%;
    height: 100%;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
    border-radius: 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.match-card-front {
    /* Sunny app-palette gradient (same as the Match Up home card) */
    background: linear-gradient(135deg, #FFB347, #FFCC33);
    color: rgba(255, 255, 255, 0.9);
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
    font-size: 28px;
    font-weight: 900;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.match-card-back {
    background: white;
    border: 3px solid #e2e8f0;
    transform: rotateY(180deg);
    font-weight: 900;
    color: #333;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.match-card-back.card-letter {
    font-size: 38px;
}

.match-card-back.card-emoji {
    font-size: 40px;
}

.match-card.matched .match-card-back {
    border-color: #4ECDC4; /* fallback; JS paints the pair's own color inline */
    background: #f0fff4;
}

.match-card.matched {
    pointer-events: none;
    animation: match-bounce 0.5s ease;
}

/* Scale lives on the outer card so the inner rotateY(180deg) flip is untouched */
@keyframes match-bounce {
    0% { transform: scale(1); }
    45% { transform: scale(1.15); }
    100% { transform: scale(1); }
}

.win-overlay {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.96);
    z-index: 20;
    gap: 12px;
}

.win-overlay.show { display: flex; }

.win-emoji { font-size: 72px; animation: pop-in 0.5s ease-out; }
.win-text { font-size: 34px; font-weight: 900; color: #333; }
.win-stats { font-size: 12px; font-weight: 700; color: #94a3b8; } /* parent-facing print */

.play-btn {
    padding: 12px 32px;
    border: none;
    border-radius: 16px;
    background: linear-gradient(135deg, #4ECDC4, #2ECC71);
    color: white;
    font-family: inherit;
    font-size: 18px;
    font-weight: 900;
    cursor: pointer;
    box-shadow: 0 4px 15px rgba(78, 205, 196, 0.4);
    transition: transform 0.15s;
    margin-top: 4px;
}

.play-btn:active { transform: scale(0.94); }

/* ===== COUNTING GAME ===== */
#mode-counting {
    padding: 0 14px;
    padding-bottom: max(14px, var(--safe-bottom));
}

#counting-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 2px 0 6px;
    flex-shrink: 0;
}

#counting-score-display {
    font-size: 22px;
    font-weight: 900;
    color: #FF8E53;
}

#counting-best {
    font-size: 11px;
    font-weight: 700;
    color: #94a3b8;
}

#counting-streak {
    font-size: 20px;
    font-weight: 900;
    color: #FF6B6B;
}

#counting-question {
    text-align: center;
    font-size: 24px;
    font-weight: 900;
    color: #64748b;
    flex-shrink: 0;
    padding: 2px 0;
}

#counting-objects {
    flex: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    align-content: center;
    justify-content: center;
    gap: 14px;
    padding: 12px 0;
    min-height: 0;
    max-width: 360px;
    margin: 0 auto;
    width: 100%;
}

.counting-obj {
    font-size: 44px;
    animation: dot-pop 0.3s ease-out backwards;
    line-height: 1.1;
    position: relative;
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
    touch-action: manipulation; /* kill the 300ms tap delay on old mobile Safari */
    transition: transform 0.2s, filter 0.2s;
}

/* Touch-counting: a counted item settles down and wears its number */
.counting-obj.counted {
    transform: scale(0.88);
    filter: saturate(0.75) brightness(1.05);
}

.count-badge {
    position: absolute;
    top: -14px;
    left: 50%;
    transform: translateX(-50%);
    min-width: 24px;
    height: 24px;
    padding: 0 6px;
    border-radius: 999px;
    color: white;
    font-family: 'Nunito', sans-serif;
    font-size: 15px;
    font-weight: 900;
    line-height: 24px;
    text-align: center;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); /* keep white legible on yellow/light hues */
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
    animation: badge-pop 0.3s ease-out;
    pointer-events: none;
}

@keyframes badge-pop {
    0% { transform: translateX(-50%) scale(0); }
    65% { transform: translateX(-50%) scale(1.3); }
    100% { transform: translateX(-50%) scale(1); }
}

/* Re-tapping an already-counted item: a friendly "I'm already counted" wiggle */
.counting-obj.count-wiggle {
    animation: count-wiggle 0.35s ease-in-out;
}

@keyframes count-wiggle {
    0%, 100% { transform: scale(0.88) rotate(0deg); }
    30% { transform: scale(0.88) rotate(-8deg); }
    70% { transform: scale(0.88) rotate(8deg); }
}

#counting-choices {
    display: flex;
    justify-content: center;
    padding: 4px 0;
    flex-shrink: 0;
    flex-wrap: wrap;
}
/* Wordless "now pick the number" cue: a brief pulse once everything's counted. */
@keyframes choices-pulse {
    0%, 100% { transform: scale(1); }
    40%      { transform: scale(1.05); }
}
#counting-choices.choices-pulse { animation: choices-pulse 0.5s ease-out 2; }
@media (prefers-reduced-motion: reduce) {
    #counting-choices.choices-pulse { animation: none; }
}

.count-choice {
    margin: 6px; /* flex-gap fallback for old Safari */
    width: 66px;
    height: 66px;
    border: none;
    border-radius: 16px;
    font-family: inherit;
    font-size: 28px;
    font-weight: 900;
    color: white;
    text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3); /* keep white legible on yellow/light hues */
    cursor: pointer;
    transition: transform 0.15s, opacity 0.3s;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}

.count-choice:active { transform: scale(0.9); }

.count-choice.correct-choice {
    animation: pop-in 0.4s ease-out;
    box-shadow: 0 0 0 4px rgba(78, 205, 196, 0.5), 0 4px 12px rgba(0, 0, 0, 0.15);
}

.count-choice.wrong-choice {
    animation: shake 0.4s ease-in-out;
    opacity: 0.35;
    pointer-events: none;
}

@keyframes shake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-8px); }
    75% { transform: translateX(8px); }
}

/* ===== CELEBRATE BANNER ===== */
/* Shared "moment" pill: pops in over the play area, clears in ~1.5s,
   pointer-events: none so it never blocks the next tap */
#celebrate-banner {
    position: fixed;
    top: 16%;
    left: 50%;
    transform: translateX(-50%);
    background: white;
    color: #333;
    font-size: 26px;
    font-weight: 900;
    padding: 14px 28px;
    border-radius: 999px;
    box-shadow: 0 8px 30px rgba(0, 0, 0, 0.18);
    pointer-events: none;
    z-index: 1001;
    display: none;
    white-space: nowrap;
    max-width: 90vw;
}

#celebrate-banner.show {
    display: block;
    animation: banner-pop 0.45s ease-out;
}

@keyframes banner-pop {
    0% { transform: translateX(-50%) scale(0); opacity: 0; }
    65% { transform: translateX(-50%) scale(1.1); opacity: 1; }
    100% { transform: translateX(-50%) scale(1); opacity: 1; }
}

/* ===== PARTICLE CANVAS ===== */
#particle-canvas {
    position: fixed;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
    z-index: 1000;
}

/* ===== ANIMATIONS ===== */
@keyframes pop-in {
    0% { transform: scale(0); opacity: 0; }
    65% { transform: scale(1.15); opacity: 1; }
    100% { transform: scale(1); opacity: 1; }
}

.pop-in { animation: pop-in 0.35s ease-out; }

@keyframes pop-burst {
    0% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.5); opacity: 0.6; }
    100% { transform: scale(0); opacity: 0; }
}

/* ===== REDUCED MOTION ===== */
/* Decorative animations off; the gameplay float (JS-driven in gameTick) stays —
   the game IS the float. ParticleSystem.burst caps itself to ~6 spin-free dots. */
@media (prefers-reduced-motion: reduce) {
    .pop-in,
    .mode-card,
    .count-dot,
    .counting-obj,
    .counting-obj.count-wiggle,
    .count-badge,
    .count-choice.correct-choice,
    .count-choice.wrong-choice,
    .win-emoji,
    #celebrate-banner.show,
    #game-ghost.ghost-in,
    .match-card.matched {
        animation: none !important;
    }
    /* No 3D card-flip spin — the reveal still works via backface-visibility. */
    .match-card-inner { transition: none !important; }
}

/* ===== RESPONSIVE ===== */

@media (max-width: 380px) {
    .explorer-word { font-size: 17px; }
    #freeplay-char { font-size: 140px; }
    .home-title { font-size: 24px; margin: auto 0 8px; }
    /* 8 cards must fit without scroll on short phones (e.g. 320x568): compact
       padding + gap so the full-width banner cards and the paired middle
       grid all land on one screen. */
    .mode-grid { gap: 7px; padding: 0 16px 12px; }
    .mode-card { padding: 9px 8px; gap: 1px; }
    .card-icon { font-size: 23px; }
    .card-label { font-size: 14px; }
    .card-desc { font-size: 10px; }
    .nav-arrow { width: 44px; height: 44px; font-size: 17px; }
    .match-card-front { font-size: 22px; }
    .match-card-back.card-letter { font-size: 28px; }
    .match-card-back.card-emoji { font-size: 30px; }
    /* Hard = 4x4: cap card size by viewport height so all four rows fit. */
    #match-grid.hard { gap: 6px; }
    #match-grid.hard .match-card { max-width: 80px; max-width: min(80px, 22vh - 40px); }
    .counting-obj { font-size: 34px; }
    .count-choice { width: 54px; height: 54px; font-size: 22px; }
    #counting-objects { gap: 10px; }
}

@media (min-width: 381px) and (max-width: 480px) {
    .explorer-word { font-size: 19px; }
    #freeplay-char { font-size: 160px; }
    .card-icon { font-size: 30px; }
}

@media (max-height: 500px) and (orientation: landscape) {
    .explorer-word { font-size: 15px; }
    .explorer-container { flex-direction: row; gap: 14px; padding: 0 14px; }
    .explorer-container > * { flex-shrink: 0; }
    .count-dots { max-width: 160px; }
    .home-title { font-size: 20px; margin: auto 0 6px; }
    /* 8 cards must fit short landscape (e.g. 844x390) without scroll: 3-col grid
       (banner cards span the row) with compact padding so all rows land. */
    .mode-grid { grid-template-columns: repeat(3, 1fr); max-width: 560px; gap: 6px; padding: 0 16px 8px; }
    .mode-card { padding: 5px 6px; gap: 0; }
    .card-icon { font-size: 17px; line-height: 1; }
    .card-label { font-size: 13px; }
    .card-desc { font-size: 9px; }
    .case-btn { margin-top: 2px; padding: 4px 14px; font-size: 13px; }
    .explorer-nav { padding: 4px 14px; padding-bottom: max(10px, var(--safe-bottom)); }
    .nav-arrow { width: 40px; height: 40px; font-size: 16px; }
    .strip-item { min-width: 40px; height: 40px; font-size: 13px; }
    #freeplay-char { font-size: 110px; }
    #match-grid { gap: 5px; padding: 6px; }
    /* Height-aware cards: Hard's 4 rows always fit short viewports */
    .match-card { max-width: 65px; max-width: min(100px, 25vh - 40px); }
    .counting-obj { font-size: 30px; }
    #counting-objects { gap: 8px; padding: 6px 0; }
}

/* Short PORTRAIT phones (e.g. 320x480, 320x520, 360x600): the home grid's 4 rows
   of cards + title overflow ~420-520px of usable height, pushing the 8th card
   (Trace It) below the fold. The max-width:380px block compacts by WIDTH only and
   the landscape block above doesn't match portrait. Shrink card padding/icon/label
   and title margins here so all 8 cards fit without scrolling. */
@media (max-height: 600px) and (orientation: portrait) {
    .home-title { font-size: 20px; margin: auto 0 6px; }
    .mode-grid { gap: 6px; padding: 0 16px 8px; }
    .mode-card { padding: 6px 8px; gap: 0; }
    .card-icon { font-size: 22px; line-height: 1; }
    .card-label { font-size: 14px; }
    .card-desc { font-size: 10px; }
}

/* min-height guard: desktop sizes must never hijack short landscape viewports
   (the max-height: 500px block above owns those) */
@media (min-width: 768px) and (min-height: 501px) {
    .explorer-word { font-size: 30px; }
    #freeplay-char { font-size: 320px; }
    #freeplay-word { font-size: 34px; }
    .mode-grid { max-width: 500px; gap: 16px; }
    .mode-card { padding: 24px 14px; }
    .card-icon { font-size: 40px; }
    .card-label { font-size: 20px; }
    .card-desc { font-size: 13px; }
    .home-title { font-size: 38px; }
    .nav-arrow { width: 64px; height: 64px; font-size: 26px; border-radius: 18px; }
    .strip-item { min-width: 44px; height: 44px; font-size: 16px; }
    .case-btn { font-size: 20px; padding: 8px 28px; }
    .match-card { max-width: 120px; max-width: min(120px, 25vh - 44px); }
    .match-card-front { font-size: 36px; }
    .match-card-back.card-letter { font-size: 48px; }
    .match-card-back.card-emoji { font-size: 52px; }
    .counting-obj { font-size: 52px; }
    .count-choice { width: 78px; height: 78px; font-size: 34px; border-radius: 20px; }
    #counting-question { font-size: 30px; }
    .win-emoji { font-size: 90px; }
    .win-text { font-size: 40px; }
    #game-score-display { font-size: 28px; }
    #game-prompt { font-size: 24px; }
    #game-target { font-size: 32px; }
}

@media (min-width: 1024px) and (min-height: 501px) {
    .mode-grid { max-width: 560px; gap: 20px; }
    .mode-card { padding: 30px 18px; border-radius: 24px; }
    .match-card { max-width: 130px; max-width: min(130px, 25vh - 44px); }
}

/* ===== Free Play: trace-the-letter ghost ===== */
/* When a popped letter is an active trace target, fade the visible glyph into a
   faint ghost the kid can trace over. Gentle; layout unchanged. */
#freeplay-char-display.fp-trace-target #freeplay-char {
    opacity: 0.30;
    -webkit-text-stroke: 2px rgba(255, 255, 255, 0.45);
    transition: opacity 0.25s ease;
}
/* While tracing, fade the word label too so the ghost glyph is the clear focus. */
#freeplay-char-display.fp-trace-target #freeplay-word {
    opacity: 0.15;
    transition: opacity 0.25s ease;
}
@media (prefers-reduced-motion: reduce) {
    #freeplay-char-display.fp-trace-target #freeplay-char,
    #freeplay-char-display.fp-trace-target #freeplay-word { transition: none; }
}

/* ===== Counting: dynamic regrouping ===== */
/* Regrouped → positioning canvas; items placed absolutely and glide between
   arrangements. Default (flex) layout untouched. */
#counting-objects.regrouped {
    display: block;
    position: relative;
    max-width: none;
    width: 100%;
    overflow: visible;
    cursor: pointer;
}
#counting-objects.regrouped .counting-obj {
    transition: left 0.55s cubic-bezier(.34, 1.2, .64, 1),
                top 0.55s cubic-bezier(.34, 1.2, .64, 1),
                transform 0.2s, filter 0.2s;
    will-change: left, top;
}
@media (prefers-reduced-motion: reduce) {
    #counting-objects.regrouped,
    #counting-objects.regrouped .counting-obj { transition: none !important; }
}

/* ===== Bubble Pop: keep a 4-button mode toggle tidy ===== */
#game-mode-toggle { flex-wrap: wrap; justify-content: center; }

/* ===== TRACE IT — guide overlay + grown-up controls ===== */
/* Overlay canvas for the animated guide dot/arrows, ABOVE the ink canvas so it
   is redrawn each frame and never baked into the rainbow. */
#trace-guide-canvas {
    position: absolute;
    top: 0; left: 0;
    width: 100%;
    height: 100%;
    pointer-events: none;
}
/* DOM layer holding the numbered start badges, above the guide canvas */
#trace-guide-layer {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    pointer-events: none;
}
.trace-badge {
    position: absolute;
    transform: translate(-50%, -50%);
    min-width: 26px; height: 26px;
    padding: 0 6px;
    border-radius: 13px;
    background: #2563eb;
    color: #fff;
    font-weight: 900;
    font-size: 15px;
    line-height: 26px;
    text-align: center;
    box-shadow: 0 1px 3px rgba(0,0,0,0.3);
}
.trace-badge.active {
    background: #22c55e;
    animation: trace-badge-pulse 1.1s ease-in-out infinite;
}
.trace-badge.done { background: #94a3b8; }
@keyframes trace-badge-pulse {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50%      { transform: translate(-50%, -50%) scale(1.18); }
}

@media (prefers-reduced-motion: reduce) {
    .trace-badge.active { animation: none; }
}

/* ===== Bubble Pop grown-up options ===== */
#game-options { position: relative; flex: 0 0 auto; }
#game-options-toggle {
    width: 44px;
    height: 44px;
    border: none;
    border-radius: 12px;
    background: #eef2ff;
    color: #475569;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
}
#game-options-toggle:active { background: #e0e7ff; }
#game-options-toggle:focus-visible { outline: 3px solid #2563eb; outline-offset: 2px; }

/* ===== Shared keyboard focus rings ===== */
/* Every interactive control gets a clear, consistent ring when reached by
   keyboard (mouse/touch unaffected via :focus-visible). The piano-key rule is
   more specific and still wins where it applies. */
.mode-card:focus-visible,
.piano-hub-card:focus-visible,
.read-hub-card:focus-visible,
.math-hub-card:focus-visible,
.tool-btn:focus-visible,
.toggle-btn:focus-visible,
.play-btn:focus-visible,
.diff-btn:focus-visible,
#piano-back:focus-visible,
#read-back:focus-visible,
#math-back:focus-visible,
#music-replay:focus-visible,
.music-big-btn:focus-visible,
.music-pill:focus-visible,
.count-choice:focus-visible,
.spell-tile:focus-visible,
#count-dots:focus-visible {
    outline: 4px solid #2563eb;
    outline-offset: 3px;
}
/* On the dark Piano/Free Play canvases a warm ring reads better. */
.dark-mode .mode-card:focus-visible,
#mode-piano .piano-hub-card:focus-visible,
#mode-piano .toggle-btn:focus-visible,
#mode-piano #piano-back:focus-visible,
#mode-piano #music-replay:focus-visible,
#mode-piano .music-big-btn:focus-visible,
#mode-piano .music-pill:focus-visible {
    outline-color: #ffd54a;
}
#game-options-panel {
    display: none;
    position: absolute;
    top: 50px;
    right: 0;
    z-index: 30;
    min-width: 200px;
    padding: 12px;
    background: white;
    border-radius: 14px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}
#game-options-panel.open { display: block; }
.game-option {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    min-height: 44px;
    flex-wrap: wrap;
}
.game-option label { font-size: 14px; font-weight: 800; color: #475569; }
.game-option input[type=checkbox] {
    width: 40px;
    height: 40px;
    flex: 0 0 auto;
    cursor: pointer;
    accent-color: #2563eb;
}
.game-option .opt-hint {
    flex-basis: 100%;
    margin-top: 4px;
    font-size: 11px;
    font-weight: 700;
    color: #94a3b8;
}

/* ===== SPELLING ===== */
#mode-spell {
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 18px;
    padding: 16px;
}
#spell-stage {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
    width: 100%;
    max-width: 560px;
}
#spell-emoji { font-size: 96px; line-height: 1; user-select: none; }
#spell-target {
    display: flex;
    gap: 6px;
    min-height: 38px; /* reserve space so layout doesn't jump in L2 */
    transition: opacity 0.4s ease;
}
#spell-target.hidden { opacity: 0; }
.spell-target-letter { font-size: 34px; font-weight: 900; letter-spacing: 1px; }
#spell-slots {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 10px;
}
.spell-slot {
    width: 56px;
    height: 64px;
    border: 4px dashed #d9d2c5;
    border-radius: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 38px;
    font-weight: 900;
    background: #fff;
    box-sizing: border-box;
}
.spell-slot.filled { border-style: solid; animation: pop-in 0.35s ease-out; }
/* The next slot to fill gently breathes AND wears a bouncing 👇 so a non-reader
   sees exactly WHERE the next letter goes — the word fills strictly left-to-right,
   first letter first. Reduced-motion keeps a static highlight + a still finger. */
.spell-slot { position: relative; }
.spell-slot.active { animation: spell-slot-pulse 1.2s ease-in-out infinite; }
.spell-slot.active::before {
    content: '👇'; position: absolute; top: -34px; left: 50%;
    font-size: 26px; line-height: 1; pointer-events: none;
    animation: spell-finger 0.7s ease-in-out infinite;
}
@keyframes spell-slot-pulse {
    0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(255, 179, 71, 0); }
    50% { transform: scale(1.06); box-shadow: 0 0 0 6px rgba(255, 179, 71, 0.35); }
}
@keyframes spell-finger {
    0%, 100% { transform: translate(-50%, 0); }
    50% { transform: translate(-50%, -6px); }
}
.spell-slot.nudge { animation: spell-fizzle 0.4s ease-in-out; }
/* The shown word (Level 1): the letter wanted NEXT pops bright, placed ones dim
   and check off — so target-letter ↔ slot ↔ tile is one obvious chain. */
.spell-target-letter { transition: transform 0.15s, opacity 0.15s; }
.spell-target-letter.active { transform: scale(1.25); filter: drop-shadow(0 2px 3px rgba(0,0,0,0.2)); }
.spell-target-letter.done { opacity: 0.35; }
.spell-target-letter.nudge { animation: spell-fizzle 0.4s ease-in-out; }
#spell-tray {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
    margin-top: 6px;
}
.spell-tile {
    min-width: 64px;
    height: 64px;
    padding: 0 10px;
    border: none;
    border-radius: 16px;
    font-family: inherit;
    font-size: 32px;
    font-weight: 900;
    color: #fff;
    cursor: pointer;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
    transition: transform 0.12s, opacity 0.3s;
    touch-action: manipulation;
}
.spell-tile:active { transform: scale(0.9); }
.spell-tile.used { opacity: 0.25; pointer-events: none; transform: scale(0.92); }
.spell-tile.fizzle { animation: spell-fizzle 0.4s ease-in-out; }
@keyframes spell-fizzle {
    0%, 100% { transform: translateX(0) rotate(0); }
    25% { transform: translateX(-4px) rotate(-3deg); }
    75% { transform: translateX(4px) rotate(3deg); }
}
#spell-tally { font-size: 20px; font-weight: 800; color: #8a7f6b; }
@media (max-width: 380px) {
    #spell-emoji { font-size: 76px; }
    .spell-slot { width: 46px; height: 54px; font-size: 30px; }
    .spell-tile { min-width: 54px; height: 54px; font-size: 26px; }
    .spell-target-letter { font-size: 28px; }
}
@media (prefers-reduced-motion: reduce) {
    .spell-slot.filled, .spell-tile.fizzle, .spell-slot.nudge, .spell-target-letter.nudge { animation: none !important; }
    /* Keep a still highlight + a still finger on the next slot. */
    .spell-slot.active { animation: none !important; box-shadow: 0 0 0 5px rgba(255, 179, 71, 0.4); }
    .spell-slot.active::before { animation: none !important; }
}

/* ===== 123 Numbers: re-visualize the dots (tap to regroup) ===== */
#count-dots.regrouped {
    position: relative;
    display: block;
    width: 100%;
    max-width: none;
    overflow: visible;
    cursor: pointer;
}
#count-dots.regrouped .count-dot {
    transition: left 0.55s cubic-bezier(.34, 1.2, .64, 1),
                top 0.55s cubic-bezier(.34, 1.2, .64, 1);
    will-change: left, top;
}
@media (prefers-reduced-motion: reduce) {
    #count-dots.regrouped .count-dot { transition: none !important; }
}

/* ===== Bubble Pop easter egg: rare rainbow bubble ===== */
/* Only the background + glow are overridden; it floats and pops like any other
   bubble. It only ever spawns on a WINNING bubble, so popping it always pays. */
.bubble.rainbow-bubble {
    background: conic-gradient(from 0deg,
        #FF6B6B, #FFB347, #FFE66D, #7ED957, #4ECDC4, #45B7D1, #9B59B6, #FF85A1, #FF6B6B) !important;
    box-shadow: 0 0 16px rgba(255, 255, 255, 0.8), 0 4px 10px rgba(0, 0, 0, 0.12);
    color: #fff;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

/* ===== MUSIC — "Bunny's Music" (count the keys) ===== */
#mode-piano { background: #1B1235; }
#mode-piano .toggle-btn { color: #b9b2d6; background: rgba(255,255,255,0.06); }
#mode-piano .toggle-btn.active { background: #fff; color: #2b2350; box-shadow: 0 2px 6px rgba(0,0,0,0.3); }

/* The two views toggle via the [hidden] attribute; be explicit so the flex
   display rules below don't override hidden. */
#piano-hub, #piano-activity { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#piano-hub[hidden], #piano-activity[hidden] { display: none; }

/* --- Hub: the music-room picker --- */
#piano-hub { align-items: center; justify-content: center; padding: 16px; gap: 14px; }
#piano-hub-head { text-align: center; }
#piano-hub-bunny { font-size: clamp(44px, 12vw, 72px); display: block; animation: hubBunny 2.6s ease-in-out infinite; }
@keyframes hubBunny { 0%,100% { transform: translateY(0) rotate(-3deg); } 50% { transform: translateY(-8px) rotate(3deg); } }
.piano-hub-title { color: #fff; font-size: clamp(22px, 5.5vw, 30px); font-weight: 900; margin: 4px 0 0; }
.piano-hub-tag { color: #b9b2d6; font-size: clamp(13px, 3.4vw, 16px); font-weight: 700; margin: 2px 0 0; }
#piano-hub-cards {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;
    width: 100%; max-width: 460px;
}
.piano-hub-card {
    position: relative; border: none; cursor: pointer; font-family: inherit;
    border-radius: 20px; padding: 18px 12px; min-height: 116px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    color: #fff; -webkit-tap-highlight-color: transparent;
    box-shadow: 0 6px 16px rgba(0,0,0,0.3); transition: transform 0.08s ease;
}
.piano-hub-card:active { transform: scale(0.97); }
.piano-hub-card[data-activity="free"]    { background: linear-gradient(135deg, #5BC0EB, #3A8DDE); }
.piano-hub-card[data-activity="chord"]   { background: linear-gradient(135deg, #FFB13B, #FF6F2C); } /* the magic glows warm */
.piano-hub-card[data-activity="echo"]    { background: linear-gradient(135deg, #5BD96B, #2EAE54); }
.piano-hub-card[data-activity="twinkle"] { background: linear-gradient(135deg, #9B6DF0, #6C44D9); }
.phc-icon { font-size: 38px; line-height: 1; }
.phc-label { font-size: clamp(16px, 4vw, 20px); font-weight: 900; }
.phc-sub { font-size: 11.5px; font-weight: 700; opacity: 0.92; text-align: center; line-height: 1.25; }
/* The bunny leads: a bouncing 🐰 perches on the "play me next" card (one card,
   never a gate — a kid can always ignore it and roam). */
.phc-next { position: absolute; top: 4px; left: 8px; font-size: 26px; line-height: 1;
    display: none; pointer-events: none; filter: drop-shadow(0 3px 4px rgba(0,0,0,0.4)); }
.piano-hub-card.suggested .phc-next { display: block; animation: hubBunny 1.4s ease-in-out infinite; }
.piano-hub-card.suggested { box-shadow: 0 6px 16px rgba(0,0,0,0.3), 0 0 0 3px rgba(255,213,74,0.55); }
@media (prefers-reduced-motion: reduce) {
    .piano-hub-card.suggested .phc-next { animation: none; }
}

/* --- Activity: focused play screen --- */
#piano-bar { display: flex; align-items: center; gap: 10px; padding: 8px 12px 2px; flex-shrink: 0; }
#piano-back {
    width: 44px; min-height: 40px; border: none; border-radius: 12px;
    background: rgba(255,255,255,0.1); color: #fff; font-size: 20px; font-weight: 900; cursor: pointer;
    -webkit-tap-highlight-color: transparent; flex-shrink: 0;
}
#piano-act-title { flex: 1; color: #fff; font-size: clamp(16px, 4.4vw, 22px); font-weight: 900; }

#piano-options { position: relative; flex-shrink: 0; }
#piano-options-toggle {
    width: 44px; min-height: 40px; border: none; border-radius: 12px;
    background: rgba(255,255,255,0.1); color: #fff; font-size: 18px; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#piano-options-panel {
    display: none; position: absolute; right: 0; top: 48px; z-index: 20;
    background: #fff; color: #2b2350; border-radius: 14px; padding: 12px 14px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.35); width: 230px;
}
#piano-options-panel.open { display: block; }
.piano-option { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.piano-option:last-child { margin-bottom: 0; }
.piano-option .opt-label { font-size: 13px; font-weight: 800; color: #5a5478; }
.piano-option .opt-hint { font-size: 11px; color: #8a84a6; line-height: 1.3; }
#piano-root-move, #piano-letters-toggle { display: flex; gap: 4px; background: #eef0f6; border-radius: 10px; padding: 3px; }
#piano-root-move .toggle-btn, #piano-letters-toggle .toggle-btn { flex: 1; min-height: 38px; color: #6a6488; background: transparent; }
#piano-letters-toggle .toggle-btn.active { background: #fff; color: #2b2350; box-shadow: 0 1px 4px rgba(0,0,0,0.12); }
#piano-root-move .toggle-btn { font-weight: 900; }
#piano-root-label { flex: 1.6; color: #5b4bd6; font-weight: 900; }

#piano-readout {
    flex-shrink: 0; text-align: center; color: #efe9ff;
    font-size: clamp(14px, 3.4vw, 19px); font-weight: 700;
    padding: 4px 14px 8px; min-height: 1.4em; line-height: 1.3;
}
#piano-readout b { color: #ffd54a; }

/* The chip strip: the chord recipe (1·5·8 → 😊) or a song's numbers, filling
   left→right as the kid counts them out. Small variant fits a whole song line. */
#music-strip {
    display: flex; gap: 6px; justify-content: center; flex-wrap: wrap;
    padding: 2px 12px 6px; flex-shrink: 0;
}
#music-strip[hidden] { display: none; }
.ms-chip {
    min-width: 38px; height: 42px; border-radius: 12px; padding: 0 6px;
    font-size: 20px; font-weight: 900; line-height: 42px; text-align: center; color: #fff;
    background: rgba(255,255,255,0.10); box-shadow: inset 0 0 0 2px rgba(255,255,255,0.18);
    transition: transform 0.15s ease;
}
#music-strip.small .ms-chip { min-width: 26px; height: 32px; line-height: 32px; font-size: 15px; border-radius: 9px; padding: 0 3px; }
.ms-chip.current { box-shadow: inset 0 0 0 3px #ffd54a; animation: msChipAsk 1s ease-in-out infinite; }
@keyframes msChipAsk { 0%,100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }
.ms-chip.filled { box-shadow: none; animation: pop-in 0.3s ease-out; }
.ms-chip.filled.happy { background: linear-gradient(135deg, #FFB13B, #FF6F2C); }
.ms-chip.filled.sleepy { background: linear-gradient(135deg, #9B6DF0, #6C44D9); }
.ms-chip.filled.song { background: linear-gradient(135deg, #5BC0EB, #3A8DDE); }
.ms-chip.result { background: rgba(255,255,255,0.06); border-radius: 50%; min-width: 42px; }
#music-strip.small .ms-chip.result { min-width: 32px; }

#piano-stage {
    flex: 1; position: relative; display: flex; align-items: flex-end;
    padding: 10px 10px 16px; min-height: 0;
}
#piano-keys { position: relative; width: 100%; height: min(62%, 300px); }

/* Classic piano geometry: whites share the row; blacks ride the cracks,
   raised and narrower (positions set in JS). Every key wears its NUMBER. */
.piano-key {
    border: none; cursor: pointer; font-family: inherit;
    display: flex; flex-direction: column; align-items: center; justify-content: space-between;
    padding: 8px 2px 10px; -webkit-tap-highlight-color: transparent;
    border-radius: 5px 5px 9px 9px; overflow: hidden;
    box-shadow: inset 0 -7px 10px rgba(0,0,0,0.12), 0 3px 7px rgba(0,0,0,0.3);
    transition: transform 0.05s ease, filter 0.1s ease;
    /* Subtle Chroma cue: a colored foot in the note's color — points, never wallpapers */
    border-bottom: 5px solid var(--note-color, transparent);
    position: absolute; top: 0;
}
.piano-key.white { background: linear-gradient(#ffffff, #e9edf4); color: #33405a; height: 100%; z-index: 1; }
.piano-key.black { background: linear-gradient(#473f63, #221d36); color: #fff; height: 62%; z-index: 2; border-radius: 3px 3px 7px 7px; padding-bottom: 8px; }

.key-letter { font-size: clamp(10px, 2.3vw, 17px); font-weight: 800; pointer-events: none; }
.key-num {
    font-size: clamp(14px, 3.6vw, 26px); font-weight: 900; line-height: 1.1; pointer-events: none;
}
/* Magic 1·5·8: the recipe keys (1·5·8 or 1·4·8) wear soft candy halos in
   their own colors — an always-on invitation, never a phase. */
.piano-key.recipe { box-shadow: 0 0 12px 2px var(--note-color), inset 0 -7px 10px rgba(0,0,0,0.12), 0 3px 7px rgba(0,0,0,0.3); }
.piano-key.recipe .key-num { text-shadow: 0 0 10px var(--note-color); }
.piano-key.recipe.is-home { box-shadow: 0 0 12px 2px var(--note-color), inset 0 0 0 3px #FF4D4D, inset 0 -7px 10px rgba(0,0,0,0.12); }
/* A latched (found) key is RINGING: bright and lifted until the chord blooms. */
.piano-key.latched { filter: brightness(1.22) saturate(1.15); transform: translateY(-3px);
    box-shadow: 0 0 24px 7px var(--note-color), inset 0 -7px 10px rgba(0,0,0,0.12); }
.piano-key.latched.is-home { box-shadow: 0 0 24px 7px var(--note-color), inset 0 0 0 3px #FF4D4D; }
/* All three ringing together: the bloom. */
.piano-key.bloom { animation: keyBloomPop 0.9s ease; }
@keyframes keyBloomPop {
    0% { transform: translateY(-3px) scale(1); }
    30% { transform: translateY(-9px) scale(1.05); filter: brightness(1.6) saturate(1.3); }
    100% { transform: translateY(0) scale(1); }
}
/* The 😊/🌙 puck that glides between the middle keys on a recipe switch —
   the major→minor lesson performed as one small motion. */
#music-slide {
    position: absolute; left: 0; top: 0; transform: translate(-50%, -130%);
    font-size: clamp(24px, 6vw, 38px); line-height: 1; pointer-events: none; z-index: 8;
    filter: drop-shadow(0 3px 5px rgba(0,0,0,0.5));
    transition: left 0.5s cubic-bezier(0.45, 1.4, 0.45, 1), top 0.5s ease, opacity 0.3s ease;
}
.ms-chip.shelf { background: rgba(255,255,255,0.14); box-shadow: none; }
.music-big-btn.pop { animation: pillPop 0.6s ease-out; }
.piano-key.black .key-num { font-size: clamp(12px, 3vw, 20px); }
/* Key 1 is HOME: a warm red landmark (its 🏠 rides in the letter slot). */
.piano-key.is-home { box-shadow: inset 0 0 0 3px #FF4D4D, inset 0 -7px 10px rgba(0,0,0,0.12), 0 3px 7px rgba(0,0,0,0.3); }
.piano-key.is-home .key-num { color: #FF4D4D; }
.piano-key.black.is-home .key-num { color: #FF8A8A; }
.piano-key.is-home .key-letter { color: #FF4D4D; }

.piano-key.lit { filter: brightness(1.18) saturate(1.1); transform: translateY(2px); }
/* A found chord key keeps ringing visually: a held glow in its OWN color. */
.piano-key.in-chord {
    filter: brightness(1.12);
    box-shadow: 0 0 18px 4px var(--note-color, #ffd54a), inset 0 -7px 10px rgba(0,0,0,0.12);
}
.piano-key.in-chord.is-home { box-shadow: 0 0 18px 4px var(--note-color, #ffd54a), inset 0 0 0 3px #FF4D4D; }
/* Echo Echo: keys outside the hunt zone dim (still playable, just "not it"). */
.piano-key.dimmed { opacity: 0.4; filter: grayscale(0.55); }

.piano-key.is-target {
    outline: 3px solid #ffd54a; outline-offset: -3px;
    animation: pianoTarget 1s ease-in-out infinite;
}
@keyframes pianoTarget {
    /* glow AND a gentle "press me" lift so the eye is pulled to this one key */
    0%, 100% { box-shadow: inset 0 -7px 10px rgba(0,0,0,0.12), 0 0 0 0 rgba(255,213,74,0.0); transform: translateY(0); }
    50%      { box-shadow: inset 0 -7px 10px rgba(0,0,0,0.12), 0 0 22px 7px rgba(255,213,74,0.8); transform: translateY(-4px); }
}

/* The bouncing finger that says "tap HERE" — positioned over the target key in JS.
   A non-reader needs no words: the hand points at exactly the key to press. */
#piano-tap-hint {
    position: absolute; left: 0; top: 0; transform: translate(-50%, -118%);
    font-size: clamp(26px, 6.5vw, 44px); line-height: 1; pointer-events: none; z-index: 7;
    filter: drop-shadow(0 3px 4px rgba(0,0,0,0.45));
    animation: tapHintBounce 0.7s ease-in-out infinite;
}
#piano-tap-hint[hidden] { display: none; }
@keyframes tapHintBounce {
    0%, 100% { transform: translate(-50%, -118%); }
    50%      { transform: translate(-50%, -150%); }
}

#piano-bunny {
    position: absolute; left: 0; top: 0; transform: translate(-50%, -100%);
    font-size: clamp(28px, 7vw, 50px); line-height: 1; pointer-events: none; z-index: 6;
    transition: left 0.16s cubic-bezier(0.3, 1.25, 0.5, 1), top 0.16s ease;
    will-change: left, top; filter: drop-shadow(0 4px 6px rgba(0,0,0,0.45));
}
#piano-bunny .bunny-face { display: block; }
#piano-bunny.hopping .bunny-face { animation: bunnyHop 0.22s ease; }
@keyframes bunnyHop {
    0% { transform: translateY(0); }
    45% { transform: translateY(-22%); }
    100% { transform: translateY(0); }
}

/* --- Context buttons under the keys --- */
#music-controls { display: flex; gap: 12px; justify-content: center; align-items: center; padding: 8px 12px 14px; flex-shrink: 0; flex-wrap: wrap; }
#music-controls[hidden] { display: none; }
.music-btn-row { display: flex; gap: 12px; justify-content: center; align-items: center; }
.music-btn-row[hidden] { display: none; }
.music-big-btn[hidden] { display: none; }
.music-big-btn {
    border: none; cursor: pointer; font-family: inherit; -webkit-tap-highlight-color: transparent;
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    color: #fff; font-weight: 900; border-radius: 18px; padding: 10px 20px; min-height: 64px; min-width: 116px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3); transition: transform 0.08s ease, box-shadow 0.15s ease;
}
.music-big-btn .mb-emoji { font-size: clamp(24px, 6vw, 32px); line-height: 1; }
.music-big-btn .mb-label { font-size: clamp(13px, 3.4vw, 17px); }
.music-big-btn:active { transform: scale(0.94); }
.music-big-btn.recipe-happy { background: linear-gradient(135deg, #FFB13B, #FF6F2C); }
.music-big-btn.recipe-sleepy { background: linear-gradient(135deg, #9B6DF0, #6C44D9); }
.music-big-btn.active { box-shadow: 0 4px 12px rgba(0,0,0,0.3), 0 0 0 3px rgba(255,255,255,0.75); }
.music-big-btn.jump-yes { background: linear-gradient(135deg, #FFB13B, #FF6F2C); min-width: 150px; } /* the JUMP is the BIG one */
.music-big-btn.jump-no { background: linear-gradient(135deg, #5BD96B, #2EAE54); }
/* Song pills: ⭐ 🐑 🔤 + 👂 — small round choices that appear as they're earned. */
.music-pill {
    border: none; cursor: pointer; font-family: inherit; font-size: 24px;
    color: #2b2350; background: rgba(255,255,255,0.14); border-radius: 50%;
    width: 54px; min-height: 54px; -webkit-tap-highlight-color: transparent;
    box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.music-pill[hidden] { display: none; }
.music-pill:active { transform: scale(0.92); }
.music-pill.active { background: #fff; box-shadow: 0 4px 12px rgba(0,0,0,0.3), 0 0 0 3px rgba(255,213,74,0.8); }
.music-pill.pop { animation: pillPop 0.6s ease-out; }
@keyframes pillPop {
    0% { transform: scale(0.4); }
    60% { transform: scale(1.25); }
    100% { transform: scale(1); }
}
#music-replay {
    border: none; cursor: pointer; font-family: inherit; font-size: 22px;
    color: #2b2350; background: #fff; border-radius: 50%; width: 56px; min-height: 56px;
    -webkit-tap-highlight-color: transparent; box-shadow: 0 4px 12px rgba(0,0,0,0.3);
    flex-shrink: 0;
}
#music-replay[hidden] { display: none; }
#music-replay:active { transform: scale(0.92); }

@media (prefers-reduced-motion: reduce) {
    #piano-bunny { transition: none; }
    #piano-bunny.hopping .bunny-face { animation: none; }
    .piano-key.is-target { animation: none; outline-color: #ffd54a; box-shadow: 0 0 14px 4px rgba(255,213,74,0.6); }
    /* Finger still shows (it's the cue) — just no bounce. */
    #piano-tap-hint { animation: none; }
    .piano-key.bloom { animation: none; }
    .piano-key.latched { transform: none; }
    .music-big-btn.pop { animation: none; }
    .ms-chip.current { animation: none; }
    .ms-chip.filled { animation: none; }
    .music-pill.pop { animation: none; }
}

/* ===== Reading — Bunny's Reading Garden ===== */
/* Clones the Piano two-pane hub/activity look (a warm garden green, never bright). */
#read-hub, #read-activity { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#read-hub[hidden], #read-activity[hidden] { display: none; }

/* --- Hub: the reading-garden picker --- */
#read-hub { align-items: center; justify-content: center; padding: 16px; gap: 14px; }
#read-hub-head { text-align: center; }
#read-hub-bunny { font-size: clamp(44px, 12vw, 72px); display: block; animation: hubBunny 2.6s ease-in-out infinite; }
.read-hub-title { color: #3a6b3f; font-size: clamp(20px, 5vw, 28px); font-weight: 900; margin: 4px 0 0; }
#read-hub-cards {
    display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px;
    width: 100%; max-width: 460px;
}
.read-hub-card {
    position: relative; border: none; cursor: pointer; font-family: inherit;
    border-radius: 20px; padding: 18px 12px; min-height: 116px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    color: #fff; -webkit-tap-highlight-color: transparent;
    box-shadow: 0 6px 16px rgba(0,0,0,0.18); transition: transform 0.08s ease;
}
.read-hub-card:active { transform: scale(0.97); }
.read-hub-card[data-activity="blend"]  { background: linear-gradient(135deg, #82C785, #4F9D5B); }
.read-hub-card[data-activity="line"]   { background: linear-gradient(135deg, #7EC8A9, #3FA08A); }
.read-hub-card[data-activity="story"]  { background: linear-gradient(135deg, #9FC97E, #6FA84F); }
.read-hub-card[data-activity="garden"] { background: linear-gradient(135deg, #E6A8C8, #C86D9C); }
.rhc-icon { font-size: 38px; line-height: 1; }
.rhc-label { font-size: clamp(15px, 4vw, 19px); font-weight: 900; text-align: center; }
.rhc-sub { font-size: 11.5px; font-weight: 700; opacity: 0.92; text-align: center; line-height: 1.25; }
/* Lock is a small corner chip, NOT a full scrim — the locked card stays legible. */
.rhc-lock { position: absolute; top: 6px; right: 6px; width: 26px; height: 26px;
    display: flex; align-items: center; justify-content: center; font-size: 15px;
    background: rgba(40,60,40,0.5); border-radius: 50%; }
.read-hub-card.locked { cursor: default; filter: grayscale(0.5); opacity: 0.85; }
.read-hub-card.nudge { animation: hubNudge 0.5s ease; }

/* --- Activity: the focused reading screen --- */
#read-bar { display: flex; align-items: center; gap: 10px; padding: 8px 12px 2px; flex-shrink: 0; }
#read-back {
    width: 44px; min-height: 40px; border: none; border-radius: 12px;
    background: rgba(60,100,60,0.12); color: #2f5e34; font-size: 20px; font-weight: 900; cursor: pointer;
    -webkit-tap-highlight-color: transparent; flex-shrink: 0;
}
#read-act-title { flex: 1; color: #2f5e34; font-size: clamp(16px, 4.4vw, 22px); font-weight: 900; }
/* The persistent "grown-up + kid" marker — this room is visibly the shared room. */
#read-pair-glyph { font-size: 24px; line-height: 1; flex-shrink: 0; opacity: 0.85; }
#read-options { position: relative; flex-shrink: 0; }
#read-options-toggle {
    width: 44px; min-height: 40px; border: none; border-radius: 12px;
    background: rgba(60,100,60,0.12); color: #2f5e34; font-size: 18px; cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
#read-options-panel {
    display: none; position: absolute; right: 0; top: 48px; z-index: 20;
    background: #fff; color: #2f4f33; border-radius: 14px; padding: 12px 14px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.25); width: 230px;
}
#read-options-panel.open { display: block; }
.read-option { display: flex; flex-direction: column; gap: 6px; margin-bottom: 10px; }
.read-option:last-child { margin-bottom: 0; }
.read-option .opt-label { font-size: 13px; font-weight: 800; color: #4f7a52; }
.read-option .opt-hint { font-size: 11px; color: #84a487; line-height: 1.3; }
#read-theme-toggle, #read-cue-toggle, #read-sound-toggle { display: flex; gap: 4px; background: #eef4ee; border-radius: 10px; padding: 3px; }
#read-theme-toggle .toggle-btn, #read-cue-toggle .toggle-btn, #read-sound-toggle .toggle-btn { flex: 1; min-height: 40px; color: #6a886c; background: transparent; }
#read-theme-toggle .toggle-btn.active, #read-cue-toggle .toggle-btn.active, #read-sound-toggle .toggle-btn.active { background: #fff; color: #2f5e34; box-shadow: 0 1px 4px rgba(0,0,0,0.12); }
/* Word-color swatches: each shows its actual content hue; active = a ring. */
#read-color-toggle { display: flex; gap: 8px; }
#read-color-toggle .swatch {
    flex: 1; min-height: 40px; min-width: 40px; border-radius: 10px; border: none;
    background: var(--sw); cursor: pointer; -webkit-tap-highlight-color: transparent;
    box-shadow: 0 1px 4px rgba(0,0,0,0.18);
}
#read-color-toggle .swatch.active { box-shadow: 0 0 0 3px #fff, 0 0 0 6px var(--sw); }

/* The reading stage. The lit cue sits ABOVE / at the word; the finger rides the
   glide band BELOW the baseline (a fingertip would otherwise occlude the word). */
#read-stage[hidden] { display: none; }
#read-stage {
    flex: 1; min-height: 0; display: flex; flex-direction: column;
    align-items: center; justify-content: center; gap: 18px; padding: 12px 18px 24px;
}
#read-emoji { font-size: clamp(64px, 18vw, 110px); line-height: 1; }
#read-line {
    font-size: clamp(30px, 8vw, 52px); font-weight: 900; line-height: 1.5;
    text-align: center; max-width: 640px; touch-action: none; cursor: pointer;
    -webkit-user-select: none; user-select: none;
}
#read-line.snap { animation: read-snap 0.4s ease-out; }
@keyframes read-snap { 0% { letter-spacing: 0.08em; } 60% { letter-spacing: -0.01em; } 100% { letter-spacing: 0; } }

/* A word: ≥40px padded hit-area even for tiny words ("a", "is"). The lit cue is
   ABOVE the word (a 👇 + a pulse), so the finger below never hides it. */
/* INVERTED colors (Bryan): the CONTENT/main words wear the chosen hue; glue words
   stay near-black (light) / near-white (dark). Hues come from CSS vars set by
   applyReadPalette() so light + dark just swap palettes. NOT a per-letter rainbow. */
.read-word {
    position: relative; display: inline-block; padding: 4px 6px; border-radius: 12px;
    color: var(--read-content, #1763B6); transition: transform 0.18s, color 0.18s, opacity 0.18s;
}
.read-word.fn { color: var(--read-fn, #232323); }
/* "Say this next" cue: the active unit gently pulses with a soft green ring. The
   pointing finger now lives on the draggable KNOB below the line (👆), not above. */
.read-word.active {
    animation: read-word-pulse 1.2s ease-in-out infinite;
    box-shadow: 0 0 0 3px rgba(79,157,91,0.35);
}
@keyframes read-word-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.08); }
}
/* Passed words dim (read in order); a freshly-committed word gives one soft settle. */
.read-word.done { opacity: 0.4; }
.read-word.just { animation: read-word-settle 0.4s ease-out; }
@keyframes read-word-settle { 0% { transform: scale(1.18); } 100% { transform: scale(1); } }
.read-word.bloom { animation: read-word-bloom 0.6s ease-out; }
@keyframes read-word-bloom { 0% { transform: scale(1); } 40% { transform: scale(1.22); } 100% { transform: scale(1); } }
/* Stretch a Word: each sound is its OWN chip with a clear gap, so the separate
   sounds are obvious to a 2-3 year old (a digraph like sh/ck is one chip). The
   active sound glows; a blended sound stays LIT green — the word builds up. */
#read-line.blend {
    display: flex; justify-content: center; align-items: center;
    flex-wrap: wrap; gap: 12px; letter-spacing: 0;
}
#read-line.blend .read-grapheme {
    padding: 8px 16px; border-radius: 18px;
    background: #fffdf7; border: 3px solid #e2ead9; color: #2b2b2b;
    box-shadow: 0 3px 8px rgba(0,0,0,0.07);
    transition: transform 0.18s, background 0.18s, border-color 0.18s, box-shadow 0.18s;
}
#read-line.blend .read-grapheme.active {
    border-color: #4F9D5B; background: #fff;
    box-shadow: 0 0 0 4px rgba(79,157,91,0.28), 0 4px 12px rgba(0,0,0,0.12);
    transform: translateY(-2px) scale(1.05);
}
#read-line.blend .read-grapheme.done {           /* a blended sound stays lit, never dims here */
    opacity: 1; background: #d7efd2; border-color: #7FBF6E; color: #2f5e34;
}
.read-punct { color: #2b2b2b; font-size: clamp(30px, 8vw, 52px); font-weight: 900; }

/* ===== The slider: a fat, friendly track the child drags the knob along ===== */
/* width is set in JS to span exactly under the word; the trail fills behind the
   knob (progress). The 👆 hint sits just BELOW the knob pointing UP at it. The band
   reserves bottom room for the hint. */
#read-glide-band {
    position: relative; height: 16px; border-radius: 10px; min-width: 160px;
    background: #e3eede; box-shadow: inset 0 1px 3px rgba(0,0,0,0.12);
    margin-top: 10px; margin-bottom: 44px; touch-action: none;
}
#read-trail {
    position: absolute; left: 0; top: 0; height: 100%; width: 0; border-radius: 10px;
    background: linear-gradient(90deg, #7FBF6E, #4F9D5B);
    transition: width 0.06s linear; pointer-events: none;
}
/* The knob is just the circle now (the finger hint is a separate element below). */
#read-knob {
    position: absolute; top: 50%; left: 0; transform: translateY(-50%);
    width: 54px; height: 54px; border-radius: 50%;
    background: #fff; border: 4px solid #4F9D5B; box-shadow: 0 4px 12px rgba(0,0,0,0.22);
    transition: left 0.06s linear; pointer-events: none; z-index: 3;
}
/* The 👆 hint: parked just below the knob center, pointing up. Invisible by default;
   .show fades it in and bounces it. JS tracks its x to the knob center. */
#read-knob-hint {
    position: absolute; top: calc(100% + 2px); left: 0; transform: translateX(-50%);
    font-size: 30px; line-height: 1; pointer-events: none; z-index: 4;
    opacity: 0; transition: opacity 0.4s ease;
}
#read-knob-hint.show { opacity: 1; animation: read-hint-bounce 1.1s ease-in-out infinite; }
@keyframes read-hint-bounce {
    0%, 100% { transform: translateX(-50%) translateY(0); }
    50% { transform: translateX(-50%) translateY(-6px); }
}
/* Parent cue: dim, low-contrast, small, NON-tappable (for the grown-up's eye). It
   fades in (.show) for the first round, then fades out. */
#read-parent-cue {
    pointer-events: none; max-width: 560px; text-align: center;
    font-size: 14px; font-weight: 700; color: rgba(60,90,62,0.5);
    line-height: 1.35; font-style: italic;
    opacity: 0; transition: opacity 0.4s ease;
}
#read-parent-cue.show { opacity: 1; }
#read-parent-cue[hidden] { display: none; }

/* My Reading Garden keepsake (reads state only; zero child-facing numbers). */
#read-garden[hidden] { display: none; }
#read-garden {
    flex: 1; min-height: 0; overflow-y: auto; padding: 18px 22px 30px;
    display: flex; flex-direction: column; align-items: center; gap: 16px;
}
#read-garden-plot {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 8px;
    font-size: clamp(30px, 8vw, 46px); max-width: 560px;
}
.rg-seed { font-size: 16px; font-weight: 700; color: #5f8a62; }
.rg-first {
    background: #fff; border-radius: 16px; padding: 14px 18px; max-width: 480px;
    font-size: 16px; font-weight: 700; color: #355c38; box-shadow: 0 4px 14px rgba(0,0,0,0.1);
    text-align: center; line-height: 1.4;
}
.rg-first b { color: var(--read-content, #1763B6); }
.rg-first.rg-hint { background: transparent; box-shadow: none; color: #6f9a72; font-style: italic; }

@media (max-width: 380px) {
    #read-line { font-size: clamp(26px, 9vw, 40px); }
    #read-emoji { font-size: 72px; }
}
@media (prefers-reduced-motion: reduce) {
    /* Snap instead of interpolate; cues hold static; petals appear; the 👆 hint still
       fades (no bounce); the knob still moves with the finger — direct feedback, not
       decoration. */
    #read-hub-bunny, .read-hub-card.nudge,
    #read-line.snap, .read-word.just, .read-word.bloom,
    .read-word.active, #read-knob-hint.show { animation: none !important; }
    #read-knob, #read-trail { transition: none !important; }
    #read-knob-hint { transition: opacity 0.4s ease !important; } /* fade kept; bounce dropped */
    .read-word.active { box-shadow: 0 0 0 4px rgba(79,157,91,0.3); }
}

/* ===== Dark mode (scoped to the reading room — body.read-dark) ===== */
body.read-dark #read-bar #read-act-title { color: #cfe6cf; }
body.read-dark .read-hub-title { color: #cfe6cf; }
body.read-dark #read-back,
body.read-dark #read-options-toggle { background: rgba(255,255,255,0.10); color: #cfe6cf; }
/* options panel */
body.read-dark #read-options-panel { background: #243029; color: #e7f0e7; box-shadow: 0 8px 24px rgba(0,0,0,0.5); }
body.read-dark .read-option .opt-label { color: #a7c6aa; }
body.read-dark .read-option .opt-hint { color: #84a487; }
body.read-dark #read-theme-toggle, body.read-dark #read-cue-toggle, body.read-dark #read-sound-toggle { background: #1c2a22; }
body.read-dark #read-theme-toggle .toggle-btn,
body.read-dark #read-cue-toggle .toggle-btn,
body.read-dark #read-sound-toggle .toggle-btn { color: #9fc0a3; }
body.read-dark #read-theme-toggle .toggle-btn.active,
body.read-dark #read-cue-toggle .toggle-btn.active,
body.read-dark #read-sound-toggle .toggle-btn.active { background: #31463a; color: #eafff0; box-shadow: none; }
body.read-dark #read-color-toggle .swatch.active { box-shadow: 0 0 0 3px #243029, 0 0 0 6px var(--sw); }
/* chips */
body.read-dark #read-line.blend .read-grapheme { background: #243029; border-color: #3a4d40; color: #f0efe6; box-shadow: 0 3px 8px rgba(0,0,0,0.35); }
body.read-dark #read-line.blend .read-grapheme.active { border-color: #7FBF6E; background: #2b3a31; box-shadow: 0 0 0 4px rgba(127,191,110,0.35), 0 4px 12px rgba(0,0,0,0.4); }
body.read-dark #read-line.blend .read-grapheme.done { background: #2f6b46; border-color: #4f9d5b; color: #eafbe6; }
body.read-dark .read-punct { color: #ECECE2; }
/* slider */
body.read-dark #read-glide-band { background: #2a3a30; box-shadow: inset 0 1px 3px rgba(0,0,0,0.4); }
body.read-dark #read-knob { background: #243029; border-color: #7FBF6E; }
/* parent cue + garden */
body.read-dark #read-parent-cue { color: rgba(220,235,220,0.55); }
body.read-dark .rg-first { background: #243029; color: #dcefe0; box-shadow: 0 4px 14px rgba(0,0,0,0.4); }
body.read-dark .rg-first b { color: var(--read-content, #6FB4F2); }
body.read-dark .rg-first.rg-hint { background: transparent; box-shadow: none; color: #8fb393; }
body.read-dark .rg-seed { color: #9fc0a3; }

/* ===== Math — Bunny's Number Garden (Add + Take Away) ===== */
/* Hub clones the Reading/Piano two-pane look (warm tangerine accents). */
#math-hub, #math-activity { flex: 1; min-height: 0; display: flex; flex-direction: column; }
#math-hub[hidden], #math-activity[hidden] { display: none; }
#math-hub { align-items: center; justify-content: center; padding: 16px; gap: 14px; }
#math-hub-head { text-align: center; }
#math-hub-bunny { font-size: clamp(44px, 12vw, 72px); display: block; animation: hubBunny 2.6s ease-in-out infinite; }
.math-hub-title { color: #b85c1a; font-size: clamp(20px, 5vw, 28px); font-weight: 900; margin: 4px 0 0; }
#math-hub-cards { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; width: 100%; max-width: 460px; }
.math-hub-card {
    position: relative; border: none; cursor: pointer; font-family: inherit;
    border-radius: 20px; padding: 18px 12px; min-height: 116px;
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px;
    color: #fff; -webkit-tap-highlight-color: transparent;
    box-shadow: 0 6px 16px rgba(0,0,0,0.18); transition: transform 0.08s ease;
}
.math-hub-card:active { transform: scale(0.97); }
.math-hub-card[data-activity="add"]  { background: linear-gradient(135deg, #F2A65A, #E8772E); }
.math-hub-card[data-activity="take"] { background: linear-gradient(135deg, #5EC984, #2FA862); }
.mhc-icon { font-size: 38px; line-height: 1; }
.mhc-label { font-size: clamp(16px, 4vw, 20px); font-weight: 900; }
.mhc-sub { font-size: 11.5px; font-weight: 700; opacity: 0.92; text-align: center; line-height: 1.25; }
.mhc-lock { position: absolute; top: 6px; right: 6px; width: 26px; height: 26px;
    display: flex; align-items: center; justify-content: center; font-size: 15px;
    background: rgba(90,55,20,0.5); border-radius: 50%; }
.math-hub-card.locked { cursor: default; filter: grayscale(0.5); opacity: 0.85; }
.math-hub-card.nudge { animation: hubNudge 0.5s ease; }

/* Activity bar (back + title + streak). */
#math-bar { display: flex; align-items: center; gap: 10px; padding: 8px 12px 2px; flex-shrink: 0; }
#math-back {
    width: 44px; min-height: 40px; border: none; border-radius: 12px;
    background: rgba(180,92,26,0.12); color: #b85c1a; font-size: 20px; font-weight: 900; cursor: pointer;
    -webkit-tap-highlight-color: transparent; flex-shrink: 0;
}
#math-act-title { flex: 1; color: #b85c1a; font-size: clamp(16px, 4.4vw, 22px); font-weight: 900; }
#math-streak { font-size: 20px; font-weight: 900; color: #E8772E; flex-shrink: 0; }

/* The equation: groups of emoji, big symbols, and = ? — laid out in one wrap row. */
#math-equation {
    flex: 1; min-height: 0; display: flex; flex-wrap: wrap; gap: 10px 12px;
    align-items: center; align-content: center; justify-content: center;
    padding: 12px 14px; max-width: 560px; margin: 0 auto; width: 100%;
}
.math-group {
    display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: center;
    max-width: 200px; padding: 8px 10px; border-radius: 18px;
    background: rgba(255,255,255,0.6); box-shadow: inset 0 0 0 2px rgba(232,119,46,0.22);
}
.math-obj { line-height: 1.1; } /* inherits .counting-obj (tap, badge, counted state) */
/* When the child taps empty space, the group becomes a positioning canvas and its
   items glide into a new arrangement (see regroupMathObjects). */
.math-group.regrouped { max-width: none; padding: 4px; }
.math-symbol {
    font-size: clamp(34px, 9vw, 52px); font-weight: 900; color: #E8772E;
    line-height: 1; padding: 0 2px; -webkit-user-select: none; user-select: none;
}
.math-num { font-size: clamp(34px, 9vw, 52px); font-weight: 900; line-height: 1; }
.math-q {
    font-size: clamp(40px, 11vw, 64px); font-weight: 900; color: #b85c1a;
    line-height: 1; -webkit-user-select: none; user-select: none;
    transition: transform 0.2s ease;
}
/* When the right answer is chosen, the "?" becomes the number with a happy pop. */
.math-q.math-q-filled { animation: math-q-pop 0.42s ease-out; }
@keyframes math-q-pop {
    0% { transform: scale(0.5); opacity: 0.4; }
    55% { transform: scale(1.35); }
    100% { transform: scale(1); opacity: 1; }
}
/* Take Away: the taken-away items hop, then settle as a faded GHOST that STAYS in
   place — so the full group of N is always shown and "N − m = ?" reads true. */
.math-obj.math-ghosting { animation: math-takeaway 0.55s ease forwards; }
@keyframes math-takeaway {
    0% { transform: translateY(0) scale(1); opacity: 1; }
    40% { transform: translateY(-16px) scale(1.08) rotate(-8deg); opacity: 0.95; }
    100% { transform: translateY(0) scale(0.82); opacity: 0.3; }
}
.math-obj.math-ghost { opacity: 0.3; filter: grayscale(0.65); transform: scale(0.82); }

/* The "− m = ?" take-away trigger: the whole thing is one tap target, but only the
   "− m" part (.math-take-op) LIGHTS UP (.invite) once the child has counted
   everything — "now take these away!" The = and ? stay calm. */
.math-take-trigger {
    display: inline-flex; align-items: center; gap: 2px;
    padding: 6px 8px; border-radius: 16px; cursor: pointer;
    -webkit-tap-highlight-color: transparent; transition: transform 0.1s;
}
.math-take-trigger:active { transform: scale(0.96); }
.math-take-op {
    display: inline-flex; align-items: center; gap: 2px;
    padding: 2px 8px; border-radius: 14px; transition: background 0.15s;
}
.math-take-op.invite { background: rgba(232,119,46,0.14); animation: math-take-invite 1.1s ease-in-out infinite; }
@keyframes math-take-invite {
    0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(232,119,46,0); }
    50% { transform: scale(1.07); box-shadow: 0 0 0 6px rgba(232,119,46,0.16); }
}

/* Answer choices reuse #counting-choices / .count-choice; this is just the wrap. */
#math-choices {
    display: flex; justify-content: center; flex-wrap: wrap;
    padding: 4px 0 10px; flex-shrink: 0;
}

@media (max-width: 380px) {
    .math-symbol, .math-num { font-size: 36px; }
    .math-q { font-size: 44px; }
}
@media (prefers-reduced-motion: reduce) {
    /* The bunny holds still; taken-away items appear as ghosts at once (no hop),
       and the "?" fills without the pop. */
    #math-hub-bunny, .math-hub-card.nudge, .math-q.math-q-filled,
    .math-take-op.invite { animation: none !important; }
    .math-take-op.invite { background: rgba(232,119,46,0.16); } /* keep the tint, drop the pulse */
    .math-obj.math-ghosting { animation: none !important; opacity: 0.3; transform: scale(0.82); filter: grayscale(0.65); }
}
