/* Lociverse — component layer, direction D "glass" (see docs/UI_SPEC.md).
   Visual values come from styles/tokens.css only. Logical properties only (RTL-ready). */

/* ---------- shell: hero band → glass card → floating dock ---------- */
body { margin: 0; background: var(--bg); color: var(--text); font-family: var(--font-ui); }   /* no white flash / 8 px UA margin around the column */

/* Browser surfaces. These ship with browser defaults that belong to no design system; themed from the
   palette, they are the cheapest signal that a page was built rather than assembled. */
::selection { background: var(--accent-soft); color: var(--text); }
:root { color-scheme: dark; accent-color: var(--accent); caret-color: var(--accent); }
:root[data-theme="light"] { color-scheme: light; }
input, textarea, [contenteditable] { caret-color: var(--accent); }

/* the rail is the desktop sidebar; on a phone it is an empty wrapper and the dock is the pill.
   display:contents makes the dock a direct child of .app, so the rail's own brand and utility nav
   must be hidden below the desktop breakpoint or they render as phone furniture. */
.rail { display: contents; }
.rail-brand, .rail-foot { display: none; }

/* the footer is a real footer on a desktop and one quiet link on a phone */
.site-foot { display: none; }

/* The shell always fills the window. There is deliberately no max-width here: the app used to be a
   430px (then 600px) column centred in the viewport, which left a wide empty margin on a tablet and
   on any window wider than the column. The background, the hero band and the dock now span the full
   width at EVERY size. Readability is kept by capping the text blocks INSIDE (`.copy` 34ch,
   `.top .sub` 56ch, `--measure` on the prose screens, 800px on a lesson) instead of the shell. */
.app {
  position: relative; inline-size: 100%; min-block-size: 100dvh;
  /* border-box is REQUIRED, not cosmetic: at ≥1024 this element also carries
     padding-inline-start: var(--rail-w), and with the default content-box a 100% width plus that
     padding overflows the window by exactly the rail's width. */
  box-sizing: border-box;
  display: flex; flex-direction: column; background: var(--bg); overflow-x: hidden;
  isolation: isolate;   /* the band's z-index:-1 layers stay above the column's own background */
}

/* the band lives on the hero and is anchored to its bottom edge — i.e. to the card line — so the
   light always gathers around the card and the copy always sits on the solid part, whatever the
   screen's title length. ::before = base (behind the title), ::after = D's glow (runs under the
   card and fades out below it). Both sit under all content (z-index -1 inside .app). */
.hero { position: relative; padding: 14px 22px 46px; }
.hero::before, .hero::after {
  content: ""; position: absolute; inset-inline: 0; pointer-events: none; z-index: -1;
}
.hero::before { inset-block: 0 calc(var(--hero-overlap) + 40px); background: var(--hero-base); }
.hero::after {
  inset-block-start: calc(100% - var(--hero-overlap) - var(--hero-glow-top));
  block-size: var(--hero-glow-h); background: var(--hero-grad);
}
[dir="rtl"] .hero::after { transform: scaleX(-1); }   /* sidelights follow the reading direction */
.hero .brandrow { display: flex; align-items: center; gap: 10px; justify-content: flex-end; }
.hero .mark { display: inline-flex; color: var(--hdr); }
/* the brand ships two cuts of the mark (cream / ink arches); the band's ink decides which shows */
/* Theme selection for the mark's two cuts. This must cover EVERY mark, not just the hero's: the rail
   brand and the site footer were added outside .hero and so were painting both cuts at once.
   Nothing here may out-specify those two rules. `.hero .mark > span` used to sit at 0-2-1 — above
   `.mark .mk-l` and `[data-theme="light"] .mark .mk-d` at 0-2-0 — so inside the hero the light cut was
   never hidden in dark and the dark cut never hidden in light: both logos, 66px wide. It was a
   duplicate of the `.mark > span` rule below it and only ever added specificity, so it is gone. */
.mark .mk-l, [data-theme="light"] .mark .mk-d { display: none; }
[data-theme="light"] .mark .mk-l { display: inline-flex; }
.mark > span { display: inline-flex; }
.hero .wordmark { font: 600 15px/1 var(--font-ui); letter-spacing: -0.01em; color: var(--hdr);
  /* the wordmark owns the left edge; everything after it (chip, settings) hugs the right, so the
     button keeps its place on heroes that carry no XP chip (Progress, lesson steps, results) */
  margin-inline-end: auto; }
.hero .xpchip {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 12px; border-radius: var(--radius-pill);
  background: var(--hero-glass); border: 1px solid var(--hero-glass-border);
  -webkit-backdrop-filter: var(--glass-blur-sm); backdrop-filter: var(--glass-blur-sm);
  font: 500 13px/1 var(--font-ui); color: var(--hdr);
}

/* title row: kicker + h1 on the left, progress ring on the right */
.top { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px;
  padding-block: 18px 0; }
.top .lead { min-width: 0; }
.top .kicker { margin: 0 0 6px; font: 500 12.5px/1 var(--font-ui); color: var(--hdr); opacity: var(--hdr-kicker-o); }
.top h1 { margin: 0; font: 500 var(--fs-h1)/var(--lh-h1) var(--font-ui);
  letter-spacing: var(--ls-h1); color: var(--hdr); }
.top h1.locus { font-size: 34px; letter-spacing: -0.025em; }
.top .sub { margin: 8px 0 0; font: 400 13.5px/1.45 var(--font-ui); color: var(--hdr);
  opacity: var(--hdr-sub-o); max-width: 30ch; }

/* progress ring — 94px, hairline track, value arc in the accent */
.ring { position: relative; inline-size: 94px; block-size: 94px; flex: none; color: var(--hdr); }
.ring svg { inline-size: 94px; block-size: 94px; display: block; }
.ring .t { fill: none; stroke: var(--ring); stroke-width: 1.5; }
.ring .v { fill: none; stroke: var(--ring-v); stroke-width: 3; stroke-linecap: round;
  transform: rotate(-90deg); transform-origin: 50% 50%; }
.ring div { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center;
  justify-content: center; gap: 2px; text-align: center; }
.ring b { font: 600 19px/1 var(--font-ui); letter-spacing: -0.01em; }
.ring small { font: 400 12px/1.2 var(--font-ui); opacity: var(--hdr-small-o); }

/* hero illustration — hand-drawn SVG from js/screens/art.js, coloured only through the --art tokens */
.hero-art { flex: none; inline-size: var(--art-w); margin-block-start: -4px; }
.hero-art.lg { inline-size: var(--art-w-lg); }
.hero-art .art { display: block; inline-size: 100%; block-size: auto; overflow: visible; }
.art .a-l { fill: none; stroke: var(--art-line); stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.art .a-gl { fill: none; stroke: var(--art-glow); stroke-width: 2.4; stroke-linecap: round; stroke-linejoin: round; }
.art .a-g { fill: var(--art-glow); }
.art .a-s { fill: var(--art-soft); }
[dir="rtl"] .hero-art .art { transform: scaleX(-1); }

/* ---------- body + the glass card that overlaps the hero ---------- */
.body { flex: 1; padding-block-end: 160px; }
.wrap { padding-inline: 22px; }

.card {
  position: relative; z-index: 1; margin-block-start: calc(-1 * var(--hero-overlap)); padding: 22px 24px;
  border-radius: var(--radius-card); background: var(--glass);
  border: 1px solid var(--glass-border); box-shadow: var(--shadow-card);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
}
.card + .card { margin-block-start: 14px; }
.card h2 { margin: 0; font: 600 var(--fs-h2)/1.15 var(--font-ui);
  letter-spacing: var(--ls-h2); color: var(--text); }
/* .k = quiet secondary line; also used as a loose note under a card (Settings) */
.card .k, .wrap > .k { font: 400 13.5px/1.4 var(--font-ui); color: var(--text-muted); }

/* chips + small labels */
.chips { display: flex; gap: 8px; flex-wrap: wrap; }
.chip { display: inline-flex; align-items: center; gap: 6px; padding: 6px 11px;
  border-radius: var(--radius-pill); background: var(--glass-flat);
  border: 1px solid var(--glass-border); font: 500 12.5px/1 var(--font-ui); color: var(--text-muted); }
.cap { font: 500 var(--fs-cap)/1 var(--font-ui); letter-spacing: var(--ls-cap);
  text-transform: uppercase; color: var(--text-faint); }
.cap.accent { color: var(--accent-text); }
.mono { font-family: var(--font-mono); font-variant-numeric: tabular-nums; }

/* number + image pair ("Today's image") */
.pair { display: flex; align-items: center; gap: 16px; margin: 14px 0 0; }
.numTile { display: flex; flex-direction: column; gap: 7px; padding: 14px 18px 12px;
  border-radius: var(--radius-tile); background: var(--glass-flat);
  border: 1px solid var(--glass-border); }
.numTile small { font: 500 10.5px/1 var(--font-ui); letter-spacing: var(--ls-cap);
  text-transform: uppercase; color: var(--text-muted); }
.numTile span { font: 600 42px/1 var(--font-mono); letter-spacing: -0.01em; color: var(--text); }
.imgpair { display: flex; align-items: center; gap: 12px; min-width: 0; }
.emoji { font-size: 40px; line-height: 1; }
.word { font: 600 23px/1.1 var(--font-ui); letter-spacing: -0.01em; color: var(--text); }
.sounds { font: 400 12.5px/1 var(--font-mono); color: var(--text-faint); }
.sounds.teaser { font-family: var(--font-ui); font-style: italic; }
.alt-word { font: 400 15px/1 var(--font-ui); color: var(--text-dim); }

.copy { margin: 14px 0 0; font: 400 14.5px/1.6 var(--font-ui); color: var(--text-muted);
  max-inline-size: 34ch; }
.hint { display: flex; gap: 10px; align-items: flex-start; margin-block-start: 16px; padding: 13px 15px;
  border: 1px solid var(--glass-border); border-radius: var(--radius-row);
  background: var(--glass-flat); color: var(--text-muted); font: 400 13.5px/1.5 var(--font-ui);
  transition: border-color var(--dur) var(--ease); }
.hint.flash { border-color: var(--accent); }
.hint .ic { color: var(--accent); flex: none; margin-block-start: 1px; }

/* the key-takeaway callout (mockup 05): same family as .hint, with the accent rule on the reading edge */
.aside { margin-block-start: 16px; padding: 12px 15px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
  border-inline-start: 3px solid var(--accent);
  font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted); }
.aside b { color: var(--text); font-weight: 600; }

/* frosted stacked rows — "Next up", "Last run", "Personal best" */
.stack { display: flex; flex-direction: column; gap: 10px; margin-block-start: 14px; }
.stack:has(.peek.above), .stack:has(.peek.below) { gap: 0; }
.peek { display: flex; align-items: center; gap: 12px; min-block-size: 62px; padding-inline: 20px;
  border-radius: var(--radius-card); background: var(--row-glass);
  border: 1px solid var(--glass-border); color: var(--text);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  font: 500 15px/1.2 var(--font-ui); }
.peek .k { color: var(--text-muted); font-weight: 400; }
.peek .end { margin-inline-start: auto; display: inline-flex; align-items: center; gap: 8px;
  color: var(--text-muted); font-weight: 500; }
.peek .mini { font-size: 20px; line-height: 1; }
.peek .ic { color: var(--accent); flex: none; }
.peek.above {
  min-block-size: 84px; padding-block-end: 32px; margin-inline: 6px;
  border-radius: var(--radius-card);
}
.peek.below {
  min-block-size: 78px; padding-block-start: 32px; margin-block-start: -36px; margin-inline: 6px;
  position: relative; z-index: 0; border-radius: var(--radius-card);
}
.peek.below .num, .peek.above .num { margin-inline-start: auto; font-family: var(--font-mono); font-weight: 600; }

/* route dots */
.route { display: flex; align-items: center; gap: 9px; margin-block-start: 18px; }
.route .d { inline-size: 9px; block-size: 9px; border-radius: 50%; background: var(--glass-flat);
  border: 1px solid var(--glass-border); }
.route .d.done { background: var(--accent); border-color: var(--accent); }
.route .d.now { inline-size: 12px; block-size: 12px; background: transparent;
  border: 2px solid var(--accent); }
.route .lbl { margin-inline-start: 6px; font: 400 11.5px/1 var(--font-ui); color: var(--text-faint); }

/* ---------- buttons ---------- */
.cta { display: flex; gap: 12px; align-items: center; margin-block: 20px 4px; }
.card .cta { margin-block: 18px 0; }
.btn { flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  min-block-size: 52px; padding-inline: 20px; border: 0; border-radius: var(--radius-pill);
  background: var(--btn-bg); color: var(--btn-fg); font: 600 15px/1 var(--font-ui); cursor: pointer;
  transition: background var(--dur) var(--ease), transform var(--dur-fast) var(--ease); }
.btn:hover { background: var(--accent-hover); color: var(--accent-ink); }
.btn:active { transform: scale(.985); }
.btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.btn.ghost { flex: 0 0 auto; background: var(--btn-ghost-bg); color: var(--btn-ghost-fg);
  border: 1px solid var(--glass-border); }
.btn.ghost:hover { background: var(--glass-flat); color: var(--text); }
.btn:disabled, .btn[disabled] { opacity: .35; cursor: not-allowed; pointer-events: none; }

/* small round glass button holding an orange glyph */
.pip { inline-size: 30px; block-size: 30px; border-radius: 50%; background: var(--surface);
  border: 1px solid var(--glass-border); display: grid; place-items: center;
  box-shadow: var(--shadow-pip); color: var(--accent); cursor: pointer; flex: none; }
