/* Minimalist pure-B/W stylesheet. System text, a serif home invitation, semantic
   HTML; inverts via prefers-color-scheme. No grays, no chromatic colors. */

:root {
    --fg: #000;
    --bg: #fff;
    --touch: 2.75rem;        /* 44px minimum tap target */
    --measure: 42rem;        /* comfortable reading measure for prose */
    accent-color: var(--fg);
    color-scheme: light;
}
@media (prefers-color-scheme: dark) {
    :root { --fg: #fff; --bg: #000; color-scheme: dark; }
}

/* ── Reset & document ─────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
    background: var(--bg);
    color: var(--fg);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
                 Roboto, "Helvetica Neue", Arial, sans-serif;
    font-size: clamp(1rem, 0.9rem + 0.4vw, 1.25rem);
    line-height: 1.6;
    -webkit-text-size-adjust: 100%;
}
body { margin: 0; min-height: 100vh; display: flex; flex-direction: column; }
main { flex: 1; width: 100%; padding: 1rem clamp(1rem, 4vw, 3rem) 3rem; }

@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}

/* ── Typography ──────────────────────────────────────────────────── */
h1, h2, h3, h4, h5, h6 {
    font-weight: 600; line-height: 1.2;
    margin: 1.6em 0 0.5em; text-wrap: balance;
    overflow-wrap: anywhere;
}
h1 { font-size: clamp(1.75rem, 1.2rem + 2vw, 3rem); letter-spacing: -0.02em; margin-top: 0.6em; }
h2 { font-size: clamp(1.35rem, 1.05rem + 1.1vw, 2.1rem); letter-spacing: -0.01em; }
h3 { font-size: clamp(1.1rem, 0.95rem + 0.6vw, 1.45rem); }
h4, h5, h6 { font-size: 1.05rem; }
h5, h6 { font-style: italic; }

p, li, dt, dd, blockquote { text-wrap: pretty; overflow-wrap: break-word; }
p { margin: 0 0 1em; }

/* Reading measure: running text caps at --measure for legibility, while
   headings (larger type, short lines) and structural elements (tables,
   figures, notation, rules, pagination) keep the full 60rem column.
   `.library-nav` is pagination, so it stays wide. */
main :is(p:not(.library-nav), ul, ol, dl, blockquote, aside, figcaption) {
    max-width: var(--measure);
}
ul, ol { padding-left: 1.5em; margin: 0 0 1em; }
li { margin: 0.2em 0; }
dl { margin: 1em 0; }
dt { font-style: italic; margin-top: 0.8em; }
dd { margin: 0 0 0.5em; padding-left: 1.2em; }

blockquote, aside {
    margin: 1.2em 0; padding-left: 1rem;
    border-left: 1px solid currentColor;
}
blockquote { border-left-width: 2px; font-style: italic; margin-block: 1.5em; }
aside { font-size: 0.9em; }
blockquote :first-child, aside :first-child { margin-top: 0; }
blockquote :last-child,  aside :last-child  { margin-bottom: 0; }

a { color: inherit; text-decoration: underline; text-underline-offset: 2px; }
a:hover, a:focus-visible { text-decoration-thickness: 2px; }
strong, b { font-weight: 700; }
em, i, .text-muted { font-style: italic; }

code, pre, kbd, samp {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.95em;
}
pre { overflow-x: auto; padding: 0.75em 1em; border: 1px solid currentColor; }

table { border-collapse: collapse; width: 100%; margin: 1.5em 0; }
th, td { padding: 0.4em 0.7em; text-align: left; border-bottom: 1px solid currentColor; }
th { font-weight: 600; }

hr { border: 0; border-top: 1px solid currentColor; margin: 2em 0; }

figure { margin: 1.5em 0; }
figcaption { font-style: italic; font-size: 0.9em; margin-top: 0.4em; }
img, svg { max-width: 100%; height: auto; }

/* ── Universal accessibility ─────────────────────────────────────── */
:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
::selection { background: var(--fg); color: var(--bg); }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
    }
}

.skip-link {
    position: absolute; top: 0; left: 1rem; z-index: 1000;
    transform: translateY(-100%);
    padding: 0.5em 0.75em;
    background: var(--bg); color: var(--fg);
    border: 1px solid currentColor;
}
.skip-link:focus { top: 0.5rem; transform: none; }

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

/* ── Page chrome (header / breadcrumb / footer) ──────────────────── */
.site-header, .site-footer { padding: 0.9rem clamp(1rem, 4vw, 3rem) 1rem; }
.site-header { border-bottom: 1px solid currentColor; }
.site-footer { border-top: 1px solid currentColor; margin-top: 3rem; }

.site-header__inner, .site-footer__inner, .breadcrumb, main > * {
    max-width: 60rem; margin-inline: auto;
}

.site-header__inner {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 1.5rem;
}
.site-brand {
    font-style: italic; font-size: 1.15rem;
    text-decoration: none; max-width: 100%;
}
.site-brand:hover { text-decoration: underline; }

.site-nav {
    list-style: none; padding: 0; margin: 0; flex: 1;
    display: flex; flex-wrap: wrap; gap: 1rem;
}
.site-nav li { margin: 0; }
.site-nav a { text-decoration: none; }
.site-nav a:hover { text-decoration: underline; }
.site-nav a[aria-current="page"] { font-style: italic; }
.site-nav details { position: relative; }
.site-nav summary { cursor: pointer; list-style: none; }
.site-nav summary:hover { text-decoration: underline; }
.site-nav summary::-webkit-details-marker { display: none; }
.site-nav summary::after { content: " \25BE"; }
.site-nav .submenu {
    position: absolute; top: 100%; right: 0; z-index: 100;
    width: max-content; min-width: min(13rem, calc(100vw - 2rem));
    max-width: min(22rem, calc(100vw - 2rem));
    margin: 0.5rem 0 0; padding: 0.75rem 1rem;
    list-style: none;
    background: var(--bg); border: 1px solid currentColor;
    display: flex; flex-direction: column; gap: 0.4rem;
}
.submenu-divider { border: 0; border-top: 1px solid currentColor; margin: 0.3rem 0; }

