/* polish.css — append-only fixes from the visual QA loop (each block tagged with its fixer group) */

/* === mock r1 === (fixer: Mock + Report + Boss, round 1) */
/* base.css's `.view-enter` used fill-mode `both`: the forwards fill kept an animated transform on <main>,
   which made <main> the containing block for every position:fixed overlay inside a screen (the Mock's
   SUBMIT dialog and map backdrop stopped at the header). `backwards` keeps the 24 px slide + fade and
   leaves nothing behind once it has played. */
.view-enter { animation-fill-mode: backwards; }

/* Boss on a phone: the Card engine lays out stem → Scratch → parts, which put the auto-focused answer box
   under the dock at 375×667. Below the rail breakpoint the parts come straight after the stem; Scratch (S)
   follows the answer boxes. ≥ 1024 the Scratch sits in the rail exactly as before. */
@media (max-width: 1023px) {
  .boss-screen .card-screen { grid-template-areas: "head" "stage" "parts" "foot" "side" "result" "solution" "sandbox"; }
}
/* The title + 3 hearts stay in view while the student answers, so a heart shatters where they can see it. */
.boss-screen .boss-head {
  position: sticky; top: var(--header-h); z-index: 5;
  margin-inline: calc(-1 * var(--gutter)); padding: 4px var(--gutter);
  /* background + border: see "mock r2" (opaque, one hairline — the r1 94 % + blur smeared the strip) */
}
/* The miss line ("Heart lost. <skill in words>" + Drill 5) now lands in the dock, right above Submit —
   where the student is looking — instead of at the top of the screen. */
#dock .boss-miss { margin: 0; padding: 8px 10px; font-size: var(--fs-1); gap: 6px 10px; }
#dock .boss-miss-line { flex: 1 1 200px; }
#dock .boss-miss .btn { flex: 0 1 auto; min-height: var(--tap); padding-inline: 12px; font-size: var(--fs-1); }
.boss-miss.is-setup { border-color: var(--warn); background: color-mix(in srgb, var(--warn) 8%, var(--surface)); }
/* Key row on a phone: 4 px gaps let the 7-key equation set sit in ONE 44 px row at 375 (7×44 + 6×4 = 332 ≤ 343);
   in a Boss the row never wraps (it scrolls sideways on a 360 px phone instead of doubling the dock). */
@media (max-width: 480px) {
  #dock .w-keys { gap: 4px; }
  :root:has(.boss-screen) #dock .w-keys { flex-wrap: nowrap; overflow-x: auto; scrollbar-width: none; }
  :root:has(.boss-screen) #dock .w-keys::-webkit-scrollbar { display: none; }
  :root:has(.boss-screen) #dock .w-key { flex: 1 0 44px; }
}
/* The Mock's resume / expired cards carry their own heading; keep them tight. */
.mock-rules .mock-resume-stats { margin: 0; display: flex; flex-wrap: wrap; gap: 4px 12px; font-size: var(--fs-2); }
.mock-rules .mock-resume-stats .mono { font-weight: 650; }
/* Report: a single-part item shows the answer without an id label. */
.report-answers dd:only-child { margin: 0; }
/* === /mock r1 === */

/* === home r1 === (Home · Onboarding · Placement · Settings — visual QA round 1) */
/* Placement / JUMP / Night blocks: the runner scrolls to the top on every item; scroll anchoring must not
   re-apply the previous item's offset when the card parts mount asynchronously. */
.ob-run-stage { overflow-anchor: none; }

/* Header tap targets ≥ 44 px (S5) with the 24 px chip and 36 px ring visuals kept:
   the T−N / "set test date" chip is a link — give it an invisible 44 px hit box (header is 56 px tall). */
.hdr a.chip { position: relative; }
.hdr a.chip::before { content: ''; position: absolute; inset: -10px -4px; }
.hdr-home { min-width: 44px; min-height: 44px; display: inline-grid; place-items: center; }

/* Text-grade warn / gold: --warn (#B8650A) and --gold (#A66F00) measure 4.03–4.29:1 on white / --bg in light
   mode (S5 asks ≥ 4.5:1 for text). Fills and borders keep --warn / --gold (≥ 3:1 is enough for those). */
