/* Smartypes design system. One self-hosted typeface (Atkinson Hyperlegible, SIL OFL 1.1, see fonts/OFL.txt) plus the
   device's own monospace for typing and code; no third-party requests. */
@font-face { font-family: 'Atkinson Hyperlegible'; src: url('../fonts/AtkinsonHyperlegible-Regular.woff2') format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Atkinson Hyperlegible'; src: url('../fonts/AtkinsonHyperlegible-Italic.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }
@font-face { font-family: 'Atkinson Hyperlegible'; src: url('../fonts/AtkinsonHyperlegible-Bold.woff2') format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'Atkinson Hyperlegible'; src: url('../fonts/AtkinsonHyperlegible-BoldItalic.woff2') format('woff2'); font-weight: 700; font-style: italic; font-display: swap; }

:root {
  /* Colors live in themes.css, generated from js/design/themes.js. */
  --font-ui: "Atkinson Hyperlegible", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Atkinson Hyperlegible", system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-brand: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;   /* the wordmark and its tile keep the serif */
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;
  --radius: 10px;
  --radius-sm: 6px;
  --type-size: 1.45rem;
  --tex: none;
}
:root[data-text="s"] { --type-size: 1.2rem; }
:root[data-text="l"] { --type-size: 1.75rem; }
:root[data-text="xl"] { --type-size: 2.1rem; }

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font: 16px/1.55 var(--font-ui);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}
main { flex: 1; }
a { color: var(--accent-text); text-underline-offset: 2px; }
a:hover { text-decoration-thickness: 2px; }
h1, h2, h3 { font-family: var(--font-display); line-height: 1.2; margin: 0 0 0.5em; font-weight: 700; }
h1 { font-size: clamp(1.9rem, 4.5vw, 2.8rem); letter-spacing: -0.01em; }
h2 { font-size: 1.5rem; }
h3 { font-size: 1.15rem; }
p { margin: 0 0 0.9em; }
:focus-visible { outline: 3px solid var(--focus); outline-offset: 2px; border-radius: 4px; }
.wrap { max-width: 980px; margin: 0 auto; padding: 0 16px; }
.muted { color: var(--muted); }
.small { font-size: 0.875rem; }
.tiny { font-size: 0.78rem; }
.mono { font-family: var(--font-mono); }
.hidden { display: none !important; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip-link { position: absolute; left: -9999px; top: 8px; background: var(--ink); color: var(--bg); padding: 8px 12px; border-radius: 6px; z-index: 100; }
.skip-link:focus { left: 8px; }

/* ── Header and footer ─────────────────────────────────────────────── */
.site-header { border-bottom: 1px solid var(--line); background: var(--bg); position: sticky; top: 0; z-index: 20; }
.site-header .wrap { display: flex; align-items: center; gap: 12px; min-height: 58px; flex-wrap: wrap; }
.brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--ink); margin-right: auto; }
.brand-mark { font-family: var(--font-brand); width: 32px; height: 32px; border-radius: 7px; background: var(--accent); color: var(--on-accent); display: grid; place-items: center; font: 800 1.05rem/1 var(--font-brand); box-shadow: 2px 2px 0 var(--ink); }
.brand-name { font: 800 1.3rem/1 var(--font-brand); letter-spacing: -0.01em; }
/* A sticky bar must not cover the control that has focus (WCAG 2.4.11): keep room for it
   when scrolling to a focused element, and let it scroll away where it would take a third of the window. */
html { scroll-padding-top: 72px; scroll-padding-bottom: 88px; }
/* --header-h: how much of the top of the window the sticky header covers, for anything that sticks below it (card headings).
   The header is 58px plus its border; app.js re-measures it where the navigation wraps. Static header: nothing is covered. */
:root { --header-h: 59px; }
@media (max-width: 720px), (max-height: 500px) { .site-header { position: static; } html { scroll-padding-top: 12px; } :root { --header-h: 0px; } }
.nav { display: flex; gap: 2px; flex-wrap: wrap; }
.nav a { color: var(--ink); text-decoration: none; padding: 7px 10px; border-radius: 8px; font-size: 0.93rem; }
.nav a:hover { background: var(--surface-2); }
.nav a[aria-current="page"] { background: var(--surface-2); font-weight: 600; }
.nav .nav-cta { background: var(--ink); color: var(--bg); font-weight: 600; }
.nav .nav-cta:hover { background: var(--ink-2); }
.nav .nav-cta[aria-current="page"] { background: var(--ink); color: var(--bg); box-shadow: 0 0 0 2px var(--accent); }
.site-footer { border-top: 1px solid var(--line); margin-top: 48px; padding: 22px 0 28px; color: var(--muted); font-size: 0.86rem; }
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: baseline; }
.site-footer a { color: var(--muted); display: inline-flex; align-items: center; min-height: 24px; }   /* a 24 px target on touch screens */
.site-footer .copy { margin-right: 0; }
.site-footer .preview-note { margin-right: auto; }

/* ── Buttons and controls ──────────────────────────────────────────── */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: 8px; font: 600 0.95rem/1 var(--font-ui); padding: 11px 18px; border-radius: 9px; border: 1px solid var(--line-strong); background: var(--surface); color: var(--ink); cursor: pointer; text-decoration: none; min-height: 42px; }
.btn:hover { background: var(--surface-2); }
.btn-primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); box-shadow: var(--shadow); }   /* BT-1: the soft card shadow; the hard 2px ink offset read as too sharp */
.btn-primary:hover { background: var(--accent); filter: brightness(1.05); }
.btn-dark { background: var(--ink); border-color: var(--ink); color: var(--bg); }
.btn-dark:hover { background: var(--ink-2); }
.btn-ghost { background: transparent; border-color: transparent; }
.btn-ghost:hover { background: var(--surface-2); }
.btn-small { padding: 7px 12px; min-height: 34px; font-size: 0.86rem; }
.btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.kbd { font: 600 0.75rem/1 var(--font-mono); border: 1px solid var(--line-strong); border-bottom-width: 2px; border-radius: 5px; padding: 3px 6px; background: var(--surface); color: var(--muted); }
.btn .kbd { background: transparent; color: inherit; border-color: currentColor; opacity: 0.75; }
.segmented { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 9px; overflow: hidden; background: var(--surface); }
.segmented button { font: 600 0.88rem/1 var(--font-ui); padding: 9px 14px; border: 0; background: transparent; color: var(--ink); cursor: pointer; min-height: 38px; }
.segmented button + button { border-left: 1px solid var(--line); }
.segmented button:focus-visible { outline-offset: -4px; }   /* the row clips anything drawn outside it */
.segmented button[aria-pressed="true"] { background: var(--ink); color: var(--bg); }
.row { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.stack > * + * { margin-top: 12px; }

/* ── Cards and tiles ───────────────────────────────────────────────── */
.card { background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius); padding: 20px; box-shadow: var(--shadow); }
.card + .card { margin-top: 16px; }
.eyebrow { font: 700 0.72rem/1.2 var(--font-ui); letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted); margin: 0 0 6px; }
.tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; }
.tile { border: 1px solid var(--line); border-radius: 9px; padding: 11px 13px; background: var(--bg); }
.tile .label { font-size: 0.75rem; color: var(--muted); text-transform: uppercase; letter-spacing: 0.07em; }
.tile .value { font: 700 1.55rem/1.15 var(--font-mono); }
.tile .note { font-size: 0.78rem; color: var(--muted); }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 760px) { .grid-2 { grid-template-columns: 1fr; } }

/* ── Home ──────────────────────────────────────────────────────────── */
.hero { padding: 42px 0 18px; }
.hero p.lede { font-size: 1.15rem; color: var(--ink-2); max-width: 44em; }
.steps { display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; margin: 24px 0; counter-reset: step; }
.steps li { list-style: none; background: var(--surface); border: 1px solid var(--line); border-radius: 10px; padding: 14px; }
.steps li::before { counter-increment: step; content: counter(step); display: inline-grid; place-items: center; width: 26px; height: 26px; border-radius: 50%; background: var(--ink); color: var(--bg); font: 700 0.85rem/1 var(--font-ui); margin-bottom: 8px; }
.steps h3 { margin: 0 0 4px; font-size: 1rem; font-family: var(--font-ui); }
.steps p { margin: 0; font-size: 0.9rem; color: var(--muted); }
@media (max-width: 760px) { .steps { grid-template-columns: 1fr 1fr; } }
@media (max-width: 420px) { .steps { grid-template-columns: 1fr; } }
.today { display: grid; grid-template-columns: 1.4fr 1fr; gap: 16px; margin-top: 22px; }
@media (max-width: 760px) { .today { grid-template-columns: 1fr; } }
.week { display: flex; gap: 6px; margin: 8px 0 4px; }
.week span { width: 26px; height: 26px; border-radius: 6px; border: 1px solid var(--line-strong); display: grid; place-items: center; font-size: 0.7rem; color: var(--muted); }
.week span.on { background: var(--ok); border-color: var(--ok); color: var(--bg); }
.week span.is-today { outline: 2px solid var(--ink); outline-offset: 1px; }
.notice { border-left: 4px solid var(--accent); background: var(--accent-soft); padding: 12px 14px; border-radius: 0 8px 8px 0; }
.notice.ok { border-color: var(--ok); background: var(--ok-soft); }