.nav-toggle {
    display: none;
    background: transparent; color: inherit;
    border: 1px solid currentColor; padding: 0.4em 0.7em;
    font: inherit; cursor: pointer;
}

.breadcrumb {
    padding: 0.6rem clamp(1rem, 4vw, 3rem);
    font-size: 0.9em; font-style: italic;
    border-bottom: 1px dotted currentColor;
}
/* The home page ships an empty breadcrumb slot; don't draw a stray rule. */
.breadcrumb:not(:has(ol)) { display: none; }
.breadcrumb ol {
    list-style: none; padding: 0; margin: 0;
    display: flex; flex-wrap: wrap; gap: 0.4rem;
}
.breadcrumb a { text-decoration: none; }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb li + li::before { content: "/ "; }

.site-footer__inner {
    display: flex; flex-direction: column; gap: 1rem;
    font-style: italic; font-size: 0.9em;
}
.site-footer p { margin: 0; }
.site-footer__sitemap {
    display: grid; gap: 1.5rem; margin-bottom: 1rem;
    grid-template-columns: repeat(auto-fit, minmax(min(15rem, 100%), 1fr));
}
.site-footer__sitemap h3 {
    font-size: 0.95em; margin: 0 0 0.5rem;
    text-transform: uppercase; letter-spacing: 0.05em; font-style: italic;
}
.site-footer__sitemap ul {
    list-style: none; padding: 0; margin: 0;
    display: flex; flex-direction: column; gap: 0.3rem; font-size: 0.92em;
}
.site-footer__sitemap a { text-decoration: none; }
.site-footer__sitemap a:hover { text-decoration: underline; }
.site-footer__credits {
    padding-top: 1rem; border-top: 1px solid currentColor;
    font-size: 0.9em;
}

/* A small musical invitation, using the same ink-and-paper palette as
   the lessons. The score is the home page's illustration and can be heard. */
.home-intro {
    display: grid; grid-template-columns: 1fr 1fr;
    gap: clamp(2rem, 5vw, 4rem); align-items: center;
    padding-block: clamp(1.5rem, 4vw, 3rem) 3rem;
}
.home-welcome h1 {
    font-family: Georgia, 'Times New Roman', serif;
    font-weight: 400; font-size: clamp(2.6rem, 4.4vw, 4rem);
    line-height: 1.08; letter-spacing: -0.035em; margin: 0 0 1.2rem;
}
.home-lead { font-size: 1.05rem; max-width: 29rem; }
.start-link {
    display: inline-flex; align-items: center; min-height: var(--touch);
    padding: 0.65rem 1rem; margin: 0.25rem 0 0.8rem;
    background: var(--fg); color: var(--bg); border: 2px solid var(--fg);
    text-decoration: none; font-weight: 600; line-height: 1.4;
    border-radius: 0.25rem;
}
.start-link:hover { background: var(--bg); color: var(--fg); }
.start-link:focus-visible { outline-color: var(--fg); outline-offset: 3px; }
.home-preparation { font-size: 0.9rem; }
.home-promise { font-size: 0.8rem; margin: 1.4rem 0 0; }
.home-tune { min-width: 0; border: 1px solid currentColor; padding: clamp(1rem, 2vw, 1.5rem); }
.home-tune h2 { font-size: 1.35rem; margin: 0 0 0.65rem; }
.home-tune p { font-size: 0.9rem; }
.home-tune figure { margin: 0.75rem 0 0; }
.home-tune figcaption { font-size: 0.8rem; margin-top: 1rem; }
.home-tune transpose-controls { margin-block: 0.75rem; }
.home-session { border-top: 1px solid currentColor; padding-top: 0.3rem; }
.first-steps {
    display: grid; grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 2rem; padding-left: 1.25rem; margin-block: 1.75rem 3rem;
}
main .first-steps { max-width: none; }
.first-steps li { padding-left: 0.35rem; }
.first-steps li::marker { font-family: Georgia, 'Times New Roman', serif; font-size: 1.3rem; }
.first-steps a { font-weight: 600; }
.first-steps p { font-size: 0.9rem; margin: 0.6rem 0 0; }
.home-paths {
    display: grid; grid-template-columns: 1fr 1.35fr; gap: 3rem;
    border-top: 1px solid currentColor; padding-block: 1.25rem 2rem;
}
.home-paths h2 { margin-top: 0.7rem; }
.home-paths > div > p { font-size: 0.95rem; }
ol.learning-paths { list-style: none; padding: 0; margin: 0; }
.learning-paths li { margin: 0; border-bottom: 1px solid currentColor; }
.learning-paths a { display: block; padding: 1rem 0.3rem; text-decoration: none; }
.learning-paths a:hover strong { text-decoration: underline; text-underline-offset: 3px; }
.learning-paths strong { font-weight: 600; }
.learning-paths span { display: block; font-size: 0.85rem; margin-top: 0.25rem; }
.home-repertoire { border-top: 1px solid currentColor; padding-block: 0.3rem 1rem; }

/* Optional lesson navigation and self-assessment stay separate from the
   music. A checked goal reflects the learner's judgement, never a score. */
