/* === Home page styles ================================================
   Extracted from the inline <style> block of index.html. Pairs with
   css/theme.css (design tokens), css/shared.css (cross-page rules:
   reset, body, .page-content, .top-section, .seo-content, .site-footer,
   .family-nav, .char-mini, .ad-slot), and css/games/* (per-game).
   Keep section banners — they map directly to the regions of the
   legacy inline block so diffs against the backup stay reviewable.
   ====================================================================== */

/* Initial-load fade-in: suppresses the flash of unstyled / empty
   layout (empty panels, stale default character) until selectFamily
   has loaded the intended character. A fallback @keyframes animation
   clears the veil after 3s in case JS stalls or throws, so the page
   is never permanently hidden. */
.game-stage {
    transition: opacity 0.25s ease;
}
body.loading .game-stage {
    opacity: 0;
    pointer-events: none;
    animation: loading-veil-fallback 0s linear 3s forwards;
}
@keyframes loading-veil-fallback {
    to { opacity: 1; pointer-events: auto; }
}

/* SEO content section sits directly on the page paper — no
   panel background, no shadow. Continuous warm cream from
   header through practice area through SEO content. */
.seo-wrapper {
    width: 100%;
    max-width: 1400px;
    background: transparent;
    /* Match top-section: vertical padding only, no horizontal
       inset, so all three sections (header / practice / SEO)
       share the same outer edges. */
    padding: 0 0 1rem;
    margin: 10px auto 0;
}

@media (min-width: 1480px) {
    .seo-wrapper {
        border-radius: 0 0 12px 12px;
    }
}

/* Header CSS (site-header / brand-* / nav / lang-switcher /
   theme-toggle / switch-link) lives in /js/header.js's
   injectHeaderCSS(). Removed from inline to keep one source. */

.char-row,
.card-area {
    user-select: none;
    -webkit-user-select: none;
}

/* === Home-page mobile portrait =====================================
   Shared mobile reductions for body / page-content / h1 / ad-slot /
   family-nav / family-tab / char-row / char-mini live in shared.css.
   These are the rules that are home-specific. */
@media (max-width: 600px) {
    .info-panel-top .romaji { font-size: 1.2rem; }
    .pronunciation-tip { font-size: 0.7rem; }

    .card-actions {
        top: 4px;
        right: 4px;
        gap: 3px;
    }

    .card-btn {
        width: 26px;
        height: 26px;
    }

    .section-divider {
        margin-top: 1rem;
    }
}

.section-divider {
    width: 100%;
    max-width: 1400px;
    border: none;
    border-top: 1px solid var(--subtle-border);
    margin: 2rem auto 0;
}

/* .seo-content + descendants, .site-footer, .family-nav + tabs (base
   + learned/review variants), .char-row, .char-mini + descendants —
   all now in /css/shared.css. Home-page-specific overrides for these
   selectors (e.g. study-active overrides) stay below. */

/* Study mode: hide hiragana, show romaji prominently */
body.study-active .char-mini .char {
    font-size: 0;
    opacity: 0;
}

body.study-active .char-mini .romaji {
    font-size: 1rem;
    color: var(--text-muted);
    margin-top: 0;
}

body.study-active .char-mini.active .romaji {
    color: var(--accent);
}

body.study-active .info-panel-top .romaji {
    /* Already romaji — keep visible */
}

/* Keep pronunciation tip visible in study mode */

body.study-active .char-details {
    display: none;
}

body.study-active .card-mastery .level-name {
    color: var(--green);
    transition: color 0.3s;
}

/* === Card area wrapper === */
.game-stage {
    position: relative;
    width: 100%;
    display: flex;
    justify-content: center;
}

.card-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    /* Match the 1400px max-width used by .site-header,
       .family-nav, and .seo-content so the practice area's
       outer edges line up with the header and SEO content. */
    max-width: 1400px;
    padding: 6px 0 0;
    position: relative;
    /* No z-index here on the resting state — that lets .full-toolbar's
       own z-index:5 (panels.js injected CSS) escape this subtree's
       stacking context and render ABOVE .swipe-game / .fall-game (which
       sit at z-index:2 in .game-stage). The .hidden branch below pushes
       the underlying content behind the overlays during the slide. */
    user-select: none;
    -webkit-user-select: none;
    -webkit-touch-callout: none;
    -webkit-tap-highlight-color: transparent;
}

/* The body wrapper holds everything below .full-toolbar — the slide-out
   hide animation (.card-area.hidden) animates THIS, not .card-area itself,
   so the toolbar stays visible while Swipe/Fall overlays take the stage.
   Spatial cue matches the carousel's left/right vocabulary (right =
   forward), so leaving via the left reads as "moving past this activity."
   The flex column + 10px gap mirrors what .three-col-layout used to apply
   directly to (titles-row + cols-row) — now those two are wrapped here. */
/* Positioning context for overlay exercises (Rain etc). Sits inside
   .three-col-layout below the toolbar, holds .card-area-body, and gives
   absolutely-positioned overlay games their bounds. width:100% +
   position:relative is all it does — the children carry the size. */
.card-area-stage {
    position: relative;
    width: 100%;
}

.card-area-body {
    width: 100%;
    display: flex;
    flex-direction: column;
    gap: 10px;
    opacity: 1;
    transform: translateX(0);
    transition: opacity 0.6s ease, transform 0.6s ease;
}

/* Lock the column heights so toggling Vocabulary mode (or switching
   deck tabs with varying content) doesn't shrink the card area below
   the writing-canvas column's natural height. Inline JS measures the
   actual canvas-mode height on first load and sets style.minHeight on
   the .col-center (see lockColCenterHeight in index.html). The
   fallback below covers the brief window before the measurement
   completes. `align-items: stretch` on .cols-row then auto-matches
   the left/right columns. */
.cols-row > .col-center {
    min-height: 660px;
}

/* Mobile: columns stack with display:block, so the desktop column-
   height matching that motivates the 660px floor doesn't apply. The
   floor just creates dead vertical space under the canvas before
   the carousel info row. Let the column size to its content. */
@media (max-width: 900px) {
    .cols-row > .col-center { min-height: 0; }
}