/* ── Session: rail, block card, surface, rep strip (DESIGN.md regions) ─ */
.session { padding-top: 16px; }
.rail { display: flex; gap: 4px; align-items: stretch; margin-bottom: 12px; }
.rail .seg { flex: var(--w, 1) 1 0; min-width: 22px; height: 30px; border-radius: 6px; background: var(--surface-2); border: 1px solid var(--line); position: relative; overflow: hidden; font-size: 0.7rem; color: var(--muted); display: flex; align-items: center; padding: 0 6px; white-space: nowrap; }
.rail .seg .fill { position: absolute; inset: 0 auto 0 0; width: 0; background: var(--ok-soft); transition: width 0.3s; }
.rail .seg .name { position: relative; overflow: hidden; text-overflow: ellipsis; }
.rail .seg.current { border-color: var(--ink); color: var(--ink); font-weight: 600; }
.rail .seg.done { color: var(--ink-2); }
.rail .seg.done .fill { width: 100%; }
.rail-meta { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--muted); margin: -6px 0 12px; }
.block-card { border-left: 4px solid var(--ink); }
.block-card .title-row { display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; }
.block-card h2 { margin: 0; font-size: 1.35rem; }
.block-card dl { display: grid; grid-template-columns: auto 1fr; gap: 4px 12px; margin: 10px 0 0; font-size: 0.94rem; }
.block-card dt { font-weight: 700; color: var(--muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; padding-top: 2px; }
.block-card dd { margin: 0; }
.surface-wrap { margin-top: 14px; }
.typing { position: relative; background: var(--surface); border: 1px solid var(--line-strong); border-radius: var(--radius); padding: 18px 20px; cursor: text; box-shadow: var(--shadow); }
.typing:focus-within { border-color: var(--ink); outline: 3px solid var(--focus); outline-offset: 2px; }
.typing .viewport { height: calc(var(--type-size) * 1.9 * 3); overflow: hidden; position: relative; }
.typing .text { font: 500 var(--type-size)/1.9 var(--font-mono); color: var(--ink-2); white-space: pre-wrap; word-break: break-word; transition: transform 0.15s ease-out; }
.typing .ch { border-radius: 3px; }
.typing .ch.done { color: var(--muted); }
/* Code practice: a line break shows a return mark at the end of its line. The mark is drawn with borders (no font glyph) and
   takes no layout space, so it can never wrap onto a line of its own when a line is exactly as wide as the box; the text
   reserves room for it at the right edge. It is also where the cursor sits while a line break is expected. Indentation
   added for the learner is dimmed and never the cursor; a closing mark stepped over (Editor style) is struck through. */
.typing .text.code { padding-right: 1.5em; }
.typing .ch.nl { position: relative; }
.typing .ch.nl::before { content: ''; position: absolute; left: 0.2em; top: 0.3em; width: 0.9em; height: 1.25em; border-radius: 3px; }
.typing .ch.nl::after { content: ''; position: absolute; left: 0.5em; top: 0.75em; width: 0.32em; height: 0.28em; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; opacity: 0.6; }
.typing .ch.nl.cur::before { background: var(--accent-soft); box-shadow: inset 0 -3px 0 var(--accent); }
.typing .ch.nl.miss::before { background: var(--err); }
.typing .ch.auto { opacity: 0.35; }
.typing .ch.skipped { text-decoration: line-through; opacity: 0.5; }
.typing .ch.had-err { text-decoration: underline wavy var(--err) 1.5px; text-underline-offset: 5px; }
.typing .ch.wrong { background: var(--err-soft); color: var(--err); }
.typing .ch.cur { color: var(--ink); background: var(--accent-soft); box-shadow: inset 0 -3px 0 var(--accent); }
.typing .ch.miss { background: var(--err); color: var(--bg); animation: miss 0.18s ease-out; }
/* Pace bar: one steady bar gliding under the text (ui/typing.js). No blinking. */
.typing .text { position: relative; }
.typing .pace-bar { position: absolute; left: 0; top: 0; width: 2ch; height: 3px; border-radius: 2px; background: var(--ok); opacity: 0.85; pointer-events: none; transition: opacity 0.2s ease-out; will-change: transform; }
.typing .pace-bar.fading { opacity: 0; }
.typing .space-mark { color: var(--err); }
@keyframes miss { from { transform: translateY(-2px); } to { transform: none; } }
.typing textarea.capture { position: absolute; opacity: 0; left: 0; top: 0; width: 1px; height: 1px; border: 0; padding: 0; resize: none; pointer-events: none; }
.typing .focus-overlay { position: absolute; inset: 0; background: color-mix(in srgb, var(--surface) 82%, transparent); display: none; place-items: center; border-radius: var(--radius); font-weight: 600; color: var(--ink); cursor: pointer; }
.typing.blurred .focus-overlay { display: grid; }
.typing .prompt { font: 500 1.05rem/1.5 var(--font-ui); color: var(--ink); margin-bottom: 10px; }
.typing .prompt .cue { color: var(--muted); font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.07em; display: block; margin-bottom: 2px; }
.typing .answer { font: 600 var(--type-size)/1.6 var(--font-mono); letter-spacing: 0.08em; min-height: 1.6em; }
.typing .answer .blank { color: var(--muted); }
.typing .answer .hint { color: var(--accent-text); text-decoration: underline; }
.typing .answer.shake { animation: answer-shake 0.28s; }
@keyframes answer-shake { 0%, 100% { transform: none; } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } }
/* Find each key: the prompt carries the finger's colour, and the answer is a keycap in it (the finger is already named). */
.typing .prompt.by-finger { border-left: 5px solid var(--c); padding-left: 10px; }
.typing .answer .keycap { display: inline-grid; place-items: center; width: 1.9em; height: 1.9em; margin-right: 6px; border-radius: 9px; border: 2px solid var(--c); background: color-mix(in srgb, var(--c) 45%, var(--surface)); color: var(--ink); box-shadow: 0 3px 0 var(--line-strong); font: 700 1.3rem/1 var(--font-mono); letter-spacing: 0; }
.typing .answer .keycap.empty { background: var(--surface); border-style: dashed; box-shadow: none; }
.typing .answer .keycap.hint { outline: 2px dotted var(--ink); outline-offset: 2px; }
.eyes-up { position: absolute; right: 14px; top: 10px; width: 28px; height: 28px; background: var(--accent); transform: rotate(45deg) scale(0.2); opacity: 0; border-radius: 4px; transition: transform 0.12s, opacity 0.12s; }
.eyes-up.show { opacity: 1; transform: rotate(45deg) scale(1); }
.caps-warning { position: absolute; left: 14px; top: -14px; background: var(--err); color: var(--bg); font: 700 0.78rem/1 var(--font-ui); padding: 6px 9px; border-radius: 6px; display: none; }
.typing.caps .caps-warning { display: block; }
.rep-strip { min-height: 30px; margin: 8px 2px 0; font-size: 0.95rem; color: var(--ink-2); display: flex; gap: 14px; align-items: center; flex-wrap: wrap; }
.rep-strip .live { font-family: var(--font-mono); color: var(--muted); }
.rep-strip .hint-line { color: var(--muted); font-size: 0.85rem; margin-left: auto; }
.session-actions { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }

/* Key guide (on-screen keyboard) */
/* safe center: a keyboard wider than its box starts at the left edge and scrolls, instead of losing its left keys. */
.keyguide { margin-top: 14px; user-select: none; overflow-x: auto; }
.keyguide .kb { display: grid; gap: 5px; justify-content: safe center; }
.keyguide .kb-row { display: flex; gap: 5px; }
.keyguide .key { width: 38px; height: 38px; border-radius: 6px; border: 1px solid var(--line-strong); background: var(--surface); display: grid; place-items: center; font: 600 0.82rem/1 var(--font-mono); color: var(--ink-2); position: relative; transition: background 0.08s; }
.keyguide .key::after { content: ""; position: absolute; left: 6px; right: 6px; bottom: 3px; height: 3px; border-radius: 2px; background: var(--finger, transparent); opacity: 0.9; }
.keyguide .key.wide { width: 70px; }
/* ISO boards: a short left Shift, then the extra key (IntlBackslash), so Z lines up with the ANSI drawing: at every size
   its width is the wide key's, less one key and one gap. Too narrow for its word on small screens, where it is left blank. */
.keyguide .key.iso-shift { width: 27px; font-size: 0.55rem; overflow: hidden; }
.keyguide .key.space { width: 250px; }
.keyguide .key.home { box-shadow: inset 0 -2px 0 var(--line-strong); }
.keyguide .key.next { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.keyguide .key.hit { background: var(--ok); color: var(--bg); }
.keyguide .key.missed { background: var(--err); color: var(--bg); }
.keyguide .key.locked { opacity: 0.35; }
.keyguide .key.heat { background: color-mix(in srgb, var(--err) calc(var(--heat, 0) * 70%), var(--surface)); }
.keyguide.faded .key:not(.next):not(.hit):not(.missed) { opacity: 0.45; }
.keyguide .guide-note { text-align: center; font-size: 0.8rem; color: var(--muted); margin-top: 6px; min-height: 1.2em; }
@media (max-width: 720px) {
  .keyguide .key { width: 26px; height: 30px; font-size: 0.7rem; }
  .keyguide .key.wide { width: 44px; }
  .keyguide .key.iso-shift { width: 15px; font-size: 0; }
  .keyguide .key.space { width: 160px; }
  .keyguide .kb, .keyguide .kb-row { gap: 3px; }
}
@media (max-width: 400px) {
  .keyguide .key { width: 21px; height: 26px; font-size: 0.62rem; }
  .keyguide .key.wide { width: 34px; }
  .keyguide .key.iso-shift { width: 11px; }
  .keyguide .key.space { width: 130px; }
  .keyguide .kb, .keyguide .kb-row { gap: 2px; }
  .keyguide .key .k2 { font-size: 0.5rem; }
  .keyguide .key .k3 { display: none; }   /* too crowded at this size; the lit key and its note still say AltGr */
}

/* Short windows (laptops with browser bars): the whole typing screen, keyboard
   and buttons included, fits without scrolling. Tested at 1240x670 and 1240x600. */
@media (min-width: 721px) and (max-height: 820px) {
  .session { padding-top: 8px; }
  .rail { margin-bottom: 8px; }
  .rail .seg { height: 24px; }
  .rail-meta { margin: -4px 0 6px; }
  .block-card { padding: 12px 16px; }
  .block-card .eyebrow { margin-bottom: 2px; }
  .block-card h2 { font-size: 1.15rem; }
  .block-card dl { margin-top: 6px; gap: 2px 10px; font-size: 0.88rem; }
  .surface-wrap { margin-top: 10px; }
  .typing { padding: 12px 16px; }
  .rep-strip { min-height: 26px; margin-top: 6px; }
  .session-actions { margin-top: 8px; }
  .keyguide { margin-top: 8px; }
  .keyguide .kb, .keyguide .kb-row { gap: 4px; }
  .keyguide .key { width: 32px; height: 32px; font-size: 0.76rem; }
  .keyguide .key.wide { width: 60px; }
  .keyguide .key.iso-shift { width: 24px; font-size: 0.45rem; }
  .keyguide .key.space { width: 212px; }
  .keyguide .guide-note { margin-top: 4px; }
}
@media (min-width: 721px) and (max-height: 700px) {
  .keyguide .key { width: 27px; height: 27px; font-size: 0.7rem; }
  .keyguide .key.wide { width: 50px; }
  .keyguide .key.iso-shift { width: 20px; font-size: 0; }
  .keyguide .key.space { width: 178px; }
  .keyguide .kb, .keyguide .kb-row { gap: 3px; }
  .keyguide { margin-top: 6px; }
  .rail .seg { height: 22px; }
  .block-card { padding: 10px 14px; }
  .block-card dl { font-size: 0.84rem; margin-top: 4px; }
  .surface-wrap { margin-top: 8px; }
  .typing { padding: 10px 14px; }
}

/* Plan and report */
.report h2 { font-size: 1.55rem; }
.observations { margin: 12px 0 0; padding: 0; list-style: none; }
.observations li { padding: 7px 0 7px 22px; border-top: 1px solid var(--line); position: relative; }
.observations li::before { content: ""; position: absolute; left: 4px; top: 16px; width: 8px; height: 8px; border-radius: 50%; background: var(--accent); }
.plan-list { list-style: none; padding: 0; margin: 12px 0 0; counter-reset: blk; }
.plan-list li { display: grid; grid-template-columns: 34px 1fr auto; gap: 4px 12px; padding: 12px 0; border-top: 1px solid var(--line); }
.plan-list li::before { counter-increment: blk; content: counter(blk); width: 28px; height: 28px; border-radius: 50%; border: 1.5px solid var(--ink); display: grid; place-items: center; font: 700 0.85rem/1 var(--font-ui); grid-row: span 2; }
.plan-list .t { font-weight: 700; }
.plan-list .m { font-family: var(--font-mono); color: var(--muted); }
.plan-list .w { grid-column: 2 / 4; color: var(--muted); font-size: 0.92rem; }
.verdict { padding: 12px 14px; border-radius: 9px; background: var(--surface-2); margin-top: 12px; }
.verdict.good { background: var(--ok-soft); }
.verdict.focus { background: var(--accent-soft); }
.badge-list { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 8px; }
.badge { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--line-strong); border-radius: 999px; padding: 5px 11px; font-size: 0.85rem; background: var(--surface); }
.badge::before { content: ""; width: 9px; height: 9px; border-radius: 50%; background: var(--ok); }
.badge.locked { color: var(--muted); border-style: dashed; }
.badge.locked::before { background: var(--line-strong); }
/* Badge emblems (ui/badgeart.js): one frame per family, colored by theme tokens; a badge not yet earned is faint and grey. */
.badge-art { display: block; flex: none; color: var(--ink); }
.badge-art.fam-days { color: var(--accent); }
.badge-art.fam-keys { color: var(--ok); }
.badge-art.fam-tier { color: var(--ink-2); }
.badge-art.locked { color: var(--muted); opacity: 0.45; }
.badge-art .ba-line { fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.badge-art .ba-heavy { stroke-width: 2.6; }
.badge-art .ba-thin { stroke-width: 1.3; }
.badge-art .ba-faint { stroke-width: 1; opacity: 0.5; }
.badge-art .ba-dots { stroke-dasharray: 0.1 3.2; stroke-width: 2.2; }
.badge-art .ba-chevron { stroke-width: 2.4; }
.badge-art .ba-fill { fill: currentColor; stroke: none; }
.badge-art .ba-text { fill: currentColor; font: 600 13px var(--font-ui); }
.badge-art.solid .ba-cap { fill: currentColor; }
.badge-art.solid .ba-cap ~ * { color: var(--surface); }
.badge-art.solid .ba-seal { fill: var(--surface); stroke: currentColor; stroke-width: 2; }
.badge-art.solid .ba-check { stroke: var(--ok); stroke-width: 2.2; }
.badge-art.solid.locked .ba-check { stroke: var(--muted); }
.badge-count { margin: 0 0 4px; color: var(--ink-2); }
.badge-grid { list-style: none; padding: 0; margin: 12px 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(132px, 1fr)); gap: 10px; }
.badge-card { display: flex; flex-direction: column; align-items: center; text-align: center; gap: 4px; padding: 12px 8px; border: 1px solid var(--line); border-radius: 12px; background: var(--surface); }
.badge-card.locked { border-style: dashed; }
.badge-card .badge-name { font-weight: 700; font-size: 0.9rem; line-height: 1.3; }
.badge-card.locked .badge-name { color: var(--ink-2); }
.badge-card .badge-sub { color: var(--muted); line-height: 1.35; }
.badge-recent { list-style: none; padding: 0; margin: 10px 0 0; display: flex; flex-wrap: wrap; gap: 12px 18px; }
.badge-recent li { display: flex; align-items: center; gap: 8px; font-size: 0.9rem; font-weight: 600; }
@media (max-width: 420px) { .badge-grid { grid-template-columns: repeat(2, 1fr); } }