.lesson-guide { max-width: var(--measure); margin-block: 1.5rem 2rem; border-block: 1px solid currentColor; }
.lesson-guide summary { cursor: pointer; min-height: var(--touch); padding-block: 0.5rem; font-weight: 600; }
.lesson-guide ul { list-style: none; padding: 0; margin: 0 0 0.75rem; columns: 2; column-gap: 2rem; }
.lesson-guide li { break-inside: avoid; margin: 0; }
.lesson-guide a { display: inline-block; min-height: var(--touch); padding-block: 0.35rem; font-size: 0.9rem; }
music-lesson h2[id] { scroll-margin-top: 1rem; }
.lesson-check { margin-top: 3rem; padding: 0.5rem 0 0; border-top: 2px solid currentColor; max-width: var(--measure); }
.lesson-check h2 { margin-top: 1rem; }
.lesson-check fieldset { min-width: 0; padding: 0; margin: 1.25rem 0; border: 0; }
.lesson-check legend { font-weight: 600; font-size: 0.85rem; margin-bottom: 0.5rem; }
.lesson-check label { display: flex; align-items: flex-start; gap: 0.75rem; padding-block: 0.6rem; min-height: var(--touch); cursor: pointer; }
.lesson-check input { flex: none; width: 1.15rem; height: 1.15rem; margin: 0.2rem 0 0; accent-color: var(--fg); }
.lesson-check-status { font-weight: 600; font-size: 0.95rem; }
.lesson-check-note { font-size: 0.8rem; }

@media (max-width: 850px) {
    .home-intro { grid-template-columns: 1fr; gap: 2rem; padding-bottom: 2rem; }
    .home-welcome h1 { font-size: clamp(2.6rem, 7vw, 4rem); }
    .home-lead { max-width: 34rem; }
    .home-tune { max-width: 34rem; width: 100%; }
    .home-paths { grid-template-columns: 1fr; gap: 0.5rem; }
}
@media (max-width: 540px) {
    .first-steps { grid-template-columns: 1fr; gap: 1.35rem; }
    .lesson-guide ul { columns: 1; }
}

/* Mobile nav: collapse into a tap-to-open panel; expand all touch targets. */
@media (max-width: 720px) {
    .nav-toggle { display: inline-block; }
    .site-nav {
        flex-basis: 100%; flex-direction: column; gap: 0; display: none;
    }
    body.nav-open .site-nav { display: flex; }
    .site-nav a, .site-nav summary { display: block; padding-block: 0.6rem; }
    .site-nav summary { cursor: default; pointer-events: none; font-style: italic; }
    .site-nav summary::after { content: ""; }
    .site-nav .submenu {
        position: static; border: 0; gap: 0;
        width: auto; min-width: 0; max-width: 100%;
        margin: 0; padding: 0 0 0 1rem;
    }
    .submenu-divider { display: none; }

    .nav-toggle,
    notation-display .chip,
    notation-display .play-btn,
    notation-display .stop-btn,
    notation-display .game-btn {
        min-height: var(--touch); padding-block: 0.6rem;
    }
    notation-display .playback-controls { gap: 1rem; row-gap: 0.6rem; }
}

/* ── Custom-element block layout ─────────────────────────────────── */
notation-display, exercise-container, music-lesson,
lesson-sidebar, transpose-controls, game-launcher {
    display: block; margin: 1.5em 0;
}
fingering-chart { display: inline-block; vertical-align: top; }

/* ── Notation (Verovio SVG, ten pre-rendered variants per snippet) ──
 * Each <notation-display> hosts ten SVGs: (soprano, alto) × (xs, sm, md,
 * lg, xl). The host is a size container; `@container` queries flip a
 * per-SVG `--on` flag so exactly one width variant is eligible, then a
 * single instrument gate displays the eligible SVG of the active
 * instrument (no body attribute — e.g. JS disabled — means soprano).
 * Thresholds must match NOTATION_VARIANTS in notation.py — generate.py
 * asserts this at build time. The queries target the descendant SVGs
 * because a container query cannot style its own container.
 * `overflow-x: auto` stays as a safety net for unusually long bars. */
notation-display {
    position: relative; overflow-x: auto;
    container-type: inline-size;
}
notation-display .notation-svg { display: none; max-width: 100%; height: auto; --on: none; }

notation-display .notation-svg[data-variant="xl"] { --on: block; }
@container (max-width: 1019px) {
    notation-display .notation-svg[data-variant="xl"] { --on: none; }
    notation-display .notation-svg[data-variant="lg"] { --on: block; }
}
@container (max-width: 779px) {
    notation-display .notation-svg[data-variant="lg"] { --on: none; }
    notation-display .notation-svg[data-variant="md"] { --on: block; }
}
@container (max-width: 599px) {
    notation-display .notation-svg[data-variant="md"] { --on: none; }
    notation-display .notation-svg[data-variant="sm"] { --on: block; }
}
@container (max-width: 459px) {
    notation-display .notation-svg[data-variant="sm"] { --on: none; }
    notation-display .notation-svg[data-variant="xs"] { --on: block; }
}

/* Instrument gate, once for all variants. */
notation-display .notation-svg[data-instrument="soprano"],
body[data-instrument="alto"] notation-display .notation-svg[data-instrument="alto"] {
    display: var(--on, none);
}
body[data-instrument="alto"] notation-display .notation-svg[data-instrument="soprano"] {
    display: none;
}

/* Per-instrument prose blocks: `data-instrument="…"` toggled by body attr. */
body[data-instrument="soprano"] [data-instrument="alto"]    { display: none; }
body[data-instrument="alto"]    [data-instrument="soprano"] { display: none; }

