/* ===========================================================================
   ChordIQ free games — /:lang/games and /:lang/games/<slug>
   ---------------------------------------------------------------------------
   Served from /apps/chordiq-games/src/, the one static path that resolves in
   development AND in production without landing/css/all.css or the tool
   layout's inline style block being rebuilt. Never move these rules into
   landing/css/stylesheet.css: the production landing pages serve a pre-built
   bundle, so an above-the-fold game would render unstyled until the next build.

   The pages live inside the tool layout (includes/layout-tools → .mt-page), so
   everything here is scoped to .mt-page and inherits the tool typography. The
   one idea of its own: the game is a lit ink board sitting in the light page,
   with the staff drawn in chalk-white on it. Everything around the board stays
   quiet so the board is the thing you look at.
   =========================================================================== */

/* Bravura (SIL OFL, licence in public/fonts/bravura-OFL.txt) — the music font
   the ChordIQ app uses. Subset to the glyphs the games draw; see
   docs/chordiq-games.md for the pyftsubset command that regenerates it.
   font-display: block on purpose: a fallback family would draw the letter
   U+E050 instead of a G clef. The core waits for document.fonts.load and keeps
   its own hand-drawn shapes until then, so nothing is ever blank. */
@font-face {
    font-family: 'Bravura';
    /* Relative, like font-awesome.css: this file is served from
       /{version}/apps/chordiq-games/src/, so ../../../public/fonts keeps the
       version prefix that an absolute /public/fonts path would lose. */
    src: url('../../../public/fonts/bravura-subset.woff2') format('woff2'),
         url('../../../public/fonts/bravura-subset.woff') format('woff');
    font-weight: normal;
    font-style: normal;
    font-display: block;
}

.mt-page {

    --cg-ink: #17142b;
    --cg-ink-2: #241f43;
    --cg-ink-3: #322c57;
    --cg-chalk: #f4f2ff;
    --cg-chalk-dim: rgba(244, 242, 255, 0.55);
    --cg-accent: #6d63f2;
    --cg-spark: #ffc247;
    --cg-right: #4ade80;
    --cg-wrong: #fb7185;
    --cg-rule: var(--mt-rule);
    --cg-display: Georgia, "Times New Roman", serif;
}

/* ------------------------------------------------------------- the board */

.cg-board-wrap { padding: 26px 0 8px; background: var(--mt-card); }

/* #cg-board is the empty <div> the server renders; the core fills it once its
   deferred script has run. Reserving the height here is what keeps CLS at 0 —
   without it the board pops in after layout and pushes the whole page down.
   The number is the start screen (332) plus the HUD row (36) plus the padding
   (44), measured at 412 px. Keep it in step with .cg-stage/.cg-screen. */
#cg-board {
    /* Never taller than the window: sideways, 412 px is more than the whole
       viewport and the guard against one problem becomes the cause of another.
       `min()` keeps the reservation where there is room and yields where there
       is not, so the CLS guard can never push the page sideways. */
    min-height: min(412px, calc(100svh - 28px));
}

.cg-board {
    position: relative;
    background:
        radial-gradient(120% 90% at 50% -20%, var(--cg-ink-3) 0%, transparent 62%),
        linear-gradient(168deg, var(--cg-ink-2) 0%, var(--cg-ink) 100%);
    color: var(--cg-chalk);
    border-radius: 22px;
    padding: 18px 18px 26px;
    box-shadow: 0 22px 50px -24px rgba(23, 20, 43, 0.75);
    overflow: hidden;
}

.cg-board:focus-within { outline: none; }

/* HUD ------------------------------------------------------------------- */

.cg-hud {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 10px;
}

.cg-hud__time {
    position: relative;
    flex: 1 1 auto;
    height: 30px;
    border-radius: 15px;
    background: rgba(255, 255, 255, 0.08);
    overflow: hidden;
}

.cg-hud__time-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: 100%;
    background: linear-gradient(90deg, var(--cg-accent), #8d86ff);
}

.cg-hud__time-text {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    font-size: 14px;
    color: #fff;
}

