/* ==========================================
   BASE / LAYOUT
   Brand tokens come from tokens.css (vendored copy of
   yorubadict/public/_tokens.css). Layout is deliberately compact:
   the top bar is a single slim row, not a hero block, so the
   actual game gets almost the whole viewport.

   This is the tone game. It shares the phonics game's shell almost
   exactly - same top bar, overlay, stage row, toast - and differs in
   the two blocks at the bottom: syllable CARDS (one per syllable,
   tone-stripped) instead of answer slots, and a three-button TONE BANK
   instead of a syllable matrix.
   ========================================== */
* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--background-primary);
    color: var(--text-primary);
    font-family: var(--font-body);
    /* Do NOT set overscroll-behavior-y here. It was used to stop elastic
       "rubber-band" scroll past the end of the page, but empirically
       (tested with a real headless Chromium instance against the live
       site) setting ANY non-default value of it on html/body - none,
       contain, even just re-asserting a value - completely breaks real
       wheel/touch scrolling on levels whose content overflows the
       viewport, while leaving programmatic scrollTo() working, which is
       what made it so easy to miss. A page that occasionally bounces
       slightly past its own end is far better than a page that cannot
       scroll its overflowing content at all.
       overflow-x is belt-and-suspenders against any single element (see
       #theme-selector below - the actual known culprit) forcing
       horizontal page overflow, which is what causes mobile browsers
       to render an unwanted zoomed-out-then-in initial view. */
    overflow-x: hidden;
}

#app-wrapper {
    max-width: 640px;
    margin: 0 auto;
    padding: 0 12px 24px;
}

#top-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 4px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
}

#brand-mark {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--step--1);
    color: var(--brand-indigo);
    text-decoration: none;
    opacity: 0.75;
    letter-spacing: 0.02em;
    transition: opacity 0.15s;
}

/* A link back to the games landing page - full opacity on hover/focus is
   the only affordance signaling that, since it's deliberately
   understated (this is a slim utility bar, not a nav). */
#brand-mark:hover,
#brand-mark:focus-visible {
    opacity: 1;
}

#brand-mark img {
    display: block;
}

#top-bar-controls {
    display: flex;
    align-items: center;
    gap: 8px;
}

#theme-selector {
    font-family: var(--font-body);
    font-size: var(--step--1);
    padding: 6px 10px;
    border-radius: 8px;
    border: 1px solid var(--border-subtle);
    background: var(--surface);
    color: var(--text-primary);
    /* A native <select> sizes itself to its longest option's full text
       by default - level names can be long ("Level 3: Body Parts
       (Ẹ̀yà Ara) — speaker3"), which was forcing horizontal page
       overflow on narrow phones (and, with it, an unwanted initial
       zoomed view, and the fullscreen button pushed off-screen).
       Capping the width and truncating instead fixes both. */
    max-width: 130px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

#game-container {
    text-align: center;
}

/* ==========================================
   START OVERLAY
   The first tap in here is mandatory, and it's also what unlocks audio
   playback - which is what lets the game autoplay each word.
   ========================================== */
#start-overlay {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(251, 246, 236, 0.85); /* --background-primary, translucent */
    backdrop-filter: blur(5px);
    display: flex;
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

#playlist-menu {
    text-align: center;
    padding: 24px;
}

#playlist-menu h2 {
    font-family: var(--font-display);
    color: var(--brand-indigo);
    margin: 0 0 16px;
}

.playlist-btn {
    display: block;
    width: 240px;
    margin: 0 auto 12px;
    padding: 16px 24px;
    font-size: var(--step-0);
    font-family: var(--font-display);
    font-weight: 600;
    background-color: var(--brand-indigo);
    color: var(--text-tertiary);
    border: none;
    border-radius: var(--radius);
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: transform 0.2s, background-color 0.2s;
}

.playlist-btn:hover {
    background-color: var(--brand-indigo-deep);
    transform: scale(1.05);
}

/* Disabled until app.js confirms this category actually has levels for
   the current data (see initializePlaylistMenu) - avoids offering a
   playlist that would just show an empty game. */