/* ── Column-options dropdown ──────────────────────────────────────
   The little caret next to the "All Characters" header in the left
   column. Owns the View toggles (Audio on click / Highlight flagged /
   3-column layout) that were previously in the toolbar's Options
   dropdown. Hidden in Vocabulary mode (no equivalent toggles yet —
   the vocab list has its own search bar). */

/* Keep each column-header dropdown inline next to its label, but
   balance the eyebrow with a hidden phantom caret on the LEFT that
   matches the real caret's dimensions. That way the label stays
   visually centered in the column while the caret hugs the title. */
.col-title[data-col="left"] .col-eyebrow,
.col-title[data-col="center"] .col-eyebrow {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.col-title[data-col="left"] .col-eyebrow::before,
.col-title[data-col="center"] .col-eyebrow::before {
    content: '\25BE'; /* ▾ — same glyph as the real caret */
    visibility: hidden;
    padding: 2px 7px;
    border: 1px solid transparent;
    border-radius: 10px;
    font-size: 0.7rem;
    line-height: 1;
    box-sizing: border-box;
}

/* In vocab mode: the left-column caret is hidden, so hide the phantom
   to keep the label centered. The center column header gets the
   "Vocabulary Decks" label and the pen dropdown is irrelevant there,
   so we hide that caret + phantom too. */
body.vocab-active .col-title[data-col="left"] .col-eyebrow::before,
body.vocab-active .col-title[data-col="center"] .col-eyebrow::before {
    display: none;
}

body.vocab-active .col-title[data-col="center"] .pen-dropdown {
    display: none;
}

/* Center-column Pen panel — more content than the All Characters
   panel (swatches + slider + select), so give it a bit more room. */
.col-title[data-col="center"] .col-options-panel {
    min-width: 280px;
}

.col-options-dropdown {
    position: relative;
    display: inline-flex;
}

body.vocab-active .col-options-dropdown {
    display: none;
}

.col-options-trigger {
    border: 1px solid var(--subtle-border);
    background: transparent;
    color: var(--text-faint);
    font-size: 0.7rem;
    line-height: 1;
    padding: 2px 7px;
    border-radius: 10px;
    cursor: pointer;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}

.col-options-trigger:hover,
.col-options-dropdown.open .col-options-trigger {
    color: var(--accent);
    border-color: var(--accent);
}

.col-options-panel {
    display: none;
    position: absolute;
    /* Anchor below the caret. Use right:0 so the panel grows leftward
       and won't clip past the column's left edge for narrower viewports. */
    top: calc(100% + 6px);
    right: 0;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--card-outline);
    border-radius: 12px;
    padding: 12px;
    min-width: 240px;
    z-index: 200;
    flex-direction: column;
    gap: 6px;
    font-family: inherit;
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.12);
    text-align: left;
    /* The header above is text-aligned center — reset for the menu. */
    letter-spacing: normal;
    text-transform: none;
}

.col-options-dropdown.open .col-options-panel {
    display: flex;
}

/* Narrow viewports — the panel was anchored with `right: 0` to grow
   leftward into the column. On mobile, the left-column caret sits near
   the viewport edge, so growing leftward clips off-screen. Re-anchor:
   left column grows rightward from the caret, center column centers on
   the caret. max-width keeps it within the viewport either way. */
@media (max-width: 600px) {
    .col-options-panel {
        max-width: calc(100vw - 16px);
    }
    .col-title[data-col="left"] .col-options-panel {
        right: auto;
        left: 0;
    }
    .col-title[data-col="center"] .col-options-panel {
        right: auto;
        left: 50%;
        transform: translateX(-50%);
    }
}

/* Right-column action row — Report Card on the left, Printable
   Practice Sheet on the right. Both buttons share .col-action-btn
   styling; the flex container splits them with space-between. */
.col-right-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 8px;
    padding: 0 8px;
}

/* Both actions are character-specific (Report Card = per-kana progress,
   Practice Sheet = current kana's printable). Hide them in Vocabulary
   mode where the right column shows Vocabulary Details instead. */
body.vocab-active .col-right-actions {
    display: none;
}

.col-right-actions .col-action-btn-corner {
    /* The corner variant ships with `margin: 8px 8px 0 auto` which
       was needed when the button was a lone block; in the flex row
       that auto-margin would push both buttons together. Reset the
       left/right autos and let justify-content space them out. */
    margin: 8px 0 0;
}
.card-area.hidden .card-area-body {
    opacity: 0;
    transform: translateX(-40px);
    pointer-events: none;
}
/* The card-area itself stays interactable (so the toolbar still works),
   but the underlying content can't be clicked through the overlays. */
.card-area.hidden {
    z-index: 0;
}

/* Info bar above card */
.carousel-info-panel {
    position: relative;
    width: 100%;
    max-width: 100%;
    margin: 0 auto;
    background: transparent;
    border-radius: 8px;
    border: none;
    padding: 8px 12px 8px;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Fixed gap between the char-info widget and the tile row.
       (Previously used space-evenly + flex:1, but distributing free
       space shifts the tiles whenever anything above changes height —
       e.g. Free Hand vs Recall — even by a pixel.) */
    justify-content: flex-start;
    gap: 10px;
}

/* Char-info widget — single fixed-height row that holds either the
   static identity (romaji · tip) or the recall feedback flash, plus
   the absolutely-positioned stroke-count badge. The reserved height
   keeps everything below from shifting when state swaps. */
.info-panel-top {
    position: relative;
    width: 100%;
    height: 2.4em;
    border: 1px dashed var(--accent);
    border-radius: 6px;
}
.char-info-static,
.char-info-feedback {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    white-space: nowrap;
}
.char-info-feedback {
    display: none;
    font-weight: 700;
    letter-spacing: 0.03em;
}
.char-info-widget.feedback .char-info-static { display: none; }
.char-info-widget.feedback .char-info-feedback { display: flex; }

.info-panel-top .romaji {
    font-size: 1.4rem;
    color: var(--accent);
    font-weight: 700;
    letter-spacing: 0.05em;
}

.info-panel-top .separator {
    color: var(--text-faint);
    font-size: 0.85rem;
}

.pronunciation-tip {
    font-size: 0.8rem;
    color: var(--text-faint);
    font-style: italic;
}

/* Family cards inside the panel */
.carousel-info-panel .char-row {
    margin: 0;
    padding: 0;
    gap: 6px;
}