.pip .ic { inline-size: 16px; block-size: 16px; }

/* round glass button in the hero's top-right corner — D puts Settings / Search / Language here.
   D draws it at 58 px; that is well above the 44 px hit-target floor, so D's value stands. */
.glassbtn { inline-size: 58px; block-size: 58px; flex: none; border-radius: 50%;
  display: grid; place-items: center; background: var(--hero-glass);
  border: 1px solid var(--hero-glass-border); color: var(--hdr); cursor: pointer;
  -webkit-backdrop-filter: var(--glass-blur-sm); backdrop-filter: var(--glass-blur-sm);
  transition: background var(--dur) var(--ease); }
.glassbtn:hover { background: var(--hero-glass-hover); }
.glassbtn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }

/* segmented control (the timed toggle from Phase 4 on; the theme switch in Settings) */
.seg { display: flex; gap: 4px; padding: 4px; border-radius: var(--radius-pill);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
  -webkit-backdrop-filter: var(--glass-blur-sm); backdrop-filter: var(--glass-blur-sm); }
.seg button { flex: 1; min-block-size: 44px; padding-inline: 14px; border: 0; border-radius: var(--radius-pill);
  background: none; color: var(--text-muted); font: 500 13.5px/1 var(--font-ui); cursor: pointer; }
.seg button[aria-selected="true"], .seg button[aria-checked="true"] { background: var(--surface); color: var(--text); }

/* settings rows — one line per setting, hairline separated */
.rows { display: flex; flex-direction: column; }
.row { display: flex; align-items: center; gap: 12px; inline-size: 100%; min-block-size: 56px;
  padding-inline: 2px; border-block-end: 1px solid var(--glass-border);
  font: 500 15px/1.2 var(--font-ui); color: var(--text); text-align: start; background: none; border-inline: 0;
  border-block-start: 0; }
.row:last-child { border-block-end: 0; }
.row .ic { color: var(--accent); flex: none; }
.row .k { min-inline-size: 0; }
.row .v { margin-inline-start: auto; color: var(--text-muted); font-weight: 400;
  display: inline-flex; align-items: center; gap: 6px; text-align: end; }
.row .seg { margin-inline-start: auto; }
.row.soon .k, .row.soon .v { color: var(--text-muted); }   /* was opacity .6: 2.6-3.2:1 */
.row.as-button { cursor: pointer; }
.row.as-button:hover .k { color: var(--accent-text); }
.row.as-button:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
/* a row whose value is a sentence, not a word: label (with its icon) on top, value underneath */
.row.stacked { flex-direction: column; align-items: flex-start; gap: 5px; padding-block: 13px; }
.row.stacked .k { display: inline-flex; align-items: center; gap: 12px; }
.row.stacked .v { margin-inline-start: 0; text-align: start; }

/* ---------- floating dock (tab bar) ---------- */
.dock {
  position: fixed; inset-block-end: var(--dock-inset); inset-inline-start: 50%; translate: -50% 0;
  display: flex; gap: 6px; padding: 6px; border-radius: var(--radius-pill);
  background: var(--glass); border: 1px solid var(--glass-border);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  box-shadow: var(--shadow-dock), var(--shadow-halo); z-index: 20;
}
[dir="rtl"] .dock { translate: 50% 0; }   /* inset-inline-start flips; the centring nudge must too (as in D) */
.dock .tab { display: flex; align-items: center; gap: 8px; min-block-size: 48px; padding-inline: 14px;
  border: 0; border-radius: var(--radius-pill); background: none; color: var(--text-muted);
  font: 500 14px/1 var(--font-ui); cursor: pointer; }
.dock .tab:hover { color: var(--text); }
.dock .tab.on { background: var(--text); color: var(--bg); }
.dock .tab.on .ic { color: var(--accent); }
.dock .tab .lbl { display: none; }
.dock .tab.on .lbl { display: inline; }

/* ---------- placeholder screens ---------- */
.soon { display: flex; flex-direction: column; align-items: flex-start; gap: 14px;
  margin-block-start: 6px; color: var(--text-muted); font: 400 14.5px/1.6 var(--font-ui); }
.soon .ic { color: var(--accent); }
.soon p { margin: 0; max-inline-size: 30ch; }

/* toast — non-blocking status note (never a blocking dialog) */
/* The account picture is the size of a real avatar, not a dot in a big empty circle: 46px inside a
   64px button, so it reads as a profile picture at a glance. */
.btn-avatar {
  inline-size: 46px; block-size: 46px; border-radius: 50%; object-fit: cover; display: block;
  background: var(--glass-flat);
}
.glassbtn:has(> .btn-avatar) { inline-size: 64px; block-size: 64px; }
.toast {
  position: fixed; inset-inline: 22px; inset-block-end: 104px; max-inline-size: calc(var(--col) - 44px);
  margin-inline: auto; padding: 12px 16px; border: 1px solid var(--glass-border);
  border-radius: var(--radius-row); background: var(--glass); color: var(--text-muted);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  font: 400 13.5px/1.5 var(--font-ui); opacity: 0; transform: translateY(6px);
  transition: opacity .18s ease, transform .18s ease; pointer-events: none; z-index: 30;
}
.toast.show { opacity: 1; transform: none; }

/* ---------- library: search field + bank rows ---------- */
.search-wrap { position: relative; display: flex; align-items: center; margin-block-end: 16px; }
.search-wrap .ic { position: absolute; inset-inline-start: 16px; color: var(--text-muted); pointer-events: none; }
.search-input {
  inline-size: 100%; min-block-size: 48px; padding-inline: 46px 18px;
  border-radius: var(--radius-pill); background: var(--glass-flat);
  border: 1px solid var(--glass-border); color: var(--text);
  font: 500 14.5px/1 var(--font-ui); -webkit-backdrop-filter: var(--glass-blur-sm);
  backdrop-filter: var(--glass-blur-sm); outline: none; box-sizing: border-box;
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.search-input::placeholder { color: var(--text-muted); }
.search-input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }

.decade-group { margin-block-end: 14px; }
.decade-group:last-child { margin-block-end: 0; }
/* the Learn bank, folded until the learner asks for it */
.bank-acc { margin-block-start: 14px; }
.bank-toggle { display: flex; align-items: center; gap: 10px; min-block-size: 44px; padding: 12px 16px;
  border-radius: var(--radius-row); background: var(--glass-flat); border: 1px solid var(--glass-border);
  color: var(--text-muted); font: 500 14px/1 var(--font-ui); cursor: pointer; list-style: none; }
.bank-toggle::-webkit-details-marker { display: none; }
.bank-toggle .ic { color: var(--accent); flex: none; }
.bank-toggle .end { margin-inline-start: auto; display: inline-flex; align-items: center; gap: 6px; }
.bank-acc[open] .bank-toggle { border-end-start-radius: 0; border-end-end-radius: 0; }
.bank-toggle:hover { border-color: var(--accent); color: var(--text); }
.decade-title {
  margin: 0 0 6px 8px; font: 600 var(--fs-cap)/1 var(--font-ui);
  letter-spacing: var(--ls-cap); text-transform: uppercase; color: var(--text-faint);
}

.bank { list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 4px; }
.bank-item {
  border-radius: var(--radius-row); background: none;
  transition: background var(--dur-fast) var(--ease);
}
.bank-item.expanded { background: var(--glass-flat); border: 1px solid var(--glass-border); }

.bank-row {
  display: grid; grid-template-columns: 44px 58px 1fr auto; align-items: center;
  inline-size: 100%; min-block-size: 46px; padding-inline: 12px; border-radius: var(--radius-row);
  border: 0; background: none; color: var(--text); cursor: pointer; text-align: start;
  font-family: var(--font-ui); transition: background var(--dur-fast) var(--ease);
}
.bank-row:hover { background: var(--glass-flat); }
.bank-row:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.bank-item.expanded .bank-row:hover { background: transparent; }

.bank-row .n { font: 600 19px/1 var(--font-ui); letter-spacing: -0.01em; color: var(--text); }
.bank-row .s { font: 500 12px/1 var(--font-mono); color: var(--text-faint); letter-spacing: 0.04em; }
.bank-row .w { font: 500 16px/1.2 var(--font-ui); color: var(--text); min-width: 0; display: flex; align-items: center; gap: 8px; }
.bank-row .emoji { font-size: 21px; line-height: 1; flex: none; }
.bank-row .image-slot { flex: none; justify-self: end; }

.stop-tag {
  display: inline-flex; align-items: center; padding: 3px 8px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--accent-text); font: 500 11px/1 var(--font-ui);
  letter-spacing: 0.02em; flex: none;
}

.bank-detail {
  padding: 8px 14px 14px; display: flex; flex-direction: column; gap: 10px;
  border-block-start: 1px solid var(--glass-border);
}
.sounds-breakdown {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap; margin-block-start: 4px;
}
.sound-chip {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px;
  border-radius: var(--radius-pill); background: var(--surface);
  border: 1px solid var(--glass-border); font: 500 13px/1 var(--font-ui); color: var(--text);
}
.sound-chip b { color: var(--accent-text); }
.sound-sep { color: var(--text-faint); font-weight: bold; }
.sound-reminder { margin: 0; font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted); }
.stop-detail {
  margin: 0; display: inline-flex; align-items: center; gap: 8px;
  font: 500 12.5px/1.4 var(--font-ui); color: var(--accent-text);
}

.bank-empty {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  padding: 42px 20px; text-align: center; color: var(--text-muted);
}
.bank-empty .ic { color: var(--text-faint); margin-block-end: 12px; }
.bank-empty p { margin: 0; max-inline-size: 30ch; }
.bank-empty .empty-title { font: 600 16px/1.3 var(--font-ui); color: var(--text); margin-block-end: 6px; }
.bank-empty .empty-sub { font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted); }

/* ---------- progress: badges, totals strip ---------- */
.badges { list-style: none; padding: 0; margin: 16px 0 0; display: flex; flex-direction: column; gap: 14px; }
.badges li { display: flex; align-items: center; gap: 14px; }
.badges .bi {
  inline-size: 44px; block-size: 44px; border-radius: 50%; display: grid; place-items: center;
  background: var(--accent-soft); color: var(--accent); flex: none;
}
.badges .bi .ic { inline-size: 20px; block-size: 20px; }
.badges b { display: block; font: 600 15.5px/1.2 var(--font-ui); color: var(--text); }
.badges small { display: block; font: 400 13px/1.35 var(--font-ui); color: var(--text-muted); margin-block-start: 2px; }
.badges li.lk .bi { background: var(--glass-flat); color: var(--text-faint); border: 1px solid var(--glass-border); }
.badges li.lk b { color: var(--text-muted); }

/* strip (totals strip) */
.strip { margin-block-start: 18px; padding-inline: 4px; }
.strip .hd {
  display: flex; justify-content: space-between; align-items: baseline;
  font: 400 14px/1 var(--font-ui); color: var(--text-muted); margin-block-end: 10px;
}
.strip .hd b { font-weight: 500; color: var(--text); }