.cg-board.is-urgent .cg-hud__time-fill {
    background: linear-gradient(90deg, #f0754a, var(--cg-wrong));
}

.cg-hud__cell {
    flex: 0 0 auto;
    min-width: 58px;
    text-align: center;
    line-height: 1.1;
}

.cg-hud__value {
    display: block;
    font-size: 22px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: var(--cg-spark);
}

.cg-hud__label {
    display: block;
    font-size: 11px;
    letter-spacing: 0.02em;
    color: var(--cg-chalk-dim);
}

/* Stage and screens ------------------------------------------------------ */

.cg-stage,
.cg-screen {
    min-height: 322px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
}

.cg-board[data-phase="start"] .cg-stage,
.cg-board[data-phase="result"] .cg-stage { display: none; }

.cg-screen { text-align: center; }

.cg-screen__blurb {
    font-family: var(--cg-display);
    font-size: 23px;
    line-height: 1.35;
    max-width: 22ch;
    margin: 0 0 22px;
    color: var(--cg-chalk);
}

.cg-screen__hint {
    font-size: 14px;
    color: var(--cg-chalk-dim);
    max-width: 40ch;
    margin: 14px 0 20px;
    min-height: 2.6em;
}

.cg-screen__best {
    font-size: 13px;
    color: var(--cg-chalk-dim);
    margin: 16px 0 0;
}

.cg-levels {
    display: inline-flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
    padding: 5px;
    border-radius: 13px;
    background: rgba(255, 255, 255, 0.06);
}

.cg-level {
    appearance: none;
    border: 0;
    background: transparent;
    color: var(--cg-chalk-dim);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    padding: 9px 14px;
    min-height: 40px;
    border-radius: 9px;
    cursor: pointer;
}

.cg-level[aria-pressed="true"] {
    background: var(--cg-chalk);
    color: var(--cg-ink);
}

.cg-cta {
    appearance: none;
    border: 0;
    font-family: inherit;
    font-size: 17px;
    font-weight: 600;
    color: #fff;
    background: var(--cg-accent);
    padding: 16px 30px;
    min-height: 54px;
    border-radius: 14px;
    cursor: pointer;
    box-shadow: 0 10px 26px -10px rgba(109, 99, 242, 0.9);
}

.cg-cta:hover { background: #5a4fe8; }

.cg-link-btn {
    appearance: none;
    border: 0;
    background: none;
    color: var(--cg-chalk-dim);
    font-family: inherit;
    font-size: 14px;
    padding: 12px;
    min-height: 44px;
    text-decoration: underline;
    cursor: pointer;
}

.cg-link-btn:hover { color: var(--cg-chalk); }

.cg-board :focus-visible {
    outline: 3px solid var(--cg-spark);
    outline-offset: 2px;
}

/* Result ----------------------------------------------------------------- */

.cg-result__eyebrow {
    font-size: 14px;
    color: var(--cg-spark);
    margin: 0;
}

.cg-result__score {
    font-family: var(--cg-display);
    font-size: 78px;
    line-height: 1;
    margin: 4px 0 16px;
    color: var(--cg-chalk);
    font-variant-numeric: tabular-nums;
}

.cg-result__stats {
    display: flex;
    gap: 26px;
    margin-bottom: 24px;
}

.cg-result__stat strong {
    display: block;
    font-size: 19px;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.cg-result__stat span {
    font-size: 12px;
    color: var(--cg-chalk-dim);
}

.cg-result__cta {
    margin-top: 26px;
    padding-top: 20px;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    width: 100%;
}

.cg-result__cta p {
    font-size: 14px;
    color: var(--cg-chalk-dim);
    margin: 0 0 12px;
}

.cg-result__cta .app-list {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 10px;
}

.cg-result__cta .app-list a { display: inline-block; width: 132px; height: 45px; }
.cg-result__cta .app-list img { width: 100%; height: 100%; }
/* chordiq-apps.jade appends a QR code for every placement but 'hero'. It
   belongs on a landing page, not inside the result screen of a game. */
.cg-result__cta .visible-md,
.cg-result__cta .visible-lg { display: none !important; }

/* Answer flash ----------------------------------------------------------- */

.cg-flash {
    position: absolute;
    inset: 0;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.16s ease;
}

.cg-flash.is-right { background: rgba(74, 222, 128, 0.16); opacity: 1; }
.cg-flash.is-wrong { background: rgba(251, 113, 133, 0.18); opacity: 1; }

.cg-live {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

/* Staff ------------------------------------------------------------------ */

.cg-staff { width: 100%; height: auto; display: block; }

/* No stroke-width here: the renderer sets it per element from Bravura's
   engravingDefaults, and a CSS width would beat the attribute. */
.cg-staff__line {
    stroke: rgba(244, 242, 255, 0.42);
    stroke-linecap: round;
}

.cg-staff__ledger { stroke: rgba(244, 242, 255, 0.72); }

.cg-staff__stem {
    stroke: var(--cg-spark);
    stroke-linecap: butt;
}

/* The hand-drawn fallback, used only until the font settles. */
.cg-staff__clef-stroke {
    fill: none;
    stroke: var(--cg-chalk);
    stroke-width: 2.4;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.cg-staff__clef-dot { fill: var(--cg-chalk); }

.cg-staff__head { fill: var(--cg-spark); }

.cg-staff__accidental { fill: var(--cg-chalk); }

/* The fallback accidental is a typographic character in the page font and is
   centred on the note; a Bravura glyph is placed by its own left edge. */
.cg-staff__accidental:not(.cg-staff__glyph) {
    font-family: inherit;
    text-anchor: middle;
}

/* Every Bravura glyph. font-family is set as an attribute by the renderer, so
   nothing here may declare one. */
.cg-staff__glyph {
    text-anchor: start;
    dominant-baseline: alphabetic;
}

.cg-staff__clef-glyph { fill: var(--cg-chalk); }

/* Piano keyboard --------------------------------------------------------- */

.cg-keys {
    position: relative;
    width: 100%;
    max-width: 560px;
    user-select: none;
}

.cg-keys__row { display: flex; }

.cg-key {
    appearance: none;
    font-family: inherit;
    cursor: pointer;
    padding: 0;
}

.cg-key--white {
    flex: 1 1 0;
    height: 132px;
    /* Low enough that a two-octave keyboard still fits a 320 px board; a game
       that wants fatter keys raises it inside its own block. */
    min-width: 20px;
    background: #f7f5ff;
    border: 1px solid #cdc8e6;
    border-radius: 0 0 6px 6px;
    display: flex;
    align-items: flex-end;
    justify-content: center;
}

.cg-key__label {
    font-size: 12px;
    color: #6b6580;
    padding-bottom: 8px;
}

.cg-keys__blacks {
    position: absolute;
    inset: 0 0 auto 0;
    height: 82px;
    pointer-events: none;
}

.cg-key--black {
    position: absolute;
    top: 0;
    height: 82px;
    background: #241f43;
    border: 1px solid #100e20;
    border-radius: 0 0 5px 5px;
    pointer-events: auto;
}

.cg-key.is-on { background: var(--cg-accent); }
.cg-key.is-right { background: var(--cg-right); }
.cg-key.is-wrong { background: var(--cg-wrong); }

/* Note Rush -------------------------------------------------------------- */

.cg-rush { width: 100%; }

.cg-rush__clef {
    text-align: center;
    font-size: 13px;
    color: var(--cg-chalk-dim);
    margin: 0 0 2px;
    min-height: 1.3em;
}

.cg-rush__staff { max-width: 420px; margin: 0 auto 18px; }

.cg-rush__hint {
    text-align: center;
    font-size: 12px;
    color: var(--cg-chalk-dim);
    margin: 12px 0 0;
}

.cg-answers {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
}

.cg-answer {
    appearance: none;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.07);
    color: var(--cg-chalk);
    font-family: inherit;
    font-size: 20px;
    font-weight: 600;
    min-height: 62px;
    border-radius: 12px;
    cursor: pointer;
    transition: background 0.1s ease;
}

.cg-answer:hover { background: rgba(255, 255, 255, 0.14); }
.cg-answer[disabled] { cursor: default; }
.cg-answer.is-right { background: var(--cg-right); color: #08240f; border-color: transparent; }
.cg-answer.is-wrong { background: var(--cg-wrong); color: #3d0713; border-color: transparent; }
.cg-answer.is-answer { background: var(--cg-chalk); color: var(--cg-ink); border-color: transparent; }

/* ------------------------------------------------------------ page prose */

.cg-section { padding: 42px 0; }
.cg-section--tint { background: var(--mt-bg); border-top: 1px solid var(--cg-rule); border-bottom: 1px solid var(--cg-rule); }

/* The page title shares the display face of the section headings. The tool
   layout sets h1 in the body sans, which put two unrelated type voices on the
   first screen. games.css loads on the game pages only. */
/* Breadcrumb above the title: games index > this game. Quiet type, but the
   link keeps a 44 px tap height on phones. */
.cg-crumbs { padding-top: clamp(10px, 2vw, 20px); }
.cg-crumbs ol { list-style: none; display: flex; flex-wrap: wrap; align-items: center; margin: 0; padding: 0; font-size: 14px; line-height: 1.3; color: var(--mt-soft); }
.cg-crumbs li { display: flex; align-items: center; min-width: 0; }
.cg-crumbs li + li::before { content: "\203A"; margin: 0 9px; color: var(--mt-soft); opacity: 0.7; }
.cg-crumbs a { display: inline-flex; align-items: center; min-height: 44px; color: var(--mt-accent); font-weight: 600; text-decoration: none; }
.cg-crumbs a:hover, .cg-crumbs a:focus-visible { text-decoration: underline; }
.cg-crumbs [aria-current="page"] { color: var(--mt-ink); overflow-wrap: anywhere; }
.mt-page .cg-crumbs + .mt-hero { padding-top: 2px; }
[dir="rtl"] .cg-crumbs li + li::before { content: "\2039"; }

.mt-page .mt-hero { padding-top: clamp(14px, 3vw, 30px); }
.mt-page .mt-hero h1 {
    font-family: var(--cg-display);
    font-weight: 700;
    font-size: clamp(28px, 4vw, 40px);
    line-height: 1.1;
    letter-spacing: -0.01em;
    max-width: 26ch;
    margin: 0 0 16px;
    text-wrap: balance;
}
.mt-page .mt-hero .mt-lede { max-width: 62ch; line-height: 1.55; }

.mt-page h2 {
    font-family: var(--cg-display);
    font-size: clamp(26px, 4vw, 34px);
    line-height: 1.15;
    margin: 0 0 18px;
    color: var(--mt-ink);
}

.mt-page h3 {
    font-family: inherit;
    font-size: 17px;
    font-weight: 600;
    margin: 0 0 6px;
    color: var(--mt-ink);
}

.cg-prose p {
    font-size: 17px;
    line-height: 1.68;
    color: var(--mt-ink);
    max-width: 68ch;
    margin: 0 0 16px;
}

/* How to play is a real sequence, so it is numbered. */
.cg-steps { list-style: none; counter-reset: cg-step; margin: 0; padding: 0; }

.cg-steps li {
    counter-increment: cg-step;
    position: relative;
    padding: 0 0 20px 46px;
    border-left: 1px solid var(--cg-rule);
    margin-left: 13px;
}

.cg-steps li:last-child { border-left-color: transparent; padding-bottom: 0; }

.cg-steps li::before {
    content: counter(cg-step);
    position: absolute;
    left: -13px;
    top: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    background: var(--cg-ink);
    color: var(--cg-chalk);
    font-size: 13px;
    font-weight: 600;
    display: flex;
    align-items: center;
    justify-content: center;
}

.cg-steps p { margin: 0; font-size: 16px; line-height: 1.6; color: var(--mt-soft); max-width: 62ch; }

/* Reference tables ------------------------------------------------------- */

.cg-ref__tables { display: flex; flex-wrap: wrap; gap: 26px; }

/* min-width:0 is the fix, not the flex basis: without it a flex item refuses
   to shrink below its content and a four-column chart pushes a 320 px screen
   sideways. The table scrolls inside its own box; the page never does. */
.cg-ref__table {
    flex: 1 1 260px;
    min-width: 0;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

.cg-ref__table h3 { margin-bottom: 10px; }

.cg-ref table { width: 100%; border-collapse: collapse; font-size: 15px; }

.cg-ref th {
    text-align: left;
    font-weight: 600;
    padding: 8px 10px;
    border-bottom: 2px solid var(--cg-ink);
    color: var(--mt-ink);
}

.cg-ref td {
    padding: 8px 10px;
    border-bottom: 1px solid var(--cg-rule);
    color: var(--mt-ink);
}

.cg-ref tr:nth-child(even) td { background: rgba(23, 20, 43, 0.03); }

.cg-ref__note { font-size: 15px; color: var(--mt-soft); margin: 16px 0 0; max-width: 68ch; }

/* ChordIQ block ---------------------------------------------------------- */

/* A contained card, never a bare band: the tool layout gives sections no
   horizontal padding, so the block brings its own. One brand gesture — the
   five staff lines running off the top-right corner — and nothing else. */
.cg-app {
    position: relative;
    overflow: hidden;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    column-gap: 40px;
    background: var(--cg-ink);
    color: var(--cg-chalk);
    padding: clamp(26px, 5vw, 52px);
    border-radius: 24px;
}

.cg-app::before {
    content: "";
    position: absolute;
    top: clamp(26px, 5vw, 52px);
    right: 0;
    width: 38%;
    height: 41px;
    background: repeating-linear-gradient(to bottom, rgba(244, 242, 255, 0.16) 0 1px, transparent 1px 10px);
    -webkit-mask-image: linear-gradient(to right, transparent, #000 70%);
    mask-image: linear-gradient(to right, transparent, #000 70%);
    pointer-events: none;
}

.cg-app > * { position: relative; grid-column: 1 / -1; min-width: 0; }

.cg-app h2 {
    color: var(--cg-chalk);
    max-width: 18ch;
    margin: 0 0 16px;
    font-size: clamp(26px, 3.4vw, 36px);
    line-height: 1.12;
    text-wrap: balance;
}

.cg-app p { font-size: 17px; line-height: 1.6; color: rgba(244, 242, 255, 0.78); max-width: 58ch; margin: 0; }

.cg-app__list { list-style: none; margin: 28px 0 26px; padding: 0; border-top: 1px solid rgba(255, 255, 255, 0.1); }

@media (min-width: 720px) {
    .cg-app__list { columns: 2; column-gap: 40px; }
    .cg-app__list li { break-inside: avoid; }
}

.cg-app__list li {
    padding: 11px 0 11px 22px;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
    font-size: 16px;
    line-height: 1.5;
    position: relative;
    color: rgba(244, 242, 255, 0.86);
}

.cg-app__list li::before {
    content: "";
    position: absolute;
    left: 0;
    top: 19px;
    width: 8px;
    height: 8px;
    border-radius: 2px;
    background: var(--cg-spark);
}

.cg-app .app-list { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 26px; }
.cg-app .app-list a { display: inline-block; width: 156px; height: 53px; border-radius: 9px; transition: transform 0.15s ease; }
.cg-app .app-list a:hover { transform: translateY(-2px); }
.cg-app .app-list a:focus-visible { outline: 2px solid var(--cg-spark); outline-offset: 3px; }
.cg-app .app-list img { width: 100%; height: 100%; display: block; }

/* The QR code (chordiq-apps.jade shows it on desktop only) is for the phone in
   the visitor's other hand: a white tile beside the heading, not a stray image
   under the badges. */
.cg-app > .visible-md.visible-lg {
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: start;
    justify-self: end;
    padding: 10px;
    background: #fff;
    border-radius: 16px;
    line-height: 0;
}
.cg-app > .visible-md.visible-lg img { width: 112px !important; height: 112px; margin: 0 !important; display: block; }

@media (min-width: 992px) {
    .cg-app { grid-template-columns: minmax(0, 1fr) auto; }
    .cg-app > h2, .cg-app > h2 + p { grid-column: 1; }
    .cg-app::before { display: none; }
}

@media (prefers-reduced-motion: reduce) {
    .cg-app .app-list a { transition: none; }
}

/* FAQ -------------------------------------------------------------------- */

.cg-faq__item { padding: 20px 0; border-top: 1px solid var(--cg-rule); }
.cg-faq__item:last-child { border-bottom: 1px solid var(--cg-rule); }
.cg-faq__item h3 { font-size: 18px; margin-bottom: 8px; }
.cg-faq__item p { font-size: 16px; line-height: 1.65; color: var(--mt-soft); margin: 0; max-width: 68ch; }

/* Sibling grid and tool links -------------------------------------------- */

/* Separate cards with real gaps. The earlier hairline grid painted its own
   background through a 2px gap, so a row that was not full (4 cards in 3
   columns) showed a grey slab where the missing cards would be. */
.cg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: 14px; }
.cg-grid > .cg-card { border: 1px solid var(--cg-rule); border-radius: 14px; }
.cg-grid + p { margin: 16px 0 0; }
.cg-grid + p a { font-weight: 600; }

.cg-card {
    display: block;
    background: var(--mt-card);
    padding: 22px 20px;
    text-decoration: none;
    color: inherit;
}

.cg-card:hover { background: var(--mt-accent-soft); text-decoration: none; }

.cg-card__skill { display: block; font-size: 12px; color: var(--mt-accent); margin-bottom: 6px; }
.cg-card__name { display: block; font-family: var(--cg-display); font-size: 22px; line-height: 1.2; color: var(--mt-ink); margin-bottom: 6px; }
.cg-card__line { display: block; font-size: 15px; line-height: 1.5; color: var(--mt-soft); }

/* Accessibility, inside the games' own scope only.
   1. The bare links in these sections inherit the site link colour (#d15844),
      which is 4.05:1 on white — under the 4.5 AA floor for 16 px text. The
      tool accent is 6.3:1.
   2. The hub card is ink-on-ink for any text not inside a coloured span: the
      card used to sit in the grid and inherit the grid's ground. */
.mt-page #more-games a:not(.cg-card),
.mt-page .cg-share__body a,
.mt-page .cg-links a { color: var(--mt-accent); }

.cg-card--hub { background: var(--cg-ink); color: var(--cg-chalk); }
.cg-card--hub:hover { background: var(--cg-ink-2); }
.cg-card--hub .cg-card__name { color: var(--cg-chalk); }
.cg-card--hub .cg-card__line { color: rgba(244, 242, 255, 0.7); }
.cg-card--hub .cg-card__skill { color: var(--cg-spark); }

/* Out of the games grid, so the section "More free music games" holds games
   only. It keeps the card look; it just stands on its own. */
.cg-card--standalone { margin-top: 18px; border-radius: 12px; }

.cg-links { list-style: none; margin: 0; padding: 0; }

.cg-links li { padding: 14px 0; border-bottom: 1px solid var(--cg-rule); }
.cg-links a { font-size: 17px; font-weight: 500; color: var(--mt-accent); }
.cg-links span { display: block; font-size: 15px; color: var(--mt-soft); margin-top: 3px; max-width: 62ch; }

/* ---------------------------------------------------------------- mobile */

@media (max-width: 560px) {
    .cg-hero { padding-top: 88px; }
    .cg-board { border-radius: 18px; padding: 14px 12px 20px; }
    .cg-ref__tables { gap: 20px; }
    .cg-ref th, .cg-ref td { padding: 8px 6px; font-size: 14px; }
    .cg-answers { gap: 4px; }
    .cg-answer { font-size: 18px; min-height: 56px; border-radius: 10px; }
    .cg-result__stats { gap: 16px; }
    .cg-result__score { font-size: 62px; }
    .cg-stage, .cg-screen { min-height: 300px; }
    #cg-board { min-height: 370px; }
    .cg-hero__badges .app-list a { width: 126px; height: 44px; }
}

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

/* ---------------------------------------------------------------- embed */

/* The chrome-less page at /:lang/games/<slug>/embed, and the block on the full
   page that hands out its snippet. The embed is deliberately plain: the game,
   the notation switch where the locale needs one, and one bar of attribution. */

.cg-embed__notation { margin-bottom: 8px; }

/* The bar carries its own white ground because the embed body is transparent:
   the host page could be any colour, and the wordmark has to clear 7:1 on
   whatever is behind it in every state. Black on white is 18:1. */
.cg-embed__bar {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 8px;
    padding: 7px 12px;
    border-radius: 10px;
    background: #ffffff;
    font-size: 13px;
}

.cg-embed__brand { display: inline-flex; align-items: center; text-decoration: none; }

/* The Songtive wordmark, set the way the site header sets it. Solid ink, full
   opacity — never a grey tint and never an opacity trick. */
.cg-embed__wordmark {
    font-family: 'Lobster Two', Georgia, 'Times New Roman', serif;
    font-style: italic;
    font-size: 21px;
    line-height: 22px;
    color: #111111;
}

.cg-embed__brand:hover .cg-embed__wordmark { color: #000000; text-decoration: none; }

.cg-embed__title { color: #3a3a44; text-decoration: none; }
.cg-embed__title:hover { color: var(--mt-accent); text-decoration: underline; }

/* The "put this on your own site" block. */
.cg-share { border: 1px solid var(--cg-rule); border-radius: 12px; padding: 0; }
.cg-share > summary {
    cursor: pointer;
    padding: 14px 16px;
    font-weight: 600;
    list-style: none;
}
.cg-share > summary::-webkit-details-marker { display: none; }
.cg-share > summary::before { content: "+ "; color: var(--mt-accent); }
.cg-share[open] > summary::before { content: "\2013 "; }
.cg-share__body { padding: 0 16px 16px; }
.cg-share__body p { font-size: 15px; line-height: 1.6; color: var(--mt-soft); max-width: 62ch; }
.cg-share__label { display: block; font-size: 13px; color: var(--mt-soft); margin-bottom: 6px; }
.cg-share__code {
    width: 100%;
    min-height: 92px;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12px;
    line-height: 1.5;
    padding: 10px;
    border: 1px solid var(--cg-rule);
    border-radius: 8px;
    background: var(--mt-bg);
    color: var(--mt-ink);
    resize: vertical;
    box-sizing: border-box;
}
.cg-share__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; margin-top: 10px; }
.cg-share__copy {
    appearance: none;
    border: 0;
    background: var(--mt-accent);
    color: #fff;
    font-family: inherit;
    font-size: 15px;
    font-weight: 600;
    padding: 10px 18px;
    min-height: 44px;
    border-radius: 8px;
    cursor: pointer;
}
.cg-share__said { font-size: 14px; color: var(--cg-right); min-height: 1.2em; }

/* ------------------------------------------------- inside the tool layout */

.mt-page .cg-badges { margin: 14px 0 0; }
.mt-page .cg-badges .app-list { display: flex; flex-wrap: wrap; gap: 10px; }
.mt-page .cg-badges .app-list a { display: inline-block; width: 132px; height: 45px; }
.mt-page .cg-badges .app-list img { width: 100%; height: 100%; }

.mt-page .cg-board-wrap { max-width: 640px; }

.mt-page .cg-notation { display: flex; align-items: center; gap: 10px; margin: 0 0 12px; font-size: 14px; }
.mt-page .cg-notation select { padding: 6px 8px; border: 1px solid var(--mt-rule); border-radius: 8px; background: var(--mt-card); font-size: 14px; min-height: 40px; }

/* ===========================================================================
   Piano Note Game — /:lang/games/piano-notes
   ---------------------------------------------------------------------------
   The sibling page Note Rush answers with flat name pills; this one answers on
   the instrument, so the keyboard is the piece with weight: a felt strip, keys
   with depth, and a press that travels. Everything above it stays flat and
   quiet — one prompt, one caption — so the eye goes prompt -> keys and nowhere
   else. The keys carry no letters: the whole point is finding them by place.
   =========================================================================== */

.cg-pianonotes { width: 100%; }

.cg-pianonotes__clef {
    text-align: center;
    font-size: 13px;
    color: var(--cg-chalk-dim);
    margin: 0 0 2px;
    min-height: 1.3em;
}

/* One box for both prompts, so the keyboard never moves between levels. */
.cg-pianonotes__target {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 146px;
    margin-bottom: 4px;
}

.cg-pianonotes__name {
    font-family: var(--cg-display);
    font-size: clamp(56px, 17vw, 88px);
    line-height: 1;
    margin: 0;
    color: var(--cg-spark);
    display: flex;
    align-items: baseline;
    justify-content: center;
    gap: 0.04em;
}

/* The music font puts a sharp or a flat on a far taller em box than the
   display serif, so the mark is set down to match the letter beside it. */
.cg-pianonotes__acc {
    font-size: 0.58em;
    line-height: 1;
    align-self: center;
}

.cg-pianonotes__staff { width: 100%; max-width: 330px; margin: 0 auto; }

.cg-pianonotes[data-mode="name"] .cg-pianonotes__staff { display: none; }
.cg-pianonotes[data-mode="staff"] .cg-pianonotes__name { display: none; }

.cg-pianonotes__find {
    text-align: center;
    font-size: 13px;
    color: var(--cg-chalk-dim);
    margin: 0 0 12px;
}

.cg-pianonotes__hint {
    text-align: center;
    font-size: 12px;
    color: var(--cg-chalk-dim);
    margin: 12px 0 0;
    min-height: 1.4em;
}

/* The instrument ---------------------------------------------------------
   Wide levels do not fit a phone at a thumb-sized key, so the keyboard scrolls
   inside this frame rather than shrinking below a tappable width. */

.cg-pianonotes__keys {
    width: 100%;
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    padding-bottom: 4px;
    scrollbar-width: thin;
    scrollbar-color: rgba(244, 242, 255, 0.35) transparent;
}

.cg-pianonotes__keys::-webkit-scrollbar { height: 6px; }
.cg-pianonotes__keys::-webkit-scrollbar-track { background: transparent; }
.cg-pianonotes__keys::-webkit-scrollbar-thumb { background: rgba(244, 242, 255, 0.3); border-radius: 3px; }

/* --cg-pn-whites is set by the game: the keyboard is that many keys wide. */
.cg-pianonotes .cg-keys {
    width: 100%;
    max-width: none;
    padding-top: 9px;
    border-radius: 10px 10px 13px 13px;
    background: linear-gradient(180deg, var(--cg-ink-3) 0%, #1a1733 72%);
    box-shadow:
        inset 0 2px 0 rgba(109, 99, 242, 0.55),
        0 12px 24px -14px rgba(0, 0, 0, 0.95);
}

/* The black row is absolute against .cg-keys, so it needs the felt height too. */
.cg-pianonotes .cg-keys__blacks { top: 9px; }

.cg-pianonotes .cg-key--white {
    position: relative;
    height: 128px;
    background: linear-gradient(180deg, #fbfaff 0%, #eae7f8 100%);
    border-color: #b7b1d6;
    box-shadow: inset 0 -8px 10px -8px rgba(23, 20, 43, 0.4);
    transition: transform 0.07s ease, background 0.12s ease;
}

.cg-pianonotes .cg-key--black {
    background: linear-gradient(180deg, #3b3569 0%, #17142b 78%);
    box-shadow: 0 3px 0 #0b0919, 0 7px 12px -4px rgba(0, 0, 0, 0.65);
    transition: transform 0.07s ease, background 0.12s ease;
    z-index: 2;
}

/* A black key is narrower than a thumb, so its hit area reaches past its ink.
   -7px is as far as it can go: two black keys a white apart are 45px between
   centres at phone size and 27px of ink, so -9 would make them touch and the
   miss would land on the wrong black key instead of on a white one. The result
   is 41 x 94, short of 44 across but generous down, which is the axis a thumb
   on a keyboard is imprecise in. */
.cg-pianonotes .cg-key--black::after {
    content: "";
    position: absolute;
    inset: 0 -7px -12px -7px;
}

.cg-pianonotes .cg-key--white:active { transform: translateY(3px); background: #e3dff5; }
.cg-pianonotes .cg-key--black:active {
    transform: translateY(3px);
    box-shadow: 0 0 0 #0b0919, 0 4px 8px -5px rgba(0, 0, 0, 0.6);
}

/* Middle C: the one key the staff levels name for you. */
.cg-pianonotes .cg-key--landmark::before {
    content: "";
    position: absolute;
    bottom: 11px;
    left: 50%;
    margin-left: -4px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--cg-accent);
    box-shadow: 0 0 0 3px rgba(109, 99, 242, 0.22);
}

/* Verdicts. Right lands, wrong shakes once, and the key that was wanted
   breathes twice — the miss is the teaching moment, so it gets the motion. */
.cg-pianonotes .cg-key.is-right {
    background: var(--cg-right);
    border-color: transparent;
    animation: cg-pn-land 0.34s ease-out;
}

.cg-pianonotes .cg-key.is-wrong {
    background: var(--cg-wrong);
    border-color: transparent;
    animation: cg-pn-miss 0.3s ease-out;
}

.cg-pianonotes .cg-key.is-answer {
    background: var(--cg-spark);
    border-color: transparent;
    box-shadow: 0 0 22px -2px rgba(255, 194, 71, 0.7);
    animation: cg-pn-wanted 0.45s ease-in-out 2;
}

@keyframes cg-pn-land {
    from { transform: translateY(4px); filter: brightness(1.55); }
    to { transform: none; filter: none; }
}

@keyframes cg-pn-miss {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-3px); }
    75% { transform: translateX(3px); }
}

@keyframes cg-pn-wanted {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.45; }
}

/* With a mouse a narrower key is still easy to hit, so the widest level fits a
   desktop board whole rather than scrolling. */
@media (min-width: 561px) {
    .cg-pianonotes .cg-key--white { min-width: 26px; }
}

@media (max-width: 560px) {
    /* The instrument reaches into the board's own padding, the way the sight
       reading keyboard does: the board clips its overflow, so nothing spills,
       and the eight keys of a one-octave level gain 24 px between them. */
    .cg-pianonotes__keys {
        width: calc(100% + 24px);
        margin: 0 -12px;
        padding-left: 0;
        padding-right: 0;
    }

    /* Thumb-sized keys win over fitting the screen; the frame scrolls instead.
       44px is the floor — the target size a thumb needs — and a one-octave
       level still fits a 360px phone whole at it (8 x 44 = 352 of the 360 the
       board now spans). The wider levels scroll, and the hint says so. */
    .cg-pianonotes .cg-keys { min-width: calc(var(--cg-pn-whites, 8) * 44px); }
    .cg-pianonotes .cg-key--white { height: 138px; }
    .cg-pianonotes__target { min-height: 128px; }
    .cg-pianonotes__name { font-size: clamp(48px, 19vw, 74px); }
    .cg-pianonotes__staff { max-width: 290px; }
}

/* A 320px screen, or a 320px embed frame, cannot hold eight keys at the floor
   above. Scrolling the entry level would be worse than slightly narrower keys,
   so the floor drops just enough for one octave to fit whole. */
@media (max-width: 340px) {
    .cg-pianonotes .cg-keys { min-width: calc(var(--cg-pn-whites, 8) * 39px); }
}

/* Ear Trainer ------------------------------------------------------------
   The one board in the family with nothing to read. The question is sound,
   so the stage is a listening field: a chalk ring that swells on every note
   onset, and one dot per sound event under it — how many sounds, and which
   one is happening, is all a player may know before answering. Pitch is
   never drawn until the answer, where the notes are spelled out and lit on
   a deliberately dim keyboard. Nothing else on the board moves. */

.cg-eartraining {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 14px;
}

.cg-eartraining .cg-ear__sense {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.cg-eartraining .cg-ear__ring { width: 104px; height: 104px; display: block; overflow: visible; }

.cg-eartraining .cg-ear__ring-core {
    fill: rgba(244, 242, 255, 0.05);
    stroke: var(--cg-chalk-dim);
    stroke-width: 1.4;
    transition: fill 0.2s ease, stroke 0.2s ease;
}

.cg-eartraining .cg-ear__ring-edge {
    fill: none;
    stroke: rgba(244, 242, 255, 0.16);
    stroke-width: 1.2;
    stroke-dasharray: 2 7;
    stroke-linecap: round;
}

.cg-eartraining .cg-ear__ring-pulse {
    fill: none;
    stroke: var(--cg-spark);
    stroke-width: 1.6;
    opacity: 0;
    transform-box: fill-box;
    transform-origin: center;
}

.cg-eartraining .cg-ear__ring.is-sounding .cg-ear__ring-core {
    fill: rgba(255, 194, 71, 0.14);
    stroke: var(--cg-spark);
}

.cg-eartraining .cg-ear__ring.is-sounding .cg-ear__ring-pulse {
    animation: cg-ear-pulse 1.1s ease-out infinite;
}

@keyframes cg-ear-pulse {
    0% { transform: scale(1); opacity: 0.55; }
    100% { transform: scale(1.75); opacity: 0; }
}

.cg-eartraining .cg-ear__ticks { display: flex; gap: 9px; min-height: 9px; }

.cg-eartraining .cg-ear__tick {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    border: 1px solid var(--cg-chalk-dim);
    transition: background 0.12s ease, border-color 0.12s ease;
}

.cg-eartraining .cg-ear__tick.is-on { background: var(--cg-spark); border-color: var(--cg-spark); }

.cg-eartraining .cg-ear__status {
    margin: 0;
    font-size: 13px;
    color: var(--cg-chalk-dim);
    min-height: 1.3em;
}

/* Replaying is free, so the control that does it is the biggest thing here. */
.cg-eartraining .cg-ear__replay {
    appearance: none;
    display: inline-flex;
    align-items: center;
    gap: 10px;
    font-family: inherit;
    font-size: 16px;
    font-weight: 500;
    color: var(--cg-chalk);
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid rgba(244, 242, 255, 0.28);
    padding: 0 26px;
    min-height: 52px;
    border-radius: 26px;
    cursor: pointer;
}

.cg-eartraining .cg-ear__replay::before {
    content: "";
    width: 0;
    height: 0;
    border-left: 9px solid var(--cg-spark);
    border-top: 6px solid transparent;
    border-bottom: 6px solid transparent;
}

.cg-eartraining .cg-ear__replay:hover { background: rgba(255, 255, 255, 0.14); }
.cg-eartraining .cg-ear__replay[disabled] { opacity: 0.4; cursor: default; }

.cg-eartraining .cg-answers {
    width: 100%;
    grid-template-columns: repeat(auto-fit, minmax(98px, 1fr));
    gap: 6px;
}

.cg-eartraining .cg-ear__answer {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-height: 52px;
    padding: 8px 4px;
    font-size: 15px;
    font-weight: 500;
    line-height: 1.2;
}

.cg-eartraining .cg-ear__key { font-size: 10px; opacity: 0.55; font-variant-numeric: tabular-nums; }
.cg-eartraining .cg-ear__name { font-size: 15px; }

/* The teaching moment: what it was, and where it lives. */
.cg-eartraining .cg-ear__reveal {
    min-height: 56px;
    text-align: center;
}

.cg-eartraining .cg-ear__reveal-name {
    margin: 0;
    font-family: var(--cg-display);
    font-size: 24px;
    line-height: 1.2;
    color: var(--cg-chalk);
}

.cg-eartraining .cg-ear__reveal-notes {
    margin: 2px 0 0;
    font-size: 15px;
    letter-spacing: 0.04em;
    color: var(--cg-spark);
}

.cg-eartraining .cg-ear__keys { max-width: 100%; }

.cg-eartraining .cg-key--white {
    min-width: 0;
    height: 62px;
    background: rgba(244, 242, 255, 0.12);
    border: 1px solid rgba(244, 242, 255, 0.2);
    cursor: default;
}

.cg-eartraining .cg-keys__blacks { height: 38px; }

.cg-eartraining .cg-key--black {
    height: 38px;
    background: rgba(9, 7, 20, 0.72);
    border-color: rgba(244, 242, 255, 0.14);
    cursor: default;
}

.cg-eartraining .cg-key.is-on {
    background: var(--cg-spark);
    border-color: var(--cg-spark);
    box-shadow: 0 0 14px rgba(255, 194, 71, 0.5);
}

.cg-eartraining .cg-ear__hint {
    margin: 0;
    text-align: center;
    font-size: 12px;
    color: var(--cg-chalk-dim);
}

@media (max-width: 560px) {
    .cg-eartraining { gap: 12px; }
    .cg-eartraining .cg-ear__ring { width: 88px; height: 88px; }
    .cg-eartraining .cg-answers { grid-template-columns: repeat(auto-fit, minmax(88px, 1fr)); }
    .cg-eartraining .cg-ear__reveal-name { font-size: 21px; }
    .cg-eartraining .cg-key--white { height: 54px; }
    .cg-eartraining .cg-keys__blacks,
    .cg-eartraining .cg-key--black { height: 33px; }
}

@media (prefers-reduced-motion: reduce) {
    /* The ring still says a sound is happening; it just stops moving. */
    .cg-eartraining .cg-ear__ring.is-sounding .cg-ear__ring-pulse {
        animation: none;
        opacity: 0.5;
    }
}

/* Sight Reading Trainer -----------------------------------------------------
   /:lang/games/sight-reading. The other boards ask about one note, so the note
   is the loud thing on them. Here the subject is a LINE, and the only thing
   that may move is the reading position: a caret travelling under the staff
   along a quiet track that spans the phrase. The note heads say the rest by
   temperature alone — chalk ahead of you, warm where you are, faded behind
   you, red where it went wrong — so nothing on the keyboard ever gives the
   next key away, which is the whole exercise.
   -------------------------------------------------------------------------- */

.cg-sightreading {
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
}

.cg-sightreading__clef {
    margin: 0 0 2px;
    min-height: 1.3em;
    font-size: 13px;
    letter-spacing: 0.01em;
    color: var(--cg-chalk-dim);
}

/* Same width as the keyboard below it: the phrase and the keys you play it
   on should read as one instrument, not two stacked widgets. */
.cg-sightreading__staff {
    width: 100%;
    max-width: 460px;
    margin: 0 auto;
}

/* Unread notes are plain chalk; the spark is spent on where you are. The
   accidental in front of a head carries the same class from the core, so the
   state colours are kept off it — a sharp is part of the notation, not part of
   how the read is going. Stems are scaffolding for the same reason. */
.cg-sightreading__head:not(.cg-staff__accidental) { fill: var(--cg-chalk); }
.cg-sightreading__head.is-done { fill: rgba(244, 242, 255, 0.3); }
.cg-sightreading__head.is-now { fill: var(--cg-spark); }
.cg-sightreading__head.is-miss { fill: var(--cg-wrong); }

.cg-sightreading .cg-staff__stem { stroke: rgba(244, 242, 255, 0.5); }

/* The extent of the phrase, drawn once and then left alone. Dotted, because a
   solid rule under a staff reads as a ledger line. */
.cg-sightreading__track {
    stroke: rgba(244, 242, 255, 0.26);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-dasharray: 0.1 6;
    transition: opacity 0.2s ease;
}

/* The one moving part on the board. */
.cg-sightreading__caret {
    fill: var(--cg-spark);
    opacity: 0;
    transition: transform 0.13s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.15s ease;
}

.cg-sightreading__caret.is-live { opacity: 1; }

.cg-sightreading__verdict {
    margin: 6px 0 14px;
    min-height: 1.5em;
    font-family: var(--cg-display);
    font-size: 18px;
    line-height: 1.3;
    color: var(--cg-chalk-dim);
}

.cg-sightreading__verdict.is-right { color: var(--cg-right); }
.cg-sightreading__verdict.is-wrong { color: var(--cg-wrong); }

.cg-sightreading .cg-keys { max-width: 460px; }

.cg-sightreading .cg-key--white { height: 124px; }

/* Two dots an octave apart: enough to place a hand, and no note name — a
   labelled keyboard would answer the question the staff is asking. */
.cg-sightreading .cg-key--white.is-anchor::after {
    content: "";
    width: 7px;
    height: 7px;
    margin-bottom: 13px;
    border-radius: 50%;
    background: #b9b2d8;
}

.cg-sightreading .cg-key.is-right::after,
.cg-sightreading .cg-key.is-wrong::after { background: rgba(0, 0, 0, 0.35); }

.cg-sightreading__hint {
    margin: 12px 0 0;
    text-align: center;
    font-size: 12px;
    color: var(--cg-chalk-dim);
}

@media (max-width: 560px) {
    /* The staff takes the board's padding for the same reason the keys do: the
       drawing is scaled to its box, so 24 px of width is 7% on every note head,
       ledger line and accidental on the phrase. */
    .cg-sightreading__staff {
        max-width: none;
        width: calc(100% + 24px);
        margin: 0 -12px;
    }
    .cg-sightreading__verdict { font-size: 16px; margin: 4px 0 10px; }
    /* Reach into the board's own padding: eight white keys across a 360 px
       phone are 43 px otherwise, and a key you play a phrase on has to clear
       44. The board clips its overflow, so nothing spills. */
    .cg-sightreading .cg-keys {
        width: calc(100% + 24px);
        margin: 0 -12px;
    }
    .cg-sightreading .cg-key--white { height: 104px; }
    .cg-sightreading .cg-keys__blacks,
    .cg-sightreading .cg-key--black { height: 64px; }
    .cg-sightreading .cg-key--white.is-anchor::after { margin-bottom: 10px; }
}

/* Chord Recognition ------------------------------------------------------ */
/*
   Note Rush asks about one note, so its board reads across: a staff and a row
   of single letters. A chord is a STACK, so this board reads up. The notes
   arrive from the bass upwards, and the four answers sit in a block of two by
   two, because a chord symbol is a word and not a letter. There is one piece
   of motion and it never fires on its own: the ring opens when the chord
   sounds, which is the only moment on this board worth looking up for.
*/

.cg-chordrecognition {
    width: 100%;
    --cg-cr-ring: rgba(255, 194, 71, 0.34);
}

.cg-chordrecognition__tag {
    text-align: center;
    font-size: 13px;
    color: var(--cg-chalk-dim);
    margin: 0 0 4px;
    min-height: 1.3em;
}

.cg-chordrecognition__show {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 176px;
}

.cg-chordrecognition__bloom {
    position: absolute;
    left: 50%;
    top: 50%;
    width: 190px;
    height: 190px;
    margin: -95px 0 0 -95px;
    border-radius: 50%;
    border: 2px solid var(--cg-cr-ring);
    opacity: 0;
    pointer-events: none;
}

.cg-chordrecognition__bloom.is-on {
    animation: cg-cr-bloom 720ms cubic-bezier(0.2, 0.7, 0.3, 1) 1;
}

@keyframes cg-cr-bloom {
    from { opacity: 0.85; transform: scale(0.55); }
    to   { opacity: 0;    transform: scale(1.35); }
}

.cg-chordrecognition__staff {
    position: relative;
    width: 100%;
    max-width: 360px;
    margin: 0 auto;
}

/* The keyboard is level 1 only, so it stays out of the flow until asked for. */
.cg-chordrecognition__keys { display: none; }
.cg-chordrecognition[data-display="keys"] .cg-chordrecognition__keys {
    display: flex;
    position: relative;
    width: 100%;
    justify-content: center;
}
.cg-chordrecognition[data-display="keys"] .cg-chordrecognition__staff { display: none; }

.cg-chordrecognition .cg-keys { max-width: 470px; }
.cg-chordrecognition .cg-key--white { min-width: 0; height: 112px; }
.cg-chordrecognition .cg-keys__blacks,
.cg-chordrecognition .cg-key--black { height: 70px; }

/* Bass note first, then the chord builds on top of it. */
.cg-chordrecognition__head { animation: cg-cr-stack 260ms ease-out both; }
.cg-chordrecognition__head:nth-of-type(2) { animation-delay: 70ms; }
.cg-chordrecognition__head:nth-of-type(3) { animation-delay: 140ms; }
.cg-chordrecognition__head:nth-of-type(4) { animation-delay: 210ms; }

@keyframes cg-cr-stack {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.cg-chordrecognition__head.is-right { fill: var(--cg-right); }
.cg-chordrecognition__head.is-wrong { fill: var(--cg-wrong); }

.cg-chordrecognition__hear {
    display: block;
    margin: 6px auto 14px;
    appearance: none;
    border: 1px solid rgba(255, 255, 255, 0.2);
    background: rgba(255, 255, 255, 0.06);
    color: var(--cg-chalk-dim);
    font-family: inherit;
    font-size: 14px;
    min-height: 44px;
    padding: 0 22px;
    border-radius: 22px;
    cursor: pointer;
}

.cg-chordrecognition__hear:hover {
    color: var(--cg-chalk);
    background: rgba(255, 255, 255, 0.12);
}

.cg-chordrecognition__answers {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
}

.cg-chordrecognition__answer {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    appearance: none;
    border: 1px solid rgba(255, 255, 255, 0.16);
    background: rgba(255, 255, 255, 0.07);
    color: var(--cg-chalk);
    font-family: inherit;
    min-height: 66px;
    padding: 12px 10px;
    border-radius: 12px;
    cursor: pointer;
    transition: background 0.1s ease;
}

.cg-chordrecognition__answer:hover { background: rgba(255, 255, 255, 0.14); }
.cg-chordrecognition__answer[disabled] { cursor: default; }

/* The digit is the key that answers, not an ornament. */
.cg-chordrecognition__key {
    position: absolute;
    left: 9px;
    top: 7px;
    font-size: 11px;
    line-height: 1;
    color: var(--cg-chalk-dim);
    font-variant-numeric: tabular-nums;
}

.cg-chordrecognition__symbol {
    font-family: var(--cg-display);
    font-size: 25px;
    line-height: 1.15;
    text-align: center;
    word-break: break-word;
}

.cg-chordrecognition__answer.is-right { background: var(--cg-right); color: #08240f; border-color: transparent; }
.cg-chordrecognition__answer.is-wrong { background: var(--cg-wrong); color: #3d0713; border-color: transparent; }
.cg-chordrecognition__answer.is-answer { background: var(--cg-chalk); color: var(--cg-ink); border-color: transparent; }

.cg-chordrecognition__answer.is-right .cg-chordrecognition__key,
.cg-chordrecognition__answer.is-wrong .cg-chordrecognition__key,
.cg-chordrecognition__answer.is-answer .cg-chordrecognition__key { color: inherit; opacity: 0.55; }

.cg-chordrecognition__hint {
    text-align: center;
    font-size: 12px;
    color: var(--cg-chalk-dim);
    margin: 12px 0 0;
}

@media (max-width: 560px) {
    .cg-chordrecognition__show { min-height: 152px; }
    .cg-chordrecognition__bloom { width: 150px; height: 150px; margin: -75px 0 0 -75px; }
    .cg-chordrecognition__answers { gap: 6px; }
    .cg-chordrecognition__answer { min-height: 58px; border-radius: 10px; }
    .cg-chordrecognition__symbol { font-size: 21px; }
    .cg-chordrecognition__hear { min-height: 44px; font-size: 13px; }
    .cg-chordrecognition .cg-key--white { height: 88px; }
    .cg-chordrecognition .cg-keys__blacks,
    .cg-chordrecognition .cg-key--black { height: 55px; }
}

@media (prefers-reduced-motion: reduce) {
    /* The shared rule shortens the animation but not the stagger, which would
       leave the upper notes blank for a fifth of a second. */
    .cg-chordrecognition__head { animation-delay: 0s !important; }
}

/* ===========================================================================
   ===== MOBILE PASS (shared) =====
   ---------------------------------------------------------------------------
   Most of the traffic is a thumb on a 360 px screen, and the thing that has to
   land is the store badge on the result screen. Everything below is written
   for that and then let out to wider screens only where it does no harm.

   It sits LAST on purpose: every rule here wins on order, so no earlier block
   had to be edited to make room for it. Read it as one layer, not as patches.
   =========================================================================== */

/* 1 ------------------------------------------------------------- touch feel
   A control on a game board is tapped, never read, selected or long-pressed.
   `manipulation` is what removes the double-tap-zoom wait; the rest removes
   the grey flash, the selection handles and the iOS callout menu. */

.cg-board,
.cg-board button,
.cg-key,
.cg-level,
.cg-cta,
.cg-link-btn {
    touch-action: manipulation;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

/* A keyboard is played with fast repeated taps, and a tap that drifts a few
   pixels must not turn into a page scroll half way through a phrase. These
   three boards never scroll, so they take the gesture outright. */
.cg-sightreading .cg-keys,
.cg-chordrecognition .cg-keys,
.cg-eartraining .cg-keys { touch-action: none; }

/* The one board that does scroll keeps exactly one axis: sideways moves the
   instrument, downwards does nothing, a tap plays. */
.cg-pianonotes__keys,
.cg-pianonotes .cg-keys,
.cg-pianonotes .cg-key { touch-action: pan-x; }

/* A flick that runs out inside the board stops there. */
.cg-board { overscroll-behavior: contain; }

/* The press, seen before it is heard. The core's own buttons had no pressed
   state at all, so on a phone a tap looked like nothing until the verdict
   came back — about 300 ms of silence on the control the round is made of. */
.cg-cta:active,
.cg-level:active,
.cg-answer:not([disabled]):active,
.cg-chordrecognition__answer:not([disabled]):active,
.cg-chordrecognition__hear:active,
.cg-ear__answer:not([disabled]):active,
.cg-ear__replay:not([disabled]):active {
    transform: translateY(1px) scale(0.985);
}

.cg-answer:not([disabled]):not(.is-right):not(.is-wrong):not(.is-answer):active,
.cg-chordrecognition__answer:not([disabled]):not(.is-right):not(.is-wrong):not(.is-answer):active,
.cg-chordrecognition__hear:active,
.cg-ear__replay:not([disabled]):active {
    background: rgba(255, 255, 255, 0.24);
}

.cg-sightreading .cg-key--white:active,
.cg-chordrecognition .cg-key--white:active { background: #ded9f2; }

/* 1b ------------------------------------------------------------- contrast
   White on --cg-accent measures 4.45:1, and 17px/600 is not large text, so
   the one button the whole page funnels into failed AA by a hair. A slightly
   deeper violet reads the same and measures 4.98:1. The token itself is left
   alone: it also paints lit keys, where it sits under nothing. */

.cg-cta { background: #6559ee; }
.cg-cta:hover { background: #564ae0; }

/* 2 ------------------------------------------------------ the board on a phone */

@media (max-width: 560px) {
    /* The page keeps a 5 px gutter; the board takes it back. Eight white keys
       then measure 45 px across a 360 px screen instead of 43.8 — the
       difference between a key a phrase can be played on and one that cannot.
       The wrap keeps its own ground, so nothing else moves. */
    .mt-page .cg-board {
        margin-left: -5px;
        margin-right: -5px;
        scroll-margin-top: 8px;
    }

    /* The stage no longer reserves 300 px it may not need: on the shortest
       phones that reservation alone pushed the answers off the screen. */
    .cg-stage { min-height: 0; }
}

/* 3 --------------------------------------------------- nothing over the board
   The site's feedback tab (public/scss/_feedback.scss) is pinned to the left
   edge at x 0-62, which is exactly the first white key and, on the result
   screen, the left store badge. A round in play owns the screen. */

/* The core puts `cg-playing` on <body> from start() and takes it off in
   finish(), so this needs no :has() — which Safari 15 and Firefox before 121
   do not have. The widget was changed on 2026-09-21: its "x" now minimises it
   to a small #feedback-handle instead of removing it, so both have to go. */
@media (max-width: 767px) {
    body.cg-playing #feedback,
    body.cg-playing #feedback-handle { display: none; }
}

/* 4 ------------------------------------------------- keyboard advice, on a phone
   "Use the A to K row" and "1 to 4 answer" are true and useless on a touch
   screen, and they cost 25-40 px each at the bottom of the board — the exact
   place the answers need. The one hint that also carries a touch instruction
   (piano-notes says when the instrument scrolls) is left alone. */

@media (pointer: coarse) and (max-width: 767px) {
    .cg-sightreading__hint,
    .cg-chordrecognition__hint,
    .cg-eartraining .cg-ear__hint { display: none; }

    /* Piano Notes writes one of two hints into the same line and labels which:
       "scroll the instrument" stays, "use the computer keyboard" goes. */
    .cg-pianonotes__hint[data-kind="keys"] { display: none; }
}

/* 4b -------------------------------------------- the page never gets wider
   The reference chart is the one block on these pages whose width is set by
   its content. A locale with long words — or a key that has not been
   translated yet, which is what every page but /en shows today — pushed the
   whole document past 360 px and gave the phone a horizontal scroll. The
   chart scrolls inside its own box instead. */

@media (max-width: 767px) {
    .cg-ref__table {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* A single unbreakable word longer than the column — a German compound, a
       chord symbol with a long suffix, or an i18n key on a locale that has not
       been filled in yet — widens the layout viewport for the whole document.
       Breaking it inside its own line is always better than a page that
       scrolls sideways.

       `anywhere`, not `break-word`: only `anywhere` lowers the element's
       min-content width, and min-content is what a grid track and the layout
       viewport are sized from. With `break-word` the sibling-games grid still
       asked for 359 px and Chrome widened the whole document to 388. */
    .mt-page h1,
    .mt-page h2,
    .mt-page h3,
    .cg-prose p,
    .cg-steps p,
    .cg-faq__item p,
    .cg-card__name,
    .cg-card__line,
    .cg-links a,
    .cg-links span,
    .cg-ref th,
    .cg-ref td { overflow-wrap: anywhere; }
}

/* 5 ------------------------------------------------ the result screen converts
   The badges used to sit under the score, the stats, the replay button and the
   level link — about 380 px down a screen that is 640 px tall with browser
   chrome on top. They now come straight after the stats, and the replay button
   drops below them, which is also where the thumb already is. */

@media (max-width: 767px) {
    .cg-screen--result {
        display: flex;
        flex-direction: column;
        align-items: center;
    }

    .cg-result__eyebrow { order: 1; }
    .cg-result__score { order: 2; font-size: 52px; margin: 0 0 2px; }
    .cg-result__stats { order: 3; }
    .cg-result__cta { order: 4; margin-top: 16px; padding-top: 14px; }
    .cg-screen--result .cg-cta { order: 5; margin-top: 16px; }
    .cg-screen--result .cg-link-btn { order: 6; }

    .cg-result__cta p { margin-bottom: 10px; }
    .cg-result__cta .app-list a { width: 148px; height: 50px; }
}

/* The visitor's own store first. `cg-ios` / `cg-android` is set on <html> by
   the game files; without it the order is the one the markup ships with. */
.cg-android .cg-result__cta .app-list { flex-direction: row-reverse; }

/* 6 ------------------------------------------- the ear trainer fits the screen
   Twelve intervals is the widest answer grid in the family, and at 360 px it
   made the board 701 px tall — a round that could not be seen whole on any
   phone. The listening ring, the answer rows, the reveal keyboard and the
   column gaps each give back a little; nothing is removed. */

@media (max-width: 560px) {
    .cg-eartraining { gap: 9px; }
    .cg-eartraining .cg-ear__sense { gap: 7px; }
    .cg-eartraining .cg-ear__ring { width: 62px; height: 62px; }
    .cg-eartraining .cg-ear__replay { min-height: 48px; font-size: 15px; }
    .cg-eartraining .cg-ear__answer { min-height: 48px; padding: 6px 4px; }

    /* 8 px is the smallest gap that stops a thumb catching the neighbour.
       Note Rush's own row of seven is left at 4 px on purpose: eight would
       take its buttons under 44 px wide, and width matters more there. */
    .cg-eartraining .cg-answers,
    .cg-chordrecognition__answers { gap: 8px; }
    .cg-eartraining .cg-ear__reveal { margin: 0; }

    /* Only the twelve-interval level goes to four columns: three would cost a
       fourth row, and four rows is what put this board past the screen. The
       five- and three-answer levels keep three columns, where a wider button
       is worth more than a tighter grid. */
    .cg-eartraining .cg-answers[data-count="12"] {
        grid-template-columns: repeat(4, 1fr);
    }

    .cg-eartraining .cg-key--white { height: 40px; }
    .cg-eartraining .cg-keys__blacks,
    .cg-eartraining .cg-key--black { height: 25px; }
}

/* 7 ------------------------------------------------------ 320 px, and long words
   A locale prints "Verminderte Quinte" where English prints "Tritone", so the
   answer labels are sized to wrap inside the button rather than out of it. */

.cg-ear__name,
.cg-chordrecognition__symbol {
    overflow-wrap: anywhere;
    hyphens: auto;
}

@media (max-width: 360px) {
    .cg-eartraining .cg-ear__name { font-size: 13px; }
    .cg-eartraining .cg-answers[data-count="12"] .cg-ear__name { font-size: 12px; }
    .cg-chordrecognition__symbol { font-size: 19px; }
    .cg-result__cta .app-list a { width: 136px; height: 46px; }
}

/* 8 ------------------------------------------------------------- landscape
   A phone turned sideways has about 350 px of height. The round stays
   playable by losing height everywhere at once rather than by hiding a part
   of itself — a game that drops its answers on rotation is broken, not
   compact. */

@media (orientation: landscape) and (max-height: 460px) {
    /* #cg-board reserves 412 px so the board does not pop in after boot. That
       is the height of the PORTRAIT start screen; sideways it is taller than
       the whole window, and the guard against one problem becomes the cause
       of another. Cap the reservation at the window and let the content win
       where it is taller — the guard still holds, it just stops overreaching.
       Measured sideways at 640x360: start 356, round 284, result 357. */
    #cg-board { min-height: min(412px, calc(100svh - 28px)); }

    .mt-page .cg-board { padding: 10px 12px 14px; }
    .cg-hud { margin-bottom: 6px; }
    .cg-stage,
    .cg-screen { min-height: 0; }
    .cg-screen__blurb { font-size: 14px; margin-bottom: 8px; }

    /* The result screen turns sideways too: the number on the left, the thing
       the page is for on the right, where a thumb holding a sideways phone
       already is. */
    .cg-screen--result {
        display: grid;
        grid-template-columns: 1fr 1fr;
        column-gap: 22px;
        align-items: center;
        justify-items: center;
    }

    .cg-result__eyebrow { grid-column: 1; grid-row: 1; }
    .cg-result__score { grid-column: 1; grid-row: 2; font-size: 38px; }
    .cg-result__stats { grid-column: 1; grid-row: 3; }
    .cg-result__cta {
        grid-column: 2;
        grid-row: 1 / span 2;
        margin: 0;
        padding: 0;
        border-top: 0;
    }
    .cg-screen--result .cg-cta { grid-column: 2; grid-row: 3; margin: 0; }
    .cg-screen--result .cg-link-btn { grid-column: 2; grid-row: 4; }

    .cg-sightreading__staff { max-width: 420px; }
    .cg-sightreading .cg-key--white { height: 74px; }
    .cg-sightreading .cg-keys__blacks,
    .cg-sightreading .cg-key--black { height: 46px; }
    .cg-sightreading__verdict { margin: 2px 0 6px; }

    .cg-pianonotes__target { min-height: 76px; }
    .cg-pianonotes__name { font-size: clamp(36px, 9vw, 56px); }
    .cg-pianonotes__staff { max-width: 240px; }
    .cg-pianonotes__find { margin-bottom: 6px; }
    /* A sideways phone is 640 px wide, so the desktop rule (min-width 26px,
       fit the widest level whole) takes over and level 4 lands on 28 px keys.
       A window this short is a phone whichever way round it is: keep the
       thumb-sized floor and let the frame scroll. */
    .cg-pianonotes .cg-key--white { height: 86px; min-width: 40px; }
    .cg-pianonotes .cg-keys { min-width: calc(var(--cg-pn-whites, 8) * 40px); }
    .cg-pianonotes .cg-keys__blacks,
    .cg-pianonotes .cg-key--black { height: 54px; }

    /* Same move as the ear trainer: a chord on a staff and four names beside
       it, rather than four names under it. The staff then has a column to be
       tall in instead of pushing the answers off the bottom. */
    .cg-chordrecognition {
        display: grid;
        grid-template-columns: 1fr 1fr;
        column-gap: 18px;
        align-items: center;
    }

    .cg-chordrecognition__tag { grid-column: 1; grid-row: 1; }
    .cg-chordrecognition__show { grid-column: 1; grid-row: 2; }
    .cg-chordrecognition__hear { grid-column: 1; grid-row: 3; }
    .cg-chordrecognition__answers { grid-column: 2; grid-row: 1 / span 3; }
    .cg-chordrecognition__hint { grid-column: 1 / -1; grid-row: 4; }

    .cg-chordrecognition__show { min-height: 104px; }
    .cg-chordrecognition__bloom { width: 104px; height: 104px; margin: -52px 0 0 -52px; }
    .cg-chordrecognition__answer { min-height: 48px; }
    .cg-chordrecognition__hear { margin: 4px auto 8px; }
    .cg-chordrecognition .cg-key--white { height: 68px; }
    .cg-chordrecognition .cg-keys__blacks,
    .cg-chordrecognition .cg-key--black { height: 42px; }

    /* The ear trainer is the one board a sideways phone cannot simply shrink:
       twelve intervals stacked under the listening ring come to 487 px on a
       375 px screen. Sideways it reads sideways — listen on the left, answer
       on the right — which is the shape the space actually has. */
    .cg-eartraining {
        display: grid;
        grid-template-columns: minmax(140px, 0.85fr) 1.5fr;
        grid-template-rows: auto auto auto auto;
        align-items: center;
        column-gap: 16px;
        row-gap: 7px;
    }

    .cg-eartraining .cg-ear__sense { grid-column: 1; grid-row: 1; }
    .cg-eartraining .cg-ear__replay { grid-column: 1; grid-row: 2; justify-self: center; }
    .cg-eartraining .cg-answers { grid-column: 2; grid-row: 1 / span 2; }
    .cg-eartraining .cg-answers[data-count="12"] { grid-template-columns: repeat(4, 1fr); }
    .cg-eartraining .cg-ear__reveal { grid-column: 1 / -1; grid-row: 3; }
    .cg-eartraining .cg-ear__keys { grid-column: 1 / -1; grid-row: 4; justify-self: center; }
    .cg-eartraining .cg-ear__hint { grid-column: 1 / -1; grid-row: 5; }

    .cg-eartraining .cg-ear__ring { width: 46px; height: 46px; }
    .cg-eartraining .cg-ear__replay { min-height: 44px; }
    .cg-eartraining .cg-ear__answer { min-height: 44px; }
    .cg-eartraining .cg-key--white { height: 32px; }
    .cg-eartraining .cg-keys__blacks,
    .cg-eartraining .cg-key--black { height: 20px; }
}

/* 8b ------------------------------------------------- the shortest landscape
   A 360 px tall window — a 16:9 phone turned over, and the floor this family
   supports — has about 50 px less than the tier above assumes. The staff is
   the block that gives it back, because it is the one thing here drawn to a
   box rather than typed into one. */

@media (orientation: landscape) and (max-height: 400px) {
    /* Note Rush. At 640x360 the 420 px staff plus the seven answers overflowed
       by 18 px. The staff gives the width back; the answers stay thumb-sized. */
    .cg-rush__staff { max-width: 300px; margin-bottom: 8px; }
    .cg-rush__clef { font-size: 11px; margin-bottom: 0; }
    .cg-rush .cg-answer { min-height: 48px; font-size: 17px; }
    .cg-rush__hint { margin-top: 6px; }

    .cg-sightreading__clef { font-size: 11px; margin-bottom: 0; }
    .cg-sightreading__staff { max-width: 320px; }
    .cg-sightreading__verdict { font-size: 14px; margin: 0 0 4px; }
    .cg-sightreading .cg-key--white { height: 60px; }
    .cg-sightreading .cg-keys__blacks,
    .cg-sightreading .cg-key--black { height: 38px; }

    .cg-pianonotes__target { min-height: 60px; }
    .cg-pianonotes__name { font-size: clamp(30px, 7vw, 44px); }
    .cg-pianonotes__staff { max-width: 190px; }
    .cg-pianonotes__clef { font-size: 11px; }
    .cg-pianonotes__find { font-size: 11px; margin-bottom: 4px; }
    .cg-pianonotes .cg-key--white { height: 70px; }
    .cg-pianonotes .cg-keys__blacks,
    .cg-pianonotes .cg-key--black { height: 44px; }

    .cg-chordrecognition__staff { max-width: 240px; }
    .cg-chordrecognition__show { min-height: 88px; }
    .cg-chordrecognition .cg-key--white { height: 56px; }
    .cg-chordrecognition .cg-keys__blacks,
    .cg-chordrecognition .cg-key--black { height: 35px; }

    .cg-eartraining .cg-ear__ring { width: 40px; height: 40px; }
    .cg-eartraining .cg-key--white { height: 26px; }
    .cg-eartraining .cg-keys__blacks,
    .cg-eartraining .cg-key--black { height: 16px; }
}