/* Verovio renders glyphs via <use> with no explicit fill, so default "black"
   would be invisible on dark backgrounds. Force every shape to current colour. */
notation-display .notation-svg,
notation-display .notation-svg .definition-scale { color: var(--fg); }
notation-display .notation-svg :where(path, use, rect, ellipse, polygon, polyline, text, tspan) {
    fill: currentColor; stroke: currentColor;
}
@media screen {
    notation-display .notation-svg .note.current,
    notation-display .notation-svg .note.current * {
        stroke-width: 1.75; paint-order: stroke;
    }
}

/* JS positions the cursor on all three axes (left, top, height) so it
   spans only the system currently playing. top/height get no transition
   on purpose: line changes should snap, not sweep diagonally. */
notation-display .play-cursor {
    position: absolute; top: 0; height: 4rem;
    left: 0; width: 0.6rem;
    background: var(--fg); mix-blend-mode: difference;
    opacity: 0; pointer-events: none;
    transition: left 80ms linear, opacity 120ms ease;
}
@media (prefers-reduced-motion: reduce) {
    notation-display .play-cursor { transition: opacity 120ms ease; }
}

notation-display .playback-controls {
    display: flex; flex-wrap: wrap; align-items: baseline;
    gap: 0.75rem; margin-top: 0.4rem;
    font-size: 0.85rem; font-style: italic;
}
/* A wide score scrolls inside its figure; its controls stay within the
   visible reading column at either end of that horizontal scroll. */
notation-display.notation-wide { overflow: visible; }
notation-display.notation-wide .playback-controls {
    position: sticky; left: 0;
    width: var(--playback-width); max-width: 100%;
}
notation-display .play-btn,
notation-display .stop-btn,
notation-display .game-btn {
    appearance: none; background: transparent; border: 0;
    color: inherit; font: inherit; cursor: pointer;
    padding: 0.2rem 0.1rem;
    text-decoration: underline; text-underline-offset: 2px;
}
notation-display .play-btn:hover,  notation-display .stop-btn:hover,
notation-display .game-btn:hover,
notation-display .play-btn:focus-visible, notation-display .stop-btn:focus-visible,
notation-display .game-btn:focus-visible {
    text-decoration-thickness: 2px;
}
notation-display .playback-controls--simple { align-items: center; font-style: normal; }
notation-display .playback-controls--simple :is(.play-btn, .stop-btn) {
    min-height: var(--touch); padding: 0.5rem 1rem;
    background: var(--fg); color: var(--bg); border: 1px solid var(--fg);
    border-radius: 0.25rem; text-decoration: none;
}
notation-display .playback-controls--simple .now-playing { font-size: 0.8rem; }
notation-display .playback-controls--simple :is(.play-btn, .stop-btn):focus-visible {
    outline-color: var(--fg); outline-offset: 3px;
}
notation-display .play-btn[disabled],
notation-display .stop-btn[disabled] {
    text-decoration: line-through; cursor: not-allowed;
}

notation-display .tempo-label {
    display: inline-flex; align-items: center; flex-wrap: wrap;
    max-width: 100%; gap: 0.4rem; font-style: italic;
}
notation-display .tempo-value {
    display: inline-flex; align-items: baseline; gap: 0.25em; white-space: nowrap;
}
notation-display .tempo-equivalent {
    flex-basis: 100%; text-align: right; font-size: 0.8em; font-style: normal;
}
notation-display .tempo-equivalent:empty { display: none; }
:is(notation-display .tempo-slider, .game-dialog input[type="range"]) {
    appearance: none; -webkit-appearance: none;
    width: 8rem; height: 2px;
    max-width: 100%; margin-inline: 0;
    /* The track is currentColor, and Chrome's UA sheet gives range inputs
       a warm grey colour of their own. */
    color: var(--fg);
    background: currentColor; cursor: pointer; vertical-align: middle;
}
/* Thumb rules must stay separate: one unknown pseudo-element in a selector
   list invalidates the whole rule, leaving the default (chromatic) thumb. */
:is(notation-display .tempo-slider, .game-dialog input[type="range"])::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 0.9rem; height: 0.9rem; border: 0; border-radius: 0;
    background: var(--fg); cursor: pointer;
}
:is(notation-display .tempo-slider, .game-dialog input[type="range"])::-moz-range-thumb {
    appearance: none;
    width: 0.9rem; height: 0.9rem; border: 0; border-radius: 0;
    background: var(--fg); cursor: pointer;
}
/* Small or touch screens: a full-height transparent hit area, with the
   visible track painted as a 4px line, so the slider stays thin but meets
   the 44px touch target. After the rule above, which it overrides. */
@media (max-width: 720px), (pointer: coarse) {
    :is(notation-display .tempo-slider, .game-dialog input[type="range"]) {
        height: var(--touch);
        background: linear-gradient(currentColor, currentColor)
                    50% 50% / 100% 4px no-repeat;
    }
}
/* A Game button while the game downloads (game-launcher.js openGame):
   aria-busy alone changes nothing a touch player can see. */
notation-display .game-btn[aria-busy="true"] { cursor: progress; text-decoration-style: dotted; }
notation-display .game-btn[aria-busy="true"]::after { content: " — loading…"; }

/* The Game button's "could not load — reload" note (game-launcher.js). */
notation-display .game-load-error { font-style: italic; }
notation-display .game-load-error button {
    appearance: none; background: transparent; border: 0;
    color: inherit; font: inherit; font-style: normal; cursor: pointer;
    min-height: var(--touch); padding: 0.2rem 0.1rem;
    text-decoration: underline; text-underline-offset: 2px;
}
notation-display .tempo-out {
    min-width: 2.2em; text-align: right;
    font-variant-numeric: tabular-nums; font-style: normal;
}
notation-display .tempo-unit { font-size: 0.8em; font-style: italic; }