/* Vocabulary card */
.word-card { text-align: left; }
.word-card .word { font: 700 2rem/1.1 var(--font-display); }
.word-card .pos { color: var(--muted); font-style: italic; margin-left: 8px; }
.word-card .def { font-size: 1.15rem; margin: 10px 0; }
.word-card .ex { border-left: 3px solid var(--line-strong); padding-left: 12px; color: var(--ink-2); }

/* Progress */
.chart { width: 100%; height: auto; display: block; }
.chart .grid line { stroke: var(--line); }
.chart .axis text { fill: var(--muted); font: 11px var(--font-ui); }
.calendar { display: grid; grid-template-columns: repeat(14, 1fr); gap: 4px; max-width: 460px; }
.calendar span { aspect-ratio: 1; border-radius: 4px; background: var(--surface-2); border: 1px solid var(--line); }
.calendar span.on { background: var(--ok); border-color: var(--ok); }
.tier-ladder { list-style: none; padding: 0; margin: 10px 0 0; }
.tier-ladder li { display: flex; justify-content: space-between; padding: 7px 10px; border-radius: 7px; }
.tier-ladder li.current { background: var(--ink); color: var(--bg); font-weight: 700; }
.tier-ladder li.reached { color: var(--ink-2); }
.tier-ladder li.ahead { color: var(--muted); }
table.plain { border-collapse: collapse; width: 100%; font-size: 0.92rem; }
table.plain th, table.plain td { text-align: left; padding: 7px 8px; border-top: 1px solid var(--line); }
table.plain th { color: var(--muted); font-weight: 600; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; }

/* Coach chat */
.chat { display: flex; flex-direction: column; gap: 10px; min-height: 260px; }
.msg { max-width: 82%; padding: 11px 14px; border-radius: 12px; line-height: 1.5; }
.msg.me { align-self: flex-end; background: var(--ink); color: var(--bg); border-bottom-right-radius: 4px; }
.msg.coach { align-self: flex-start; background: var(--surface-2); border-bottom-left-radius: 4px; }
.msg.coach .who { display: block; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--muted); margin-bottom: 3px; }
.chat-form { display: flex; gap: 8px; margin-top: 14px; }
.chat-form input { flex: 1; }
.chat-earlier { margin-bottom: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.chat-earlier[hidden] { display: none; }
.chat-earlier-head { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; margin: 0 0 4px; font-size: 0.85rem; color: var(--muted); }
.chat-earlier-head .btn { margin-left: auto; }
.chat-past > summary { padding: 7px 2.4em 7px 0; min-height: 36px; }
.chat-past > .msg { margin: 2px 0 10px; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 10px; }
.chip { border: 1px solid var(--line-strong); background: var(--surface); border-radius: 999px; padding: 6px 12px; font-size: 0.85rem; cursor: pointer; color: var(--ink); }
.chip:hover { background: var(--surface-2); }

/* Forms */
label.field { display: block; margin-bottom: 14px; }
label.field > span { display: block; font-weight: 600; margin-bottom: 5px; }
input[type="text"], input[type="email"], textarea, select { font: inherit; color: var(--ink); background: var(--bg); border: 1px solid var(--line-strong); border-radius: 8px; padding: 10px 12px; width: 100%; }
textarea { min-height: 140px; resize: vertical; }
.settings-grid { display: grid; grid-template-columns: 220px minmax(0, 1fr); gap: 14px 20px; align-items: center; }
.settings-grid .desc { grid-column: 2; margin-top: -8px; font-size: 0.85rem; color: var(--muted); }
@media (max-width: 640px) { .settings-grid { grid-template-columns: minmax(0, 1fr); } .settings-grid .desc { grid-column: 1; } }

/* Content pages */
.prose { max-width: 46em; }
.prose h2 { margin-top: 1.6em; }
.prose h3 { margin-top: 1.3em; }
.prose li { margin-bottom: 0.35em; }
.prose .ref { font-size: 0.9rem; color: var(--muted); }
.ref-toggle { margin-top: 1.6em; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.ref-toggle > summary { padding: 12px 2.4em 12px 16px; min-height: 44px; display: flex; align-items: center; }
.ref-toggle > summary h2 { margin: 0; }
.ref-toggle .ref-count { color: var(--muted); font-weight: 400; }
.ref-toggle .ref { margin: 0; padding: 0 16px 16px 2.9em; }   /* room for two-digit list numbers inside the card's border */
.ref-toggle .ref li { overflow-wrap: anywhere; }
.prose blockquote { margin: 1em 0; padding: 10px 16px; border-left: 4px solid var(--line-strong); background: var(--surface); border-radius: 0 8px 8px 0; }
.page-head { padding: 34px 0 8px; }
.claim { border: 1px solid var(--line); border-radius: 10px; padding: 14px 16px; background: var(--surface); margin: 12px 0; }
.claim .src { font-size: 0.85rem; color: var(--muted); margin-top: 6px; display: block; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
}
:root[data-motion="reduce"] *, :root[data-motion="reduce"] *::before, :root[data-motion="reduce"] *::after { animation: none !important; transition: none !important; }

/* Disclosure: every <details> shows the same chevron, so anything that opens looks like it opens. A summary styled as flex or
   grid loses the browser's own marker, so the marker is replaced here, once, and drawn out of the layout (absolute) so it
   never becomes a grid or flex item. Components leave 2.4em on the right of their summary. Enforced by tools/consistency_audit.py. */
details > summary { list-style: none; cursor: pointer; position: relative; padding-right: 2.4em; min-height: 24px; }   /* a 24 px target on touch screens */
details > summary::-webkit-details-marker { display: none; }
details > summary::after { content: ""; position: absolute; right: 14px; top: calc(50% - 6px); width: 9px; height: 9px; border-right: 2px solid var(--muted); border-bottom: 2px solid var(--muted); transform: rotate(45deg); transition: transform 0.15s; }
details[open] > summary::after { transform: rotate(-135deg); top: calc(50% - 2px); }
/* An open card keeps its heading in view under the site header, so it can be closed without scrolling back up. */
.qcard[open] > summary, .ref-toggle[open] > summary { position: sticky; top: calc(var(--header-h) - 1px);   /* overlaps the header by a pixel so a fractional height (zoom, high-density screens) never leaves a gap to see content through */ z-index: 10; background: var(--surface); border-radius: var(--radius) var(--radius) 0 0; }
.qcard[open] > summary { box-shadow: 0 1px 0 var(--line); }
@media (forced-colors: active) { details > summary::after { border-color: CanvasText; } }

.mt-24 { margin-top: 24px; }
.mt-12 { margin-top: 12px; }
.mt-0 { margin-top: 0; }

/* Support page: contribution menu */
.donate-menu { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr)); gap: 12px; margin: 12px 0; }
.donate-option { border: 1px solid var(--line); border-radius: 10px; padding: 14px; background: var(--bg); }
.donate-option h3 { margin: 0 0 4px; font-family: var(--font-ui); font-size: 1.05rem; }
.donate-option .address { font-size: 0.9rem; word-break: break-all; background: var(--surface-2); border-radius: 6px; padding: 8px 10px; margin: 8px 0; }
.donate-option .warnings { margin: 10px 0 0; padding-left: 18px; }
/* Side by side, the cards share rows, so Ko-fi's button sits level with Copy address and Show QR code. */
@supports (grid-template-rows: subgrid) {
  .donate-option { display: grid; grid-template-rows: subgrid; grid-row: span 7; row-gap: 0; }
  .donate-option > * { min-width: 0; }
  .donate-option .d-title { grid-row: 1; }
  .donate-option .d-note { grid-row: 2; }
  .donate-option .d-send { grid-row: 3; }
  .donate-option .d-address { grid-row: 4; }
  .donate-option .d-about { grid-row: 3 / 5; margin: 8px 0; }
  .donate-option .d-actions { grid-row: 5; align-self: start; }
  .donate-option .d-qr { grid-row: 6; }
  .donate-option .d-warn { grid-row: 7; align-self: start; }
}
.qr-box { margin-top: 10px; }
.qr-box svg { display: block; border-radius: 6px; }

/* Cards: no stray space above the first or below the last element */
.card > :first-child { margin-top: 0; }
.card > :last-child { margin-bottom: 0; }