.stroke-count-btn {
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
    width: 24px;
    height: 24px;
    border-radius: 50%;
    border: 1px solid var(--subtle-border);
    background: var(--subtle-bg);
    color: var(--accent);
    font-size: 0.75rem;
    font-weight: 700;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;
    z-index: 2;
}

.stroke-count-btn:hover {
    background: var(--accent-bg);
    border-color: var(--accent-border);
}

.stroke-tooltip {
    display: none;
    position: absolute;
    top: 50%;
    right: 36px;
    transform: translateY(-50%);
    background: var(--bg);
    border: 1px solid var(--subtle-border);
    border-radius: 6px;
    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
    padding: 6px 10px;
    font-size: 0.75rem;
    color: var(--text);
    white-space: nowrap;
    z-index: 10;
}

.stroke-tooltip.visible {
    display: block;
}

/* Score + mode row */
.card-status {
    width: 100%;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
    padding: 0 4px;
    min-height: 24px;
}

.mode-label {
    display: none;
}

.mode-label.visible { display: none; }

/* Old card button styles removed — toolbar handles positioning */
.mode-label.trace { color: var(--orange); }
.mode-label.freehand { color: var(--accent); }
.mode-label.study { color: var(--green); }


/* === Main Card — just the canvas === */
.card {
    width: 290px;
    height: 290px;
    background: var(--card-bg);
    border-radius: 20px;
    box-shadow: var(--card-shadow);
    display: flex;
    align-items: center;
    justify-content: center;
    position: relative;
    overflow: hidden;
    cursor: pointer;
    transition: transform 0.3s ease, box-shadow 0.3s ease;
    /* pan-y so vertical page scrolls aren't blocked when the user
       drags from white space inside the canvas. The canvas's own
       pointerdown handler upgrades to full capture only when the
       touch lands on the character. */
    touch-action: pan-y;
    user-select: none;
    -webkit-user-select: none;
}

.card:hover {
    transform: translateY(-3px);
    box-shadow: var(--card-shadow-hover);
}

/* Guide lines handled by .carousel-grid */

.canvas-container {
    width: 100%;
    height: 100%;
    position: relative;
    touch-action: pan-y;
}

.canvas-container canvas {
    width: 100%;
    height: 100%;
    /* Allow vertical page scroll when the user touches empty
       white space. The pointerdown handler upgrades this to
       full capture only when the touch lands on the character. */
    touch-action: pan-y;
    -webkit-touch-callout: none;
}

.card-wrapper {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    position: relative;
    gap: 6px;
    padding-bottom: 6px;
    flex: 1;
    touch-action: pan-y;
}

/* Canvas navigation row — full width, nav buttons flank the canvas */
.carousel-nav-row {
    display: flex;
    touch-action: pan-y;
    align-items: stretch;
    width: 100%;
}

.canvas-nav {
    flex: 0 0 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    align-self: stretch;
    /* Quiet nav — just the arrow glyph, no panel chrome. Designer's
       Tegami treatment: transparent background, faint ink color,
       accent on hover only. */
    background: transparent;
    border: none;
    color: var(--text-faint);
    font-size: 1.8rem;
    font-weight: 400;
    cursor: pointer;
    user-select: none;
    -webkit-user-select: none;
    transition: color 0.15s, background 0.15s;
}
body.dark .canvas-nav {
    background: transparent;
}

.canvas-nav-left,
.canvas-nav-right {
    border-radius: 4px;
}

@media (hover: hover) {
    .canvas-nav:hover {
        color: var(--accent);
        background: var(--accent-bg);
    }
}

.canvas-nav:active {
    color: var(--accent);
    background: var(--accent-hover);
}

/* Recall mode: character progression is SRS-driven, not user-driven —
   grey out the canvas nav arrows and the character mini-tiles to
   prevent manual override. */
body.study-active .canvas-nav {
    opacity: 0.35;
    pointer-events: none;
    cursor: not-allowed;
}
body.study-active .char-mini {
    pointer-events: none;
    cursor: not-allowed;
}

@media (max-width: 600px) {
    .canvas-nav {
        flex: 0 0 30px;
        font-size: 1.5rem;
    }
    .carousel-info-panel { padding-top: 6px; }
}

/* === Carousel === */
/* Carousel CSS injected by /js/carousel.js */

.card.shake-wrong {
    animation: cardShake 0.4s ease-out;
    box-shadow: 0 0 0 3px var(--red), var(--card-shadow);
}
@keyframes cardShake {
    0% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(5px); }
    60% { transform: translateX(-3px); }
    80% { transform: translateX(2px); }
    100% { transform: translateX(0); }
}

.card.glow-warn {
    box-shadow: 0 0 0 3px var(--orange), var(--card-shadow);
    transition: box-shadow 0.8s ease-out;
}

.stroke-feedback {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    font-size: 1.2rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.3s;
    z-index: 10;
    text-shadow: 0 1px 4px rgba(0,0,0,0.15);
}

/* Recall surfaces feedback in the romaji+tip line below the canvas
   instead of overlaying the writing area. Other modes still use the
   centered overlay. */
body.study-active .stroke-feedback { display: none; }

.trace-score {
    position: absolute;
    top: 8px;
    right: 12px;
    font-size: 0.85rem;
    font-weight: 700;
    letter-spacing: 0.03em;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.3s;
    z-index: 10;
    text-shadow: 0 1px 3px rgba(0,0,0,0.15);
}

/* Below card: label + mastery */
.card-below {
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 14px;
}




/* Action buttons below card */
/* Toolbar above carousel frame */
.carousel-toolbar {
    width: 100%;
    max-width: 100%;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4px 8px;
    background: var(--ink-fill);
    color: var(--on-ink);
    border-radius: 8px;
    border: 1px solid var(--ink-fill);
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    position: relative;
    z-index: 5;
    min-height: 38px;
    box-sizing: border-box;
}

/* Default icon-button colors inside the dark toolbar — light icons on
   dark fill. Specific buttons (play, hint, recall.active) override. */