.days {
  list-style: none; padding: 0; margin: 0; display: flex; justify-content: space-between; gap: 8px;
}
.days li {
  flex: 1; min-inline-size: 52px; padding: 10px 4px 8px; border-radius: var(--radius-tile);
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.days li.on {
  background: var(--glass); border-color: var(--accent); box-shadow: var(--shadow-card);
}
.days small { font: 500 11.5px/1 var(--font-ui); text-transform: uppercase; letter-spacing: 0.04em; color: var(--text-faint); }
.days b { font: 600 18px/1 var(--font-ui); color: var(--text); }
.days i { inline-size: 5px; block-size: 5px; border-radius: 50%; background: var(--text-faint); opacity: 0.4; }
.days i.no { background: transparent; }
.days li.on i { background: var(--accent); opacity: 1; }

.empty-framing {
  margin-block-start: 14px; padding: 16px 18px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.empty-framing h3 { margin: 0 0 6px; font: 600 14.5px/1.2 var(--font-ui); color: var(--text); }
.empty-framing p { margin: 0; font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted); }

/* button as peek */
button.peek {
  inline-size: 100%; border: 1px solid var(--glass-border); cursor: pointer;
  text-align: start; font-family: var(--font-ui);
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
button.peek:hover { background: var(--surface); border-color: var(--accent); }
button.peek:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* boot failure surface (dev aid; never expected in production) */
.boot-error { color: var(--accent-text); font: 12.5px var(--font-mono); white-space: pre-wrap; padding: 18px; }

/* ---------- practice & result components (Direction D "glass") ---------- */
.card.first { margin-block-start: 0; }
.lab {
  display: flex; align-items: center; justify-content: space-between;
  font: 400 15px/1 var(--font-ui); color: var(--text-muted);
}
.chunks {
  display: grid; grid-template-columns: repeat(var(--chunks-cols, 5), 1fr);
  gap: 6px; margin-block: 8px 4px; padding: 0; list-style: none;
}
.chunks li {
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding-block: 12px; border-radius: var(--radius-tile);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.chunks .emoji { font-size: 28px; line-height: 1; }
.chunks b { font: 600 20px/1 var(--font-mono); letter-spacing: -0.01em; color: var(--text); }
.chunks small { font: 400 12.5px/1 var(--font-ui); color: var(--text-muted); }

.go {
  margin-block-start: 12px; min-block-size: 54px; inline-size: 100%; border: 0;
  border-radius: var(--radius-pill); background: #0B0C10; color: #FFFFFF;
  display: flex; align-items: center; justify-content: center; gap: 10px;
  font: 600 17px/1 var(--font-ui); cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), background var(--dur) var(--ease);
}
.go:hover { transform: translateY(-1px); }
.go:active { transform: scale(.985); }
.go:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
.go small { font: 400 15px/1 var(--font-ui); color: #9EA2AB; }
.go.split { justify-content: space-between; padding-inline: 8px 22px; }
.go.split .ic {
  inline-size: 42px; block-size: 42px; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; flex: none;
  transition: background var(--dur) var(--ease);
}
.go.split .ic .ic { inline-size: 20px; block-size: 20px; color: var(--accent-ink); }
.go:hover .ic { background: var(--accent-hover); }

/* The primary action on a screen that used to offer four equally loud choices. The play disc in the
   accent is the only filled orange here, so the eye lands on the one thing to press. */
.go.icon-lead { justify-content: center; gap: 12px; padding-inline: 20px; }
.go.icon-lead .ic {
  inline-size: 42px; block-size: 42px; border-radius: 50%;
  background: var(--accent); color: var(--accent-ink);
  display: grid; place-items: center; flex: none;
  transition: background var(--dur) var(--ease);
}
.go.icon-lead .ic .ic { inline-size: 20px; block-size: 20px; color: var(--accent-ink); }

/* The one digits control: labelled number inputs, each a −/value/+ stepper (digits, seconds, and
   the learner's chosen group size). It replaced the 1 min / 5 min / Own preset rows, which made the
   learner choose from three fixed options.
   .digits-fields / .digits-field below are the OLD two-column layout. The markup moved to
   .digits-field-row and these rules were left behind, so every row fell back to block flow: the
   label was a block at the left edge, the stepper took only its content width, and the three rows
   each sized themselves differently — ragged + buttons, unit labels hanging left under each box.
   The grid below is kept because it still describes the intent; .digits-field-row is what the
   screens actually render, and every row is the same fixed width so the controls line up. */
.digits-fields { display: grid; grid-template-columns: repeat(2, minmax(0, 150px)); gap: 16px; }
.digits-field { display: flex; flex-direction: column; gap: 6px; min-inline-size: 0; }
.digits-field .field-lab { margin: 0; }
/* One labelled stepper row. Full width: every row spans the card so the three controls share one
   left and right edge, whatever the number's width. The label sits above the control rather than
   beside it, because "Seconds to memorise" does not fit beside a stepper without wrapping. */
.digits-field-row {
  display: flex; flex-direction: column; gap: 6px;
  inline-size: 100%; box-sizing: border-box;
}
.digits-field-row .field-lab { margin: 0; }
/* The unit sits inside the box, right-aligned, so the number keeps the optical centre. flex:1 lives
   HERE, not in the ≥1024 block: as a flex item with the default flex:0 1 auto it took only its
   content width, so on a full-width row the two −/+ buttons flew to the far ends and left a small
   input stranded in the middle. */
.digits-field-row .digits-box {
  position: relative; flex: 1 1 auto; min-inline-size: 0;
  display: flex; align-items: center;
}
/* The unit word is pinned inside the box's right edge at every width, and the input reserves room for
   it. Also lifted out of the ≥1024 block: left in flow, it became a flex sibling of a 100%-wide input
   and was pushed out of the box entirely. */
.digits-field-row .digits-input { padding-inline-end: 64px; }
.digits-field-row .digits-unit {
  position: absolute; inset-inline-end: 16px; pointer-events: none;
  font: 500 14px/1 var(--font-ui); color: var(--text-faint);
}
/* The three rows read as one control block, so they share a rhythm. */
.digits-setup .digits-field-row + .digits-field-row { margin-block-start: 14px; }
/* The −/+ steppers around each number input. Sized OUTSIDE any media query on purpose: inside the
   ≥1024 block they were desktop-only, so on the phone the buttons fell back to text size (24×24 px)
   and broke the 44 px hit-target floor.
   align-items:flex-start (not stretch, not center): .digits-box is taller than the input because the
   unit label sits inside it, so centring dropped the buttons ~8px below the input they belong to. */
.digits-stepper { display: flex; align-items: flex-start; gap: 8px; }
.step-btn {
  flex: 0 0 auto; inline-size: 46px; block-size: 52px; min-block-size: 44px; border-radius: 14px;
  border: 1px solid var(--glass-border); background: var(--glass-flat); color: var(--text-muted);
  font: 500 22px/1 var(--font-ui); cursor: pointer; padding: 0;
  display: grid; place-items: center;
  transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.step-btn:hover { background: var(--glass-flat); color: var(--text); border-color: var(--track); }
.step-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.digits-input {
  inline-size: 100%; box-sizing: border-box; min-block-size: 52px; padding: 10px 14px;
  border-radius: 12px; border: 1px solid var(--glass-border); background: var(--glass-flat);
  color: var(--text); font: 600 20px/1 var(--font-mono);
  -webkit-appearance: textfield; appearance: textfield;
}
.digits-input::-webkit-outer-spin-button,
.digits-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.digits-input:hover { border-color: var(--track); }
.digits-input:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

.name-locked { display: flex; align-items: baseline; gap: 10px; margin-block: 10px 0; }
.name-locked .field-lab { margin: 0; }
.name-value { font: 500 15px/1.2 var(--font-ui); color: var(--text); }

/* length picker on practice screen */
.length-picker-wrap,
.window-picker-wrap {
  margin-block: 10px 14px;
}
.length-picker {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: space-between;
}
.picker-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  min-block-size: 44px;
  min-inline-size: 44px;
  padding-block: 8px;
  padding-inline: 4px;
  border-radius: var(--radius-tile);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  color: var(--text-muted);
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
  font: 500 12px/1 var(--font-ui);
}
.picker-btn:hover {
  border-color: var(--accent);
}
.picker-btn:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.picker-btn .num {
  font: 600 17px/1 var(--font-mono);
  color: var(--text);
}
/* A chosen setting is quieter than the primary action. It was a 2px orange border with a halo, which
   put it in competition with the one filled orange button on the screen; now it is a filled quiet
   surface with the accent only on the number. */
.picker-btn.selected,
.picker-btn.active {
  border-color: var(--glass-border);
  background: var(--glass-flat);
  color: var(--text);
  box-shadow: inset 0 0 0 1px var(--track);
}
.picker-btn.selected .num,
.picker-btn.active .num {
  color: var(--accent-text);
}
.picker-pb {
  margin-block: 8px 0;
  font: 500 13px/1.4 var(--font-ui);
  color: var(--text-muted);
  text-align: center;
}
.picker-pb .mono {
  font-family: var(--font-mono);
  color: var(--text);
}
.length-picker-readonly {
  display: flex;
  align-items: center;
  gap: 6px;
  font: 500 13px/1 var(--font-ui);
  color: var(--text-muted);
  margin-block: 8px 12px;
}
.length-picker-readonly .chip {
  padding-block: 4px;
  padding-inline: 8px;
  border-radius: var(--radius-pill);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  font: 600 13px/1 var(--font-mono);
  color: var(--accent-text);
}

/* active run screen inside practice */
.run-box {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 14px; padding-block: 8px;
}
.run-locus-name { font: 600 24px/1.2 var(--font-ui); color: var(--text); margin: 0; }
.run-form { display: flex; flex-direction: column; align-items: center; gap: 12px; inline-size: 100%; }
.run-input-wrap { display: flex; justify-content: center; margin-block: 4px; }
.run-input {
  inline-size: 130px; block-size: 68px; text-align: center;
  font: 600 40px/1 var(--font-mono); letter-spacing: 0.08em;
  background: var(--glass-flat); border: 2px solid var(--glass-border);
  border-radius: var(--radius-tile); color: var(--text);
  outline: none; transition: border-color var(--dur) var(--ease);
}
.run-input:focus { border-color: var(--accent); }
.run-stop-btn {
  display: inline-flex; align-items: center; gap: 6px; background: none;
  border: 0; color: var(--text-faint); font: 500 13px/1 var(--font-ui);
  cursor: pointer; min-block-size: 44px; padding: 8px 14px; border-radius: var(--radius-pill);
  transition: color var(--dur) var(--ease);
}
.run-stop-btn:hover { color: var(--text); }
.run-stop-btn .ic { inline-size: 14px; block-size: 14px; color: var(--accent); }

/* result screen elements */
.top h1.num { font-family: var(--font-mono); font-variant-numeric: tabular-nums; font-size: 38px; }
.top p.sm { font-size: 13.5px; font-weight: 400; color: var(--hdr); opacity: var(--hdr-sub-o); margin: 6px 0 0; }
.checks { display: flex; gap: 8px; flex-wrap: wrap; margin-block: 8px 4px; }
.checks > span {
  display: inline-flex; align-items: center; gap: 6px; min-block-size: 36px;
  padding-inline: 10px 12px; border-radius: var(--radius-pill);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
  font: 500 14px/1 var(--font-ui); color: var(--text);
}
.checks .ic { color: var(--accent); flex: none; }
.checks .emoji { font-size: 16px; line-height: 1; }

.xp {
  display: inline-flex; align-items: center; gap: 6px; align-self: flex-start;
  min-block-size: 32px; padding-inline: 10px 12px; border-radius: var(--radius-pill);
  background: var(--accent); color: var(--accent-ink); font: 600 14px/1 var(--font-ui);
}
.xp .ic { color: var(--accent-ink); flex: none; }

.strip { padding: 18px 6px 0; }
.strip .hd {
  display: flex; justify-content: space-between; font: 400 14px/1 var(--font-ui);
  color: var(--text-muted); margin-block-end: 10px;
}
.strip .hd b { font-weight: 500; color: var(--text); }
.days { display: flex; justify-content: space-between; gap: 6px; list-style: none; padding: 0; margin: 0; }
.days li {
  flex: 1; min-inline-size: 50px; padding-block: 9px 8px; padding-inline: 4px;
  border-radius: 20px; display: flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.days small { font: 400 13px/1 var(--font-ui); color: var(--text-muted); }
.days b { font: 600 16px/1 var(--font-mono); color: var(--text); }
.days .e { font-size: 18px; line-height: 1; }
.days i { inline-size: 4px; block-size: 4px; border-radius: 50%; background: var(--text-faint); }
.days i.no { background: transparent; }
.days li.on { background: rgba(255, 255, 255, 0.12); border-color: rgba(255, 255, 255, 0.2); }
[data-theme="light"] .days li.on { background: rgba(255, 255, 255, 0.85); box-shadow: 0 10px 24px -12px rgba(18, 20, 24, 0.35); }
.days li.on i { background: var(--accent); }

.badges { display: flex; flex-direction: column; gap: 12px; list-style: none; padding: 0; margin: 8px 0 0; }
.badges li { display: flex; align-items: center; gap: 14px; }
.badges .bi {
  inline-size: 44px; block-size: 44px; border-radius: 50%;
  display: grid; place-items: center; background: var(--accent-soft);
  color: var(--accent); flex: none;
}
.badges .bi .ic { inline-size: 20px; block-size: 20px; }
.badges b { display: block; font: 600 15px/1.2 var(--font-ui); color: var(--text); }
.badges small { font: 400 13px/1.3 var(--font-ui); color: var(--text-muted); }
.empty-note { font: 400 14px/1.5 var(--font-ui); color: var(--text-muted); margin: 6px 0 0; }

.breakdown { display: flex; flex-direction: column; gap: 8px; list-style: none; padding: 0; margin: 12px 0 0; }
.breakdown-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 10px 14px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.breakdown-locus { display: flex; flex-direction: column; gap: 3px; min-inline-size: 0; flex: 1; }
.breakdown-name { font: 500 14px/1.2 var(--font-ui); color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.breakdown-target { display: inline-flex; align-items: center; gap: 6px; font: 400 13px/1 var(--font-ui); color: var(--text-muted); }
.breakdown-target .emoji { font-size: 16px; line-height: 1; }
.breakdown-target b { font-family: var(--font-mono); color: var(--text); }
.breakdown-answer { display: flex; align-items: center; gap: 8px; flex: none; }
.breakdown-given { font: 600 15px/1 var(--font-mono); color: var(--text); }
.breakdown-given.miss { text-decoration: line-through; color: var(--text-muted); }
.breakdown-status { display: inline-flex; align-items: center; }
.breakdown-status.ok { color: var(--accent); }
.breakdown-status.miss { color: var(--text-faint); }

/* ---------- steprail (docs/design/SPEC-learn-course.md) ---------- */
.steprail { display: flex; align-items: center; gap: 12px; margin-block-start: 16px; }
.steprail ol { flex: 1; display: flex; gap: 4px; margin: 0; padding: 0; list-style: none; }
.steprail li { flex: 1; block-size: 4px; border-radius: var(--radius-pill); background: var(--ring); }
.steprail li.done { background: var(--ring-v); }
.steprail li.now { background: var(--ring-v); opacity: .5; }
.steprail li.extra { flex: .5; }                          /* an inserted reteach step: half width */
.steprail span { flex: none; font: 500 12.5px/1 var(--font-ui); color: var(--hdr); opacity: var(--hdr-kicker-o); }
.steprail span b { font-family: var(--font-mono); font-weight: 600; }

/* card head: label + round glass pip */
.card .lab { margin-block-end: 14px; font-size: 13.5px; display: flex; align-items: center; justify-content: space-between; color: var(--text-muted); }
.card .lab .pip { color: var(--accent); }
/* a card label that is also the section's heading (Help): same look as the plain label */
.card h2.lab { font: 400 13.5px/1 var(--font-ui); letter-spacing: 0; color: var(--text-muted); }
.card h2 + .copy { margin-block-start: 10px; }
.card .meta { margin: 8px 0 0; font: 400 13.5px/1.45 var(--font-ui); color: var(--text-muted); }
.card .meta b { color: var(--text); font-weight: 500; }

/* mini rail inside a card (resume card) */
.minirail { display: flex; gap: 4px; margin: 16px 0 0; padding: 0; list-style: none; }
.minirail li { flex: 1; block-size: 4px; border-radius: var(--radius-pill); background: var(--track); }
.minirail li.done { background: var(--accent); }
.minirail li.now { background: var(--accent); opacity: .45; }

/* sound-table key strip (ladder) — the whole strip is one button that opens the table */
.keystrip { display: block; inline-size: 100%; margin-block-start: 14px; padding: 14px 16px 10px;
  border-radius: var(--radius-tile); background: var(--row-glass); border: 1px solid var(--glass-border);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  color: var(--text); text-align: start; font-family: var(--font-ui); cursor: pointer; box-sizing: border-box; }
.keystrip:hover { background: var(--glass); border-color: var(--accent); }
.keystrip .hd { display: flex; align-items: center; gap: 10px; font: 500 14.5px/1 var(--font-ui); }
.keystrip .hd .ic { color: var(--accent); }
.keystrip .hd .end { margin-inline-start: auto; display: inline-flex; align-items: center; gap: 4px;
  font-weight: 400; font-size: 13.5px; color: var(--text-muted); }
.keystrip ol { display: grid; grid-template-columns: repeat(10, 1fr); margin: 12px 0 0; padding: 0; list-style: none; }
.keystrip li { display: flex; flex-direction: column; align-items: center; gap: 6px; padding-block: 6px;
  border-inline-start: 1px solid var(--track); }
.keystrip li:first-child { border-inline-start: 0; }
.keystrip li b { font: 600 17px/1 var(--font-mono); color: var(--text); }
.keystrip li small { font: 500 12px/1 var(--font-mono); color: var(--text-muted); }
/* A card that follows the keyboard strip is NOT tucked under the hero band: the negative
   pull-up only belongs to the first card directly under the hero. Without this the course
   card slides up under the strip and clips it. */
.keystrip + .card { margin-block-start: 12px; }

/* ---------- ladder: 9-lesson curriculum list & path ---------- */
.path { position: relative; list-style: none; margin: 12px 0 0; padding: 0; }
.path li { position: relative; }
.path li::before { content: ""; position: absolute; inset-inline-start: 21px; inset-block: 0; inline-size: 2px;
  background: var(--track); }
.path li:first-child::before { inset-block-start: 22px; }
.path li:last-child::before { inset-block-end: 50%; }
.path li.done::before, .path li.part.done::before { background: var(--accent); }
.path li.now::after { content: ""; position: absolute; inset-inline-start: 21px; inset-block: 0 50%; inline-size: 2px;
  background: var(--accent); }
.path li.part { padding: 16px 0 6px 58px; }
.path li.part::before { display: none; }
.path li.part .cap { display: block; font: 600 var(--fs-cap)/1 var(--font-ui); letter-spacing: var(--ls-cap); text-transform: uppercase; color: var(--text-faint); }

.lesson, .ladder-card { position: relative; z-index: 1; display: grid; grid-template-columns: 44px 1fr auto; align-items: center;
  gap: 14px; inline-size: 100%; min-block-size: 64px; padding-block: 10px; padding-inline: 0 12px;
  border: 0; border-radius: var(--radius-row); background: none; color: var(--text); text-align: start;
  font-family: var(--font-ui); cursor: pointer; transition: background var(--dur-fast) var(--ease); box-sizing: border-box; }
.lesson:hover, .ladder-card.open:hover, .ladder-card.done:hover { background: var(--glass-flat); }
.lesson:focus-visible, .ladder-card:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
.lesson[aria-disabled="true"], .ladder-card.locked { cursor: default; opacity: 0.65; }
.lesson[aria-disabled="true"]:hover, .ladder-card.locked:hover { background: none; }
.node, .ladder-status { inline-size: 44px; block-size: 44px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--track); color: var(--text-muted);
  font: 600 15px/1 var(--font-mono); flex: none; }
.done .node, .ladder-card.done .node, .ladder-card.done .ladder-status { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.now .node, .open .node, .ladder-card.open .ladder-status { border: 2px solid var(--accent); color: var(--text); box-shadow: var(--shadow-halo); }
.lesson .t b, .ladder-card .ladder-title { display: block; font: 600 15.5px/1.25 var(--font-ui); letter-spacing: -0.005em; color: var(--text); }
.lesson .t small, .ladder-card .ladder-kicker { display: block; margin-block-start: 3px; font: 400 13px/1.35 var(--font-ui); color: var(--text-muted); }
.lesson .t .step { display: inline-flex; align-items: center; gap: 6px; margin-block-start: 8px;
  font: 500 12px/1 var(--font-ui); color: var(--text); }
.lesson .t .step i { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--accent); }
.lesson .x, .ladder-card .ladder-xp { font: 600 12.5px/1 var(--font-mono); color: var(--text-muted); white-space: nowrap; }
.now .lesson, .now.ladder-card { background: var(--glass-flat); box-shadow: inset 0 0 0 1px var(--glass-border); }
.now .lesson .x, .now.ladder-card .ladder-xp { color: var(--text); }
.locked .lesson .t b, .locked.ladder-card .ladder-title { color: var(--text-muted); font-weight: 500; }

/* image slot (docs/ICON_CONTRACT.md) */
.image-slot {
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  position: relative;
  overflow: hidden;
  inline-size: var(--slot-size, 48px);
  block-size: var(--slot-size, 48px);
}
.image-slot .emoji {
  font-size: calc(var(--slot-size, 48px) * 0.8);
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  user-select: none;
}
.image-slot .num-icon {
  inline-size: 100%;
  block-size: 100%;
  fill: none;
  stroke: currentColor;
  stroke-width: 4;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* drill card & stage */
.chiprow { display: flex; align-items: center; gap: 8px; }
.chiprow .lab { flex: 1; margin: 0; }
button.chip { min-block-size: 44px; padding-inline: 14px; cursor: pointer; color: var(--text); font-family: var(--font-ui); border: 0; background: var(--glass-flat); border-radius: var(--radius-pill); }
button.chip .ic { color: var(--accent); }
.gen { display: flex; align-items: flex-start; gap: 8px; margin: 12px 0 0; font: 400 13px/1.45 var(--font-ui); color: var(--text-muted); }
.gen .ic { color: var(--accent); flex: none; margin-block-start: 1px; }
.stage { margin-block-start: 16px; padding: 16px 16px 20px; border-radius: var(--radius-tile); background: var(--glass-flat);
  border: 1px solid var(--glass-border); display: flex; flex-direction: column; align-items: center; gap: 14px; }
.stage .count { align-self: stretch; display: flex; align-items: center; justify-content: space-between;
  font: 500 12.5px/1 var(--font-ui); color: var(--text-muted); }
.stage .count .dots { display: inline-flex; gap: 5px; }
.stage .count .dots i { inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--track); }
.stage .count .dots i.done { background: var(--accent); }
.stage .count .dots i.now { background: var(--text); }
.numTile.lg { align-items: center; padding: 14px 26px 12px; background: var(--surface); }
.numTile.lg span { font-size: 56px; }
.answer { display: flex; align-items: center; gap: 14px; }
.tag { display: inline-flex; align-items: center; gap: 6px; padding: 5px 9px; border-radius: var(--radius-pill);
  background: var(--accent-soft); color: var(--text); font: 500 11.5px/1 var(--font-ui); }
.tag::before { content: ""; inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--accent); }
.grade { display: flex; gap: 10px; margin-block-start: 16px; inline-size: 100%; }

/* ---------- Find a match: the searching globe (Uiverse) ----------
   Sits in the "Looking for an opponent" title row, in place of the old pulsing dot, so it runs for
   the whole queue search. Sized down from the original 7.5em to 2em so it reads as an indicator beside
   the text rather than competing with it.
   The land paths are fill="currentColor" rather than the paste's hard-coded #7CC133, so the colour
   lives in one place here. The globe keeps its own blue/green: it is a picture of the Earth, not UI
   chrome, and recolouring it orange would make it read as Mars. */
.earth { display: inline-flex; flex: none; }
.earth-loader {
  --water: #3344c1;
  --land: #7cc133;
  display: block; position: relative; overflow: hidden;
  inline-size: 2em; block-size: 2em; border-radius: 50%;
  background-color: var(--water);
  border: solid 0.09em var(--glass-border);
  box-shadow: inset 0 0.3em rgba(255, 255, 255, 0.25), inset 0 -0.3em rgba(0, 0, 0, 0.25);
}
/* The paste's `startround` keyframes hold `filter: brightness(500%)` for the first 0.75 s — a white
   flash, intended as a one-time materialise when the component first appears. Here the card re-renders
   on every paint, so that one-shot intro replayed as a white flash on each search and each reload.
   Removed rather than neutralised: the globe should simply be there. round1/round2 are untouched. */
/* fill, not colour: the land is a graphic, not text, and the a11y contrast checker (correctly)
   refuses a text token it cannot pair. The markup's fill="currentColor" is overridden here. */
.earth-loader svg path { fill: var(--land); }
.earth-loader svg { position: absolute; inline-size: 1.87em; block-size: auto; }
.earth-loader svg:nth-child(1) { bottom: -0.53em; animation: round1 5s infinite linear 0.75s; }
.earth-loader svg:nth-child(2) { top: -0.8em; animation: round1 5s infinite linear; }
.earth-loader svg:nth-child(3) { top: -0.67em; animation: round2 5s infinite linear; }
.earth-loader svg:nth-child(4) { bottom: -0.59em; animation: round2 5s infinite linear 0.75s; }
@keyframes round1 {
  0% { left: -0.53em; opacity: 100%; transform: skewX(0deg) rotate(0deg); }
  30% { left: -1.6em; opacity: 100%; transform: skewX(-25deg) rotate(25deg); }
  31% { left: -1.6em; opacity: 0%; transform: skewX(-25deg) rotate(25deg); }
  35% { left: 1.87em; opacity: 0%; transform: skewX(25deg) rotate(-25deg); }
  45% { left: 1.87em; opacity: 100%; transform: skewX(25deg) rotate(-25deg); }
  100% { left: -0.53em; opacity: 100%; transform: skewX(0deg) rotate(0deg); }
}
@keyframes round2 {
  0% { left: 1.33em; opacity: 100%; transform: skewX(0deg) rotate(0deg); }
  75% { left: -1.87em; opacity: 100%; transform: skewX(-25deg) rotate(25deg); }
  76% { left: -1.87em; opacity: 0%; transform: skewX(-25deg) rotate(25deg); }
  77% { left: 2.13em; opacity: 0%; transform: skewX(25deg) rotate(-25deg); }
  80% { left: 2.13em; opacity: 100%; transform: skewX(25deg) rotate(-25deg); }
  100% { left: 1.33em; opacity: 100%; transform: skewX(0deg) rotate(0deg); }
}
.grade .btn, .grade .btn.ghost { flex: 1; }
.note { margin: 12px 0 0; text-align: center; font: 400 12.5px/1.4 var(--font-ui); color: var(--text-muted); }

/* sound table modal sheet */
.scrim { position: fixed; inset: 0; z-index: 40; background: var(--scrim); }
.sheet { position: fixed; inset-inline: 0; inset-block-end: 0; z-index: 41; max-block-size: calc(100% - 72px); max-inline-size: var(--col); margin-inline: auto; overflow: auto; padding: 10px 20px 30px;
  border-start-start-radius: var(--radius-card); border-start-end-radius: var(--radius-card);
  background: var(--glass); border: 1px solid var(--glass-border); border-block-end: 0;
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); box-shadow: var(--shadow-panel); box-sizing: border-box; }
[data-theme="light"] .sheet { background: var(--surface); }
.grabber { inline-size: 40px; block-size: 5px; margin: 0 auto 10px; border-radius: var(--radius-pill); background: var(--track); }
.sheet .head { display: flex; align-items: flex-start; gap: 12px; }
.sheet .head div { flex: 1; }
.sheet h2 { margin: 6px 0 0; font: 600 var(--fs-h2)/1.15 var(--font-ui); letter-spacing: var(--ls-h2); }
.sheet .head p { margin: 6px 0 0; font: 400 13.5px/1.45 var(--font-ui); color: var(--text-muted); }
.roundbtn { inline-size: 44px; block-size: 44px; flex: none; border-radius: 50%; display: grid; place-items: center;
  background: var(--glass-flat); border: 1px solid var(--glass-border); color: var(--text); cursor: pointer; }
[data-theme="light"] .roundbtn { background: var(--surface-2); }
.soundtable { inline-size: 100%; margin-block-start: 14px; border-collapse: collapse; table-layout: fixed; }
.soundtable col.d { inline-size: 40px; } .soundtable col.s { inline-size: 70px; } .soundtable col.x { inline-size: 122px; }
.soundtable th { padding: 0 6px 8px; text-align: start; font: 500 var(--fs-cap)/1 var(--font-ui);
  letter-spacing: var(--ls-cap); text-transform: uppercase; color: var(--text-muted);
  border-block-end: 1px solid var(--track); }
.soundtable td { box-sizing: border-box; padding: 7px 6px; block-size: 48px; vertical-align: middle; border-block-end: 1px solid var(--track); }
.soundtable tr:last-child td { border-block-end: 0; }
.soundtable td.d { font: 600 22px/1 var(--font-mono); color: var(--text); text-align: center; }
.soundtable td.s { font: 600 13px/1.25 var(--font-mono); color: var(--text); word-spacing: -0.15em; }
.soundtable td.h { font: 400 13px/1.35 var(--font-ui); color: var(--text-muted); }
.soundtable td.x { font: 500 13.5px/1.2 var(--font-ui); color: var(--text); }
.soundtable td.x .e { font-size: 18px; margin-inline-end: 6px; vertical-align: -2px; }
.soundtable td.x .e.image-slot { display: inline-grid; vertical-align: -3px; margin-inline-end: 6px; }
.soundtable td.x small { margin-inline-start: 6px; font: 400 11.5px/1 var(--font-mono); color: var(--text-muted); }
.soundtable tr.hi td { background: var(--accent-soft); }
.soundtable tr.hi td:first-child { border-start-start-radius: 12px; border-end-start-radius: 12px; box-shadow: inset 3px 0 0 var(--accent); }
[dir="rtl"] .soundtable tr.hi td:first-child { box-shadow: inset -3px 0 0 var(--accent); }
.soundtable tr.hi td:last-child { border-start-end-radius: 12px; border-end-end-radius: 12px; }
.sheet .foot { margin: 12px 0 0; font: 400 12.5px/1.45 var(--font-ui); color: var(--text-muted); }

/* fresh walk preview */
.tiers {
  display: flex;
  align-items: flex-start;
  margin-block-start: 4px;
  overflow-x: auto;
  padding-block-end: 6px;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.tiers::-webkit-scrollbar { display: none; }
.tiers .tier { display: flex; flex-direction: column; align-items: center; gap: 7px; inline-size: 56px; flex: none; }
.tiers .tier small { font: 500 11.5px/1 var(--font-ui); color: var(--text-muted); text-align: center; }
.tiers .tier.now small { color: var(--text); }
.tiers .tier.next small { color: var(--accent-text); }
.tiers .bar { flex: 1; min-inline-size: 14px; block-size: 2px; margin-block-start: 21px; background: var(--track); }
.tiers .bar.done { background: var(--accent); }
.tiers .tier .node { font-size: 15px; }
.tiers .tier.done .node { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }
.tiers .tier.now .node { border: 2px solid var(--accent); color: var(--text); box-shadow: var(--shadow-halo); }
.tiers .tier.next .node { border: 1.5px dashed var(--accent); color: var(--accent-text); }

/* mode toggle */
.fresh-mode-row {
  margin-block: 16px 8px;
  padding: 12px 14px;
  border-radius: var(--radius-row);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
}
.toggle-control {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
  cursor: pointer;
  user-select: none;
}
.toggle-control input[type="checkbox"] {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  opacity: 0;
  margin: 0;
  cursor: pointer;
  z-index: 1;
}
.toggle-track {
  position: relative;
  display: inline-block;
  inline-size: 44px;
  block-size: 24px;
  background: var(--surface-2);
  border: 1px solid var(--glass-border);
  border-radius: var(--radius-pill);
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
  flex: none;
}
.toggle-thumb {
  position: absolute;
  inset-block-start: 2px;
  inset-inline-start: 2px;
  inline-size: 18px;
  block-size: 18px;
  background: var(--text-muted);
  border-radius: 50%;
  transition: transform var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.toggle-control input:checked + .toggle-track {
  background: var(--accent);
  border-color: var(--accent);
}
.toggle-control input:checked + .toggle-track .toggle-thumb {
  transform: translateX(20px);
  background: var(--on-accent);
}
[dir="rtl"] .toggle-control input:checked + .toggle-track .toggle-thumb {
  transform: translateX(-20px);
}
.toggle-control:focus-within .toggle-track {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
}
.toggle-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.toggle-label b {
  font: 600 14.5px/1.2 var(--font-ui);
  color: var(--text);
}
.toggle-label small {
  font: 400 12.5px/1.4 var(--font-ui);
  color: var(--text-muted);
}

.chunks.walk8 { --chunks-cols: 4; margin-block-start: 16px; }
.chunks li { position: relative; }
.chunks li.new { border-style: dashed; border-color: var(--accent); }
.chunks li .stopno { position: absolute; inset-block-start: 7px; inset-inline-start: 9px; font: 500 10.5px/1 var(--font-mono); color: var(--text-muted); }
.chunks.walk8 li { padding-block: 24px 11px; }
.chunks li .stoplocus {
  display: block;
  font: 400 10.5px/1.2 var(--font-ui);
  color: var(--text-muted);
  margin-block-start: 4px;
  max-inline-size: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.card .checks { margin-block-start: 14px; display: flex; gap: 14px; }
.checks > span { font-size: 13.5px; display: inline-flex; align-items: center; gap: 6px; color: var(--text-muted); }
.checks .dot { inline-size: 7px; block-size: 7px; border-radius: 50%; background: var(--accent); }
.checks .dot.new { background: transparent; border: 1.5px dashed var(--accent); }

/* fresh walk card stats surface on ladder */
.fresh-stats-surface {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-start: 8px;
}
.stat-pill {
  font: 500 11.5px/1.2 var(--font-mono);
  color: var(--text-muted);
  background: var(--surface-2);
  padding: 3px 7px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--glass-border);
}
.stat-pill.bests {
  color: var(--accent-text);
}


/* ---------- lesson player ---------- */
.teach-bullets {
  margin: 14px 0 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px;
}
.teach-bullets li {
  display: flex; align-items: baseline; gap: 10px; font: 400 14px/1.5 var(--font-ui); color: var(--text-muted);
}
.teach-bullets .b-dot {
  inline-size: 6px; block-size: 6px; border-radius: 50%; background: var(--accent); flex: none;
  margin-block-start: 6px;
}
.route .d.tappable {
  cursor: pointer;
  transition: transform var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.route .d.tappable:hover {
  transform: scale(1.3);
}

/* drill styling */
.drill-box {
  margin-block-start: 16px; display: flex; flex-direction: column; gap: 14px;
}
.drill-card {
  padding: 16px 18px; border-radius: var(--radius-row); background: var(--glass-flat);
  border: 1px solid var(--glass-border); display: flex; flex-direction: column; gap: 12px;
}
.drill-prompt {
  font: 500 14.5px/1.4 var(--font-ui); color: var(--text); margin: 0;
}
.drill-options {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-block-start: 8px;
}
.drill-opt-btn {
  min-block-size: 44px; padding-inline: 12px; border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--glass-border); color: var(--text);
  font: 600 16px/1 var(--font-mono); cursor: pointer;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.drill-opt-btn:hover {
  background: var(--glass-flat); border-color: var(--accent);
}
.drill-opt-btn.correct {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text);
}
.drill-opt-btn.wrong {
  color: var(--text-muted); border-color: var(--text-faint); text-decoration: line-through;
}

/* stops builder */
.stops-list {
  display: flex; flex-direction: column; gap: 10px; margin-block: 16px 12px;
}
.stop-input-row {
  display: flex; align-items: center; gap: 10px;
}
.stop-num-badge {
  inline-size: 32px; block-size: 32px; border-radius: 50%; display: grid; place-items: center;
  background: var(--surface); border: 1px solid var(--glass-border);
  font: 600 13px/1 var(--font-mono); color: var(--accent-text); flex: none;
}
.stop-input {
  flex: 1; min-block-size: 44px; padding-inline: 14px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border); color: var(--text);
  font: 500 14px/1 var(--font-ui); outline: none; box-sizing: border-box;
  transition: border-color var(--dur) var(--ease);
}
.stop-input:focus {
  border-color: var(--accent);
}

/* checkpoint */
.checkpoint-options {
  display: flex; flex-direction: column; gap: 10px; margin-block: 16px 12px;
}
.checkpoint-opt {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px;
  border-radius: var(--radius-row); background: var(--glass-flat);
  border: 1px solid var(--glass-border); color: var(--text);
  font: 500 14px/1.4 var(--font-ui); cursor: pointer; text-align: start;
  transition: background var(--dur-fast) var(--ease), border-color var(--dur-fast) var(--ease);
}
.checkpoint-opt:hover {
  background: var(--surface); border-color: var(--accent);
}
.checkpoint-opt.correct {
  background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text);
}
.checkpoint-opt.wrong {
  color: var(--text-muted); border-color: var(--text-faint);   /* was opacity .5 (3.2-3.6:1); it can still be retried */
}
.checkpoint-opt .mk { flex: none; }
.checkpoint-explain {
  margin-block-start: 12px; padding: 12px 14px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border);
  font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted);
}