/* Results page: the next step stays in view until the plan's Start button is */
.session.has-next-bar { padding-bottom: 76px; }
.next-bar { position: fixed; left: 0; right: 0; bottom: 0; z-index: 15; background: var(--surface); border-top: 1px solid var(--line-strong); box-shadow: 0 -6px 20px rgba(0, 0, 0, 0.12); padding: 10px 0; transition: transform 0.2s ease-out, opacity 0.2s ease-out, visibility 0.2s; }
.next-bar .wrap { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.next-bar .next-text { margin-right: auto; }
.next-bar.is-hidden { transform: translateY(110%); opacity: 0; visibility: hidden; }

/* Progress: past sessions */
.history { border-top: 1px solid var(--line); margin-top: 8px; }
.history-item { border-bottom: 1px solid var(--line); padding: 2px 0; }
.history-item summary { display: grid; grid-template-columns: 8.5em 14em 1fr; gap: 4px 12px; padding: 9px 2.4em 9px 4px; align-items: baseline; }
.history-item summary .when { font-weight: 600; }
.history-item summary .nums { color: var(--muted); font-family: var(--font-mono); font-size: 0.88rem; }
.history-item[open] { padding-bottom: 12px; }
.history-item .history-head { font-weight: 600; margin: 0 0 4px; }
@media (max-width: 640px) { .history-item summary { grid-template-columns: 1fr; } }

/* Where the time went (results, blocks, summary) */
.time-split { border: 1px solid var(--line); border-radius: 9px; padding: 0 12px; background: var(--bg); }
.time-split > summary::after { right: 2px; }
.time-split summary { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; padding: 10px 2.4em 10px 0; }
.time-split summary .more { color: var(--muted); font-size: 0.85rem; margin-left: auto; display: flex; align-items: center; gap: 4px; }
.time-split[open] { padding-bottom: 10px; }
.split-bar { display: flex; height: 12px; border-radius: 6px; overflow: hidden; background: var(--surface-2); margin: 2px 0 8px; }
.split-bar .seg { flex: var(--w, 0) 1 0; min-width: 0; }
.split-bar .seg.t-typing, .split-legend .t-typing::before { background: var(--ok); }
.split-bar .seg.t-errors, .split-legend .t-errors::before { background: var(--err); }
.split-bar .seg.t-pauses, .split-legend .t-pauses::before { background: var(--line-strong); }
.split-legend { display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 8px; }
.split-legend .k::before { content: ""; display: inline-block; width: 10px; height: 10px; border-radius: 3px; margin-right: 6px; vertical-align: -1px; }

/* Textures (Settings: Texture). Sparse gray specks: light themes multiply them in
   (a few darker flecks), dark themes screen them in (a few lighter ones). Soft light,
   used before 2026-09-26, cannot darken a near-white page or lighten black, so the
   texture was invisible on most themes (measured: luminance spread 0.5 to 1.6 of 255;
   now about 3 to 6, with the page's mean shifted by 3 to 6). Text stays on top,
   untouched. No image files: the tiles are small SVG filters. */
:root {
  --tex-grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncR type='gamma' amplitude='-0.06' exponent='2.5' offset='1'/%3E%3CfeFuncG type='gamma' amplitude='-0.06' exponent='2.5' offset='1'/%3E%3CfeFuncB type='gamma' amplitude='-0.06' exponent='2.5' offset='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
  --tex-grain-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncR type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3CfeFuncG type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3CfeFuncB type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
  --tex-parchment-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9 0.035' numOctaves='2' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncR type='gamma' amplitude='-0.055' exponent='2.5' offset='1'/%3E%3CfeFuncG type='gamma' amplitude='-0.055' exponent='2.5' offset='1'/%3E%3CfeFuncB type='gamma' amplitude='-0.055' exponent='2.5' offset='1'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
  --tex-parchment-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n' color-interpolation-filters='sRGB'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9 0.035' numOctaves='2' seed='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncR type='linear' slope='3' intercept='-1'/%3E%3CfeFuncG type='linear' slope='3' intercept='-1'/%3E%3CfeFuncB type='linear' slope='3' intercept='-1'/%3E%3CfeFuncA type='linear' slope='0' intercept='1'/%3E%3C/feComponentTransfer%3E%3CfeComponentTransfer%3E%3CfeFuncR type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3CfeFuncG type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3CfeFuncB type='gamma' amplitude='0.05' exponent='2.5' offset='0'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url%28%23n%29'/%3E%3C/svg%3E");
}
/* Each theme picks the light or dark strength (themes.css: --tex-grain, --tex-parchment). */
:root[data-texture="grain"] { --tex: var(--tex-grain); }
:root[data-texture="parchment"] { --tex: var(--tex-parchment); }
body, .card, .tile, .typing, .site-header, .donate-option, .time-split, .next-bar { background-image: var(--tex); background-blend-mode: var(--tex-blend, multiply); }

/* Progress: finger map and word list */
.fingers { display: grid; grid-template-columns: repeat(9, minmax(0, 1fr)); gap: 8px; align-items: end; height: 190px; margin: 8px 0 6px; }
.finger { display: grid; grid-template-rows: auto 1fr auto auto; justify-items: center; height: 100%; text-align: center; }
.finger .bar { align-self: end; width: 70%; max-width: 44px; height: calc(var(--h, 0) * 100%); min-height: 6px; border-radius: 6px 6px 3px 3px; background: var(--c, var(--line-strong)); border: 1px solid var(--line-strong); }
.finger .bar.empty { background: transparent; border-style: dashed; }
.finger .v { font: 700 0.95rem/1.2 var(--font-mono); }
.finger .n { font-size: 0.72rem; color: var(--muted); margin-top: 4px; white-space: nowrap; }
.finger .a { font-size: 0.72rem; font-family: var(--font-mono); }
.finger.thumb .n { font-weight: 600; }
@media (max-width: 560px) { .fingers { gap: 3px; height: 150px; } .finger .n { font-size: 0.62rem; white-space: normal; } }
.word-list { list-style: none; padding: 0; margin: 8px 0 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 4px 12px; }
.word-list li { display: flex; justify-content: space-between; gap: 8px; border-bottom: 1px solid var(--line); padding: 3px 0; }

/* Typing surface: looking back or ahead (wheel, trackpad, Up/Down) */
.typing.peeking .viewport { box-shadow: inset 0 -2px 0 var(--accent-soft), inset 0 2px 0 var(--accent-soft); }
.typing .peek-note { display: none; position: absolute; right: 12px; bottom: 6px; font: 600 0.72rem/1 var(--font-ui); color: var(--muted); background: var(--surface); padding: 3px 6px; border-radius: 5px; }
.typing.peeking .peek-note { display: block; }

.sql-scroll { overflow-x: auto; margin: 8px 0; }
.table-scroll { overflow-x: auto; }   /* a table wider than a phone scrolls inside its card, not the page */
.table-scroll td.mono { white-space: nowrap; }
.sql-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
table.plain caption { text-align: left; color: var(--muted); font-size: 0.85rem; padding: 4px 0; caption-side: top; }
table.plain td.num, table.plain th.num { text-align: right; font-variant-numeric: tabular-nums; }
.sql-scroll table.plain td { white-space: nowrap; }
.sql-scroll table.plain th { text-transform: none; letter-spacing: 0; font-size: 0.9rem; white-space: nowrap; }
.sql-scroll table.wrap td, .sql-scroll table.wrap th { white-space: normal; }
.py-output { margin: 8px 0; padding: 10px 14px; background: var(--surface-2); border: 1px solid var(--line); border-radius: 8px; overflow-x: auto; font: 0.9rem/1.5 var(--font-mono); white-space: pre; }
.py-output:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.sql-null { color: var(--muted); font-style: italic; }
.sql-change { font-weight: 600; }
.sql-db h3 { font-size: 1rem; margin: 0; }
.plain-reading { background: var(--accent-soft); border-radius: 8px; padding: 10px 14px; margin: 0 0 10px; }

/* Hand-position picture (ui/hands.js): see-through hands on the home row. */
.hands { margin-top: 14px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.hands > summary { padding: 12px 2.4em 12px 16px; font-weight: 600; min-height: 44px; display: flex; align-items: center; }
.hands-body { display: grid; grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr); gap: 18px; padding: 0 16px 16px; align-items: center; }
.hands-figure { width: 100%; height: auto; max-height: 300px; }
.hands-figure .hf-key { fill: var(--surface); stroke: var(--line-strong); stroke-width: 1.5; }
.hands-figure text { fill: var(--ink); font: 600 13px var(--font-ui); text-anchor: middle; }
.hands-figure .hf-keytxt { font: 700 17px var(--font-mono); }
.hands-figure .hf-keytxt.hf-small { font: 600 12px var(--font-ui); fill: var(--muted); }
.hands-figure .hf-fname, .hands-figure .hf-hname { fill: var(--ink-2); font-size: 12px; }
.hands-figure .hf-finger, .hands-figure .hf-palm { fill: var(--c, var(--f-th)); fill-opacity: 0.5; stroke: var(--ink-2); stroke-opacity: 0.55; stroke-width: 1.5; }
.hands-figure .hf-palm { --c: var(--f-th); fill-opacity: 0.22; }
.hands-figure .hf-thumb { stroke: var(--f-th); stroke-opacity: 0.6; stroke-width: 24; stroke-linecap: round; }
.hands-figure .hf-bump { stroke: var(--ink-2); stroke-width: 3; stroke-linecap: round; }
.f-lp { --c: var(--f-lp); } .f-lr { --c: var(--f-lr); } .f-lm { --c: var(--f-lm); } .f-li { --c: var(--f-li); }
.f-ri { --c: var(--f-ri); } .f-rm { --c: var(--f-rm); } .f-rr { --c: var(--f-rr); } .f-rp { --c: var(--f-rp); }
.hands-tips { margin: 0; padding-left: 1.1em; }
.hands-tips li { margin: 5px 0; }
@media (max-width: 720px) { .hands-body { grid-template-columns: 1fr; } }
.hands.compact .hands-body { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 12px; padding-bottom: 12px; }
.hands.compact .hands-figure { max-height: 150px; }
.hands.compact .hands-tips { font-size: 0.88rem; }
.hands.compact .hands-tips li { margin: 3px 0; }
.hands.compact .hands-body > div > p { display: none; }
@media (max-width: 720px) { .hands.compact .hands-body { grid-template-columns: 1fr; } }

/* Home row page: exercise first, then the hand picture; compact heading and result strip */
.page-head.compact { padding: 16px 0 4px; margin-bottom: 8px; }
.page-head.compact h1 { font-size: clamp(1.5rem, 3.4vw, 2rem); margin-bottom: 4px; }
.page-head.compact p { margin: 0; }
/* Step map: how far along each Home row step is, in shape as well as colour. */
.hr-map { margin-bottom: 8px; }
.hr-map-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }
.hr-tile, .hr-key-tile { box-sizing: border-box; border: 2px solid var(--line-strong); background: var(--surface); color: var(--ink); }
.hr-tile { display: grid; place-items: center; width: 34px; height: 34px; border-radius: 8px; font: 700 0.8rem/1 var(--font-mono); text-decoration: none; cursor: pointer; position: relative; padding: 0; }
.hr-key-tile { display: inline-block; width: 12px; height: 12px; border-radius: 3px; vertical-align: -1px; }
.hr-tile[data-state="started"], .hr-key-tile[data-state="started"] { border-color: var(--accent); background: linear-gradient(to top, color-mix(in srgb, var(--accent) 40%, var(--surface)) 50%, var(--surface) 50%); }
.hr-tile[data-state="completed"], .hr-key-tile[data-state="completed"] { border-color: var(--accent); background: color-mix(in srgb, var(--accent) 40%, var(--surface)); }
.hr-tile[data-state="mastered"], .hr-key-tile[data-state="mastered"] { border-color: var(--accent); background: var(--accent); color: var(--on-accent); }
.hr-tile[data-state="mastered"]::after { content: "\2713"; position: absolute; top: -6px; right: -5px; font: 700 0.7rem/1 var(--font-ui); background: var(--ink); color: var(--bg); border-radius: 999px; width: 15px; height: 15px; display: grid; place-items: center; }
.hr-tile[aria-current="step"] { box-shadow: 0 0 0 2px var(--bg), 0 0 0 4px var(--ink); }
.hr-map-caption { margin: 8px 0 0; }
.hr-map-key { white-space: nowrap; margin-left: 4px; }
@media (forced-colors: active) { .hr-tile[aria-current="step"] { outline: 3px solid Highlight; } .hr-tile[data-state="mastered"] { forced-color-adjust: none; } }
.hr-fingers { display: flex; flex-wrap: wrap; gap: 6px; }
.hr-fingers[hidden] { display: none; }
.hr-finger { font: inherit; font-size: 0.88rem; color: var(--ink); background: var(--surface); border: 1px solid var(--line-strong); border-bottom: 4px solid var(--c); border-radius: 8px; padding: 6px 10px; cursor: pointer; }
.hr-finger[aria-pressed="true"] { background: color-mix(in srgb, var(--c) 30%, var(--surface)); border-color: var(--c); font-weight: 700; }
.hr-finger-home { font-family: var(--font-mono); color: var(--muted); }
.hr-stepper { display: flex; align-items: center; gap: 4px; border: 1px solid var(--line-strong); border-radius: 9px; background: var(--surface); padding: 4px; }
.hr-stepper .btn[disabled] { opacity: 0.35; }
.hr-step-label { flex: 1; min-width: 0; text-align: center; display: flex; flex-direction: column; gap: 0; }
.hr-step-count { font-size: 0.76rem; color: var(--muted); }
.hr-step-name { font: 600 0.92rem/1.25 var(--font-ui); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.hr-step-done { font: 600 0.76rem/1.3 var(--font-ui); color: var(--ok); }
.hr-step-done::before { content: "\2713  "; }
.hr-stepper .btn.hr-next-ready { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
@media (max-width: 480px) { .hr-step-name { white-space: normal; text-overflow: clip; } }
.hr-ready { margin: 0 0 6px; color: var(--muted); }
.hr-last { padding: 8px 12px; }
.hr-top { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 6px 12px; }
.hr-last .ft-grid { margin-top: 6px; }
.hr-headline { margin: 0; }
.mt-8 { margin-top: 8px; }
.ft-grid { list-style: none; margin: 8px 0 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(92px, 1fr)); gap: 6px; }
.ft { display: grid; grid-template-columns: auto 1fr; grid-template-rows: auto auto; column-gap: 8px; align-items: baseline; border: 1px solid var(--line-strong); border-left-width: 5px; border-radius: 8px; padding: 4px 8px; background: var(--surface); }
.ft .k { font: 700 1rem/1 var(--font-mono); grid-row: 1 / 3; align-self: center; }
.ft .v { font: 700 0.95rem/1.1 var(--font-mono); text-align: right; }
.ft .n { font-size: 0.7rem; color: var(--muted); text-align: right; }
.ft.ok { border-left-color: var(--ok); }
.ft.mid { border-left-color: color-mix(in srgb, var(--ok) 50%, var(--err) 50%); }
.ft.low { border-left-color: var(--err); }
.keyguide .key .k2 { position: absolute; top: 3px; left: 5px; font-size: 0.6rem; font-weight: 600; opacity: 0.8; }
.keyguide .key .k3 { position: absolute; bottom: 6px; right: 4px; font-size: 0.55rem; font-weight: 600; opacity: 0.75; }
.kb-line { margin: 0 0 8px; }
.kb-line a { font-weight: 600; }
@keyframes attention { 0% { box-shadow: 0 0 0 0 var(--accent); } 100% { box-shadow: 0 0 0 10px transparent; } }
.settings-flash { animation: attention 1.4s ease-out 2; border-radius: 8px; }
@media (prefers-reduced-motion: reduce) { .settings-flash { animation: none; outline: 3px solid var(--accent); } }
.brand-name .tm { font-size: 0.5em; font-weight: 400; margin-left: 1px; vertical-align: super; }

.preview-tag { align-self: center; margin-left: 2px; border: 1px solid var(--accent); border-radius: 999px; padding: 2px 9px; font: 700 0.68rem/1.3 var(--font-display); letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink); background: var(--surface); }