.playlist-btn:disabled {
    background-color: var(--border-subtle);
    color: var(--text-secondary);
    cursor: not-allowed;
    box-shadow: none;
    transform: none;
}

/* ==========================================
   STAGE ROW - prev/next navigation flanks the image as a symmetric
   pair, instead of a separate text-button row below it.
   ========================================== */
#stage-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
}

.icon-btn {
    flex-shrink: 0;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid var(--border-subtle);
    background: var(--surface);
    color: var(--text-secondary);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}

.icon-btn:hover { background: var(--background-secondary); }

/* Smaller variant for the hint toggle sitting beside the cards (see
   #answer-row) - doesn't need to match the nav buttons' size. */
.icon-btn-small {
    width: 30px;
    height: 30px;
}

/* Shown while toggled on: tone hint (see app.js toggleToneHint) or
   active fullscreen (see toggleFullscreen). */
#hint-btn.active,
#fullscreen-btn.active {
    background: var(--brand-accent);
    border-color: var(--brand-accent-deep);
    color: var(--brand-indigo-deep);
}

#skip-btn {
    border-color: rgba(198, 56, 90, 0.35); /* --accent-games */
    color: var(--accent-games);
}
#skip-btn:hover { background: rgba(198, 56, 90, 0.08); }

/* ==========================================
   ANSWER ROW - hint toggle sits beside the cards, but the cards (not
   the row as a whole) must be the thing centered on the page. Classic
   1fr/auto/1fr grid centering: the middle column sizes to the cards'
   content and is centered independent of the side columns, so the
   hint button (in the first column) reads as ancillary rather than
   shifting the "true" center.
   ========================================== */
#answer-row {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 10px;
    margin: 12px 0 4px;
}

#answer-row .cards-container {
    grid-column: 2;
}

#hint-btn {
    grid-column: 1;
    justify-self: end; /* hugs the right edge of its column, i.e. just left of the cards */
}

/* ==========================================
   IMAGE PROMPT AREA
   ========================================== */
.prompt-container {
    position: relative;
    width: 200px;
    height: 200px;
    border-radius: var(--radius);
    overflow: hidden;
    cursor: pointer;
    box-shadow: var(--shadow);
    transition: transform 0.1s ease;
}

.prompt-container:active {
    transform: scale(0.95);
}

#prompt-image {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

.audio-overlay {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background: rgba(21, 26, 61, 0.3); /* --brand-indigo-deep, translucent */
    display: flex;
    justify-content: center;
    align-items: center;
    opacity: 0.75;
    transition: opacity 0.2s ease;
}

.prompt-container:hover .audio-overlay {
    opacity: 1;
}

/* Correct-answer checkmark badge - hidden by default, shown briefly via
   JS toggling .show (see app.js's checkAnswer). */