/* reward step */
.reward-box {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 16px; padding-block: 14px;
}
.reward-icon {
  inline-size: 64px; block-size: 64px; border-radius: 50%;
  background: var(--accent-soft); color: var(--accent);
  display: grid; place-items: center;
}


/* practice mode switch (Palace walk · Digits) — the settings .seg, full width in the card */
.practice-mode { margin-block: 4px 12px; }

/* practice mode B: the digit-string drill */
.digits-howto { margin-block: 6px 0; font: 400 var(--fs-body)/var(--lh-body) var(--font-ui); color: var(--text-muted); }
.digit-string {
  display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 14px;
  margin-block: 14px; padding-block: 18px; padding-inline: 12px;
  border-radius: var(--radius-tile); background: var(--glass-flat); border: 1px solid var(--glass-border);
  font: 600 26px/1 var(--font-mono); letter-spacing: 0.06em; color: var(--text);
  font-variant-numeric: tabular-nums;
  /* The memorise digits must not be selectable: during the memorise window they are on screen, and
     selecting them would let a learner paste the whole string straight into the recall box. This is
     the rule that does the work; js/ui.js `makeUncopyable` blocks the clipboard and right-click.
     It does NOT stop anyone reading the digits off the screen — see makeUncopyable's note. */
  user-select: none; -webkit-user-select: none;
}
.digit-string .dg-group { display: inline-flex; white-space: nowrap; }
.digit-input {
  inline-size: 100%; min-block-size: 58px; padding-inline: 16px; text-align: center;
  font: 600 22px/1 var(--font-mono); letter-spacing: 0.08em;
  background: var(--glass-flat); border: 2px solid var(--glass-border);
  border-radius: var(--radius-tile); color: var(--text);
  outline: none; transition: border-color var(--dur) var(--ease);
}
.digit-input:focus { border-color: var(--accent); }
.digits-hint { font: 400 13px/1 var(--font-ui); color: var(--text-faint); }
.digits-time { margin-block: 4px 10px; font: 500 14px/1.3 var(--font-ui); color: var(--text-muted); }