/* Windows high-contrast (forced colors) drops backgrounds and shadows: keep the cursor, the lit key and the chosen toggle visible. */
@media (forced-colors: active) {
  .typing .ch.cur { outline: 2px solid Highlight; }
  .typing .ch.wrong { text-decoration: line-through; }
  .keyguide .key.next { outline: 3px solid Highlight; }
  .segmented button[aria-pressed="true"] { outline: 2px solid Highlight; outline-offset: -3px; }
}
.msg .source { display: block; margin-top: 8px; font-size: 0.85rem; }

/* Loading: the home row keys tap in a rolling wave and light up in their finger colors as the real loading
   steps finish (js/app.js sets --p and the .on keys). It fades in after a short delay, so a fast load never
   flashes it. Reduced motion: no waves and no fades, just the keys and the bar. */
.boot { display: grid; justify-items: center; gap: 16px; padding: 88px 0 48px; animation: boot-in 0.4s ease-out 0.18s backwards; }
.boot-keys { display: flex; gap: 7px; }
.boot-key { width: 42px; height: 42px; border-radius: 9px; border: 1px solid var(--line-strong); background: var(--surface); display: grid; place-items: center; font: 700 1.05rem/1 var(--font-mono); color: var(--muted); box-shadow: 0 3px 0 var(--line-strong); animation: boot-tap 1.5s ease-in-out infinite; transition: background 0.25s, border-color 0.25s, color 0.25s; }
.boot-key:nth-child(2) { animation-delay: 0.1s; } .boot-key:nth-child(3) { animation-delay: 0.2s; } .boot-key:nth-child(4) { animation-delay: 0.3s; }
.boot-key:nth-child(5) { animation-delay: 0.4s; } .boot-key:nth-child(6) { animation-delay: 0.5s; } .boot-key:nth-child(7) { animation-delay: 0.6s; } .boot-key:nth-child(8) { animation-delay: 0.7s; }
.boot-key.on { background: color-mix(in srgb, var(--c) 45%, var(--surface)); border-color: var(--c); color: var(--ink); }
.boot-line { width: min(378px, 82vw); height: 5px; border-radius: 3px; background: var(--surface-2); overflow: hidden; }
.boot-fill { display: block; height: 100%; width: calc(var(--p, 0.08) * 100%); min-width: 8%; border-radius: 3px; background: linear-gradient(90deg, var(--f-lp), var(--f-lr), var(--f-lm), var(--f-li), var(--f-ri), var(--f-rm), var(--f-rr), var(--f-rp)); transition: width 0.3s ease-out; }
.boot-text { margin: 0; letter-spacing: 0.04em; }
@keyframes boot-tap { 0%, 55%, 100% { transform: none; box-shadow: 0 3px 0 var(--line-strong); } 25% { transform: translateY(3px); box-shadow: 0 0 0 var(--line-strong); } }
@keyframes boot-in { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
/* BOOT-2: with every animation off, the screen showed at once and flashed for 60 to 90 ms on a quick start. It waits the same
   0.18 s here, hidden and then shown without a fade (a wait is not motion), so it appears only when a start is actually slow. */
@keyframes boot-wait { from, to { visibility: hidden; } }
@media (prefers-reduced-motion: reduce) { .boot { animation: boot-wait 0.18s step-end !important; } }
:root[data-motion="reduce"] .boot { animation: boot-wait 0.18s step-end !important; }
@media (max-width: 420px) { .boot-keys { gap: 5px; } .boot-key { width: 34px; height: 36px; font-size: 0.95rem; } }

/* Progress charts (ui/charts.js): themed by tokens; meaning never rests on color alone (shape and shade too). */
.chart .plot { fill: var(--surface); stroke: var(--line); }
.chart .band { fill: var(--accent); opacity: 0.2; stroke: none; }
.chart .fit { fill: none; stroke: var(--ink); stroke-width: 2; }
.chart .band-then { fill: var(--ink-2); opacity: 0.14; stroke: none; }
.chart .fit-then { fill: none; stroke: var(--ink-2); stroke-width: 2; stroke-dasharray: 7 5; }
.chart .trail { fill: none; stroke: var(--line-strong); stroke-width: 1.2; }
.pt.pt-stale { opacity: 0.35; }
.chart .pair-link { stroke: var(--accent); stroke-width: 1.2; opacity: 0.45; }
/* Opening check: a filled circle; closing check: a hollow diamond drawn around it, so a pair nests when the two agree. */
.pt.pt-open, .chart-legend .pt-open { fill: var(--accent); stroke: none; }
.chart .pt-latest-open { stroke: var(--ink); stroke-width: 1.5; }
.pt.pt-close, .chart-legend .pt-close { fill: none; stroke: var(--accent); stroke-width: 1.6; }
.chart .panel-title { fill: var(--ink-2); font: 600 12px var(--font-ui); }
.chart .ref-line { stroke: var(--muted); stroke-width: 1; stroke-dasharray: 4 4; }
.chart .margin-label text { fill: var(--muted); font: 11px var(--font-ui); }
.chart .margin-label.end text { fill: var(--ink-2); font-weight: 600; }
.chart .margin-label.step-current text { fill: var(--ink); font-weight: 700; }
.chart polyline.step { fill: none; stroke: var(--muted); stroke-width: 1; opacity: 0.7; }
.chart polyline.step-current { stroke: var(--ink); stroke-width: 2; opacity: 1; }
.chart .axis-title { fill: var(--muted); font: 600 11px var(--font-ui); }
.chart .range { stroke: var(--ink-2); stroke-width: 2; }
.pt { stroke: var(--bg); stroke-width: 1; }
.pt-old { fill: var(--muted); opacity: 0.55; }
.pt-new { fill: var(--accent); opacity: 0.85; }
.pt-latest { fill: var(--ink); stroke: var(--accent); stroke-width: 2.5; }
.chart .pt-then, .chart-legend .pt-then { fill: none; stroke: var(--ink-2); stroke-width: 1.8; }
.pt-alt, .pt-main { fill: var(--accent); }
.pt-hand { fill: var(--ink-2); }
.pt-finger { fill: var(--err); }
.pt-repeat { fill: var(--ok); }
.chart .pt-slow { stroke: var(--ink); stroke-width: 2; }
.chart-legend { list-style: none; display: flex; flex-wrap: wrap; gap: 6px 16px; padding: 0; margin: 8px 0 0; font-size: 0.85rem; }
.chart-legend li { display: flex; align-items: center; gap: 6px; }
.page-links { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 0 0 12px; font-size: 0.9rem; }
@media (forced-colors: active) { .pt { stroke: CanvasText; } .pt.pt-close { fill: none; } .chart .step, .chart .ref-line { stroke: CanvasText; } .chart .fit, .chart .fit-then, .chart .range { stroke: CanvasText; } .chart .band-then { fill: GrayText; opacity: 0.25; } .chart .pt-then { stroke: CanvasText; } .chart .band { fill: Highlight; opacity: 0.3; } }

/* ── Progress: view switch, insight cards, question cards ─────────────── */
.view-toggle { display: inline-flex; border: 1px solid var(--line-strong); border-radius: 9px; overflow: hidden; background: var(--surface); margin: 0 0 16px; }
.view-toggle .view-link { font: 600 0.88rem/1 var(--font-ui); padding: 11px 16px; color: var(--ink); text-decoration: none; min-height: 40px; display: inline-flex; align-items: center; }
.view-toggle .view-link + .view-link { border-left: 1px solid var(--line); }
.view-toggle .view-link[aria-current="page"] { background: var(--ink); color: var(--bg); }
.view-toggle .view-link:focus-visible { outline-offset: -4px; }
/* FOC-1: the ring on a selected switch item is drawn inside it, on --ink, where --focus falls to 1.6 to 2.7 to 1; --bg on
   --ink is at least 4.5 to 1 in every theme (tests/design.test.js). */
.view-toggle .view-link[aria-current="page"]:focus-visible, .segmented button[aria-pressed="true"]:focus-visible { outline-color: var(--bg); }
.insights { margin-top: 20px; }
.insights h2, .qcards h2 { margin: 0 0 4px; }
.insights .lede, .qcards .lede { margin: 0 0 12px; }
.insight { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); padding: 16px 18px; display: flex; flex-direction: column; gap: 8px; box-shadow: var(--shadow); }
.insight + .insight { margin-top: 12px; }
.insight .tag { align-self: flex-start; font: 700 0.72rem/1.2 var(--font-ui); letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); }
.insight.good .tag::before { content: ""; display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--ok, var(--accent)); margin-right: 7px; }
.insight .find { margin: 0; font-size: 1.05rem; line-height: 1.45; font-weight: 600; }
.insight .why { margin: 0; color: var(--muted); font-size: 0.92rem; }
.insight .do { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: center; margin-top: 2px; }
.insights-empty { border: 1px dashed var(--line-strong); border-radius: var(--radius); padding: 14px 18px; color: var(--muted); }
.qcards { margin-top: 28px; }
.qcard { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); box-shadow: var(--shadow); }
.qcard + .qcard { margin-top: 10px; }
.qcard > summary { padding: 14px 2.6em 14px 18px; display: grid; grid-template-columns: 1fr; gap: 2px 12px; align-items: center; }
.qcard > summary::after { right: 18px; }
.qcard .q-title { font-weight: 700; }
.qcard .q-sum { grid-column: 1; color: var(--muted); font-size: 0.9rem; }
.qcard .qbody { padding: 0 18px 18px; }
.qcard .qbody > .card, .qcard .qbody > section.card { box-shadow: none; }
.qcard .qbody > * + * { margin-top: 12px; }
.time-bar { display: flex; height: 16px; border-radius: 5px; overflow: hidden; background: var(--surface-2); border: 1px solid var(--line); }
.time-bar .typing { background: var(--ok-soft, var(--surface-2)); }
.time-bar .fixing { background: var(--accent); }
.code-card .code-head { display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.code-card .code-head h2 { margin: 0; }
.code-card .code-insight { margin: 12px 0 0; }
.code-card details.sub { border-top: 1px solid var(--line); margin-top: 12px; padding-top: 4px; }
.code-card details.sub > summary { padding: 8px 2.4em 8px 0; display: flex; flex-wrap: wrap; gap: 2px 12px; align-items: baseline; }
.code-card details.sub > summary .q-title { font-weight: 700; }
.code-card details.sub > summary .q-sum { color: var(--muted); font-size: 0.9rem; }
@media (max-width: 640px) { .insight { padding: 14px; } .qcard > summary { padding: 12px 2.6em 12px 14px; } .qcard > summary::after { right: 14px; } .qcard .qbody { padding: 0 14px 14px; } }

.insight.coach-note { border-left: 4px solid var(--accent); }
.insight.coach-note .tag { text-transform: none; letter-spacing: 0.02em; font-size: 0.82rem; }
.insight + .insight { margin-top: 12px; }

.pair-cell { display: inline-flex; align-items: center; }
.flag-ring, .flag-gap { display: inline-block; width: 12px; height: 12px; margin-right: 8px; flex: none; }
.flag-ring { border: 2px solid var(--ink); border-radius: 50%; }
.chart-legend circle.pt-hollow { fill: none; stroke: var(--ink); stroke-width: 2; }

/* The update notice from the service worker (js/sw-register.js). */
.update-note { position: fixed; left: 16px; right: 16px; bottom: 16px; z-index: 50; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; justify-content: center; max-width: 640px; margin: 0 auto; padding: 12px 16px; background: var(--surface); color: var(--ink); border: 1px solid var(--line-strong); border-radius: 10px; box-shadow: 0 6px 24px rgba(0, 0, 0, 0.18); }

/* A dot on a header link where something is new (js/ui/badges.js), and the Coach's note for the day on Home. */
.nav-dot { display: inline-block; width: 8px; height: 8px; margin-left: 6px; border-radius: 50%; background: var(--accent); vertical-align: middle; }
.coach-note, .whats-new { margin: 12px 0; }
.coach-note .row, .whats-new .row { margin-top: 8px; }
.whats-new ul { margin: 6px 0 0; padding-left: 20px; }

/* Key check (ui/views/keycheck.js): a list of key groups, each a card, and the result below the check. */
.kc-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.kc-group h2 { margin-bottom: 4px; }
.kc-keys { letter-spacing: 0.12em; overflow-wrap: anywhere; }
.kc-result h3 { margin: 16px 0 6px; font-size: 1rem; }
.row.small input[type="checkbox"] { width: 24px; height: 24px; flex: none; }   /* the Feedback page's details checkbox: a 24 px target */

/* Surfacing fix: which colour is which finger, under the Progress keyboard. */
.finger-legend .finger-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; background: var(--finger); vertical-align: -1px; }