.carousel-toolbar .flag-btn { color: var(--on-ink-muted); }
.carousel-toolbar .flag-btn.flagged { color: var(--accent); opacity: 1; }
.carousel-toolbar .play-btn { background: rgba(255,255,255,0.08); border-color: var(--on-ink-border); color: var(--on-ink); }
.carousel-toolbar .play-btn:hover { background: var(--accent); color: #fff; border-color: var(--accent); }
.carousel-toolbar button.hint-btn { background: rgba(80,216,144,0.15); border-color: var(--green-border); color: var(--green); }
.carousel-toolbar button.opacity-trigger { background: rgba(255,255,255,0.08); border-color: var(--on-ink-border); color: var(--on-ink); }
.carousel-toolbar button.opacity-trigger:hover { background: var(--accent); color: #fff; border-color: var(--accent); }

.toolbar-left {
    position: absolute;
    left: 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.toolbar-right {
    position: absolute;
    right: 16px;
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Generic dashed chip — the visual base shared by every neutral
   trigger on the bar. */
.toolbar-btn {
    background: transparent;
    color: var(--on-bar);
    border: var(--dash);
    border-radius: 8px;
    padding: 7px 16px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
    white-space: nowrap;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: inherit;
}

@media (hover: hover) {
    .toolbar-btn:hover {
        border-color: var(--on-bar);
        color: var(--on-bar);
        background: var(--on-bar-hover-bg);
    }
}
.toolbar-btn:active {
    background: var(--on-bar-hover-bg);
}

.toolbar-arrow { font-size: 0.55rem; opacity: 0.6; }

/* Dropdown */
.toolbar-dropdown { position: relative; }

.toolbar-dropdown-panel {
    display: none;
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    background: var(--bg);
    border: 1px solid var(--subtle-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    min-width: 160px;
    z-index: 100;
    overflow: hidden;
}

.toolbar-dropdown.open .toolbar-dropdown-panel { display: block; }

.toolbar-dropdown-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    color: var(--text);
    text-decoration: none;
    font-size: 0.8rem;
    font-weight: 500;
    border: none;
    background: none;
    width: 100%;
    cursor: pointer;
    transition: background 0.15s;
}

.toolbar-dropdown-item:hover { background: var(--accent-bg); color: var(--accent); }

.toolbar-dropdown-item #practice-sheet-char {
    font-family: 'Noto Sans JP', sans-serif;
    font-size: 1rem;
}

/* Mode toggle — Trace + Recall.
   Both buttons read as a paired toggle: the inactive side is neutral
   (dashed soft border, muted text), the active side is the only red
   element on the bar (solid accent fill + white text). This way only
   one button at a time appears chromatic, and the user can tell at a
   glance which mode they're in. Recall keeps its uppercase letter-
   spacing as a typographic distinguisher independent of active state. */
.mode-toggle {
    background: transparent;
    border: none;
    box-shadow: none;
    display: flex;
    align-items: center;
    gap: 14px;
}

.mode-toggle-btn {
    background: transparent;
    color: var(--text-muted);
    border: var(--dash-soft);
    border-radius: 8px;
    padding: 7px 16px;
    font-size: 0.8rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
    white-space: nowrap;
    font-family: inherit;
}
@media (hover: hover) {
    .mode-toggle-btn:hover {
        border-color: var(--accent);
        color: var(--accent);
        background: var(--accent-bg);
    }
}

/* Recall keeps the uppercase typography as a static style hint
   (whichever mode is the "louder" one, regardless of state). */
.mode-toggle-btn[data-mode="study"] {
    letter-spacing: 0.08em;
    text-transform: uppercase;
    padding: 7px 22px;
}

/* Active mode — same treatment for both buttons: solid accent
   outline, accent text, bold. Transparent fill so the active state
   reads as a highlighted stroke rather than a filled chip — matches
   the rest of the toolbar's outline-first language. */
.mode-toggle-btn.active {
    background: transparent;
    color: var(--accent);
    border: 1.5px solid var(--accent);
    font-weight: 700;
}
@media (hover: hover) {
    .mode-toggle-btn.active:hover {
        background: var(--accent-bg);
        color: var(--accent);
        border-color: var(--accent);
    }
}

.recall-wrap { position: relative; display: inline-flex; }
.recall-btn-label { position: relative; z-index: 1; }

/* Tagline under the mode-toggle row explaining the progression */
.mode-tagline {
    text-align: center;
    font-size: 0.72rem;
    color: var(--text-faint);
    margin: 4px 0 0;
    line-height: 1.3;
    font-style: italic;
}
/* In Recall mode the tagline is repurposed for the per-character
   prompt instead of being hidden, so the canvas doesn't jump. */
body.study-active .mode-tagline { color: var(--accent); font-style: italic; }

/* Shared sizing for the three single-icon toolbar buttons so the
   toolbar layout stays stable regardless of which is active.
   Higher-specificity (button + class) beats the .toolbar-btn padding
   rule at the mobile breakpoint without resorting to !important. */
button.play-btn,
button.hint-btn,
button.opacity-trigger {
    width: 28px;
    height: 28px;
    min-width: 28px;
    padding: 0;
    box-sizing: border-box;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    font-size: 0.85rem;
    line-height: 1;
    gap: 0;
}

/* Single shared slot for the three context buttons. Whichever button
   is active for the current mode occupies this position; the others
   are visibility:hidden but stay in the grid cell. */
.toolbar-action-slot {
    display: grid;
    width: 28px;
    height: 28px;
}
.toolbar-action-slot > * {
    grid-area: 1 / 1;
}

.play-btn {
    background: var(--accent-bg);
    border-color: var(--accent-border);
    color: var(--accent);
}
.play-btn:hover {
    background: var(--accent);
    color: white;
    border-color: var(--accent);
}
/* Hide-but-keep-space so hiding Play in practice modes doesn't
   shift the rest of the toolbar. */
.play-btn.hidden {
    visibility: hidden;
}

/* Outline-toggle + Play action cards inside the char-row — both
   mirror the .char-mini family-card vocabulary (52×64 rounded
   rectangle, dashed accent border, transparent fill). Together they
   bookend the row: [outline-toggle][char-mini ...][play]. Layout
   centering comes from .char-row-wrap's existing flex. */
.char-row-wrap > .outline-toggle-btn,
.char-row-wrap > .play-btn {
    width: 52px;
    height: 64px;
    min-width: 52px;
    border-radius: 12px;
    /* Light-grey dashed outline (warm-dark @ ~30% opacity via the
       shared --dash-soft token). The icon inside stays red via
       `color: var(--accent)` so the action affordance still reads. */
    border: var(--dash-soft);
    background: transparent;
    color: var(--accent);
    font-size: 1.3rem;
    line-height: 1;
    padding: 0;
    /* Center the SVG icon inside the card. */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s, border-color 0.15s, color 0.15s,
                opacity 0.25s;
}
@media (hover: hover) {
    .char-row-wrap > .outline-toggle-btn:hover,
    .char-row-wrap > .play-btn:hover {
        background: var(--accent-bg);
        border-color: var(--accent);
        color: var(--accent);
    }
}
.char-row-wrap > .outline-toggle-btn { margin-right: 8px; }
.char-row-wrap > .play-btn          { margin-left: 8px; }

/* "Off" state for the outline-toggle — border + icon color stay
   the same (grey outline, red icon); the eye-open ↔ eye-off swap
   below is the primary state cue. */

/* Recall mode — the outline-toggle has nothing to act on (no
   watermark in Recall), so dim it + block clicks. The play card,
   on the other hand, becomes the Hint button: its triangle SVG
   hides and the ? SVG shows (see icon-swap rules below), and the
   click handler dispatches to the standalone #hint-btn's logic. */
body.study-active .char-row-wrap > .outline-toggle-btn {
    pointer-events: none;
    opacity: 0.35;
    cursor: not-allowed;
}
/* `visibility: visible` overrides the .play-btn.hidden rule that
   enterDrawMode legacy-adds in practice mode — we want the card
   visible so it can carry the hint icon. */
body.study-active .char-row-wrap > .play-btn {
    visibility: visible;
}

/* Play-icon swap — Trace shows the triangle, Recall shows the ? */
.char-row-wrap > .play-btn .play-icon-trace { display: inline-block; }
.char-row-wrap > .play-btn .play-icon-hint  { display: none; }
body.study-active .char-row-wrap > .play-btn .play-icon-trace { display: none; }
body.study-active .char-row-wrap > .play-btn .play-icon-hint  { display: inline-block; }

/* The standalone #hint-btn (in .canvas-action-slot, bottom-right of
   the canvas) is no longer the visible hint surface — the play card
   covers that. Hide it; programmatic .click() on it still fires the
   existing handler. */
body.study-active #hint-btn { display: none; }

/* Eye-open / eye-off icon swap — pressed (watermark visible) shows
   the open eye; not-pressed (watermark hidden) shows the eye with a
   slash. Default state matches aria-pressed="true". */
.char-row-wrap > .outline-toggle-btn .outline-icon-on  { display: inline-block; }
.char-row-wrap > .outline-toggle-btn .outline-icon-off { display: none; }
.char-row-wrap > .outline-toggle-btn[aria-pressed="false"] .outline-icon-on  { display: none; }
.char-row-wrap > .outline-toggle-btn[aria-pressed="false"] .outline-icon-off { display: inline-block; }

@media (max-width: 600px) {
    .char-row-wrap > .outline-toggle-btn,
    .char-row-wrap > .play-btn {
        width: 42px;
        height: 52px;
        min-width: 42px;
    }
    .char-row-wrap > .outline-toggle-btn { margin-right: 4px; }
    .char-row-wrap > .play-btn          { margin-left: 4px; }
    .char-row-wrap > .outline-toggle-btn svg,
    .char-row-wrap > .play-btn svg {
        width: 22px;
        height: 22px;
    }
}


/* Exercise dropdown — quick-launch a game without going through Recall.
   Dashed neutral trigger; panel mirrors the Options dropdown language. */
.exercise-dropdown { position: relative; }

.exercise-trigger {
    background: transparent;
    border: var(--dash);
    color: var(--on-bar);
    border-radius: 8px;
    padding: 7px 16px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    line-height: 1.2;
    cursor: pointer;
    font-family: inherit;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
}
@media (hover: hover) {
    .exercise-trigger:hover {
        background: var(--on-bar-hover-bg);
        border-color: var(--on-bar);
        color: var(--on-bar);
    }
}

.exercise-dropdown-panel {
    display: none;
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--card-outline);
    border-radius: 12px;
    box-shadow: none;
    padding: 8px;
    z-index: 100;
    /* 220px lets "Include All Characters" sit on one line. */
    min-width: 220px;
    flex-direction: column;
    gap: 4px;
    font-family: inherit;
}
.exercise-dropdown.open .exercise-dropdown-panel { display: flex; }

.exercise-option {
    background: transparent;
    border: var(--dash-soft);
    border-radius: 8px;
    padding: 9px 12px;
    font-size: 0.78rem;
    font-weight: 600;
    letter-spacing: 0.03em;
    color: var(--text);
    cursor: pointer;
    text-align: left;
    font-family: inherit;
    transition: border-color 0.15s, color 0.15s;
}
@media (hover: hover) {
    .exercise-option:hover {
        border-color: var(--accent);
        color: var(--accent);
    }
}
/* Disabled exercise option — empty primary pool. */
.exercise-option:disabled,
.exercise-option.disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
@media (hover: hover) {
    .exercise-option:disabled:hover,
    .exercise-option.disabled:hover {
        border-color: var(--dash-soft);
        color: var(--text);
    }
}
/* "Include All Characters" toggle that sits above the game list. */
.exercise-toggle {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--text-muted);
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    font-family: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;
}
.exercise-toggle input {
    margin: 0;
    cursor: pointer;
    accent-color: var(--accent);
}
.exercise-divider {
    height: 0;
    border-top: var(--dash-faint);
    margin: 4px 4px;
}
/* Recall mode greys out the Exercise dropdown — visible but disabled. */
body.study-active .exercise-dropdown {
    opacity: 0.35;
    pointer-events: none;
}

/* Hint button — rendered as a "?" icon, hidden-but-spaced when the
   current mode doesn't support hints. */
.hint-btn {
    visibility: hidden;
    background: var(--green-bg);
    border-color: var(--green-border);
    color: var(--green);
}

.hint-btn:hover {
    background: var(--green);
    color: white;
    border-color: var(--green);
}

.hint-btn.visible {
    visibility: visible;
}

.flag-btn {
    font-size: 1rem;
    line-height: 1;
    opacity: 0.4;
    transition: all 0.2s;
}

.flag-btn:hover {
    opacity: 0.7;
}

.flag-btn.flagged {
    opacity: 1;
    color: var(--red);
}

/* Stroke color/opacity picker — round indicator + popover panel */
.color-picker-wrap {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
}
.color-picker-btn {
    width: 28px;
    height: 28px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: transparent;
    border: 1px solid var(--on-ink-border);
}
.color-picker-btn:hover { background: var(--on-ink-hover); }
.color-picker-swatch {
    width: 16px;
    height: 16px;
    border-radius: 50%;
    background: conic-gradient(#e74c3c, #f39c12, #2ecc71, #1abc9c, #3498db, #9b59b6, #e74c3c);
    border: 1px solid rgba(0,0,0,0.18);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,0.18);
}
.color-picker-panel {
    position: absolute;
    top: calc(100% + 8px);
    left: 0;
    min-width: 220px;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--subtle-border);
    border-radius: 10px;
    padding: 10px;
    box-shadow: 0 12px 36px rgba(0,0,0,0.18);
    z-index: 200;
    display: none;
}
.color-picker-panel.open { display: block; }
.color-multi-btn {
    display: block;
    width: 100%;
    padding: 6px 10px;
    margin-bottom: 8px;
    border-radius: 6px;
    background: transparent;
    border: 1px solid var(--subtle-border);
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 700;
    cursor: pointer;
    background-image: linear-gradient(90deg, #e74c3c, #f39c12, #2ecc71, #3498db, #9b59b6);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}
.color-multi-btn:hover { border-color: var(--accent); }
.color-multi-btn.active {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-bg);
}
.color-swatch-grid {
    display: grid;
    grid-template-columns: repeat(5, 28px);
    gap: 8px;
    justify-content: center;
    margin-bottom: 10px;
}
.color-swatch {
    width: 28px;
    height: 28px;
    border-radius: 50%;
    border: 2px solid transparent;
    cursor: pointer;
    padding: 0;
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.18);
    transition: transform 0.1s, border-color 0.15s;
}
.color-swatch:hover { transform: scale(1.08); }
.color-swatch.active { border-color: var(--accent); box-shadow: 0 0 0 2px var(--accent-bg); }
.color-opacity-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--subtle-border);
}
.color-opacity-label {
    font-size: 0.72rem;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.color-opacity-slider { flex: 1; min-width: 0; }
.color-opacity-val {
    font-size: 0.78rem;
    font-weight: 700;
    color: var(--text);
    min-width: 38px;
    text-align: right;
}

/* Panel header — group the right-side action buttons */
.panel-header-actions {
    display: flex;
    align-items: center;
    gap: 6px;
}
.panel-header-icon-btn {
    padding: 4px 8px;
    font-size: 1rem;
    line-height: 1;
    opacity: 0.7;
}
.panel-header-icon-btn:hover { opacity: 1; }
.flag-filter-btn.active {
    background: var(--red);
    border-color: var(--red);
    color: #fff;
    opacity: 1;
}
.sound-toggle-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    opacity: 1;
}
.sound-toggle-btn svg { display: block; }