/* the per-position diff: each digit is a cell; a miss shows the typed digit underneath */
.digit-diff { font-size: 22px; gap: 10px 12px; }
.digit-diff .dg { display: inline-flex; flex-direction: column; align-items: center; min-inline-size: 0.8em; }
.digit-diff .dg.ok { color: var(--diff-ok); }
.digit-diff .dg.miss { color: var(--diff-miss); background: var(--diff-miss-bg); border-radius: var(--radius-sm); padding-inline: 2px; }
.digit-diff .dg small { font: 500 12px/1.3 var(--font-mono); color: var(--text); }   /* sits on the miss tint */
.digit-diff .dg small.typed { text-decoration: line-through; }

.digits-sub { margin-block: 6px 8px; font: 600 15px/1.2 var(--font-ui); color: var(--text); }
/* The recall heading is a bare h2, and `.card h2 { margin: 0 }` left it hard against the input below —
   0px of space under it while there was 14px above, so the two read as one block. Two classes, not
   one: `.card h2` is 0-1-1 and would otherwise win and keep the margin at 0. */
.card h2.digits-recall-head { margin-block: 0 14px; }
.digit-misses { display: flex; flex-direction: column; gap: 8px; list-style: none; padding: 0; margin: 0; }
.digit-misses li {
  display: flex; align-items: center; gap: 12px; padding-block: 8px; padding-inline: 10px 14px;
  border-radius: var(--radius-row); background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.digit-misses b { font: 600 20px/1 var(--font-mono); color: var(--text); }
.digit-misses .w { font: 500 15px/1.2 var(--font-ui); color: var(--text); }
.digit-misses small { margin-inline-start: auto; font-size: 12px; color: var(--text-faint); }
.digits-allright { margin: 0; font: 500 15px/1.4 var(--font-ui); color: var(--text); }
/* On the digits result the back control is a real button, not a ghost text link: it sits under a
   full-width primary, so a borderless label read as an afterthought. Outlined, same height, same
   width — a deliberate stack. The mid-run "Stop run" button keeps .run-stop-btn's bare look, which
   is right there: it is a way out of a timer, not a destination. */
.digits-back {
  display: flex; align-items: center; justify-content: center; gap: 6px;
  inline-size: 100%; box-sizing: border-box; margin-block-start: 10px;
  min-block-size: 52px; padding: 8px 20px; border-radius: var(--radius-pill);
  background: var(--btn-ghost-bg); color: var(--btn-ghost-fg);
  border: 1px solid var(--glass-border);
  font: 600 15px/1 var(--font-ui);
  transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
}
.digits-back:hover { background: var(--glass-flat); color: var(--text); }
.digits-back .ic { inline-size: 16px; block-size: 16px; color: currentColor; }

/* ---------- help / how it works (#/help) ---------- */
.help-copy { margin: 0; font: 400 var(--fs-body)/var(--lh-body) var(--font-ui); color: var(--text); }
.help-copy + .help-copy, .help-example + .help-copy { margin-block-start: 12px; }
.help-example {
  display: flex; align-items: center; gap: 12px; margin-block-start: 14px; padding-block: 10px; padding-inline: 14px;
  border-radius: var(--radius-row); background: var(--glass-flat); border: 1px solid var(--glass-border);
}
.help-example-num { font: 600 22px/1 var(--font-mono); color: var(--text); }
.help-example-sounds { font-size: 13px; color: var(--text-muted); }
.help-example-word { margin-inline-start: auto; font: 500 15px/1.2 var(--font-ui); color: var(--text); }

.help-steps-list { display: flex; flex-direction: column; gap: 12px; margin: 0; padding-inline-start: 20px; }
.help-steps-list li::marker { font: 600 14px var(--font-mono); color: var(--accent-text); }
.help-steps-list b { display: block; font: 600 15px/1.3 var(--font-ui); color: var(--text); }
.help-steps-list span { display: block; margin-block-start: 2px; font: 400 13.5px/1.45 var(--font-ui); color: var(--text-muted); }
.help-links { display: flex; flex-wrap: wrap; gap: 8px; margin-block-start: 16px; }

.help-faq-list { display: flex; flex-direction: column; gap: 16px; margin: 0; padding: 0; list-style: none; }
.help-faq-item h3 { margin: 0; font: 600 15px/1.3 var(--font-ui); color: var(--text); }
.help-faq-item p { margin-block: 4px 0; font: 400 13.5px/1.45 var(--font-ui); color: var(--text-muted); }

.help-footer { display: flex; justify-content: center; gap: 8px; margin-block-start: 18px; }

/* the quiet link under the Learn ladder */
.help-link { display: flex; justify-content: center; margin-block: 18px 0; }
.help-link-btn {
  display: inline-flex; align-items: center; gap: 4px; min-block-size: 44px; padding-block: 8px; padding-inline: 12px;
  border: 0; border-radius: var(--radius-pill); background: none; cursor: pointer;
  font: 500 13.5px/1 var(--font-ui); color: var(--text-muted);
}
.help-link-btn:hover { color: var(--text); background: var(--glass-flat); }
.help-link-btn:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

/* ---------- accessibility floor (docs/tasks/TASK-a11y.md) ---------- */
/* faint text never sits on a frosted tile: there the glow behind the card leaves it under 4.5:1 */
.stage .sounds, .stage .alt-word, .bank-row:hover .s, .bank-item.expanded .s { color: var(--text-muted); }

/* one visible ring for every focusable thing that doesn't draw its own */
:where(a, button, input, select, textarea, summary, [role="button"], [role="tab"], [role="radio"], [tabindex]):focus-visible {
  outline: 2px solid var(--focus-ring); outline-offset: 2px;
}
/* the screen root and headings are programmatic focus targets (tabindex -1), never Tab stops */
#screen:focus, [tabindex="-1"]:focus:not(:focus-visible) { outline: none; }
#screen:focus-visible { outline: none; }
/* text fields drew only a 1-2 px border change on focus; add the soft ring the search field uses */
.stop-input:focus-visible, .run-input:focus-visible, .digit-input:focus-visible, .search-input:focus-visible {
  border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 5px var(--focus-ring);
}
.sr-only {
  position: absolute !important; inline-size: 1px; block-size: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}
/* the brand mark link: 22 px glyph, 44 px target (padding out, margin back in: layout unchanged) */
.hero .mark { padding: 11px; margin: -11px; border-radius: var(--radius-pill); }
/* tappable route dots stay 9 px to the eye; the hit area grows to 24 px. The Prev button is the
   44 px equivalent control for the same action. */
.route .d.tappable { position: relative; }
.route .d.tappable::after { content: ""; position: absolute; inset-block-start: 50%; inset-inline-start: 50%;
  inline-size: 24px; block-size: 24px; translate: -50% -50%; }
[dir="rtl"] .route .d.tappable::after { translate: 50% -50%; }
.textbtn { min-block-size: 44px; margin-block-start: 4px; padding-inline: 4px; border: 0; background: none;
  color: var(--text-muted); font: 500 13.5px/1.2 var(--font-ui); text-decoration: underline;
  text-underline-offset: 3px; cursor: pointer; }
.textbtn:hover { color: var(--text); }

/* ---------- palaces: the learner's own routes (docs/tasks/TASK-palaces.md) ---------- */
.field-lab { display: block; margin-block: 16px 6px; font: 500 13.5px/1.3 var(--font-ui); color: var(--text-muted); }
.field-err { margin: 6px 0 0; font: 500 13px/1.4 var(--font-ui); color: var(--accent-text); }
.field-err[hidden], .chunks li[hidden], .setup-route li[hidden] { display: none; }
.stop-input[aria-invalid="true"] { border-color: var(--accent); }
.palace-list { list-style: none; margin: 12px 0 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.palace-item { padding: 14px 16px; border-radius: var(--radius-row); background: var(--glass-flat);
  border: 1px solid var(--glass-border); }
.palace-item.on { border-color: var(--accent); }
.palace-head { display: flex; align-items: center; gap: 10px; }
.palace-head h2 { flex: 1; min-inline-size: 0; overflow-wrap: anywhere; font-size: 19px; }
.palace-meta { margin: 4px 0 0; font: 400 13.5px/1.3 var(--font-mono); color: var(--text-muted); }
.palace-go { inline-size: 100%; margin-block-start: 12px; min-block-size: 44px; }
.palace-actions { display: flex; flex-wrap: wrap; gap: 4px 14px; align-items: center; margin-block-start: 6px; }
.palace-rename .palace-actions, .palace-confirm .palace-actions { gap: 10px; margin-block-start: 12px; }
.palace-rename .stop-input { inline-size: 100%; }
.palace-confirm p { margin: 12px 0 0; font: 400 14px/1.5 var(--font-ui); color: var(--text); }
.palace-editor > .stop-input { inline-size: 100%; }
.palace-stops-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.palace-stops-head .counter { font: 600 13px/1 var(--font-mono); color: var(--text-muted); }
.palace-hint { margin: 0 0 8px; font: 400 13px/1.4 var(--font-ui); color: var(--text-muted); }
.palace-hint:empty { display: none; }
/* many stops scroll inside the card; the padding leaves room for the focus rings */
.palace-stops { list-style: none; margin: 0; padding: 6px; display: flex; flex-direction: column; gap: 8px;
  max-block-size: min(52vh, 460px); overflow-y: auto; overscroll-behavior: contain;
  border-radius: var(--radius-row); border: 1px solid var(--glass-border); }
.palace-stop { display: grid; grid-template-columns: auto 1fr auto auto auto; align-items: center; gap: 6px; }
.palace-stop .stop-input { min-inline-size: 0; }
.palace-stop .field-err { grid-column: 2 / -1; margin: 0; }
.iconbtn { inline-size: 44px; block-size: 44px; display: grid; place-items: center; flex: none;
  border-radius: var(--radius-row); border: 1px solid var(--glass-border); background: var(--glass-flat);
  color: var(--text-muted); cursor: pointer; transition: border-color var(--dur-fast) var(--ease); }
.iconbtn:hover { border-color: var(--accent); color: var(--text); }
.iconbtn:disabled { opacity: .35; cursor: not-allowed; }
.iconbtn.up .ic { rotate: 90deg; }
.iconbtn.down .ic { rotate: -90deg; }
.palace-add { inline-size: 100%; margin-block-start: 10px; min-block-size: 44px; }
.palace-editor .cta { margin-block-start: 12px; }
.palace-chooser { margin-block: 12px 0; }
.palace-chooser .field-lab { margin-block-start: 0; }
.palace-chooser .field-row { display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  margin-block-end: 6px; }
.palace-chooser .field-row .field-lab { margin-block: 0; }
.own-picker { margin-block-start: 8px; }
.palace-select { inline-size: 100%; min-block-size: 44px; padding-inline: 14px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border); color: var(--text);
  font: 500 14px/1 var(--font-ui); }
.palace-select option { background: var(--surface); color: var(--text); }
.palace-demo-hint p { margin: 0; }
.palace-demo-hint .textbtn { margin-block-start: 0; padding-inline: 0; }
.chunks .chunk-locus { font-size: 11.5px; line-height: 1.2; text-align: center; padding-inline: 4px;
  overflow-wrap: anywhere; }
/* the Practice setup previews the route by locus name only; the numbers wait for Start run */
.setup-route { margin-block: 8px 0; padding-inline-start: 2.4em; columns: 2 12em; column-gap: 16px;
  font: 400 14px/1.35 var(--font-ui); color: var(--text); }
.setup-route li { padding-block: 3px; break-inside: avoid; overflow-wrap: anywhere; }
.setup-route li::marker { color: var(--text-muted); font-family: var(--font-mono); font-size: 12.5px; }
.setup-hidden-note { margin-block: 8px 0; font: 400 13px/1.4 var(--font-ui); color: var(--text-muted); }

/* The run's terms, and the disclosure that opens the pickers. This is the whole point of the change:
   a returning user reads one line and presses Start, and nothing else competes for the eye. */
.setup-summary {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 0; padding-block-end: 2px;
}
.setup-summary-txt { font: 500 15px/1.4 var(--font-ui); color: var(--text); }
.setup-summary .textbtn { padding-inline: 0; font-size: 13.5px; }
.setup-settings { margin-block-start: 12px; }
.setup-settings[hidden] { display: none; }

/* The route as one line of quiet text. The list itself stays in the markup (it is what the harness
   counts, and what a screen reader reads in order); it is simply no longer painted as a list. */
.setup-route-line { margin: 0 0 2px; font: 400 13.5px/1.5 var(--font-ui); color: var(--text-muted); }
.setup-walk .setup-route { display: none; }
.setup-walk .setup-hidden-note { display: none; }
.account-card .account-header { display: flex; align-items: center; gap: 16px; margin-block-end: 12px; }
.account-card .avatar { inline-size: 56px; block-size: 56px; border-radius: 50%; display: grid; place-items: center; flex: none; background: var(--glass-flat); border: 1px solid var(--glass-border); color: var(--accent-text); }
.account-card .avatar.initial { font: 600 22px/1 var(--font-ui); color: var(--text); }
.account-card .avatar.photo { overflow: hidden; }
.account-card .avatar img { inline-size: 100%; block-size: 100%; border-radius: 50%; object-fit: cover; }
.account-card .account-info { min-inline-size: 0; }
.account-card .account-info h2 { margin: 0; font: 600 var(--fs-h2)/1.2 var(--font-ui); color: var(--text); }
.account-card .account-desc,
.account-card .account-email,
.account-card .account-joined { margin: 4px 0 0; font: 400 13.5px/1.4 var(--font-ui); color: var(--text-muted); }
.account-benefit-box { margin-block-start: 12px; padding: 12px 14px; border-radius: var(--radius-row); background: var(--glass-flat); border: 1px solid var(--glass-border); }
.account-benefit-box .account-benefit { margin: 0; font: 400 13px/1.4 var(--font-ui); color: var(--text-muted); }
.account-card .google-btn { inline-size: 100%; min-block-size: 44px; }

/* ---------- compete: lobby, live match, result (docs/tasks/TASK-compete-pane.md) ---------- */
.soon h2 { margin: 0; }
/* only the first card overlaps the hero; the phase card sits below the players card and the clocks */
[data-compete] .stack > .card { margin-block-start: 0; }
.compete-rating .rating-line { display: flex; align-items: baseline; flex-wrap: wrap; gap: 6px 14px; margin: 0; }
.rating-num { font: 600 44px/1 var(--font-mono); letter-spacing: -0.02em; color: var(--text); }
.rating-num .prov { margin-inline-start: 2px; font-size: 26px; color: var(--accent-text); }
.rank-name { font: 600 17px/1.2 var(--font-ui); color: var(--accent-text); }
.rank-bar { block-size: 6px; margin-block-start: 14px; border-radius: var(--radius-pill); background: var(--track); overflow: hidden; }
.rank-bar span { display: block; block-size: 100%; border-radius: var(--radius-pill); background: var(--accent); }
.compete-rating .chips { margin-block-start: 12px; }
.compete-name { inline-size: 100%; }
.link-row { display: flex; gap: 8px; align-items: center; }
.link-row .stop-input { min-inline-size: 0; }
.link-row .btn { flex: 0 0 auto; min-block-size: 44px; }
.match-code { margin: 0; font: 600 40px/1.1 var(--font-mono); letter-spacing: 0.14em; color: var(--text); }
.created .textbtn { margin-block-start: 6px; }
.searching { margin-block-start: 14px; padding: 14px 16px; border-radius: var(--radius-row);
  background: var(--glass-flat); border: 1px solid var(--glass-border); }
.searching .meta:first-of-type { margin-block-start: 6px; }
.search-title { display: flex; align-items: center; gap: 10px; margin: 0; font: 600 16px/1.3 var(--font-ui); color: var(--text); }
.join-form { margin-block-start: 6px; }
.players { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; }
.player { display: flex; align-items: center; gap: 10px; min-block-size: 52px; border-block-end: 1px solid var(--glass-border); }
.player:last-child { border-block-end: 0; }
.player .pname { flex: 1; min-inline-size: 0; overflow-wrap: anywhere; font: 600 16px/1.25 var(--font-ui); color: var(--text); }
.player .pname small { font-weight: 400; color: var(--text-muted); }
.player .prating { font: 500 14px/1 var(--font-mono); color: var(--text-muted); }
.player .pwins { min-inline-size: 36px; padding: 8px 0; text-align: center; border-radius: var(--radius-pill);
  background: var(--glass-flat); border: 1px solid var(--glass-border); font: 600 16px/1 var(--font-mono); color: var(--text); }
.player.me .pwins { border-color: var(--accent); }
.chip.conn.off { color: var(--accent-text); }
.round-dots { display: flex; gap: 8px; margin: 14px 0 0; padding: 0; list-style: none; }
.round-dots .rd { flex: 1; block-size: 6px; border-radius: var(--radius-pill); background: var(--track); }
.round-dots .rd.won { background: var(--accent); }
.round-dots .rd.lost { background: var(--text-muted); }
.round-dots .rd.draw { background: var(--text-faint); opacity: .6; }
.round-dots .rd.now { background: var(--accent); opacity: .45; }
.clocks { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; margin-block-end: 10px; }
.clock { display: flex; flex-direction: column; gap: 6px; padding: 12px 16px; border-radius: var(--radius-row);
  background: var(--row-glass); border: 1px solid var(--glass-border);
  -webkit-backdrop-filter: var(--glass-blur-sm); backdrop-filter: var(--glass-blur-sm); }
.clock .k { font: 500 12.5px/1 var(--font-ui); color: var(--text-muted); }
.clock .num { font: 600 24px/1 var(--font-mono); color: var(--text); }
.big-clock { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin: 16px 0 0; }
.big-clock .k { font: 500 14px/1.3 var(--font-ui); color: var(--text-muted); }
.big-clock .num { font: 600 32px/1 var(--font-mono); color: var(--text); }
.phase-card h2 + .meta { margin-block-start: 8px; }
.scores { list-style: none; margin: 14px 0 0; padding: 0; }
.scores li { display: flex; align-items: center; gap: 12px; min-block-size: 44px; border-block-end: 1px solid var(--glass-border); }
.scores li:last-child { border-block-end: 0; }
.scores .k { flex: 1; min-inline-size: 0; overflow-wrap: anywhere; font: 500 15px/1.3 var(--font-ui); color: var(--text); }
.scores .v { font: 500 14px/1 var(--font-mono); color: var(--text-muted); }
.digit-string.small { font-size: 17px; gap: 6px 10px; padding-block: 12px; }
.rating-delta { margin: 0; font: 600 34px/1.1 var(--font-mono); color: var(--text); }
.compete-table { inline-size: 100%; border-collapse: collapse; }
.compete-table th { padding: 0 6px 8px; text-align: start; font: 500 var(--fs-cap)/1.2 var(--font-ui);
  letter-spacing: var(--ls-cap); text-transform: uppercase; color: var(--text-muted); border-block-end: 1px solid var(--track); }
.compete-table tbody th, .compete-table td { padding: 10px 6px; text-align: start; vertical-align: middle;
  border-block-end: 1px solid var(--track); font: 500 13.5px/1.3 var(--font-ui); color: var(--text); letter-spacing: 0;
  text-transform: none; }
.compete-table td.mono { font-family: var(--font-mono); }
.compete-table tr:last-child th, .compete-table tr:last-child td { border-block-end: 0; }

/* ---------- progress detailed statistics (Direction D "glass") ---------- */
.stats-section {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-block-start: 14px;
}
.stats-empty {
  padding: 18px 20px;
  border-radius: var(--radius-row);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
}
.stats-empty h3 {
  margin: 10px 0 6px;
  font: 600 16px/1.2 var(--font-ui);
  color: var(--text);
}
.stats-empty p {
  margin: 0;
  font: 400 13.5px/1.5 var(--font-ui);
  color: var(--text-muted);
}
.stat-card {
  padding: 18px 20px;
}
.stat-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 10px;
  margin-block-end: 14px;
}
.stat-sub {
  display: block;
  font: 400 12.5px/1.35 var(--font-ui);
  color: var(--text-muted);
  margin-block-start: 3px;
}
.stat-badges {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.stat-pill {
  font: 500 12px/1 var(--font-mono);
  padding: 4px 8px;
  border-radius: 999px;
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  color: var(--text-muted);
}
.stat-pill.best {
  border-color: var(--accent);
  color: var(--accent-text);
  background: var(--accent-soft);
}
.chart-wrap {
  inline-size: 100%;
  overflow: hidden;
}
.stat-chart {
  inline-size: 100%;
  block-size: auto;
  display: block;
}
.chart-dot.is-pb {
  filter: drop-shadow(0 0 3px var(--accent));
}

/* Mistake Heat Strip */
.heat-strip {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(52px, 1fr));
  gap: 6px;
  margin-block: 4px 10px;
}
.heat-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  padding: 10px 4px 8px;
  border-radius: var(--radius-tile);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  text-align: center;
}
.heat-cell.warm {
  background: var(--accent-soft);
  border-color: var(--accent);
}
.heat-cell.hot {
  border-color: var(--accent-hover);
  box-shadow: 0 0 8px rgba(221, 122, 26, 0.25);
}
.heat-locus {
  font: 500 11px/1 var(--font-ui);
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-faint);
}
.heat-bar {
  inline-size: 100%;
  max-inline-size: 24px;
  block-size: 3px;
  border-radius: 2px;
  background: var(--track);
}
.heat-cell.warm .heat-bar {
  background: var(--accent);
}
.heat-val {
  font-size: 16px;
  color: var(--text);
}
.heat-tag {
  font: 400 10.5px/1 var(--font-ui);
  color: var(--text-muted);
}
.heat-cell.warm .heat-tag {
  color: var(--accent-text);
  font-weight: 500;
}
.mistake-takeaway {
  margin: 6px 0 0;
  font: 400 12.5px/1.4 var(--font-ui);
  color: var(--text-muted);
}