/* DM-1 Key colors: each character a tile in its finger's colour (.f-* sets --c). Inline tiles keep the line pitch the scroll
   depends on. In V1 the finger and the Shift side are shown by colour alone (the two Shift colours are close); V3 adds the
   finger pips (below) that make it more than colour. A character typed with Shift has
   a top edge in the Shift finger's colour. */
.typing .text.keytiles .ch.kt { background: color-mix(in srgb, var(--c) 24%, transparent); box-shadow: inset 0 -2px 0 var(--c); border-radius: 3px; }
.typing .text.keytiles .ch.f-th { --c: var(--f-th); }
.typing .text.keytiles .ch.kt.sp { background: color-mix(in srgb, var(--f-th) 14%, transparent); }
.typing .text.keytiles .ch.kt.sh-lp { box-shadow: inset 0 -2px 0 var(--c), inset 0 2px 0 var(--f-lp); }
.typing .text.keytiles .ch.kt.sh-rp { box-shadow: inset 0 -2px 0 var(--c), inset 0 2px 0 var(--f-rp); }
.typing .text.keytiles .ch.kt.done { background: transparent; box-shadow: inset 0 -2px 0 color-mix(in srgb, var(--c) 35%, transparent); }
.typing .text.keytiles .ch.kt.cur { background: var(--accent-soft); box-shadow: inset 0 -3px 0 var(--accent); }
.typing .text.keytiles .ch.kt.wrong { background: var(--err-soft); box-shadow: none; }
/* The miss flash and a capital's Shift edge must survive .cur, which every missed or next key carries (review 4, M1 and S1). */
.typing .text.keytiles .ch.kt.miss { background: var(--err); box-shadow: none; }
.typing .text.keytiles .ch.kt.cur.sh-lp { box-shadow: inset 0 -3px 0 var(--accent), inset 0 2px 0 var(--f-lp); }
.typing .text.keytiles .ch.kt.cur.sh-rp { box-shadow: inset 0 -3px 0 var(--accent), inset 0 2px 0 var(--f-rp); }
/* DM-1 V3 finger pips, so the finger is never shown by colour alone: under each letter still to type, one to four dots count
   the finger from the index (1) to the pinky (4), set toward the left for the left hand and toward the right for the right.
   Sized in em so four fit inside one character at every text size; drawn below the tile, in the line's gap, never above a
   letter (they would read as accents). The group is exactly n tiles wide and `round` fits exactly n dots, whatever the
   pixel rounding (review dm1v3 S4). Spaces, typed letters, and a letter that carries the error underline after a Backspace
   (review S1) have none. Each group sits 0.05em in from its letter's edge, so a right-hand group and the next letter's
   left-hand group are twice as far apart as two dots. */