notation-display .chip {
    appearance: none; background: transparent; color: inherit;
    border: 1px solid currentColor; border-radius: 999px;
    padding: 0.1rem 0.55rem;
    font: inherit; font-style: italic; font-size: 0.82rem;
    line-height: 1.3; cursor: pointer;
}
notation-display .chip:hover,
notation-display .chip:focus-visible {
    box-shadow: inset 0 0 0 1px currentColor;
}
notation-display .chip[aria-pressed="true"] {
    background: var(--fg); color: var(--bg);
    border-color: var(--fg); font-style: normal;
}

notation-display .now-playing {
    margin-left: auto; min-height: 1.2em;
    font-style: italic; font-variant-numeric: tabular-nums;
}

/* ── Sight-reading game (js/game/overlay.js, cards.js) ──────────────
 * A full-screen <dialog>: top bar, the Phaser stage, and HTML cards
 * over it. Same palette as the page — fill vs outline, never grey. The
 * dialog and form controls get explicit colours because the browser
 * defaults are grey. */
html.game-open { overflow: hidden; }

.game-dialog {
    position: fixed; inset: 0;
    width: 100vw; height: 100vh; height: 100dvh;
    max-width: none; max-height: none;
    margin: 0; padding: 0; border: 0;
    background: var(--bg); color: var(--fg);
    overscroll-behavior: contain;
    container: game-dialog / size;
}
.game-dialog::backdrop { background: var(--bg); }
.game-shell {
    display: flex; flex-direction: column; height: 100%;
    /* Fullscreen puts the shell on its own (black) backdrop. */
    background: var(--bg); color: var(--fg);
}