/* Container always present so the toolbar slot is reserved.
   Hide the entire wrapper (not just the trigger) when not in trace
   mode — otherwise the empty wrapper sits on top of the shared
   toolbar-action-slot and intercepts clicks meant for Play / Hint. */
.opacity-dropdown {
    position: relative;
}
.opacity-dropdown:not(.visible) {
    visibility: hidden;
}
.opacity-trigger {
    background: var(--accent-bg);
    border-color: var(--accent-border);
    color: var(--accent);
}
.opacity-trigger:hover {
    background: var(--accent);
    color: white;
    border-color: var(--accent);
}

.opacity-dropdown-panel {
    display: none;
    position: absolute;
    /* Opens UPWARD from the trigger. The trigger now sits in the
       canvas-action-slot near the bottom of col-center; a downward
       popup would clip past the column edge. */
    bottom: calc(100% + 6px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--bg);
    border: 1px solid var(--subtle-border);
    border-radius: 8px;
    box-shadow: 0 8px 24px rgba(0,0,0,0.12);
    padding: 12px 8px;
    z-index: 100;
}

.opacity-dropdown.open .opacity-dropdown-panel {
    display: flex;
    align-items: center;
    justify-content: center;
}

.opacity-slider-v {
    -webkit-appearance: slider-vertical;
    appearance: slider-vertical;
    writing-mode: vertical-lr;
    direction: rtl;
    width: 20px;
    height: 100px;
    accent-color: var(--accent);
    cursor: pointer;
}