.correct-badge {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(251, 246, 236, 0.55);
    opacity: 0;
    transform: scale(0.6);
    pointer-events: none;
    transition: opacity 0.25s ease, transform 0.25s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.correct-badge.show {
    opacity: 1;
    transform: scale(1);
}

/* ==========================================
   SYLLABLE CARDS
   One card per syllable of the word, always visible, always tappable.
   The syllable is shown with its tone mark STRIPPED (the mark is the
   answer), and re-rendered with the mark applied once a tone is picked -
   so the word's real spelling assembles itself as the player goes.
   ========================================== */
.cards-container {
    display: flex;
    justify-content: center;
    gap: 8px;
    min-height: 74px;
}

.card {
    position: relative;
    min-width: 58px;
    height: 72px;
    padding: 4px 8px;
    border: 2px dashed var(--border-subtle);
    border-radius: 10px;
    background: var(--surface);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 1px;
    cursor: pointer;
    font-family: var(--font-yoruba);
    color: var(--text-primary);
    transition: border-color 0.2s, background-color 0.2s, transform 0.2s;
}

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

.card-text {
    font-size: 1.3rem;
    font-weight: 700;
    line-height: 1.15;
}

/* Reserves its own line whether or not a tone has been picked, so the
   syllable text doesn't jump vertically when one is. */
.card-glyph {
    font-family: var(--font-mono);
    font-size: 0.9rem;
    line-height: 1;
    height: 1em;
    color: var(--text-secondary);
}

/* A card with a tone picked: solid border, and the tone's own color on
   the border and glyph. Same orange/grey/blue as everywhere else. */
.card.filled { border-style: solid; }

.card.picked-high { border-color: rgba(154, 106, 8, 0.55); background: rgba(154, 106, 8, 0.08); }
.card.picked-mid  { border-color: var(--border-subtle);     background: var(--background-secondary); }
.card.picked-low  { border-color: rgba(46, 111, 158, 0.55); background: rgba(46, 111, 158, 0.08); }

.card.picked-high .card-glyph { color: var(--brand-accent-deep); }
.card.picked-mid  .card-glyph { color: var(--text-secondary); }
.card.picked-low  .card-glyph { color: var(--accent-videos); }

/* The card the next tone pick will land on. Indigo (a brand color that
   isn't one of the three tone colors) so "where am I" never reads as
   "which tone is this". */
.card.active {
    border-color: var(--brand-indigo);
    box-shadow: 0 0 0 3px rgba(33, 41, 92, 0.14);
}

/* Applied to every card the instant a win is detected, for a clear,
   immediate visual "yes, that's right" independent of the toast. */
.cards-container.correct .card {
    border-color: var(--accent-courses);
    border-style: solid;
    background: rgba(47, 122, 77, 0.12); /* --accent-courses, translucent */
    transform: scale(1.06);
}

/* Only the cards whose tone was actually wrong, and only for the moment
   before everything clears. Saffron rather than red: this isn't a
   failure, there's no score and no penalty, it just means listen again. */
.card.wrong {
    border-color: var(--brand-accent-deep);
    border-style: solid;
    background: rgba(233, 168, 44, 0.18);
    animation: card-shake 0.32s ease;
}

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

/* Tone-hint dot above each card - always rendered, only made visible
   while the hint is toggled on. Here the hint is literally the answer,
   which is the same role it plays in the phonics game. */
.card::before {
    content: '';
    position: absolute;
    top: -8px;
    left: 50%;
    transform: translateX(-50%);
    width: 16px;
    height: 5px;
    border-radius: 3px;
    opacity: 0;
    transition: opacity 0.15s;
}

/* Orange/grey/blue, not red/grey/blue - a colorblind-safe combination
   (Okabe-Ito palette) that works across every common form of color
   vision deficiency, unlike red-based schemes. Also stops "high tone"
   from sharing a color with the (semantically unrelated) Skip button,
   which uses red. */
.card.tone-high::before { background: var(--brand-accent-deep); }
.card.tone-mid::before  { background: var(--text-secondary); }
.card.tone-low::before  { background: var(--accent-videos); }

.cards-container.show-hint .card::before {
    opacity: 1;
}

/* ==========================================
   WORD REVEAL
   The properly tone-marked spelling, shown only once the word is solved -
   the payoff for a game played on stripped syllables.
   ========================================== */
#word-reveal {
    font-family: var(--font-yoruba);
    font-size: var(--step-1);
    font-weight: 600;
    color: var(--accent-courses);
    min-height: 1.6em;
    opacity: 0;
    transform: translateY(-4px);
    transition: opacity 0.25s ease, transform 0.25s ease;
}

#word-reveal.show {
    opacity: 1;
    transform: translateY(0);
}

/* ==========================================
   TOAST - transient feedback (correct/skip/error/level-complete),
   floating over the page rather than reserving a permanent line.
   Hidden (opacity 0, no pointer events) until app.js's showToast()
   adds .show; auto-hidden again after its duration.
   ========================================== */
#toast {
    position: fixed;
    top: 64px;
    left: 50%;
    transform: translate(-50%, -6px);
    background: var(--surface);
    border: 1px solid var(--border-subtle);
    box-shadow: var(--shadow);
    border-radius: 999px;
    padding: 8px 18px;
    font-size: var(--step--1);
    font-weight: 700;
    color: var(--text-secondary);
    opacity: 0;
    pointer-events: none;
    max-width: 90vw;
    text-align: center;
    transition: opacity 0.2s ease, transform 0.2s ease;
    z-index: 500;
}