.typing .text.keytiles .ch.kt { position: relative; }
.typing .text.keytiles .ch.kt::after { content: ''; position: absolute; bottom: -0.2em; height: 0.08em; width: calc(var(--pips, 0) * 0.13em);
  background: linear-gradient(90deg, var(--ink-2) 0 0.08em, transparent 0.08em) 0 0 / 0.13em 100%; background-repeat: round no-repeat; }
.typing .text.keytiles .ch.kt:is(.f-lp, .f-lr, .f-lm, .f-li)::after { left: 0.05em; }
.typing .text.keytiles .ch.kt:is(.f-rp, .f-rr, .f-rm, .f-ri)::after { right: 0; }
.typing .text.keytiles .ch.kt:is(.f-li, .f-ri) { --pips: 1; }
.typing .text.keytiles .ch.kt:is(.f-lm, .f-rm) { --pips: 2; }
.typing .text.keytiles .ch.kt:is(.f-lr, .f-rr) { --pips: 3; }
.typing .text.keytiles .ch.kt:is(.f-lp, .f-rp) { --pips: 4; }
.typing .text.keytiles .ch.kt:is(.done, .sp, .had-err)::after { content: none; }
.typing .text.keytiles .pace-bar { margin-top: 0.25em; }   /* below the pips, not over them (review S2) */
/* DM-1: the Plain text / Key colors switch under the typing card (site/js/ui/displayswitch.js); its line says when it applies. */
.display-switch { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 12px; margin-top: 10px; }
.session-actions .display-switch { margin: 0 auto 0 0; }   /* in the session it leads the Skip and End row, adding no height */
.display-switch .segmented button { min-height: 32px; padding: 7px 12px; font-size: 0.82rem; }
/* Forced colours drop the tile colours and shadows, so the pips are the finger cue left: they keep their exact count
   (forced-color-adjust: none on the dots only, drawn in CanvasText), the tile keeps an edge, and a Shift letter keeps a top
   edge (review M1 and S3). The current key keeps its Highlight ring. */
@media (forced-colors: active) {
  .typing .text.keytiles .ch.kt:not(.done, .sp, .cur) { outline: 1px solid CanvasText; outline-offset: -1px; }
  .typing .text.keytiles .ch.kt::after { forced-color-adjust: none;
    background: linear-gradient(90deg, CanvasText 0 0.08em, transparent 0.08em) 0 0 / 0.13em 100%; background-repeat: round no-repeat; }
  .typing .text.keytiles .ch.kt:is(.sh-lp, .sh-rp):not(.done) { border-top: 2px solid CanvasText; }
}