/* Hide dropdown during practice */
body.study-active .toolbar-dropdown-panel,
body.practice-active .toolbar-dropdown-panel {
    display: none !important;
}

@media (max-width: 600px) {
    .carousel-toolbar {
        width: 96vw;
        gap: 4px;
        padding: 3px 6px;
        /* Drop center alignment so the three groups can space out
           evenly without the absolutely-positioned right group
           overlapping the centered mode-toggle. */
        justify-content: space-between;
    }
    /* Pull toolbar-left/right out of absolute positioning on mobile
       so they participate in the flex layout. */
    .carousel-toolbar .toolbar-left,
    .carousel-toolbar .toolbar-right {
        position: static;
        left: auto;
        right: auto;
    }
    .toolbar-btn { font-size: 0.72rem; padding: 4px 8px; }
    .mode-toggle-btn { font-size: 0.72rem; padding: 4px 10px; }
    .exercise-trigger { font-size: 0.7rem; padding: 4px 6px; }
}

/* Overlay shown in Recall mode before the user has drawn anything —
   gives a prompt like "Write 'a' from memory" in the empty canvas.
   Always laid out (display:flex) so opacity transitions interpolate
   cleanly across character switches; pointer-events:none keeps it
   from interfering when invisible. Visible only while the body has
   study-active and *not* study-drawing.  */
.study-hint-overlay {
    display: flex;
    position: absolute;
    inset: 0;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    pointer-events: none;
    color: var(--text-faint);
    text-align: center;
    padding: 0 12px;
    opacity: 0;
    transition: opacity 0.4s ease;
}
body.study-active:not(.study-drawing) .study-hint-overlay { opacity: 1; }
/* During a beat-sequenced recall transition (Character → Swipe etc.),
   pin the canvas overlay to 0 with no transition so it can't ghost-
   appear while the parent .card-area is fading out. Without this
   the overlay's own 0→1 transition fires the moment study-drawing
   is cleared, briefly compositing the romaji/tip/bar against the
   fading parent — exactly the "completed character repeats" jank. */