:root { --warn-ink: #9A5208; --gold-ink: #8A5C00; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --warn-ink: var(--warn); --gold-ink: var(--gold); } }
:root[data-theme="dark"] { --warn-ink: var(--warn); --gold-ink: var(--gold); }
.weak-m,
.skill-row[data-tone="weak"] .skill-m,
.plan-warn,
.ob-tight.warn,
.chip[data-tone="warn"] { color: var(--warn-ink); }
.skill-row[data-tone="mastered"] .skill-m,
.rd-band[data-band="ready"], .rd-band[data-band="locked"] { color: var(--gold-ink); }

/* Hero: no one-word orphan on the provisional note (the JS also joins "lock it" with an nbsp). */
.rd-note { text-wrap: pretty; }

/* Readiness sparkline: an end dot, a baseline and a mono caption so it reads as a chart, not a stray stroke. */
.rd-spark { display: flex; align-items: center; gap: 8px; width: auto; height: auto; margin-top: 6px; }
.rd-spark svg { width: 96px; height: 24px; flex: 0 0 auto; }
.rd-spark .spark-base { stroke: var(--line); stroke-width: 1; fill: none; }
.rd-spark .spark-dot { fill: var(--accent); stroke: none; }
.rd-spark .spark-cap { font-size: var(--fs-1); color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* === card r1 === Card screen + widgets fix round 1 (findings: Submit idempotent, phone order,
   pips, inline H1, wedge hit floor, one Continue, landscape, equation msg row). Appended only. */

/* the equation slot's reserved result line shares the row with "Skip setup" (msg left, buttons right) */
.w-eq-actions { align-items: center; }
.w-eq-actions .w-msg { min-width: 0; }   /* flex basis + margin: see "home r2" (full-width row, hidden while empty) */

/* wedge hit areas ≥ 44 px at 375 (S5/S9 #9): fixed in figure/svg.js (WEDGE_MAX / BAND / MIN_CHORD), not
   here — a transparent stroke on the hit paths was tried and let the later-painted composite bands steal
   the atomic wedges' taps. */

/* ---- phone order: head · stage · parts · foot · result · solution · side (Scratch + ladder last) ----
   Below 1024 the answer boxes follow the paper directly; the ≥ 1024 rail (screens.css T09) is unchanged. */
@media (max-width: 1023px) {
  .card-screen { grid-template-areas: "head" "stage" "parts" "foot" "result" "solution" "side" "sandbox"; }
  .card-scratch-label { display: none; }
  .card-scratch-wrap[data-open="false"] .card-scratch { display: none; }
  .card-scratch-wrap[data-open="true"] .card-scratch-caret { transform: rotate(180deg); }
}
.card-scratch-toggle {
  display: flex; align-items: center; gap: 4px; width: 100%; min-height: var(--tap, 44px);
  padding: 0 12px; border: 1px solid var(--line); border-radius: var(--radius-sm, 8px);
  background: var(--surface); color: var(--text); font: inherit; text-align: left; cursor: pointer;
}
.card-scratch-toggle:hover { background: var(--surface2); }
.card-scratch-caret { margin-inline-start: auto; color: var(--muted); transition: transform .2s cubic-bezier(.2,.8,.2,1); }
@media (min-width: 1024px) { .card-scratch-toggle { display: none; } .card-scratch-wrap[data-open="false"] .card-scratch { display: block; } }

/* the dock's Hint (phones only): thumb-zone twin of the ladder button */
.card-dock-hint { flex: 0 1 auto; min-width: 88px; }
.card-dock-hint .mono { margin-inline-start: 4px; opacity: .8; }
@media (min-width: 1024px) { .card-dock-hint { display: none; } }
.w-dock-actions .card-submit, .w-dock-actions .card-continue { flex: 2 1 auto; }

/* the hint inline in the part box (the ladder is the record; this is where the eyes are) */
.card-inline { display: flex; flex-direction: column; gap: 6px; margin-top: 2px; }
.card-inline-hint {
  display: flex; flex-wrap: wrap; gap: 4px 8px; align-items: flex-start;
  padding: 8px 10px; border-radius: var(--radius-sm, 8px);
  background: color-mix(in srgb, var(--accent) 9%, var(--surface)); border: 1px solid color-mix(in srgb, var(--accent) 35%, var(--line));
  font-size: var(--fs-2); line-height: 1.45; opacity: 0; transform: translateY(4px);
  transition: opacity .2s cubic-bezier(.2,.8,.2,1), transform .2s cubic-bezier(.2,.8,.2,1);
}
.card-inline-hint.is-in { opacity: 1; transform: none; }
.card-inline-hint .hint-text { flex: 1 1 180px; min-width: 0; }
.card-inline-hint .hint-auto { flex: 1 1 100%; }
@media (prefers-reduced-motion: reduce) { .card-inline-hint, .card-scratch-caret { transition: none; } }

/* landscape phone (S5 "two columns: figure left, input right"): stage left ≈ 55 %, parts right */
@media (max-height: 480px) and (orientation: landscape) and (max-width: 1023px) {
  .card-screen {
    grid-template-columns: minmax(0, 55fr) minmax(0, 45fr);
    grid-template-areas: "head head" "stage parts" "stage foot" "result result" "solution solution" "side side" "sandbox sandbox";
    column-gap: 16px; row-gap: 12px; align-items: start;
  }
  .card-figure { max-height: 200px; margin-top: 8px; }
  .card-paper { padding: 12px 12px 12px 36px; }
  .card-stem { font-size: var(--fs-2); }
  .card-side { flex-direction: row; flex-wrap: wrap; }
  .card-side > * { flex: 1 1 260px; }
}
@media (max-width: 1023px) { .card-screen { gap: 12px; } }

/* === binder r1 === Binder + Stats + Sheet + Night (visual QA round 1) */

/* -- light-mode bronze: a visible copper, not a second ochre (6.1:1 on white). The dark blocks in
      theme.css carry higher specificity (:root:not([data-theme=light]) / :root[data-theme=dark]), so
      this only ever changes the light palette. */
:root { --bronze: #9A4B1F; }

/* -- tiles: the BODY is tinted, not only the 3 px foot bar (S9 #8 "what would lose points, at a glance") */
.tile::after { height: 4px; }
.tile[data-rarity="bronze"] { background: color-mix(in srgb, var(--bronze) 12%, var(--surface)); }
.tile[data-rarity="silver"] { background: color-mix(in srgb, var(--silver) 16%, var(--surface)); }
.tile[data-rarity="gold"] { background: color-mix(in srgb, var(--gold) 16%, var(--surface)); }
.tile[data-rarity="platinum"] { background: color-mix(in srgb, var(--plat) 18%, var(--surface)); }
@supports not (background: color-mix(in srgb, red 10%, white)) {
  .tile[data-rarity="bronze"] { background: rgba(154, 75, 31, .12); }
  .tile[data-rarity="silver"] { background: rgba(127, 138, 153, .16); }
  .tile[data-rarity="gold"] { background: rgba(166, 111, 0, .16); }
  .tile[data-rarity="platinum"] { background: rgba(46, 132, 176, .18); }
}

/* -- list view: two lines of the stem, real notation, the rarity as a glyph on a phone */
.bnd-row-main { align-items: flex-start; padding-block: 8px; }
.bnd-row-num { padding-top: 2px; }
.bnd-row-stem {
  white-space: normal; text-overflow: clip; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.bnd-row .tile-chip { margin-top: 1px; }
.bnd-row .tile-chip-glyph { display: none; }
@media (max-width: 479px) {
  .bnd-row .tile-chip { padding-inline: 6px; }
  .bnd-row .tile-chip-word { display: none; }
  .bnd-row .tile-chip-glyph { display: inline; }
}
.bnd-viewtoggle { padding: 0; }
.bnd-viewtoggle button { min-height: 44px; padding-inline: 14px; }   /* S5: tap targets ≥ 44 px */

/* -- the tile sheet: clamped beside its tile on a laptop, scrolling inside the viewport, never over the header */
.bnd-pop[data-placement="anchored"] { max-height: calc(100vh - var(--header-h) - 24px); }
.bnd-pop-stem { max-height: none; display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; }
.bnd-pop-x { min-width: var(--tap); min-height: var(--tap); }

/* -- Stats: sparkline that reads as a chart */
.st-spark-box { display: grid; gap: 2px; }
.st-spark-wrap { position: relative; }
.st-spark-base { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.st-spark-tick { stroke: var(--line); stroke-width: 1; vector-effect: non-scaling-stroke; }
.st-spark-tick[data-logged="true"] { stroke: var(--muted); }
.st-spark-dot, .st-spark-head { fill: none; stroke: var(--accent); stroke-linecap: round; vector-effect: non-scaling-stroke; }
.st-spark-dot { stroke-width: 5; }
.st-spark-head { stroke-width: 7; }
.st-spark-val {
  position: absolute; transform: translate(8px, -50%); font-size: var(--fs-1); font-weight: 650; color: var(--accent-ink);
  padding: 0 5px; border-radius: 4px; background: var(--surface); box-shadow: 0 0 0 1px var(--line); white-space: nowrap; pointer-events: none;
}
.st-spark-val[data-side="left"] { transform: translate(calc(-100% - 8px), -50%); }
.st-spark-axis { display: flex; justify-content: space-between; gap: 8px; }
.st-spark-list { margin: 0; line-height: 1.6; }
/* tap targets ≥ 44 px (S5): the section chips and Drill 5 keep their size, the hit area grows */
.st-jump { gap: 10px 12px; }
.st-jump .chip { position: relative; height: 32px; line-height: 30px; padding-inline: 12px; }
.st-jump .chip::before { content: ""; position: absolute; inset: -6px; }
.st-skill-drill { position: relative; min-height: 36px; }
.st-skill-drill::before { content: ""; position: absolute; inset: -4px 0; }

/* -- Night Before: the mini-mock under Mock rules (no per-item feedback), the report with real notation */
.nb-mini .w-msg, .nb-mini .card-result, .nb-mini .card-solution, .nb-mini .card-showsol,
.nb-mini .card-part-reveal, .nb-mini .hint-ladder { display: none !important; }
.nb-mini .card-part[data-state="ok"], .nb-mini .card-part[data-state="revealed"] { border-color: var(--line); }
.nb-mini .card-part[data-state="ok"] .card-part-h::after { content: none; }
.nb-mini .w-field[data-state], .nb-mini [data-state="bad"], .nb-mini [data-state="ok"], .nb-mini [data-state="almost"] { --ok: var(--line); --bad: var(--line); --almost: var(--line); }
.nb-mini .ob-run-stage[data-locked="true"] .card-parts { pointer-events: none; opacity: .85; }
.nb-mini-next { display: grid; gap: 8px; margin-top: 12px; padding: 12px 14px; border: 1px solid var(--accent); border-radius: var(--radius); background: var(--surface); }
.nb-mini-next p { margin: 0; }
.nb-mini-next .btn { justify-self: start; }
.nb-mini-next { scroll-margin-bottom: 180px; }   /* clears the sticky Answer Dock when scrolled into view */
.ob-tick[data-state="skip"] { background: var(--line); }
.nb-rep-item[data-ok="skip"] { border-left-color: var(--line); }
.nb-rep-item[data-ok="skip"] .nb-rep-mark { color: var(--muted); }
.nb-rep-stem { display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.5; }
.nb-rep-count { margin: 0; }
.nb-rep-count[data-counted="false"] { color: var(--warn); }
.nb-rep-count[data-counted="true"] { color: var(--ok); }
.nb-sheet-list li { line-height: 1.5; }

/* === page r1 === Today's Page run + Summary + BLITZ + Drill (fixer round 1) */
/* --ok-ink: the text-only green. --ok (#178A55) is a fill colour — 4.11:1 on the light --bg at 13 px;
   #12744A measures ≈ 4.9:1. Dark keeps --ok (#3DD68C ≈ 9:1). Fills keep --ok everywhere. */
:root { --ok-ink: #12744A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --ok-ink: #3DD68C; } }
:root[data-theme="dark"] { --ok-ink: #3DD68C; }

/* HP pips read as stray unchecked checkboxes (10 px squares at the far right of the chip row). Now: 8 px
   round dots in --muted with a mono "0/2" counted by CSS counters from the pips themselves — no JS —
   next to the chips, vertically centred on the chip row. The aria-label is already "0 of 2 parts cleared". */
.card-pips { counter-reset: pipsAll pipsFull; gap: 3px; margin-top: 0; align-self: center; }
.card-pips .hp-pip { width: 8px; height: 8px; border-radius: 50%; border-color: var(--muted); counter-increment: pipsAll; }
.card-pips .hp-pip.is-full { background: var(--accent); border-color: var(--accent); counter-increment: pipsAll pipsFull; }
.card-pips .hp-pip.is-lost { counter-increment: pipsAll; }
.card-pips::after { content: counter(pipsFull) "/" counter(pipsAll); margin-left: 4px; font-family: var(--font-mono); font-size: var(--fs-1); color: var(--muted); line-height: 1; }
/* === /page r1 === */

/* === content r2 === ASN verdict line + ⚑ note at text grade (S5 ≥ 4.5:1 in light mode).
   Measured on the white card: --ok #178A55 at 15 px = 4.37:1, --warn #B8650A at 13 px = 4.28:1.
   The text-grade tokens above (--ok-ink #12744A ≈ 5.6:1, --warn-ink #9A5208 ≈ 5.5:1) already exist for this;
   dark mode maps both back to the fill colours (≈ 9–10:1), so nothing changes there. */
.w-msg[data-state="ok"] { color: var(--ok-ink, var(--ok)); }
.w-msg[data-state="almost"] { color: var(--warn-ink, var(--almost)); }
.w-asn-flag { color: var(--warn-ink, var(--warn)); }
/* === /content r2 === */

/* === home r2 === (Home · Onboarding · Placement · Settings — visual QA round 2) */
/* Header T−N / "set test date" chip: the r1 ::before hit box was clipped by base.css's `.chip { overflow:hidden }`
   (an elementFromPoint scan measured 42×24). The header chips are ≤ 13 chars, so the ellipsis was never
   needed there; inset −12 px on the 24 px chip is a 48 px hit box (a pixel scan reads 2–3 px under the box).
   base.css's overflow:hidden stays for every other chip. */
.hdr a.chip { position: relative; overflow: visible; text-overflow: clip; }
.hdr a.chip::before { content: ''; position: absolute; inset: -12px -4px; }

/* Hero meta line: every term is one unbreakable token (nowrap spans) and the T−N is gone (the header chip
   already shows it), so the line can only wrap at a " · " and never leaves a one-word third line. */
.rd-terms { text-wrap: balance; }
.rd-terms .rd-term { white-space: nowrap; }

/* Home paints before page.js / plan.js arrive (they are lazy now — 233 KB of cards + 311 KB of generators):
   the CTA slot is a real button-shaped placeholder until the composed queue lands, never a blank. */
.home-primary[data-kind="loading"] { pointer-events: none; opacity: .72; }
@media (prefers-reduced-motion: no-preference) {
  .home-primary[data-kind="loading"] { animation: home-cta-breathe 1.2s ease-in-out infinite alternate; }
  @keyframes home-cta-breathe { from { opacity: .58; } to { opacity: .82; } }
}

/* Equation slot's action row (surfaced on the onboarding sandbox at 390–430 px): the reserved message line
   took a 160 px basis beside "+ second equation" and orphaned "Skip setup" on a third line. Now the message
   is a full-width row ONLY while it has something to say; empty, it is out of the flow and the two buttons
   share one 44 px row at every width. */
.w-eq-actions .w-msg { flex: 1 1 100%; margin-inline-end: 0; }
.w-eq-actions .w-msg[data-state=""] { display: none; }

/* Placement's sticky run head, compact (`data-compact="true"`, set by createSequence for the placement):
   one headline row (title · item label · counter) + the ticks — ~48 px instead of 106–129. The sub-line
   and the two ghost buttons are gone from the sticky region: "Skip the rest (n)" sits in the dock beside
   Submit / Continue, and the way out is the card's ← (the intro, with its honest "I'll start from zero"). */
.ob-run-head[data-compact="true"] { gap: 6px; padding-block: 4px; }
.ob-run:has(> .ob-run-head[data-compact="true"]) { gap: 8px; }
.ob-run-head[data-compact="true"] .ob-run-meta { display: none; }
.ob-run-headline { align-items: center; }
.ob-run-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--muted); font-size: var(--fs-1); }
.ob-run-label:empty { display: none; }
.ob-run-head[data-compact="true"] .ob-run-title { font-size: var(--fs-2); line-height: 1.3; }
#dock .ob-dock-skip { flex: 0 1 auto; min-height: var(--tap); padding-inline: 12px; font-size: var(--fs-1); font-weight: 600; white-space: nowrap; }
/* === /home r2 === */

/* === page r2 === Today's Page run + Summary + BLITZ + Drill (fixer round 2) */
/* Continue fills the dock row like Submit's row does (widgets.css caps a lone .btn at 320 px → 23 px strip). */
.w-dock-actions .card-continue { max-width: none; }
/* The inline hint is scrolled into view (card.js revealHint) — clear the sticky header and the dock. */
.card-inline-hint { scroll-margin-top: calc(var(--header-h) + 12px); scroll-margin-bottom: 200px; }
.card-part > .card-inline + .card-part-body { margin-top: 10px; }
/* A miss scrolls the verdict to the top of the screen; the solution opens right under it. */
.card-result { scroll-margin-top: calc(var(--header-h) + 8px); }
/* BLITZ: the pressed option and the right one are marked for the lockout — ✗ / ✓ glyph + border + a 120 ms
   6 px shake on the offending option only (S5); the untouched options fade, the marked ones stay legible. */
@keyframes page-r2-shake { 0%, 100% { transform: translateX(0); } 25% { transform: translateX(-6px); } 75% { transform: translateX(6px); } }
.blitz-answers[data-locked="true"] { opacity: 1; }
.blitz-answers[data-locked="true"] > :not([data-state]) { opacity: .55; }
.blitz-answers[data-locked="true"] > [data-state]:disabled { opacity: 1; }   /* the marked pair stays legible through the lockout */
.blitz-opt[data-state="bad"], .blitz-asn[data-state="bad"] { border-color: var(--bad); animation: page-r2-shake 120ms var(--ease) 1; }
.blitz-opt[data-state="ok"], .blitz-asn[data-state="ok"] { border-color: var(--ok); }
.blitz-opt[data-state="bad"] .blitz-key, .blitz-asn[data-state="bad"] .blitz-key { color: var(--bad); border-color: var(--bad); }
.blitz-opt[data-state="ok"] .blitz-key, .blitz-asn[data-state="ok"] .blitz-key { color: var(--ok-ink, var(--ok)); border-color: var(--ok); }
.blitz-mark { margin-left: auto; padding-left: 8px; font-weight: 700; font-size: var(--fs-3); line-height: 1; }
.blitz-asn .blitz-mark { margin-left: 0; padding-left: 0; font-size: var(--fs-2); }
[data-state="bad"] > .blitz-mark { color: var(--bad); }
[data-state="ok"] > .blitz-mark { color: var(--ok-ink, var(--ok)); }
@media (prefers-reduced-motion: reduce) { .blitz-opt[data-state="bad"], .blitz-asn[data-state="bad"] { animation: none; } }
/* === /page r2 === */

/* === mock r2 === (fixer: Mock + Report + Boss, round 2) */
/* Boss head: opaque with one hairline — r1's 94 % + blur smeared the strip and the chips through it while
   scrolling. Same recipe as the Mock bar (screens.css T13). */
.boss-screen .boss-head { background: var(--bg); border-bottom: 1px solid var(--line); backdrop-filter: none; -webkit-backdrop-filter: none; }

/* Boss meta row at 375: the HP pips sit on the skill line (bottom-right corner of the head) so the chip row
   is chips only and wraps freely; the skill line keeps clear of the pips. */
.boss-screen .card-head { position: relative; }
.boss-screen .card-pips { position: absolute; right: 0; bottom: 2px; margin: 0; }
.boss-screen .card-skills { padding-inline-end: 72px; }

/* Dock Submit / Continue span the key row on a phone (widgets.css caps every dock button at 320 px);
   on a wide screen the actions row is centred under the keys instead of a left-hugging slab. */
@media (max-width: 480px) { #dock .w-dock-actions .btn { max-width: none; } }
@media (min-width: 481px) { #dock .w-dock-actions { justify-content: center; } }

/* Mock: no verdict until SUBMIT, so the widgets' reserved result line (.w-msg, 22 px + the widget gap) is
   dead space inside every answer card — under the A/S/N buttons and under the cloze / mc chips. */
.mock-parts .w-msg { display: none; }

/* Mock paper clips the ∠ wedge hover band that reaches past the figure on a laptop (svg.js WEDGE_MAX). */
.mock-paper { overflow: hidden; }

/* The miss box in the dock: 4 px vertical padding on a phone. */
@media (max-width: 480px) { #dock .boss-miss { padding-block: 4px; } }

/* Boss with the OS keyboard open (`data-kb` from widgets/base.js) or on any viewport this short: the head
   stops being sticky and the dock's miss box collapses to ONE 44 px row — two clamped lines of text plus
   "Drill 5" / "Skip the setup" as an inline link (48 px hit box via ::before) — so the answer box keeps
   ≥ 180 px of room between the app header and the dock at 375×407 after a miss. */
:root[data-kb="open"] .boss-screen .boss-head { position: static; }
:root[data-kb="open"] #dock .boss-miss { max-height: 44px; overflow: hidden; flex-wrap: nowrap; align-items: center; gap: 8px; padding: 4px 10px; }
:root[data-kb="open"] #dock .boss-miss-line { flex: 1 1 auto; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
:root[data-kb="open"] #dock .boss-miss .btn { position: relative; flex: 0 0 auto; min-height: 0; padding: 0; border: 0; background: none; color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; font-size: var(--fs-1); }
:root[data-kb="open"] #dock .boss-miss .btn::before { content: ''; position: absolute; inset: -14px -8px; }
:root[data-kb="open"] #dock .boss-miss .btn .muted, :root[data-kb="open"] #dock .boss-miss .boss-drill-skill { display: none; }
@media (max-height: 520px) {
  .boss-screen .boss-head { position: static; }
  #dock .boss-miss { max-height: 44px; overflow: hidden; flex-wrap: nowrap; align-items: center; gap: 8px; padding: 4px 10px; }
  #dock .boss-miss-line { flex: 1 1 auto; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; line-height: 1.3; }
  #dock .boss-miss .btn { position: relative; flex: 0 0 auto; min-height: 0; padding: 0; border: 0; background: none; color: var(--accent-ink); text-decoration: underline; text-underline-offset: 2px; font-size: var(--fs-1); }
  #dock .boss-miss .btn::before { content: ''; position: absolute; inset: -14px -8px; }
  #dock .boss-miss .btn .muted, #dock .boss-miss .boss-drill-skill { display: none; }
}
/* === /mock r2 === */

/* === binder r2 === (fixer: Binder + Stats + Sheet + Night, round 2) */
/* Mini-mock silence (S7 "no hints, no per-item feedback", S9 #6/#7): nothing per box or per item until hand-in —
   no per-field reason line, no strip ANSWER row, no "Setup: 0 of 2 pts" split, no HP pips, no ✓ / ✗ / ← marks. */
.nb-mini .w-field .w-fmsg, .nb-mini .w-strip-msg, .nb-mini .w-eq-split, .nb-mini .card-pips { display: none !important; }
.nb-mini .w-field[data-state] .w-mark, .nb-mini .wd-opt[data-state] .wd-opt-mark, .nb-mini .w-strip-mark { visibility: hidden; }
.nb-mini .wd-chip[data-state]::after { content: none; }
.nb-mini .wd-opt[data-state="bad"] .wd-opt-t { text-decoration: none; }
.nb-mini .wd-opt[data-state="bad"], .nb-mini .wd-chip[data-state="bad"] { opacity: 1; }
.nb-mini .wd-opt[data-state="ans"], .nb-mini .wd-chip[data-state="ans"] { border-style: solid; }
.nb-mini .card-part[data-state] { border-color: var(--line); }
/* One way forward, the same for a right and a wrong item: the runner's own row (night.js offerNext), not the dock's Continue. */
.nb-mini .card-continue, :root:has(.nb-mini) #dock .card-continue { display: none !important; }
/* A settled strip slot under Mock rules (`answered`, js/widgets/strip.js): neutral and locked, no ✓ / ✗. */
.w-strip-slot[data-state="answered"] { border-color: var(--line); }
.w-strip-slot[data-state="answered"] .w-strip-n { border-color: var(--muted); color: var(--muted); }
.w-strip-slot[data-state="answered"] .w-strip-mark::after { content: "–"; color: var(--muted); }
/* Format help is not answer feedback: "Write an equation — it needs an = sign." stays readable. */
.nb-mini .w-msg[data-state="almost"] { display: flex !important; --almost: var(--warn-ink, var(--warn)); color: var(--warn-ink, var(--warn)); }
/* Progress ticks: an answered item is done, not judged — green / red only on the report. */
.ob-tick[data-state="done"] { background: var(--muted); }
/* Text-grade contrast (S5 ≥ 4.5:1 in light mode): --gold #A66F00 = 4.29:1, --plat #2F86B3 ≈ 3.9:1, --warn 4.03:1,
   --ok 4.11–4.37:1 at 13 px. The -ink tokens (home r1 / page r1) carry the text; borders keep --gold / --plat. */
:root { --plat-ink: #23678A; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --plat-ink: var(--plat); } }
:root[data-theme="dark"] { --plat-ink: var(--plat); }
.tile-chip[data-rarity="gold"] { color: var(--gold-ink); }
.tile-chip[data-rarity="platinum"] { color: var(--plat-ink); }
.nb-rep-count[data-counted="false"] { color: var(--warn-ink); }
.nb-rep-count[data-counted="true"] { color: var(--ok-ink); }
.bnd-hist-mark[data-ok="true"] { color: var(--ok-ink); }
/* Stats: at phone width the error card's date + Rematch drop under the text instead of squeezing it into a
   155 px column; ≥ 720 the skill meta ("n=5 · mastered · placed · w3") sizes to its content and never wraps. */
@media (max-width: 719px) {
  .st-errors li { flex-wrap: wrap; }
  .st-err-main { flex: 1 1 100%; }
  .st-err-side { flex: 1 1 100%; justify-content: space-between; }
}
@media (min-width: 720px) {
  .st-skills li { grid-template-columns: minmax(0, 190px) minmax(0, 1fr) 46px 200px 64px; }   /* fixed meta + drill columns: every bar starts and ends on the same x */
  .st-skill-meta { white-space: nowrap; }
  .st-skill-drill { justify-self: end; }
}
/* === /binder r2 === */

/* === card r2 === Card screen + widgets fix round 2 (findings: pairs verdict under the figure, compact
   optional setup, setup msg row, ✓ / silver contrast, doc-07 wedge labels, ASN chips, card-skills wrap,
   dock Continue width). Appended only. */

/* ---- pairs: the last verdict mirrored right under the figure (widgets/pairs.js figNote; the widget's own
        msg slot stays the record). A 44 px row; muted (`data-stale`) as soon as the next pick starts. */
.w-pairs-figmsg {
  display: flex; align-items: center; gap: 8px; margin: 8px 0 0; padding: 6px 12px; min-height: var(--tap, 44px);
  border: 1px solid var(--line); border-radius: var(--radius-sm, 8px); background: var(--surface);
  font-size: var(--fs-2); line-height: 1.35; color: var(--text);
  transition: opacity .2s cubic-bezier(.2,.8,.2,1);
}
.w-pairs-figmsg[data-state="bad"] { border-color: var(--bad); color: var(--bad); background: color-mix(in srgb, var(--bad) 8%, var(--surface)); }
.w-pairs-figmsg[data-state="ok"] { border-color: var(--ok); color: var(--ok-ink, var(--ok)); background: color-mix(in srgb, var(--ok) 8%, var(--surface)); }
.w-pairs-figmsg[data-state="almost"] { border-color: var(--warn); color: var(--warn-ink, var(--warn)); }
.w-pairs-figmsg[data-stale="true"] { opacity: .55; }
.w-pairs-figmsg .w-msg-glyph { flex: 0 0 auto; font-weight: 700; }
.w-pairs-figmsg-t { min-width: 0; overflow-wrap: anywhere; }
@media (prefers-reduced-motion: reduce) { .w-pairs-figmsg { transition: none; } }

/* ---- text-grade greens and the SILVER chip (S5 ≥ 4.5:1 in light mode): the field ✓ mark measured 4.37:1 on
        white with --ok; --silver (#7F8A99) text 3.5:1. Fills and borders keep the fill tokens. */
.w-field[data-state="ok"] .w-mark { color: var(--ok-ink, var(--ok)); }
:root { --silver-ink: #5E6978; }
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --silver-ink: var(--silver); } }
:root[data-theme="dark"] { --silver-ink: var(--silver); }
.rarity[data-r="silver"] { color: var(--silver-ink); }

/* ---- dock: after a clear the single Continue is the whole row (the hidden Hint / Submit no longer hold a
        flex gap and the 320 px cap left a 23 px dead strip on the right at 375). */
.w-dock-actions > [hidden] { display: none !important; }
.w-dock-actions .card-continue { flex: 1 1 100%; max-width: none; }

/* ---- head: the two-skill line wraps to two lines below 480 instead of "Solve by Facto…" */
@media (max-width: 479px) {
  .card-skills { white-space: normal; text-overflow: clip; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-height: 1.3; }
}

/* ---- ASN reason chips: one sentence per row (full width, 14 px), not three 88 px pills */
.w-asn-why .wd-chiprow { gap: 6px; }
.w-asn-why .wd-chip { width: 100%; gap: 6px; padding: 4px 10px; font-size: var(--fs-2); line-height: 1.3; border-radius: var(--radius-sm, 8px); }
.w-asn-why .wd-chip-n { min-width: 14px; }
.w-asn-why .wd-sub { margin: 6px 0 4px; }

/* ---- multi: labels of different heights ("upper-right angle · 4y + x − 5" wraps) no longer stagger the two
        boxes of a row — each field bottom-aligns, so the inputs of a row line up */
.w-multi .w-fields .w-field { justify-content: flex-end; }

/* ---- the optional setup slot is ONE compact row: label · box · Skip (≈ 96 px), so the required answer
        field is a screen closer on every wp-* / ang-02..11 / doc-06/07 card. The parse hint shows only
        while the box has focus (or the slot is skipped); the verdict line takes its own full-width row
        when it has something to say. `display: contents` on the action row lets Skip sit beside the box. */
.card-part[data-optional="true"] { gap: 6px; }
.card-part-h-aside { font-weight: 400; }
.card-part[data-prompt="default"] .w-eq-head { display: none; }
.card-part[data-optional="true"] .w-equation {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; column-gap: 8px; row-gap: 0; align-items: start;
  grid-template-areas: "head head" "fields skip" "keys keys" "hint hint" "msg msg" "add add" "split split";
}
/* row-gap stays 0 — an empty grid track still takes its gap, and seven tracks cost 36 px; the rows that
   actually show carry their own top margin instead */
.card-part[data-optional="true"] .w-eq-head { grid-area: head; margin-bottom: 6px; }
.card-part[data-optional="true"] .w-eq-head .w-prompt { margin: 0; font-size: var(--fs-2); }
.card-part[data-optional="true"] .w-eq-fields { grid-area: fields; }
.card-part[data-optional="true"] .w-equation > .w-keys { grid-area: keys; margin-top: 6px; }
.card-part[data-optional="true"] .w-eq-actions .w-msg, .card-part[data-optional="true"] .w-eq-add, .card-part[data-optional="true"] .w-eq-split { margin-top: 6px; }
.card-part[data-optional="true"] .w-eq-hint { grid-area: hint; min-height: 0; display: none; margin-top: 6px; }
.card-part[data-optional="true"] .w-equation:focus-within .w-eq-hint:not([hidden]),
.card-part[data-optional="true"] .w-equation[data-skipped="true"] .w-eq-hint:not([hidden]) { display: block; }
.card-part[data-optional="true"] .w-eq-actions { display: contents; }
.card-part[data-optional="true"] .w-eq-actions .w-msg { grid-area: msg; }
.card-part[data-optional="true"] .w-eq-add { grid-area: add; justify-self: start; }
.card-part[data-optional="true"] .w-eq-skip { grid-area: skip; align-self: end; min-height: var(--input-h, 48px); }
.card-part[data-optional="true"] .w-eq-split { grid-area: split; }
/* skipped by the student (the widget's own state): the boxes fold away, "Write the setup" stays beside the hint */
.card-part[data-optional="true"] .w-equation[data-skipped="true"] .w-eq-fields { display: none; }
.card-part[data-optional="true"] .w-equation[data-skipped="true"] { grid-template-areas: "head head" "hint skip" "keys keys" "msg msg" "add add" "split split"; align-items: center; }
/* the card is over and the slot was never tried (card.js lockAll → box "skipped", widget locked): only the label
   row stays — not an empty dashed box with a disabled Skip floating in it */
.card-part[data-optional="true"][data-state="skipped"] .w-equation[data-locked="true"] > :not(.w-eq-head) { display: none; }

/* ---- ≥ 1024: the figure caps at 300 px, and on a card WITH a figure the paper is two columns — stem left,
        figure (≤ 340 px, wedges still ≥ 44 px) right — so the paper is ≈ 260 px instead of 454 and the first
        required field lands well inside an 800 px laptop (instruction, note and the pairs strip span both). */
@media (min-width: 1024px) {
  .card-figure, .card-figure .fig { max-height: 300px; }
  .card-paper:has(> .card-figure:not([hidden])) {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 280px); column-gap: 20px; align-items: start;
  }
  /* a pairs card answers IN the figure: keep it 340 px wide so every wedge stays ≥ 44 px */
  .card-screen:has(.card-part[data-type="pairs"]) .card-paper:has(> .card-figure:not([hidden])) { grid-template-columns: minmax(0, 1fr) minmax(0, 340px); }
  .card-paper:has(> .card-figure:not([hidden])) > .card-instruction,
  .card-paper:has(> .card-figure:not([hidden])) > .card-note,
  .card-paper:has(> .card-figure:not([hidden])) > .w-pairs-figmsg,
  .card-paper[data-no="long"]:has(> .card-figure:not([hidden])) > .card-no { grid-column: 1 / -1; }
  .card-paper:has(> .card-figure:not([hidden])) > .card-stem { grid-column: 1; }
  .card-paper:has(> .card-figure:not([hidden])) > .card-figure { grid-column: 2; grid-row: span 1; margin-top: 0; }
  .card-paper:has(> .card-figure:not([hidden])) > .card-note { margin-top: 0; }
}
/* === /card r2 === */
/* === mock r2 (addendum) === the Drill 5 link is "Drill 5" + a skill span: no flex gap between them, so it
   reads "Drill 5: Word Problems: Linear" and not "Drill 5 : Word…". */
.boss-drill { gap: 0; }
/* === /mock r2 (addendum) === */

/* === integration r2 === (integrator, QA round 2) */
/* Readiness sparkline fits the hero column at 375: the chart flexes 48–96 px (preserveAspectRatio="none" in
   home.js; strokes are non-scaling) so the nowrap caption never pushes past the card edge. */
.rd-spark { min-width: 0; }
.rd-spark svg { flex: 1 1 96px; width: auto; min-width: 48px; max-width: 96px; }
.rd-spark path { vector-effect: non-scaling-stroke; }
.rd-spark .spark-base { vector-effect: non-scaling-stroke; }
.rd-spark .spark-dot { fill: none; stroke: var(--accent); stroke-width: 5; stroke-linecap: round; }
/* === /integration r2 === */

/* === fix5:run r1 === Today's Page on a phone: the answer control above the sticky dock (S9 #3 "rough edges"),
   and the Summary's family tiles (S4 family ladder, no orphaned comma).
   Below 1024 the run head is ONE slim row — 44 px "←" Quit · title · "0 of 13 done" — with the progress bar
   as a 3 px line riding the head's bottom border (was three rows, 84 px). The card's chip row keeps the skill
   name beside the chips instead of forcing it onto its own line. On a short viewport (≤ 760 px tall) the paper
   pads 12 px, the notation preview is 60 px (not 84) and a figure that is not the answer surface caps at 150 px; a pairs card (the figure IS the
   answer) keeps its full width so the wedges stay ≥ 44 px — card.js revealAnswer() lifts its field instead.
   ≥ 1024 is untouched. */
@media (max-width: 1023px) {
  .run-screen { gap: 8px; }
  .run-head { position: relative; gap: 8px; padding-bottom: 4px; }
  .run-head:has(> .run-progress) { flex-wrap: nowrap; }   /* BLITZ's clock + score HUD keeps its own wrap row */
  .run-titles { flex: 1 1 auto; min-width: 0; display: flex; align-items: baseline; gap: 8px; }
  .run-title { flex: 0 1 auto; min-width: 0; font-size: var(--fs-3); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .run-sub { flex: 1 1 0; min-width: 0; margin: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
  .run-progress { flex: 0 0 auto; gap: 0; }
  .run-progress-n { white-space: nowrap; }
  .run-progress-track { position: absolute; left: 0; right: 0; bottom: -1px; min-width: 0; max-width: none; height: 3px; border-radius: 0; background: transparent; }
  .run-progress-fill { border-radius: 0 2px 2px 0; }
  .card-head { gap: 6px; }
  .card-skills { flex: 1 1 110px; }
}
@media (max-width: 639px) {
  .run-quit { width: var(--tap); padding: 0; font-size: var(--fs-3); }
  .run-quit-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .run-head[data-kind="page"] .run-sub { display: none; }   /* r2: the Page's "11 new + 2 variants" only — other runs' subtitles are rules (fix5:run r2) */
}
@media (max-width: 1023px) and (max-height: 760px) {
  .card-screen { gap: 8px; }
  .card-paper { padding: 12px 12px 12px 36px; }
  .card-no { left: 8px; top: 12px; }
  .card-paper[data-no="long"] { padding-left: 12px; }
  .card-paper[data-no="long"] .card-no { margin-bottom: 6px; }
  .card-figure { margin-top: 10px; }
  .card-screen:not(:has(.card-part[data-type="pairs"])) .card-figure,
  .card-screen:not(:has(.card-part[data-type="pairs"])) .card-figure .fig { max-height: 150px; }
  .card-stem { line-height: 1.42; }
  #view:has(> .run-screen) { padding-top: 8px; }
  .card-screen .w-nt-preview { min-height: 60px; margin-bottom: 8px; padding-block: 6px; }
}

/* ≥ 1024 (found while checking this lane for regressions, pre-existing since W4): base.css `.screen { max-width:
   var(--col) }` capped the run screen at 680 px, so the card inside it laid out its 680 + 320 rail in 680 —
   the paper got 336 px, its two-column stem track 0 px, and the stem printed one letter per line
   (qa/screenshots/s9/v-laptop-light-page.png). A run that hosts a card gets the card route's width. */
@media (min-width: 1024px) {
  .run-screen:has(> .run-stage > .card-screen) { max-width: none; }
}

/* Summary family tiles: a family tile takes two grid columns (130 px) so its third line — where it stands on
   the ladder, "1/6 ◆ → Silver at 2" (r2 wording) — fits; the name never breaks inside "(a > 1)" and no caption line can start
   with punctuation (the 60 px caption's `overflow-wrap: anywhere` split "Quadratics, a > 1" into "Quadratics" /
   ", a > 1"). A one-line legend under the grid prints the family rule the Binder tooltip prints. */
.sum-tiles > li { align-content: start; }   /* a two-column family cell makes its row taller: neighbours keep their caption under the tile */
.sum-tiles > li[data-fam="true"] { grid-column: span 2; width: 130px; }
.sum-tiles > li[data-fam="true"] .sum-tile-cap { width: 130px; overflow-wrap: normal; word-break: normal; }
.sum-tile-cap { overflow-wrap: break-word; }
.sum-nowrap { white-space: nowrap; }
.sum-tile-fam { font-family: var(--font-mono); font-size: 11px; line-height: 1.2; }
.sum-fam-legend { margin: 10px 0 0; line-height: 1.4; max-width: 60ch; }
.sum-fam-legend-k { color: var(--text); font-weight: 600; }
/* === /fix5:run r1 === */

/* === fix5:home r1 === */
/* S9 scorecard #1: a just-started skill (answered, never wrong) is grey, never the warn colour. */
.skill-row[data-tone="started"] .skill-name, .skill-row[data-tone="started"] .skill-m { color: var(--muted); }
.skill-row[data-tone="started"] .skill-fill { background: var(--muted); opacity: .55; }
.weak-started { margin: 8px 0 0; line-height: 1.4; }
/* S9 scorecard #5: the plan's Mock link (and "How did it go?") is a real 44 px tap target (S5 "Tap targets ≥ 44 px"). */
.plan-mock, .plan-post-link { min-height: var(--tap, 44px); min-width: 44px; margin-top: 2px; }
/* === /fix5:home r1 === */

/* === fix5:gen r1 === T-notation mini-figures: the unlettered plane outline (poly `outline`, figure/svg.js) */
.fig-plane { fill: none; stroke: var(--fig-line, currentColor); stroke-width: 1.5; stroke-linejoin: round; opacity: .55; }
/* === /fix5:gen r1 === */

/* === fix5:run r2 === (1) Run subtitles are rules ("hints off, first try only", "these pay full XP", "+XP for
   finishing"): below 1024 every run except the Page shows its subtitle on its own full-width muted line under
   the one-row head (the Page's "11 new + 2 variants" stays hidden on a phone — r1). (2) Short phones: the
   notation builder's preview box 44 px (was 60), so item 1's first row of symbol buttons shows whole above the
   dock with no scroll. (3) Summary family ladder line never wraps (≤ 19 characters by construction). */
@media (max-width: 1023px) {
  .run-head:not([data-kind="page"]):has(.run-sub) { flex-wrap: wrap; row-gap: 2px; }
  .run-head:not([data-kind="page"]):has(.run-sub) > .run-titles { display: contents; }
  .run-head:not([data-kind="page"]):has(.run-sub) .run-title { flex: 1 1 0; }
  .run-head:not([data-kind="page"]) .run-sub { order: 3; flex: 1 1 100%; min-width: 0; white-space: normal; overflow: visible; text-overflow: clip; line-height: 1.35; }
  /* BLITZ: the full title keeps the row; its rule line, then the clock/score HUD row under it (no "BLITZ · Vocabu…") */
  .run-head[data-kind="blitz"] .run-title { flex: 1 1 auto; white-space: normal; }
  .run-head[data-kind="blitz"] > .blitz-hud { order: 4; }
}
@media (max-width: 1023px) and (max-height: 760px) {
  .card-screen .w-nt-preview { min-height: 44px; padding-block: 4px; margin-bottom: 4px; }
  .card-figure { margin-top: 6px; }
}
.sum-tiles > li[data-fam="true"] .sum-tile-fam { white-space: nowrap; }
/* === /fix5:run r2 === */

/* === fix5:home r3 === placement summary: the sibling note ("needs the ratio item clean too") is its own line under the
   label, and the right-hand tag can never take more than half the row — the label no longer breaks per syllable. */
.ob-result-note { display: block; margin-top: 1px; line-height: 1.35; }
.ob-result-row > .ob-result-tag { max-width: 48vw; text-align: right; }
.ob-result-name { overflow-wrap: normal; }
/* === /fix5:home r3 === */

/* === fix5:integrate r1 === Short portrait phones (≤ 760 px tall): fix5:run r1 capped every non-pairs card figure at
   150 px so the notation builder's first row clears the dock. On a shipped figure with algebra labels (ang-10:
   "−x + 84", "2x² − 4x + 3") that scaled 13-unit labels to ≈ 7.5 px (fix5:gen note). Only notation-builder cards
   keep the 150 px cap; any other non-pairs figure gets its natural 375-px height back (≈ 190 px), and the first
   control still sits above the dock (qa/fix5-run-measure.mjs). Landscape (≤ 480 px tall) keeps its own 200 px rule. */
@media (max-width: 1023px) and (min-height: 481px) and (max-height: 760px) {
  .card-screen:not(:has(.card-part[data-type="pairs"])):not(:has(.card-part[data-type="notation"])) .card-figure,
  .card-screen:not(:has(.card-part[data-type="pairs"])):not(:has(.card-part[data-type="notation"])) .card-figure .fig { max-height: 190px; }
}
/* === /fix5:integrate r1 === */