.game-dialog :is(button, select) {
    appearance: none; background: var(--bg); color: var(--fg);
    border: 1px solid currentColor; border-radius: 0;
    font: inherit; min-height: var(--touch);
}
.game-dialog button { padding: 0.3rem 0.8rem; cursor: pointer; line-height: 1.2; }
.game-dialog button:hover { box-shadow: inset 0 0 0 1px currentColor; }
.game-dialog .primary { background: var(--fg); color: var(--bg); border-color: var(--fg); }
.game-dialog button:disabled { cursor: not-allowed; text-decoration: line-through; }
.game-dialog select {
    max-width: 100%; padding: 0.3rem 2rem 0.3rem 0.6rem;
    /* A drawn chevron: appearance:none removes the (grey) native one. */
    background-image: linear-gradient(45deg, transparent 50%, currentColor 50%),
                      linear-gradient(135deg, currentColor 50%, transparent 50%);
    background-position: calc(100% - 1.1rem) 55%, calc(100% - 0.75rem) 55%;
    background-size: 0.35rem 0.35rem, 0.35rem 0.35rem;
    background-repeat: no-repeat;
}
.game-dialog input[type="range"] { width: min(16rem, 100%); }
/* Drawn radios and checkboxes: the native ones fill grey in dark mode. */
.game-dialog :is(input[type="radio"], input[type="checkbox"]) {
    appearance: none; -webkit-appearance: none;
    display: inline-grid; place-content: center; flex: none;
    width: 1.1rem; height: 1.1rem; margin: 0;
    border: 1px solid currentColor; border-radius: 0;
    background: var(--bg); color: var(--fg); cursor: pointer;
}
.game-dialog input[type="radio"] { border-radius: 50%; }
.game-dialog :is(input[type="radio"], input[type="checkbox"])::before {
    content: ""; width: 0.6rem; height: 0.6rem;
    background: currentColor; transform: scale(0);
}
.game-dialog input[type="radio"]::before { border-radius: 50%; }
.game-dialog input[type="checkbox"]::before {
    clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
.game-dialog :is(input[type="radio"], input[type="checkbox"]):checked::before { transform: scale(1); }
.game-dialog input:disabled { cursor: not-allowed; border-style: dashed; }
.game-dialog input:disabled + span { text-decoration: line-through; }
.game-dialog kbd {
    font-size: 0.8em; padding: 0 0.3em;
    border: 1px solid currentColor; font-style: normal;
}

/* Top bar */
.game-bar {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1rem;
    padding: 0.35rem clamp(0.5rem, 2vw, 1rem);
    border-bottom: 1px solid currentColor;
}
.game-title { margin: 0; font-size: 1rem; letter-spacing: 0; }
.game-exercise {
    flex: 1 1 4rem; min-width: 0; margin: 0;
    font-style: italic; font-size: 0.9rem;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.game-bar-actions { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-left: auto; }
.game-rotate { display: none; order: 1; flex-basis: 100%; margin: 0; font-style: italic; font-size: 0.85rem; }
@media (orientation: portrait) {
    .game-dialog[data-state="play"] .game-rotate { display: block; }
}
/* Small screens: one row of controls. The title still labels the dialog. */
@media (max-width: 600px), (max-height: 500px) {
    .game-title {
        position: absolute; width: 1px; height: 1px; overflow: hidden;
        clip: rect(0, 0, 0, 0); white-space: nowrap;
    }
    .game-bar { gap: 0.2rem 0.5rem; padding-block: 0.25rem; }
    .game-bar-actions { gap: 0.3rem; }
    .game-bar-actions button {
        padding-inline: 0.3rem;
        min-height: max(44px, 1.8em);
    }
}

/* Stage: its size never depends on the canvas (an inline canvas's
   baseline gap would grow it, and the ResizeObserver would chase it). */
.game-main { position: relative; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }
.game-stage {
    position: relative; flex: 1 1 auto; min-width: 0; min-height: 0;
    overflow: hidden; contain: strict;
    touch-action: none; user-select: none;
    -webkit-user-select: none; -webkit-touch-callout: none;
}
.game-stage:focus { outline: none; }
.game-stage > canvas { display: block; position: absolute; left: 0; top: 0; }

/* Cards. The layer is opaque: the last frame of a run (its HUD, the
   recorder, stubs of the staff) must not show around a card, and the
   Game's loop sleeps behind it. */
.game-cards {
    position: absolute; inset: 0;
    display: flex; align-items: center; justify-content: center;
    padding: clamp(0.5rem, 3vw, 1.5rem);
    background: var(--bg);
}
.game-cards[hidden] { display: none; }
.game-card {
    --pad: clamp(0.9rem, 3vw, 1.5rem);
    width: 100%; max-width: 34rem; max-height: 100%; overflow: auto;
    padding: 1rem var(--pad) 0;
    background: var(--bg); color: var(--fg); border: 1px solid currentColor;
    overscroll-behavior: contain;
}
.game-card-title { margin: 0 0 0.75rem; font-size: 1.35rem; }
.game-card-title:focus { outline: none; }
.game-card h3 { margin: 1.25rem 0 0.4rem; font-size: 1rem; }
.game-card p { margin: 0 0 0.75rem; }
.game-card fieldset { min-width: 0; margin: 1rem 0 0; padding: 0; border: 0; }
.game-card legend { padding: 0; margin-bottom: 0.25rem; font-weight: 600; }
.game-note { font-style: italic; font-size: 0.9rem; }
.game-card .game-note:empty { display: none; }
.game-dialog [hidden] { display: none !important; }
.game-choice { display: flex; align-items: flex-start; gap: 0.5rem; padding-block: 0.3rem; line-height: 1.4; }
.game-choice > input { margin-top: 0.15em; }
.game-choice-note { margin-left: 0.3rem; font-size: 0.85rem; }
.game-field, .game-row {
    display: flex; flex-wrap: wrap; align-items: center; gap: 0.4rem 0.75rem;
    margin: 0.75rem 0;
}
.game-field > label:first-child { min-width: 5rem; font-weight: 600; }
.game-bars label { display: inline-flex; align-items: center; gap: 0.4rem; }
.game-field output { font-style: italic; font-variant-numeric: tabular-nums; }
.game-prompts { margin: 0.5rem 0 0.75rem; padding-left: 1.2em; }
.game-goal { font-style: italic; font-size: 0.9rem; }
.game-goal > span { font-style: normal; }
/* Wide screens: setup and results in two columns (what to play | how to
   play it; the numbers | the music). A card may still scroll at laptop
   sizes, but what matters first sits above the action bar: the chosen
   mode's controls, and the Practice button above a long bar strip. */
@media (min-width: 60rem) and (min-height: 32rem) {
    .game-card:has(> .game-cols) { max-width: 62rem; }
    .game-cols {
        display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        gap: 0 2.5rem; align-items: start;
    }
    .game-col > :first-child { margin-top: 0; }
}
.game-advanced { margin-top: 1rem; }
.game-advanced > summary { cursor: pointer; font-weight: 600; }
/* "Another keyboard layout?" (browsers that cannot read the layout). */
.game-keypos { margin: 0.5rem 0 0.75rem; }
.game-keypos > summary { cursor: pointer; }
.game-keypos > p { margin: 0.4rem 0 0; }
.game-actions {
    position: sticky; bottom: 0;
    display: flex; flex-wrap: wrap; gap: 0.5rem;
    margin: 1rem calc(-1 * var(--pad)) 0; padding: 0.75rem var(--pad);
    background: var(--bg); border-top: 1px solid currentColor;
}

/* Landscape phones: cards use the width, and the actions are one row
   (scrolling sideways if they must), so the bar does not take half the
   card. It stays sticky: Start and Again stay in reach. */
@media (max-height: 500px) {
    .game-card { max-width: none; }
    /* One system at a time in a box of its own, inside the card's own
       scroll, hides the marks: let the card be the only scroller. */
    .game-results .game-score { max-height: none; overflow: visible; }
    .game-actions {
        flex-wrap: nowrap; overflow-x: auto;
        margin-top: 0.5rem; padding-block: 0.4rem;
    }
    .game-actions > button { flex: none; padding-inline: 0.65rem; }
}

/* Enlarged text can leave only a few lines below the top bar, even on
   portrait phones. Keep the card's content reachable instead of covering
   it with several rows of sticky actions. rem tracks the user's text size. */
@container game-dialog (height < 24rem) {
    .game-actions { position: static; }
    .game-rotate { display: none !important; }
}

/* The page's own engraving, copied into a card. */
.game-score {
    max-height: 40vh; overflow: auto; margin: 0 0 0.75rem; padding-block: 0.5rem;
    border-block: 1px solid currentColor;
}
.game-score svg { display: block; width: 100%; max-width: 100%; height: auto; color: var(--fg); }
.game-score svg :where(path, use, rect, ellipse, polygon, polyline, text, tspan) {
    fill: currentColor; stroke: currentColor;
}
.game-score svg .game-mark { fill: none; stroke: currentColor; }

/* Microphone level: filled bar, with the room's noise floor as a tick
   standing out above and below it. */
.game-meter {
    position: relative; flex: 1 1 8rem; height: 0.75rem; min-width: 6rem;
    border: 1px solid currentColor;
}
.game-meter-level {
    position: absolute; left: 0; top: 0; bottom: 0;
    width: calc(var(--level, 0) * 100%); background: currentColor;
}
.game-meter-floor {
    position: absolute; top: -0.3rem; bottom: -0.3rem; width: 2px;
    left: calc(var(--floor, 0) * 100%); background: currentColor;
}

/* "Check your keyboard" */
.game-keys-row { display: flex; flex-wrap: wrap; gap: 0.3rem; margin: 0.5rem 0; }
.game-key {
    min-width: 2rem; padding: 0.15rem 0.4rem; text-align: center;
    border: 1px solid currentColor;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 0.85rem;
}
.game-key.is-down { background: var(--fg); color: var(--bg); }

/* Results */
.game-stars { margin: 0 0 0.5rem; font-size: 2rem; line-height: 1; letter-spacing: 0.1em; }
.game-badge {
    display: inline-block; margin-left: 0.5rem; padding: 0.05rem 0.5rem; vertical-align: middle;
    border: 1px solid currentColor; font-size: 0.8rem; font-style: italic; font-weight: 400;
}
.game-stats {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
    gap: 0.5rem 1rem; margin: 0 0 1rem;
}
/* The counts and the timing sentence get a whole row each. */
.game-stats > div:nth-child(n+4) { grid-column: 1 / -1; }
.game-stats dt { margin: 0; font-style: italic; font-size: 0.8rem; }
.game-stats dd { margin: 0; padding: 0; font-variant-numeric: tabular-nums; }
.game-playlist { margin: 0.5rem 0 1rem; font-size: 0.9rem; }
.game-strip { display: flex; flex-wrap: wrap; gap: 1rem 0.5rem; margin: 0.5rem 0 1.25rem; }
.game-strip-key { margin-bottom: 0.25rem; }
.game-practice:empty { display: none; }
.game-dialog .game-cell {
    position: relative;
    min-width: var(--touch); padding: 0;
    font-size: 0.8rem; font-variant-numeric: tabular-nums;
}
/* A long piece's strip: smaller cells, except on touch screens. */
@media (pointer: fine) {
    .game-dialog .game-strip.is-long { gap: 1rem 0.4rem; }
    .game-dialog .game-strip.is-long .game-cell { min-width: 2rem; min-height: 2rem; }
}
.game-dialog .game-cell.is-clean { background: var(--fg); color: var(--bg); }
.game-dialog .game-cell.is-crossed {
    background-image:
        linear-gradient(to top right, transparent calc(50% - 1px), currentColor calc(50% - 1px), currentColor calc(50% + 1px), transparent calc(50% + 1px)),
        linear-gradient(to top left, transparent calc(50% - 1px), currentColor calc(50% - 1px), currentColor calc(50% + 1px), transparent calc(50% + 1px));
}
.game-dialog .game-cell.is-crossed > span { padding: 0 0.15em; background: var(--bg); }
.game-dialog .game-cell.is-empty { border-style: dashed; }
/* A bar that only holds a tied note on: nothing to play, but not a rest. */
.game-dialog .game-cell.is-held { border-style: dotted; border-width: 2px; }
.game-dialog .game-cell[aria-pressed="true"] { outline: 3px solid var(--fg); outline-offset: 2px; }
/* Chosen for practice: underlined as well as outlined, so it never reads
   as just another outlined ("some misses") cell. */
.game-dialog .game-cell[aria-pressed="true"]::after {
    content: ""; position: absolute; left: -5px; right: -5px; bottom: -0.65rem;
    height: 0.2rem; background: var(--fg);
}
/* Focus rings. The global ring is currentColor, which on a filled button
   or cell is the background colour: invisible. A chosen cell's outline
   is already the focus ring's width, so focus doubles it. */
.game-dialog :is(.primary, .game-cell):focus-visible { outline-color: var(--fg); }
.game-dialog .game-cell[aria-pressed="true"]:focus-visible { outline-style: double; outline-width: 6px; }
.game-diagnoses, .game-suggestions { margin: 0.5rem 0 1rem; }
.game-diagnoses { list-style: none; padding: 0; }
.game-diagnoses li { display: flex; align-items: flex-start; gap: 0.75rem; margin: 0 0 0.75rem; }
.game-diagnoses p { margin: 0; }
.game-suggestions { padding-left: 1.2em; font-style: italic; font-size: 0.9rem; }

/* ── Fingering grid ──────────────────────────────────────────────── */
.fingering-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
    gap: 1rem; justify-items: center;
    margin: 1.5em 0; padding: 1rem 0;
    border-top: 1px solid currentColor;
    border-bottom: 1px solid currentColor;
}
.fingering-cell { text-align: center; }

/* ── Lesson list & pagination ────────────────────────────────────── */
.lesson-pagination {
    display: flex; justify-content: space-between; flex-wrap: wrap; gap: 1.5rem;
    margin-top: 2.5rem; padding-top: 1.25rem;
    border-top: 1px solid currentColor;
    font-size: 0.95rem; font-style: italic;
}
.lesson-prev::before { content: "\2190 "; font-style: normal; }
.lesson-next::after  { content: " \2192"; font-style: normal; }

/* Book-to-book links on song-library pages share the pagination design. */
.library-nav {
    margin-top: 2.5rem; padding-top: 1.25rem;
    border-top: 1px solid currentColor;
    font-size: 0.95rem; font-style: italic;
}

ol.lesson-list { list-style: none; padding: 0; margin: 1.5em 0; }
ol.lesson-list .lesson-item {
    margin: 0; padding: 0.6rem 0; line-height: 1.5;
    border-bottom: 1px solid currentColor;
}
.lesson-num {
    display: inline-block; min-width: 2.2rem;
    font-style: italic; font-variant-numeric: tabular-nums;
}
.lesson-desc { display: block; padding-left: 2.2rem; font-style: italic; font-size: 0.9em; }
.lesson-count { font-style: italic; font-size: 0.9em; margin-left: 0.4rem; }

/* ── Glossary ────────────────────────────────────────────────────── */
.glossary-term {
    background: transparent; border: 0; padding: 0; margin: 0;
    color: inherit; font: inherit; cursor: help;
    text-decoration: underline dotted; text-underline-offset: 3px;
}
.glossary-popover {
    position: absolute; z-index: 150;
    max-width: min(22rem, 90vw); padding: 0.6rem 0.8rem;
    max-height: calc(100dvh - 16px); overflow: auto;
    background: var(--bg); color: var(--fg);
    border: 1px solid currentColor;
    font-size: 0.9em; line-height: 1.5;
}
.glossary-popover strong {
    display: block; margin-bottom: 0.3em;
    font-style: italic; font-weight: 600;
}

/* ── Print ───────────────────────────────────────────────────────── */
/* Let the print dialog choose Letter or A4; reserve room for the browser's
   default page headers/footers without depending on background printing. */
@page { margin: 18mm 16mm; }
.notation-print { display: none; }
.lesson-print-ending { display: contents; }

@media print {
    /* Paper is always black-on-white, even for dark-mode visitors. The
       custom properties must be reset too: notation SVGs and the shadow-DOM
       fingering charts draw with var(--fg)/var(--bg), and would otherwise
       print white-on-white. */
    :root { --fg: #000; --bg: #fff; --measure: 100%; color-scheme: light; }

    .skip-link, .site-header, .site-footer, .breadcrumb,
    .lesson-footer, .lesson-pagination, .library-nav, .lesson-guide, .lesson-check, lesson-sidebar, transpose-controls,
    game-launcher, .game-dialog,
    .nav-toggle, .glossary-popover,
    notation-display .playback-controls,
    notation-display .play-cursor { display: none !important; }

    html { font-size: 10.5pt; line-height: 1.4; }
    html.game-open { overflow: visible; }
    body { display: block; min-height: 0; color: #000; background: #fff; }
    main { padding: 0; }
    main > *, music-lesson { max-width: none; margin: 0; }
    music-lesson > *, .lesson-print-ending > * { margin-bottom: 0.65rem; }
    .lesson-print-ending { display: block; break-inside: avoid; page-break-inside: avoid; }
    h1 { font-size: 22pt; }
    h2 { font-size: 16pt; }
    h3 { font-size: 13pt; }
    h2, h3, h4, h5, h6 { margin-top: 1em; }
    blockquote { margin-top: 0.8em; }
    a    { text-decoration: none; color: #000; }
    .glossary-term { text-decoration: none; }
    /* Override the inline scrolling/min-width used by dense screen scores. */
    figure { overflow: visible !important; }
    notation-display { min-width: 0 !important; width: 100%; overflow: visible; container-type: normal; }

    /* Use the wide engraving for a comfortable printed staff size and more
       bars per line, regardless of the screen width.
       JS supplies individual systems so long movements can paginate. The
       original SVG remains a fallback if components have not loaded. */
    notation-display > .notation-svg { --on: none; }
    notation-display > .notation-svg[data-variant="xl"] { --on: block; }
    notation-display.notation-print-ready > .notation-svg { display: none !important; }
    notation-display .notation-print { display: block; }
    notation-display .notation-print-system {
        display: block; width: 100%; max-width: 100%; height: auto;
        color: #000; break-inside: avoid; page-break-inside: avoid;
    }
    notation-display .notation-print-system :where(path, use, rect, ellipse, polygon, polyline, text, tspan) {
        fill: currentColor; stroke: currentColor;
    }

    figure, table, notation-display, exercise-container, .fingering-grid {
        break-inside: auto; page-break-inside: auto;
    }
    /* Keep short drills with their instructions; complete movements are
       allowed to continue on the next page between staff systems. */
    exercise-container:not(:has(.notation-print-system:nth-child(n+5))) {
        break-inside: avoid; page-break-inside: avoid;
    }
    fingering-chart, .fingering-cell, tr, dl, dd, blockquote, aside {
        break-inside: avoid; page-break-inside: avoid;
    }
    thead { display: table-header-group; }
    tfoot { display: table-footer-group; }
    th, td { overflow-wrap: anywhere; }
    pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: visible; }
    h1, h2, h3, h4, h5, h6, dt { break-after: avoid; page-break-after: avoid; }
    figcaption { break-before: avoid; page-break-before: avoid; }
    p, li { orphans: 2; widows: 2; }

    /* Put provenance beside the instrument label, where it cannot create a
       trailing page of its own when the lesson exactly fills the paper. */
    music-lesson::before {
        content: "learntoplayrecorder.com \00b7\0020 Soprano recorder";
        display: block; font-size: 9pt; font-style: italic;
        break-after: avoid; page-break-after: avoid;
    }
    body[data-instrument="alto"] music-lesson::before {
        content: "learntoplayrecorder.com \00b7\0020 Alto recorder";
    }
}

.offline-access { max-width: 70rem; margin: 1.5rem auto; padding: 1rem; }
.offline-access p { margin: .5rem 0; }
.offline-access progress { display: block; width: min(100%, 30rem); margin-top: .75rem; }
.offline-access [hidden] { display: none; }
@media print { .offline-access { display: none; } }