#toast.show {
    opacity: 1;
    transform: translate(-50%, 0);
}

#toast.correct  { color: var(--accent-courses); border-color: rgba(47, 122, 77, 0.35); }
#toast.skipping { color: var(--accent-games); border-color: rgba(198, 56, 90, 0.35); }
#toast.error    { color: var(--accent-games); border-color: rgba(198, 56, 90, 0.35); }
#toast.info     { color: var(--brand-indigo); border-color: var(--border-subtle); }

/* ==========================================
   TONE BANK
   Three tones, three panels, same bordered-panel-with-accent-bar
   language as the phonics game's syllable matrix - but one big button
   each instead of a grid of syllables. Each button carries the tone's
   REAL measured pitch contour as a line (drawn by app.js's
   renderTonePitchLines from the same data that drives the synthesis),
   so the shape is visible as well as audible.

   Colors are orange/grey/blue (not red-based) - the Okabe-Ito
   colorblind-safe palette's two most distinguishable hues across every
   common type of color vision deficiency. The glyph badge stays too:
   color alone isn't reliable for colorblind users.
   ========================================== */
.tone-bank {
    display: flex;
    gap: 10px;
    margin-top: 20px;
}

.tone-group {
    position: relative;
    flex: 1;
    text-align: left;
    background: var(--surface);
    border: 1px solid var(--border-subtle);
    border-left-width: 5px;
    border-radius: 10px;
    padding: 8px 8px 10px;
}

.tone-group-high { border-left-color: var(--brand-accent-deep); }
.tone-group-mid  { border-left-color: var(--text-secondary); }
.tone-group-low  { border-left-color: var(--accent-videos); }

.tone-badge {
    position: absolute;
    top: -9px;
    left: 10px;
    font-family: var(--font-mono);
    font-size: 0.85rem;
    line-height: 1;
    padding: 2px 6px;
    border-radius: 999px;
    background: var(--surface);
    border: 1px solid currentColor;
    z-index: 1;
}

.tone-group-high .tone-badge { color: var(--brand-accent-deep); }
.tone-group-mid  .tone-badge { color: var(--text-secondary); }
.tone-group-low  .tone-badge { color: var(--accent-videos); }

/* Chunky and full-width inside its panel - these three are the primary
   controls of the whole game and get tapped constantly. */
.tone-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    width: 100%;
    padding: 18px 6px 14px;
    border-radius: 10px;
    font-size: var(--step-0);
    font-family: var(--font-display);
    font-weight: 700;
    cursor: pointer;
    transition: transform 0.1s;
}

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

/* --font-yoruba, not --font-display: these labels carry real tone marks
   (Dò / Re / Mí), and that stack is the one chosen for diacritic coverage.
   It also means the mark on the button is drawn in the same typeface as the
   mark that appears on the syllable cards. */
.tone-btn-label {
    font-family: var(--font-yoruba);
    line-height: 1;
}

/* Inherits the button's own tone color via currentColor (the polyline is
   stroked with currentColor - see renderTonePitchLines). */
.tone-line {
    display: block;
    width: 100%;
    max-width: 84px;
    /* Tall on purpose. All three lines share one vertical scale spanning only
       3.3-3.5 semitones (the real measured distance from low to high), so the
       stack is subtle by nature - height is what makes it readable rather
       than exaggerating the data. */
    height: 42px;
    opacity: 0.85;
}

/* Tone-specific button fills, harmonized with the brand accent
   palette (same three accents as the panel border/badge above). */
.btn-high { background-color: rgba(154, 106, 8, 0.10); border: 2px solid rgba(154, 106, 8, 0.35); color: var(--brand-accent-deep); }
.btn-mid  { background-color: var(--background-secondary); border: 2px solid var(--border-subtle); color: var(--text-primary); }
.btn-low  { background-color: rgba(46, 111, 158, 0.10); border: 2px solid rgba(46, 111, 158, 0.35); color: var(--accent-videos); }