/* Palace Performance */
.palace-stat-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.palace-stat-item {
  padding: 12px 14px;
  border-radius: var(--radius-tile);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.palace-stat-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
}
.palace-name {
  font: 600 14.5px/1.2 var(--font-ui);
  color: var(--text);
}
.palace-stops {
  font-size: 12px;
  color: var(--text-muted);
}
.palace-stat-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
}
.p-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.p-stat small {
  font: 500 11px/1 var(--font-ui);
  text-transform: uppercase;
  color: var(--text-faint);
}
.p-stat b {
  font-size: 14px;
  color: var(--text);
}
.p-stat .date {
  font-size: 12px;
  color: var(--text-muted);
}

/* Mode Split */
.mode-split-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
}
@media (max-width: 360px) {
  .mode-split-grid {
    grid-template-columns: 1fr;
  }
}
.mode-stat-card {
  padding: 12px;
  border-radius: var(--radius-tile);
  background: var(--glass-flat);
  border: 1px solid var(--glass-border);
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.mode-name {
  font: 600 13px/1.2 var(--font-ui);
  color: var(--text);
}
.mode-numbers {
  display: flex;
  justify-content: space-between;
  gap: 6px;
}
.m-metric {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.m-metric small {
  font: 500 10.5px/1 var(--font-ui);
  text-transform: uppercase;
  color: var(--text-faint);
}
.m-metric b {
  font-size: 14px;
  color: var(--text);
}

/* ---------- the wide layout (mockups/06-wide.html, docs/tasks/TASK-wide-screens.md) ----------
   Every rule below sits inside a min-width query: under 768 px the phone layout is untouched.
   768–1023 loosens the column and keeps the dock. From 1024 the dock becomes a left rail with its
   labels, and the content is a bounded area centred in the rest of the window. #screen carries
   data-view (the route name) so a few screens can take their own shape. */
@media (min-width: 1024px) {
  /* The shell is the whole window less the rail's room. The CONTENT also fills it: there is no
     --screen-max cap here, because a centred cap is exactly the empty area this change removes.
     Long prose stays readable because the text blocks inside carry their own measure
     (`.copy` 34ch, `.top .sub` 56ch, `--measure` on the prose screens, 800px on a lesson). */
  .app { max-inline-size: none; border-inline: 0; padding-inline-start: var(--rail-w); }
  .body { box-sizing: border-box; inline-size: 100%;
    max-inline-size: none; padding-block-end: 72px; }
  /* the prose screens keep a reading measure — applied to the inner .wrap, not to the shell, so the
     background still fills the window */
  .body[data-view="account"] .wrap, .body[data-view="settings"] .wrap, .body[data-view="help"] .wrap,
  .body[data-view="result"] .wrap { max-inline-size: var(--measure); margin-inline: auto; }

  /* the band runs edge to edge across the whole window (under the glass rail) */
  .hero { padding: 28px 32px 46px; }
  .hero::before, .hero::after {
    --bleed: calc((100vw - var(--rail-w) - 100vw) / 2 + var(--rail-w));
    inset-inline: calc(-1 * var(--bleed)) 0;
  }
  .top .sub { max-inline-size: 56ch; }
  .hero-art { inline-size: var(--art-w-wide); }
  .hero-art.lg { inline-size: var(--art-w-wide-lg); }
  .wrap { padding-inline: 32px; }

  /* ---- the rail: a real full-height sidebar, the way a site has one ----
     The dock stops being a floating pill and becomes the nav list inside it. It runs the full height
     of the viewport, flush to the inline-start edge, so the page reads as a document with navigation
     rather than a phone column parked in a large window. */
  .rail {
    display: flex; flex-direction: column; position: fixed; inset-block: 0; inset-inline-start: 0;
    inline-size: var(--rail-w); box-sizing: border-box; padding: 20px 16px 16px;
    background: var(--surface); border-inline-end: 1px solid var(--border); z-index: 30;
  }
  .rail-brand {
    display: flex; align-items: center; gap: 10px; padding: 6px 10px 18px;
    color: var(--text); text-decoration: none;
  }
  .rail-brand .mark { display: inline-flex; color: var(--text); }
  
  .rail-brand .wordmark { font: 600 15px/1 var(--font-ui); letter-spacing: 0.01em; }
  .rail-brand:hover .wordmark { color: var(--accent-text); }

  /* the dock is the nav list now: no glass, no halo, no fixed positioning, no centring nudge */
  .dock {
    position: static; translate: none; inset: auto; inline-size: auto; box-sizing: border-box;
    display: flex; flex-direction: column; gap: 4px; padding: 0; border: 0; border-radius: 0;
    background: none; box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
  }
  [dir="rtl"] .dock { translate: none; }
  .dock .tab {
    justify-content: flex-start; gap: 12px; inline-size: 100%; min-block-size: 44px;
    padding-inline: 12px; border-radius: var(--radius-row, 10px); text-align: start;
    font: 500 14.5px/1 var(--font-ui); color: var(--text-muted);
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  }
  .dock .tab .ic { flex: 0 0 auto; }
  .dock .tab .lbl { display: inline; }
  .dock .tab:hover { background: var(--glass-flat); color: var(--text); }
  .dock .tab.on { background: var(--accent-soft); color: var(--text); box-shadow: inset 2px 0 0 var(--accent); }
  [dir="rtl"] .dock .tab.on { box-shadow: inset -2px 0 0 var(--accent); }
  .dock .tab.on .ic { color: var(--accent); }

  /* the rail's utility nav, pinned to the bottom of the sidebar */
  .rail-foot { margin-block-start: auto; display: flex; flex-direction: column; gap: 2px;
    padding-block-start: 14px; border-block-start: 1px solid var(--border); }
  .rail-link {
    display: flex; align-items: center; gap: 12px; inline-size: 100%; min-block-size: 44px;
    padding-inline: 12px; border: 0; border-radius: var(--radius-row, 10px); background: none;
    color: var(--text-muted); font: 500 14.5px/1 var(--font-ui); text-align: start; cursor: pointer;
    transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  }
  .rail-link .ic { flex: 0 0 auto; }
  .rail-link:hover { background: var(--glass-flat); color: var(--text); }
  .rail-link:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }

  /* the brand now lives in the rail, so the hero keeps only the session state (XP + account) */
  .hero .brandrow > .mark, .hero .brandrow > .wordmark { display: none; }
  .hero .brandrow { justify-content: flex-end; }

  /* ---- the footer: a real one, pushed to the bottom of the page ---- */
  .site-foot {
    display: block; margin-block-start: auto; border-block-start: 1px solid var(--border);
    background: var(--bg); padding: 22px 32px 28px;
  }
  .site-foot-inner {
    max-inline-size: var(--content-max); margin-inline: auto;
    display: flex; align-items: center; gap: 20px 28px; flex-wrap: wrap;
  }
  .site-foot-id { display: flex; align-items: center; gap: 9px; color: var(--text-muted); }
  .site-foot-id .mark { display: inline-flex; color: var(--text-muted); }
  
  .site-foot-id .wordmark { font: 600 14px/1 var(--font-ui); }
  .site-foot-note { margin: 0; color: var(--text-faint); font: 400 13.5px/1.5 var(--font-ui); }
  .site-foot-links { display: flex; gap: 6px; margin-inline-start: auto; }
  /* The footer links are text, so their box is only as tall as the text. Padding grows the hit
     target to the 44 px floor from the inside (the same approach .rail-link uses), so the links
     get bigger without pushing anything else around. */
  .site-foot-links a {
    color: var(--text-muted); font: 500 13.5px/1 var(--font-ui); text-decoration: none;
    display: inline-flex; align-items: center; min-block-size: 44px; padding-inline: 10px;
    border-radius: var(--radius-row, 10px); transition: background var(--dur-fast) var(--ease), color var(--dur-fast) var(--ease);
  }
  .site-foot-links a:hover { color: var(--accent-text); background: var(--glass-flat); }
  .site-foot-links a:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 2px; }
  .site-foot-year { margin: 0; color: var(--text-faint); font: 400 13px/1 var(--font-mono); }

  /* denser desktop: a wide screen does not need the generous padding a phone does */
  .card { padding: 20px 22px; border-radius: 20px; }
  .wrap { padding-block: 20px; }

  .toast { inset-inline: calc(var(--rail-w) + 22px) 22px; inset-block-end: 32px; }
  .sheet { inset-inline-start: var(--rail-w); max-inline-size: 560px; }

  /* buttons stop stretching across a wide card; the primary keeps its single orange treatment */
  .cta .btn { flex: 0 1 auto; min-inline-size: 220px; }
  .cta .btn.ghost { min-inline-size: 52px; }
  /* ...except when the CTA holds ONE action. The rule above exists so a row of buttons does not smear
     across a wide card; a lone action is not a row, and at the 220px floor it reads as an afterthought
     next to a 305px content column. Omran, 2026-09-27: "make this be wider, appropriately" — after
     the digits result dropped its "Next length" button, leaving Try again alone. */
  .cta .btn:only-child { flex: 1 1 auto; min-inline-size: 0; }

  /* a grid of cards that sits on the card line: the grid overlaps the band once, its cards don't */
  .wide-grid, [data-view="learn"] > .wrap, [data-compete="lobby"], [data-compete="match"] {
    margin-block-start: calc(-1 * var(--hero-overlap)); }

  /* ---- Learn: Continue + the sound strip, then the course as a grid of course cards ---- */
  [data-view="learn"] > .wrap { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 16px; align-items: start; }
  [data-view="learn"] > .wrap > * { grid-column: 1 / -1; margin-block: 0; }
  [data-view="learn"] .path { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  [data-view="learn"] .path li::before, [data-view="learn"] .path li.now::after { display: none; }
  [data-view="learn"] .path li.part { grid-column: 1 / -1; padding: 14px 4px 2px; }
  [data-view="learn"] .path .lesson { block-size: 100%; min-block-size: 84px; padding: 12px 14px;
    background: var(--glass-flat); box-shadow: inset 0 0 0 1px var(--glass-border); }
  [data-view="learn"] .path .lesson:not([aria-disabled="true"]):hover { box-shadow: inset 0 0 0 1px var(--accent); }

  /* ---- the number bank: a tile wall, one decade per row ---- */
  .bank-card .decade-group { margin-block-end: 18px; }
  .bank-card .decade-title { margin-inline-start: 4px; }
  .bank-card .bank { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 8px; }
  .bank-card .bank-item { min-inline-size: 0; }
  .bank-card .bank-item.expanded { grid-column: 1 / -1; }
  .bank-card .bank-item:not(.expanded) .bank-row {
    display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 6px;
    box-sizing: border-box; block-size: 100%; min-block-size: 108px; padding: 12px 6px 10px; text-align: center;
    background: var(--glass-flat); border: 1px solid var(--glass-border); }
  .bank-card .bank-item:not(.expanded) .bank-row:hover { background: var(--glass-flat); border-color: var(--accent); }
  .bank-card .bank-item:not(.expanded) .bank-row .n { order: 0; font-family: var(--font-mono); }
  .bank-card .bank-item:not(.expanded) .bank-row .image-slot { order: 1; justify-self: auto; }
  .bank-card .bank-item:not(.expanded) .bank-row .w { order: 2; max-inline-size: 100%; font-size: 13.5px;
    flex-direction: column; justify-content: center; gap: 4px; }
  .bank-card .bank-item:not(.expanded) .bank-row .w > span:first-child { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .bank-card .bank-item:not(.expanded) .bank-row .s { order: 3; color: var(--text-muted); }
  .bank-card .bank-item:not(.expanded) .stop-tag { padding: 2px 6px; font-size: 10.5px; }

  /* ---- Lesson: the text at a reading measure, a rail beside it (aside, or the number + image) ---- */
  [data-view="lesson"] > .wrap > * { max-inline-size: 800px; }
  /* The two-column lesson (text | rail) is capped as a PAIR, not allowed to stretch: with the shell
     now filling the window, an uncapped `1fr` would open a 1500px void between the text and the
     tip at 2560. The measure belongs to the content, the background still fills. */
  [data-view="lesson"] > .wrap > .card:has(> .lesson-rail) {
    max-inline-size: min(100%, 1200px); margin-inline: auto;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(260px, 340px); column-gap: 48px; align-items: start;
  }
  [data-view="lesson"] .card:has(> .lesson-rail) > * { grid-column: 1; }
  [data-view="lesson"] .card:has(> .lesson-rail) > .lesson-rail { grid-column: 2; grid-row: 1 / span 12;
    margin-block-start: 0; }
  [data-view="lesson"] .card:has(> .lesson-rail) > .lesson-rail > .cap:first-child { margin-block-start: 0 !important; }
  [data-view="lesson"] .card:has(> .lesson-rail) .copy { max-inline-size: 68ch; }

  /* ---- Practice: options | the walk; numbers five across; the timer grows ---- */
  .setup-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr); column-gap: 40px; align-items: start; }

  /* Practice is a desktop application, not a phone card: the league picker is a left column of
     rows, the explanation and Start share the right. One wide surface, aligned, no floating stack. */
  [data-view="practice"] .stack, [data-view="practice"] .wrap { max-inline-size: none; }
  /* One grid, two columns: settings + the instructions share the left, the action owns the right.
     The fields are number inputs, so they are sized for a number and left with real air around
     them - they were 518px each in a full-width row sitting flush against the text below. */
  .digits-about { min-inline-size: 0; }
  .digits-about h2 { margin-block: 0 10px; font-size: 21px; }
  .digits-about .digits-howto { max-inline-size: 60ch; }
  .digits-start { display: flex; flex-direction: column; gap: 12px; align-items: stretch; }
  /* The time sits right beside the label, as a grouped unit. Pushing it to the far end with
     margin-inline-start:auto spread the button into a wide bar with a value at each end, which
     reads as a slider track rather than a button. */
  .digits-start .go { margin-block-start: 0; justify-content: center; gap: 10px; padding-inline: 28px; }
  .digits-start .picker-pb { margin: 0; text-align: center; font-size: 13.5px; }
  .digits-about { display: flex; flex-direction: column; gap: 2px; max-inline-size: 52ch; }
  .digits-about .digits-howto { margin: 0; }
  .digits-start .go small {
    margin-inline-start: 0; padding-inline-start: 10px; color: var(--text-muted);
    border-inline-start: 1px solid var(--track); font: 500 15px/1 var(--font-mono);
  }
  /* Practice is one focused task, not a dashboard: a narrow panel, centred in the space under the
     band, so the page is not a strip at the top with 450px of nothing below it. */
  [data-view="practice"] .stack, [data-view="practice"] .wrap { max-inline-size: none; }
  [data-view="practice"] .wrap {
    display: flex; justify-content: center;
    min-block-size: clamp(320px, calc(100dvh - 420px), 620px);
  }
  [data-view="practice"] .card.digits-card {
    inline-size: min(100%, 640px); box-sizing: border-box; align-self: center;
    padding: 30px 34px 32px; border-radius: 20px;
  }
  .digits-setup { display: flex; flex-direction: column; gap: 18px; }
  /* Full width, so all three rows share the card's left and right edge. A width-less row took only
     its content, which put each + button at a different x and left the unit labels hanging. */
  .digits-field-row { display: flex; flex-direction: column; gap: 7px; inline-size: 100%; box-sizing: border-box; }
  .digits-field-row .field-lab { margin: 0; }
  .digits-box { position: relative; flex: 1 1 auto; min-inline-size: 0; display: flex; align-items: center; }
  .digits-box .digits-input { padding-inline-end: 64px; }
  .digits-unit {
    position: absolute; inset-inline-end: 16px; pointer-events: none;
    font: 500 14px/1 var(--font-ui); color: var(--text-faint);
  }
  [data-view="practice"] .digits-about, [data-view="practice"] .digits-start { display: contents; }
  .digits-setup .digits-howto { margin: 0; max-inline-size: 52ch; }
  .digits-setup .go { margin-block-start: 6px; }
  .digits-setup .picker-pb { margin: 0; text-align: center; }

  .setup-walk > h2 { margin-block-start: 12px; }
  [data-view="practice"] .chunks:has(> li:nth-child(5)) { grid-template-columns: repeat(5, minmax(0, 1fr)); }
  [data-view="practice"] .chunks:not(:has(> li:nth-child(5))) { max-inline-size: calc(var(--chunks-cols, 5) * 200px); }
  [data-view="practice"] .chunks { gap: 10px; margin-block: 16px 6px; }
  [data-view="practice"] .chunks li { padding-block: 16px; }
  [data-view="practice"] .chunks .emoji { font-size: 34px; }
  [data-view="practice"] .chunks b { font-size: 22px; }
  [data-view="practice"] .card > .go:not(.split) { max-inline-size: 440px; margin-inline: auto; }
  .peek.clock-region { font-size: 17px; }
  .peek.clock-region .end { font: 600 28px/1 var(--font-mono); color: var(--text); }
  .run-input { inline-size: 240px; block-size: 88px; font-size: 52px; }
  .digit-input, .digit-string:not(.small) { max-inline-size: 760px; margin-inline: auto; box-sizing: border-box; }

  /* ---- Progress: the stat cards two across (badges beside the totals from 1440) ---- */
  [data-view="progress"] .stats-section:not(.is-empty) { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px; align-items: start; margin-block-start: 24px; }
  [data-view="progress"] .stats-section > .lab { grid-column: 1 / -1; }
  [data-view="progress"] .stats-section > .card { margin-block-start: 0; }
  [data-view="progress"] .stat-chart { max-block-size: 280px; }

  /* ---- Compete: my standing | create and join; in a match, players | the round ---- */
  [data-compete="lobby"] { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 16px; align-items: start; }
  [data-compete="lobby"] > .card { grid-column: 2; margin-block-start: 0; }
  [data-compete="lobby"] > .compete-rating { grid-column: 1; grid-row: 1 / span 4; }
  [data-compete="match"] { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 16px; align-items: start; }
  [data-compete="match"] > * { grid-column: 1; margin-block-start: 0; }
  [data-compete="match"] > .stack { grid-column: 2; grid-row: 1 / span 4; }
  [data-compete="match"] > #playersCard { margin-block-start: 0; }
  [data-compete="result"], [data-compete="offline"] { max-inline-size: 800px; }

  /* ---- Palaces: the list as a grid of palace cards; the editor at a reading measure ---- */
  [data-view="palaces"] .palace-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
  [data-view="palaces"] .palace-editor, [data-view="palaces"] .palaces-empty { max-inline-size: 800px; }
  [data-view="palaces"] .card > .go { max-inline-size: 440px; }
}