body.recall-transitioning .study-hint-overlay {
    opacity: 0 !important;
    transition: none !important;
}

/* SRS dual-ring gauge for the currently-selected character — sits to
   the left of the char-row tiles, vertically centered on the row.
   Absolute positioning keeps the tile row's own centering intact. */
.char-row-wrap {
    position: relative;
    width: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
/* Char-row SRS gauge is hidden everywhere now. SRS state is still
   tracked in the background; the gauge component is just no longer
   surfaced to the user. */
.char-row-srs-gauge { display: none; }
/* Small audio-on-click toggle inside the char-info widget, mirroring
   the stroke-count badge on the right. Half-opaque by default so it
   doesn't distract; jumps to full opacity + accent fill when active. */
.char-row-sound-toggle {
    position: absolute;
    left: 8px;
    top: 50%;
    transform: translateY(-50%);
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1px solid var(--ink-border);
    background: transparent;
    color: var(--text-faint);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    opacity: 0.5;
    padding: 0;
    z-index: 2;
    transition: opacity 0.15s, background 0.15s, color 0.15s, border-color 0.15s;
}
.char-row-sound-toggle:hover { opacity: 1; }
.char-row-sound-toggle.active {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
    opacity: 1;
}
.char-row-sound-toggle svg { display: block; }
.study-hint-romaji {
    font-size: 2.4rem;
    font-weight: 700;
    color: var(--accent);
    letter-spacing: 0.04em;
    line-height: 1;
    opacity: 0.85;
}
.study-hint-prompt {
    font-size: 0.9rem;
    font-style: italic;
    opacity: 0.85;
}
/* Draggable progress bar toward graduation. ONLY the tick captures
   pointer events — the track + label are transparent to clicks so
   the user can keep drawing strokes that pass behind the bar.
   Pinned to the BOTTOM of the .card overlay area as a thin
   horizontal tile (cream bg + dashed soft border) so it reads as
   its own affordance distinct from the writing area above. */
.study-hint-attempts {
    position: absolute;
    left: 50%;
    bottom: 14px;
    transform: translateX(-50%);
    min-height: 22px;
    padding: 4px 14px 6px;
    margin-top: 0;
    background: var(--bg);
    border: var(--dash-soft);
    border-radius: 10px;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;        /* keep the parent overlay's pass-through behavior */
}
.advance-bar {
    position: relative;
    width: 200px;
    /* Slim down so the track + tick sit centered on the bar's
       vertical midline — that's the same line the flex parent
       aligns the "Unfamiliar" / "Mastered" labels to, so all three
       elements share a single visual baseline. */
    height: 14px;
}
.advance-bar-track {
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    transform: translateY(-50%);
    height: 2px;
    background: var(--text);
    opacity: 0.55;
    border-radius: 1px;
    pointer-events: none;
}
/* Outlined red circle that rides the track at the current
   proficiency point. JS sets `left: <pct>%`; the translate(-50%, -50%)
   centers the circle on that point both horizontally and vertically. */
.advance-bar-tick {
    position: absolute;
    top: 50%;
    width: 14px;
    height: 14px;
    /* Opaque cream fill — same as the tile background — so the track
       line behind the circle is fully hidden inside the outline (the
       previous --accent-bg fill is semi-transparent and let the
       track bleed through). The red border carries the visual; the
       interior just acts as a clean knock-out. */
    background: var(--bg);
    border: 2px solid var(--red);
    border-radius: 50%;
    transform: translate(-50%, -50%);
    transition: left 0.45s cubic-bezier(0.2, 0.9, 0.3, 1.1);
    box-sizing: border-box;
}
/* Expanded invisible hit zone around the tick (parent overlay's
   pointer-events: none is overridden here so only the tick can
   catch a drag — clicks elsewhere on the bar pass through to the
   canvas, so an in-progress stroke isn't blocked). */
body.study-active:not(.study-drawing) .study-hint-overlay .advance-bar-tick {
    pointer-events: auto;
    cursor: grab;
    touch-action: none;
}
body.study-active:not(.study-drawing) .study-hint-overlay .advance-bar-tick.dragging {
    cursor: grabbing;
}
.advance-bar-tick::before {
    content: '';
    position: absolute;
    inset: -8px -12px;
}
/* During drag, kill the tick's eased transition so it tracks the
   pointer 1:1 instead of lagging behind. */
.advance-bar-tick.dragging { transition: none; }
/* Flanking labels — "Unfamiliar" on the left, "Mastered" on the
   right of the slider. The parent .study-hint-attempts is
   display:flex; align-items:center, so all three children sit on
   the same row separated by a small gap. line-height:1 ensures the
   labels' visual midline aligns with the slider's track height
   instead of being padded by the default line-height. */
.advance-bar-label {
    font-size: 0.7rem;
    line-height: 1;
    color: var(--text-muted);
    opacity: 0.8;
    white-space: nowrap;
    pointer-events: none;
}
.study-hint-attempts > .advance-bar-label-left  { margin-right: 10px; }
.study-hint-attempts > .advance-bar-label-right { margin-left: 10px; }

/* === Recall intro overlay — landing screen shown each time the user
   enters Recall mode. Cushions the involuntary character jump by
   orienting them on overall progress and the next due character.
   Family rows are clickable, letting the user override the default
   jump (current family's first unlearned). */

/* card-actions removed — buttons now in toolbar */

/* === Reading + Writing gauge circles on mini cards === */
.char-mini .gauge-row {
    display: flex;
    gap: 3px;
    margin-top: 3px;
    justify-content: center;
}
.char-mini .gauge-circle {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: transparent;
    border: 1px solid var(--text-faint);
    transition: background-color 0.3s, border-color 0.3s;
}
.char-mini .gauge-circle.filled {
    border-color: transparent;
}

/* === Card mastery display === */
.card-mastery {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    margin-top: 6px;
    font-size: 0.75rem;
    color: var(--text-faint);
    cursor: pointer;
    padding: 4px 12px 4px 6px;
    border-radius: 20px;
    border: 1.5px solid var(--subtle-border);
    background: var(--card-bg);
    transition: all 0.2s;
}

.card-mastery:hover {
    border-color: var(--accent-border);
    background: var(--accent-bg);
}

.card-mastery.active {
    border-color: var(--green);
    background: var(--green-bg);
}

.card-mastery .mastery-ring {
    width: 28px;
    height: 28px;
    position: relative;
}

.card-mastery .mastery-ring svg {
    width: 100%;
    height: 100%;
    transform: rotate(-90deg);
}

.card-mastery .mastery-ring circle {
    fill: none;
    stroke-width: 3;
}

.card-mastery .mastery-ring .ring-bg {
    stroke: var(--ring-bg);
}

.card-mastery .mastery-ring .ring-fill {
    stroke: var(--accent);
    stroke-linecap: round;
    transition: stroke-dashoffset 0.4s;
}

.card-mastery .level-text {
    color: var(--text-muted);
}

.card-mastery .level-name {
    color: var(--accent);
    font-weight: 600;
}

.char-details {
    margin-top: 6px;
    text-align: center;
    font-size: 0.82rem;
}

/* Mobile-only back button at the top of the Character/Vocabulary
   Details panel — lets the user return to the left tab without
   having to find the .col-title tab bar. Hidden on desktop where
   all three columns are visible side-by-side. */
.details-back-btn { display: none; }
@media (max-width: 900px) {
    .details-back-btn {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        padding: 4px 10px;
        margin: 0 0 8px;
        border: 1px solid var(--subtle-border);
        background: transparent;
        color: var(--text-faint);
        border-radius: 14px;
        font: inherit;
        font-size: 0.85rem;
        cursor: pointer;
    }
    .details-back-btn:hover,
    .details-back-btn:focus-visible {
        color: var(--accent);
        border-color: var(--accent);
        outline: none;
    }
}

.char-example {
    color: var(--text-faint);
}

/* Swipe game styles moved to css/games/swipe.css. */

/* Fall game styles moved to css/games/fall.css. */

.overlay-title {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--red);
    margin-bottom: 6px;
}