@media (min-width: 1440px) {
  .hero { padding-inline: 40px; }
  .wrap { padding-inline: 40px; }
  [data-view="learn"] > .wrap > .resume { grid-column: 1; }
  [data-view="learn"] > .wrap > .keystrip { grid-column: 2; align-self: stretch; display: flex; flex-direction: column; }
  [data-view="learn"] > .wrap > .keystrip ol { margin-block: auto; padding-block-start: 12px; }
  [data-view="learn"] .path { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* the bank: search in its own column, the full decade on one row */
  .bank-card { display: grid; grid-template-columns: 300px minmax(0, 1fr); column-gap: 28px; align-items: start; }
  .bank-card > .search-wrap { position: sticky; inset-block-start: 24px; margin-block-end: 0; }
  .bank-card .bank { grid-template-columns: repeat(10, minmax(0, 1fr)); }
  /* Progress: badges beside the totals */
  [data-view="progress"] .wrap > .stack { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    column-gap: 24px; align-items: start; }
  [data-view="progress"] .wrap > .stack > * { grid-column: 1 / -1; }
  [data-view="progress"] .wrap > .stack > .card { grid-column: 1; grid-row: 1; }
  /* beside the badges the totals sit on the band's glow, so they get the card's glass (on the phone they
     sit on the plain page under the card) */
  [data-view="progress"] .wrap > .stack > .strip { grid-column: 2; grid-row: 1; position: relative; z-index: 1;
    padding: 22px 24px; border-radius: var(--radius-card); background: var(--glass); border: 1px solid var(--glass-border);
    box-shadow: var(--shadow-card); -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur); }
}