.overlay-title.success {
    color: var(--green);
}

.overlay-stats {
    font-size: 0.85rem;
    color: var(--text-muted);
    margin-bottom: 16px;
}

.overlay-buttons {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    justify-content: center;
}

.overlay-btn {
    padding: 8px 24px;
    border-radius: 20px;
    background: transparent;
    border: 1px solid var(--accent);
    color: var(--accent);
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    font-family: inherit;
    transition: all 0.2s;
}

.overlay-btn:hover {
    background: var(--accent-hover);
}

.overlay-btn-secondary {
    background: var(--close-bg);
    border-color: var(--puck-border);
    color: var(--text-muted);
}

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

/* Rain game styles moved to css/games/rain.css. */

/* Report Card Button */

/* Utility row — right-justified, above SEO divider */
/* .ad-slot + descendants and the print-hide rule now live in
   /css/shared.css. */

.util-row {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    width: 100%;
    max-width: 1400px;
    gap: 8px;
    margin-top: 0.5rem;
    padding-bottom: 0.5rem;
    border-bottom: 1px solid var(--divider);
}

.util-btn {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--subtle-bg);
    border: 1.5px solid var(--subtle-border);
    color: var(--text-faint);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    transition: all 0.2s;
    text-decoration: none;
}

.util-btn:hover {
    border-color: var(--accent-border);
    color: var(--accent);
    background: var(--accent-bg);
}

.util-btn svg {
    width: 16px;
    height: 16px;
}

.util-char {
    font-family: 'Noto Sans JP', sans-serif;
    font-size: 1.1rem;
    font-weight: 700;
    line-height: 1;
}

.romaji-alt {
    display: none;
}

body.study-active .char-alt {
    display: none;
}

body.study-active .romaji-alt {
    display: inline;
}

.util-char .romaji-alt {
    font-family: 'Segoe UI', system-ui, sans-serif;
    font-size: 0.75rem;
}

/* Report Card Modal */
.report-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0,0,0,0.5);
    z-index: 1000;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.3s;
    padding: 20px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

.report-modal-backdrop.visible {
    opacity: 1;
    pointer-events: auto;
}

.report-modal {
    max-width: 420px;
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 16px;
    margin: auto;
    padding: 20px 0;
    flex-shrink: 0;
}

.report-card {
    width: 100%;
    background: var(--card-bg);
    border-radius: 20px;
    padding: 24px;
    box-shadow: 0 8px 32px rgba(0,0,0,0.15);
}

.report-header {
    text-align: center;
    margin-bottom: 20px;
}

.report-title {
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--heading);
    margin: 0 0 8px 0;
}

.report-overall {
    font-size: 0.85rem;
    color: var(--text-muted);
}

.report-overall strong {
    color: var(--accent);
    font-size: 1.1rem;
}

.report-grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.report-family {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 0;
}

.report-family-name {
    width: 36px;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--text-muted);
    text-align: right;
    flex-shrink: 0;
}

.report-bar-track {
    flex: 1;
    height: 18px;
    background: var(--subtle-bg);
    border-radius: 9px;
    overflow: hidden;
    position: relative;
}

.report-bar-fill {
    height: 100%;
    border-radius: 9px;
    background: var(--accent);
    transition: width 0.6s ease;
    min-width: 0;
}

.report-bar-fill.complete {
    background: var(--green);
}

.report-bar-label {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 0.6rem;
    font-weight: 600;
    color: var(--text-muted);
}

.report-family-chars {
    display: flex;
    gap: 3px;
    flex-shrink: 0;
}

.report-char-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--subtle-bg);
    border: 1px solid var(--divider);
}

.report-char-dot.in-progress {
    background: var(--accent);
    border-color: var(--accent);
}

.report-char-dot.learned {
    background: var(--green);
    border-color: var(--green);
}

.report-footer {
    text-align: center;
    margin-top: 16px;
    padding-top: 12px;
    border-top: 1px solid var(--divider);
}

.report-site {
    font-size: 0.7rem;
    color: var(--text-faint);
    letter-spacing: 0.02em;
}

.report-actions {
    display: flex;
    gap: 8px;
    align-items: center;
}

.report-share-btn {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1.5px solid var(--subtle-border);
    background: var(--card-bg);
    color: var(--text);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.2s;
}

.report-share-btn:hover {
    border-color: var(--heading);
    color: var(--heading);
    background: var(--card-bg);
    box-shadow: 0 2px 8px rgba(0,0,0,0.12);
    transform: translateY(-1px);
}