/* ---- ultra wide: use the extra room for MORE COLUMNS, never wider text ----
   The shell now fills any window, so a `1fr` card would grow to 2000px+ and its text with it. At
   1920 and up the multi-column grids gain a column instead: more cards per row, each still a
   comfortable size. Single-column screens (lesson, practice, compete, palaces, help, account,
   settings) are already capped by their own measure and need nothing here. */
@media (min-width: 1920px) {
  [data-view="learn"] .path { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  /* the top pair (Continue | sound strip) is 2fr/1fr, so at 2560 the resume card alone is 1477px.
     Three equal columns keep each card a readable size. */
  [data-view="learn"] > .wrap { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  [data-view="learn"] > .wrap > .resume { grid-column: span 2; }
  [data-view="progress"] .stats-section:not(.is-empty) { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  /* the empty state has no cards to grid, so it needs the same cap the filled state gets */
  [data-view="progress"] .stats-section.is-empty, [data-view="progress"] .stats-empty {
    max-inline-size: 900px;
  }
  [data-view="progress"] .wrap > .stack { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  [data-view="progress"] .wrap > .stack > .card { grid-column: 1; grid-row: 1; }
  [data-compete="lobby"] { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr); }
  [data-compete="lobby"] > .compete-rating { grid-column: 1; }
  [data-compete="lobby"] > #rankedCard, [data-compete="lobby"] > #friendlyCard { grid-column: auto; }
}

@media (prefers-reduced-motion: reduce) {
  /* durations are already 0 via tokens; this removes the movement itself */
  *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important;
    scroll-behavior: auto !important; }
  .btn:active, .go:active, .go:hover, .route .d.tappable:hover { transform: none; }
  .toast { transform: none; transition: none; }
  .toggle-thumb, .toggle-track { transition: none; }
  .pulse { animation: none; }
}
