/* Typing tutor. One stylesheet, tokens first, dark mode via data-theme or the system. */
:root {
  --paper: #eef1f8; --paper-2: #e2e7f2; --card: #ffffff; --line: #d6dded; --line-2: #bfc9de;
  --ink: #161a24; --ink-2: #474e61; --muted: #586176;
  /* The accent does three jobs, and one blue cannot pass all three at 4.5:1:
     --accent is rings, borders, bars and icons (3:1 is enough); --accent-fill is a
     surface carrying white text (the brand #2F6FED, 4.55:1 against white); and
     --accent-text is blue words on the page's own grounds (5:1 or better on
     --paper-2, the darkest of them). Measured with bin/contrast, 2026-10-11. */
  --accent: #2f6fed; --accent-fill: #2f6fed; --accent-text: #2459c9; --accent-ink: #ffffff; --accent-soft: #e6eefc;
  --ok: #17a673; --ok-soft: #dff5ea; --bad: #e0533d; --bad-soft: #fde5e0; --gold: #f2b53d; --gold-soft: #fff3d6;
  /* Text set in the ok, bad or gold color on its own soft tint: the fills are too light to read.
     The -fill pair is a surface under white text (a danger button, a heat-map key). */
  --ok-ink: #0b6b49; --gold-ink: #8a5a00; --bad-ink: #b8321f; --ok-fill: #0e7c55; --bad-fill: #c43d28;
  --f-l5: #f7c6d9; --f-l4: #fbd9a8; --f-l3: #d6efa6; --f-l2: #b9dcf7; --f-l1: #e4e4e8;
  --f-r5: #f7c6d9; --f-r4: #fbd9a8; --f-r3: #d6efa6; --f-r2: #b9dcf7; --f-r1: #e4e4e8;
  --radius: 12px; --radius-sm: 8px; --shadow: 0 1px 2px rgba(20,24,40,.06), 0 8px 24px rgba(20,24,40,.06);
  --sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --brand-mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  --key-edge: #b6c1d6; --key-edge-accent: #1f4fb8;
  --serif: "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  color-scheme: light;
}
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) { --paper: #13161d; --paper-2: #1a1e27; --card: #1f2430; --line: #2c3240; --line-2: #3a4152; --ink: #eceef3; --ink-2: #b6bcc9; --muted: #969eb0; --accent: #5b8dff; --accent-fill: #3567e0; --accent-text: #7ea6ff; --accent-soft: #1f2d4d; --ok: #2fc48c; --ok-soft: #173a2d; --bad: #f0715c; --bad-soft: #4a221c; --gold: #f5c04f; --gold-soft: #3f3418; --ok-ink: #2fc48c; --gold-ink: #f5c04f; --bad-ink: #f58a77; --ok-fill: #0e7c55; --bad-fill: #c43d28; --f-l5: #5a2f44; --f-l4: #5a4526; --f-l3: #36502a; --f-l2: #274461; --f-l1: #2f3542; --f-r5: #5a2f44; --f-r4: #5a4526; --f-r3: #36502a; --f-r2: #274461; --f-r1: #2f3542; --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3); --key-edge: #3a4152; --key-edge-accent: #2148a8; color-scheme: dark; } }
:root[data-theme="dark"] { --paper: #13161d; --paper-2: #1a1e27; --card: #1f2430; --line: #2c3240; --line-2: #3a4152; --ink: #eceef3; --ink-2: #b6bcc9; --muted: #969eb0; --accent: #5b8dff; --accent-fill: #3567e0; --accent-text: #7ea6ff; --accent-soft: #1f2d4d; --ok: #2fc48c; --ok-soft: #173a2d; --bad: #f0715c; --bad-soft: #4a221c; --gold: #f5c04f; --gold-soft: #3f3418; --ok-ink: #2fc48c; --gold-ink: #f5c04f; --bad-ink: #f58a77; --ok-fill: #0e7c55; --bad-fill: #c43d28; --f-l5: #5a2f44; --f-l4: #5a4526; --f-l3: #36502a; --f-l2: #274461; --f-l1: #2f3542; --f-r5: #5a2f44; --f-r4: #5a4526; --f-r3: #36502a; --f-r2: #274461; --f-r1: #2f3542; --shadow: 0 1px 2px rgba(0,0,0,.4), 0 8px 24px rgba(0,0,0,.3); --key-edge: #3a4152; --key-edge-accent: #2148a8; color-scheme: dark; }

* { box-sizing: border-box; }
[hidden] { display: none !important; }
:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; border-radius: 4px; }
.skip-link { position: absolute; left: 1rem; top: -3rem; background: var(--ink); color: var(--paper); padding: .5rem .8rem; border-radius: 8px; z-index: 100; font-weight: 600; }
.skip-link:focus { top: 1rem; }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; } }
html { scrollbar-gutter: stable; }
body { margin: 0; font-family: var(--sans); color: var(--ink); background: var(--paper); line-height: 1.5; -webkit-font-smoothing: antialiased; }
a { color: var(--accent-text); text-decoration: none; } a:hover { text-decoration: underline; }
/* A link inside prose is told apart from the words around it by more than its color (WCAG 1.4.1). */
.sect-p a, .qa-item a, .fine a, .muted a, .legal-body a, p a, .field-hint a, .notice a, .log-body a { text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
h1, h2, h3 { line-height: 1.15; margin: 0 0 .4em; letter-spacing: -.01em; }
h1 { font-size: 2rem; letter-spacing: -.02em; } h2 { font-size: 1.35rem; } h3 { font-size: 1.05rem; }
.type-mono { font-family: var(--mono); }
p { margin: 0 0 .8em; }
code, kbd { font-family: var(--mono); font-size: .9em; background: var(--paper-2); padding: .05em .35em; border-radius: 5px; }
kbd { border: 1px solid var(--line-2); border-bottom-width: 2px; }
.muted { color: var(--muted); } .small { font-size: .85rem; } .fine { font-size: .8rem; } .center { text-align: center; } .nowrap { white-space: nowrap; }
.font-mono { font-family: var(--mono); } .font-sans { font-family: var(--sans); } .font-serif { font-family: var(--serif); }
.kicker { text-transform: uppercase; letter-spacing: .08em; font-size: .72rem; font-weight: 700; color: var(--muted); margin-bottom: .35rem; }
hr { border: 0; border-top: 1px solid var(--line); margin: .5rem 0; }

/* Buttons */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .45em; height: 2.6rem; padding: 0 1.1rem; border-radius: var(--radius-sm); border: 1px solid transparent; border-bottom-width: 3px; font: inherit; font-weight: 600; font-size: .95rem; cursor: pointer; text-decoration: none !important; white-space: nowrap; transition: transform .05s, background .15s, border-bottom-width .05s; }
.btn:active { transform: translateY(2px); border-bottom-width: 1px; }
.btn-primary { background: var(--accent-fill); color: var(--accent-ink); border-color: var(--key-edge-accent); } .btn-primary:hover { filter: brightness(1.06); }
.btn-accent { background: var(--gold); color: #2a2000; border-color: #c48f1e; } .btn-accent:hover { filter: brightness(1.04); }
.btn-ghost { background: var(--card); color: var(--ink); border-color: var(--line-2); border-bottom-color: var(--key-edge); } .btn-ghost:hover { background: var(--paper-2); }
.btn-danger { background: var(--bad-fill); color: #fff; border-color: #8f2a1a; }
.btn-sm { height: 2.1rem; padding: 0 .8rem; font-size: .85rem; } .btn-lg { height: 3.1rem; padding: 0 1.6rem; font-size: 1.05rem; } .btn-block { width: 100%; }
.btn kbd { background: rgba(255,255,255,.2); border: 0; color: inherit; font-size: .75em; padding: .1em .4em; }
.btn-ghost kbd { background: var(--paper-2); }
/* Readable by a screen reader, invisible on screen. The waitlist's email field
   needs a real label and has no room for a visible one beside the button. */
/* !important because a utility has to beat input[type="email"] { width: 100% }, which outranks a
   bare class: the password forms' hidden username was spanning the page and scrolling it sideways. */
.sr-only { position: absolute !important; width: 1px !important; height: 1px !important; padding: 0 !important; margin: -1px !important;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0 !important; }
.btn-row { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; margin-top: 1rem; }
/* A small text link ("Full stats →", "Change goal") with a 44px hit area that
   takes no more room than its own line: the box grows to 44px and negative
   margins hand the extra height back, so nothing moves. */
.tap { display: inline-flex; align-items: center; min-height: 44px; margin-block: calc((1.5em - 44px) / 2); }
.link-btn { background: none; border: 0; padding: 0; color: var(--accent-text); font: inherit; cursor: pointer; } .link-btn.danger { color: var(--bad-ink); }
form.button_to { display: contents; }

/* Wraps are chosen, not left to the viewport (wrapcheck, Derick 2026-10-01):
   prose never strands one word on its last line, headings balance, and a
   .cl clause moves to the next line whole before it breaks inside. */
p, li, figcaption, td, th, dd, blockquote { text-wrap: pretty; }
h1, h2, h3, h4, .u-b, .sect-p { text-wrap: balance; }
.cl { display: inline-block; }
.nw { white-space: nowrap; }

/* Cards, pages */
.card { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.25rem; box-shadow: var(--shadow); }
.page { max-width: 1120px; margin: 0 auto; padding: 1.5rem 1.25rem 4rem; }
.page.narrow { max-width: 720px; }
.page-head { display: flex; justify-content: space-between; align-items: flex-end; gap: 1rem; margin-bottom: 1.25rem; flex-wrap: wrap; padding-bottom: 1rem; border-bottom: 1px solid var(--line); }
.page-head h1 { margin-bottom: .1rem; } .page-head p { margin: 0; }
.section { margin-top: 1.25rem; }
/* Cards stacked directly in a page keep the grid gap between them. */
.page > .card + .card, .page > .two-col + .card, .page > .card + .two-col { margin-top: 1.25rem; }
.two-col { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 1.25rem; margin-top: 1.25rem; }
@media (max-width: 800px) { .two-col { grid-template-columns: minmax(0, 1fr); } }
.lead { font-size: 1.15rem; color: var(--ink-2); }

/* App header */
.app-header { background: var(--card); border-bottom: 1px solid var(--line); position: sticky; top: 0; z-index: 20; }
.app-wrap { max-width: 1120px; margin: 0 auto; padding: 0 1.25rem; display: flex; align-items: center; gap: 1.25rem; height: 3.5rem; }
.brand { display: inline-flex; align-items: center; gap: .55rem; color: var(--ink); font-weight: 700; text-decoration: none !important; }
.brand-name { font-family: var(--brand-mono); font-weight: 700; letter-spacing: -.02em; font-size: 1.05rem; } .brand-name b { color: var(--accent); font-weight: 700; }
.brand-mark svg { display: block; }
.app-nav { display: flex; gap: .15rem; margin-left: .5rem; }
.nav-item { color: var(--ink-2); padding: .4rem .7rem; border-radius: 8px; font-weight: 500; font-size: .95rem; white-space: nowrap; }
.nav-item:hover { background: var(--paper-2); text-decoration: none; } .nav-item.active { background: var(--accent-soft); color: var(--accent-text); }
.app-tools { margin-left: auto; display: flex; gap: .75rem; align-items: center; }
.menu { position: relative; } .menu summary { list-style: none; cursor: pointer; } .menu summary::-webkit-details-marker { display: none; }
.menu-button { display: inline-flex; align-items: center; gap: .5rem; padding: .3rem .5rem .3rem .3rem; border-radius: 999px; border: 1px solid var(--line); background: var(--card); }
.menu-button .chev { display: inline-flex; color: var(--muted); }
.menu-panel { position: absolute; right: 0; top: calc(100% + .4rem); min-width: 16rem; width: max-content; max-width: 22rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); box-shadow: var(--shadow); padding: .4rem; z-index: 30; }
.menu-section { font-size: .72rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); padding: .4rem .6rem .2rem; }
.menu-row { display: flex; align-items: center; gap: .5rem; width: 100%; min-width: 100%; min-height: 2.75rem; text-align: left; padding: .5rem .6rem; border-radius: 8px; color: var(--ink); background: none; border: 0; font: inherit; cursor: pointer; }
.menu-row:hover { background: var(--paper-2); text-decoration: none; } .menu-row.current { font-weight: 600; cursor: default; }
/* Games and the Practice Log: in the header nav on a wide screen, so the menu carries them
   only where the header nav gives way to the five-tab bar. That happens below 1000px:
   between 861 and 999 the seven links and See Plans did not fit, and the page scrolled
   sideways by up to 93px (measured 2026-10-15). */
.menu-narrow { display: none; }
@media (max-width: 999px) { .menu-narrow { display: block; } }
.avatar { display: inline-flex; align-items: center; justify-content: center; width: 1.9rem; height: 1.9rem; border-radius: 50%; background: color-mix(in srgb, var(--avatar) 22%, transparent); border: 2px solid var(--avatar); font-size: 1rem; }
.avatar.sm { width: 1.5rem; height: 1.5rem; font-size: .8rem; border-width: 1.5px; } .avatar.lg { width: 3rem; height: 3rem; font-size: 1.5rem; }
.tabbar { display: none; }
@media (max-width: 999px) {
  .app-nav { display: none; } .menu-name { display: none; }
  .tabbar { position: fixed; bottom: 0; left: 0; right: 0; z-index: 25; display: grid; grid-template-columns: repeat(5, 1fr); background: var(--card); border-top: 1px solid var(--line); padding: .35rem .25rem calc(.35rem + env(safe-area-inset-bottom)); }
  .tabbar a { display: flex; flex-direction: column; align-items: center; gap: .1rem; font-size: .7rem; font-weight: 600; color: var(--muted); padding: .3rem 0; border-radius: 8px; }
  .tabbar a .ico { display: block; } .tabbar a.active { color: var(--accent-text); }
  .app-main { padding-bottom: 5rem; }
  body.focus .tabbar { display: none; }
}
.impersonation-bar { background: var(--gold); color: #2a2000; text-align: center; padding: .4rem; font-size: .9rem; }
.impersonation-bar .link-btn { color: inherit; text-decoration: underline; margin-left: .5rem; }
.touch-notice { display: grid; grid-template-columns: 1fr 2.75rem; gap: .25rem .5rem; align-items: start; margin: 1rem 1.25rem 0; padding: .7rem .4rem .7rem 1rem; background: var(--card); border: 1px solid var(--line-2); border-radius: var(--radius); font-size: .9rem; }
.touch-notice[hidden] { display: none; }
.touch-notice p { margin: 0; color: var(--ink-2); } .touch-notice strong { color: var(--ink); }
.touch-notice-close { display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; margin: -.55rem 0; border: 0; border-radius: 8px; background: none; color: var(--muted); cursor: pointer; }
.touch-notice-close:hover { background: var(--paper-2); color: var(--ink); }
body.focus .touch-notice { margin: 1rem 0 0; }

/* Flash: at the top of <main>, in the flow, so it pushes the page down rather
   than covering its heading (it was a fixed toast at 67px, over the heading on a
   phone and over a test's heading sideways). Centered under the header, as wide
   as its words up to 36rem; a full-width bar on a phone. */
.flash-wrap { display: grid; justify-items: center; gap: .5rem; padding: .9rem 1.25rem 0; }
body.focus .flash-wrap { padding-inline: 0; }
.flash { display: grid; grid-template-columns: minmax(0, 1fr) 2.75rem; align-items: center; gap: .25rem; width: max-content; max-width: min(36rem, 100%); background: var(--ink); color: var(--paper); padding: 0 0 0 1rem; border-radius: 999px; font-size: .9rem; box-shadow: var(--shadow); }
.flash-msg { padding: .55rem 0; text-wrap: balance; }
.flash-close { display: inline-grid; place-items: center; width: 2.75rem; height: 2.75rem; border: 0; border-radius: 999px; background: none; color: inherit; opacity: .75; cursor: pointer; }
.flash-close:hover { opacity: 1; }
@media (max-width: 560px) { .flash { width: 100%; border-radius: 12px; } }
.flash-alert { background: var(--bad-fill); color: #fff; }

/* Forms */
.form .field { margin-bottom: 1rem; }
/* A form's submit after a stack of cards (onboarding) keeps the cards' gap. */
.form > .card + .btn { margin-top: 1.25rem; }
.form label, .field > label { display: block; font-weight: 600; font-size: .9rem; margin-bottom: .35rem; }
input[type="text"], input[type="email"], input[type="password"], input[type="search"], input[type="date"], textarea, .listbox-button { width: 100%; height: 2.8rem; padding: 0 .85rem; border: 1px solid var(--line-2); border-radius: var(--radius-sm); background: var(--card); color: var(--ink); font: inherit; font-size: 1rem; }
textarea { height: auto; padding: .7rem .85rem; line-height: 1.5; resize: vertical; }
input:focus, textarea:focus, .listbox-button:focus { outline: 2px solid var(--accent); outline-offset: 1px; border-color: var(--accent); }
.form-errors { background: var(--bad-soft); color: var(--bad-ink); border-radius: var(--radius-sm); padding: .6rem .85rem; margin-bottom: 1rem; font-size: .9rem; overflow-wrap: anywhere; text-wrap: balance; }
.inline-form { display: flex; gap: .5rem; align-items: center; } .inline-form input:not([type="submit"]) { height: 2.1rem; width: 16rem; min-width: 0; }
@media (max-width: 480px) { .inline-form { width: 100%; } .inline-form input:not([type="submit"]) { flex: 1; width: auto; } }
.password-wrap { position: relative; } .password-wrap input { padding-right: 2.8rem; }
.password-toggle { position: absolute; right: .3rem; top: 50%; transform: translateY(-50%); width: 2.2rem; height: 2.2rem; display: inline-flex; align-items: center; justify-content: center; background: none; border: 0; color: var(--muted); cursor: pointer; border-radius: 6px; }
.password-toggle:hover { color: var(--ink); background: var(--paper-2); }
.field-hint { margin: .35rem 0 0; font-size: .85rem; color: var(--muted); }
input[type="checkbox"] { width: 1.15rem; height: 1.15rem; accent-color: var(--accent); }
input[type="radio"] { accent-color: var(--accent); }
.toggle-inline { display: inline-flex; align-items: center; gap: .4rem; cursor: pointer; }
.choice-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: .6rem; } @media (max-width: 640px) { .choice-grid { grid-template-columns: 1fr; } }
.choice { position: relative; display: flex; gap: .6rem; align-items: center; padding: .75rem .9rem; border: 1px solid var(--line-2); border-radius: var(--radius-sm); cursor: pointer; background: var(--card); }
.choice:has(input:checked) { border-color: var(--accent); background: var(--accent-soft); }
/* A choice whose radio is hidden (a pill, a swatch) shows keyboard focus on the
   whole choice, since the input itself is invisible. */
.choice:has(input:focus-visible) { outline: 3px solid var(--accent); outline-offset: 2px; }
.choice-body { display: flex; flex-direction: column; }
.choice.pill { justify-content: center; min-height: 2.75rem; padding: .45rem .9rem; border-radius: 999px; font-weight: 600; }
.choice.pill input, .choice.swatch input { position: absolute; opacity: 0; width: 0; height: 0; margin: 0; }
/* The selected pill is filled, so one of five reads as chosen at a glance. */
.choice.pill:has(input:checked) { background: var(--accent-fill); border-color: var(--key-edge-accent); color: var(--accent-ink); }
.choice-row { display: flex; gap: .5rem; flex-wrap: wrap; }
.choice-row .choice.pill { min-width: 5.5rem; } /* one width for every pill in the row */
/* A fixed set of choices (the profile icons, the colors) is a grid sized from its
   count by the view (--cols, --cols-sm), so its rows are always full. */
.choice-grid-fixed { display: grid; grid-template-columns: repeat(var(--cols, 5), 2.75rem); gap: .5rem; }
@media (max-width: 480px) { .choice-grid-fixed { grid-template-columns: repeat(var(--cols-sm, var(--cols, 5)), 2.75rem); } }
.choice.swatch { padding: 0; width: 2.75rem; height: 2.75rem; border-radius: 50%; background: var(--sw); border: 3px solid transparent; justify-content: center; }
/* Keeps its own color when chosen (.choice:has(:checked) would paint it the accent
   tint) and gets a ring, with a gap of card between ring and color. */
.choice.swatch:has(input:checked) { background: var(--sw); border-color: var(--ink); box-shadow: inset 0 0 0 2px var(--card); }
.emoji-row .choice { width: 2.75rem; height: 2.75rem; padding: 0; font-size: 1.25rem; font-weight: 400; }
.emoji-row .choice:has(input:checked) { background: var(--accent-soft); border: 2px solid var(--accent); color: var(--ink); }
fieldset.field { border: 0; padding: 0; margin: 0 0 1rem; min-width: 0; }
fieldset.field > legend { display: block; padding: 0; font-weight: 600; font-size: .9rem; margin-bottom: .35rem; }
.saved-toast { background: var(--ok-soft); color: var(--ok-ink); padding: .3rem .7rem; border-radius: 999px; font-size: .85rem; font-weight: 600; } .saved-toast.bad { background: var(--bad-soft); color: var(--bad-ink); }
.setting-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: .7rem 0; border-top: 1px solid var(--line); cursor: pointer; }
.setting-row:first-of-type { border-top: 0; } .setting-row .listbox { width: 12rem; flex: none; }
/* Every box in the column one size, whatever the note beside it wraps to:
   a flex row was shrinking the first one (13px against 18px). */
.setting-row input[type=checkbox] { flex: none; width: 18px; height: 18px; margin: 0; }
.setting-label { display: flex; flex-direction: column; font-weight: 500; } .setting-note { font-weight: 400; color: var(--muted); font-size: .85rem; }
.danger-zone { border-color: color-mix(in srgb, var(--bad) 40%, var(--line)); }
.settings-row { display: grid; grid-template-columns: 14rem 1fr; gap: 1.5rem; padding: 1.4rem 0; border-top: 1px solid var(--line); } .settings-row:first-of-type { border-top: 0; padding-top: 0; } .page-head + .settings-row { border-top: 0; padding-top: .4rem; }
.settings-row h2 { font-size: 1.05rem; margin: 0 0 .2rem; } .settings-row .why { color: var(--muted); font-size: .88rem; margin: 0; }
@media (max-width: 720px) { .settings-row { grid-template-columns: 1fr; gap: .6rem; } }
.plan-card { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap; padding: 1rem 1.2rem; border: 1px solid var(--line-2); border-radius: var(--radius-sm); background: var(--paper-2); }
.plan-card .plan-name { font-weight: 700; font-size: 1.1rem; } .plan-card .plan-sub { color: var(--muted); font-size: .9rem; }
.status-chip { display: inline-flex; align-items: center; gap: .4rem; padding: .25rem .7rem; border-radius: 999px; font-size: .8rem; font-weight: 700; background: var(--accent-soft); color: var(--accent-text); } .status-chip::before { content: ""; width: .5rem; height: .5rem; border-radius: 50%; background: currentColor; }
.status-chip.ok { background: var(--ok-soft); color: var(--ok-ink); } .status-chip.warn { background: var(--gold-soft); color: var(--gold-ink); } .status-chip.off { background: var(--paper-2); color: var(--muted); }

/* Listbox */
.listbox { position: relative; } .listbox-native { width: 100%; height: 2.8rem; } .listbox[data-listbox-ready] .listbox-native { position: absolute; opacity: 0; pointer-events: none; width: 1px; height: 1px; }
.listbox-button { display: none; align-items: center; justify-content: space-between; gap: .5rem; text-align: left; cursor: pointer; }
.listbox[data-listbox-ready] .listbox-button { display: flex; }
.listbox-chevron svg { width: 1em; height: .7em; stroke: currentColor; fill: none; stroke-width: 1.8; }
.listbox-list { position: absolute; z-index: 30; top: calc(100% + .3rem); left: 0; min-width: 100%; width: max-content; max-width: min(22rem, 90vw); margin: 0; padding: .3rem; list-style: none; background: var(--card); border: 1px solid var(--line-2); border-radius: var(--radius-sm); box-shadow: var(--shadow); max-height: 18rem; overflow: auto; }
.listbox-option { display: flex; gap: .5rem; align-items: center; padding: .5rem .6rem; border-radius: 6px; cursor: pointer; }
.listbox-option.active { background: var(--accent-soft); } .listbox-tick { width: 1em; visibility: hidden; color: var(--accent); } .listbox-option[aria-selected="true"] .listbox-tick { visibility: visible; }

/* Dev sign-in block */
.auth-wrap { max-width: 26rem; margin: 3rem auto; padding: 0 1rem; }
.auth-brand { display: flex; align-items: center; justify-content: center; gap: .6rem; margin-bottom: 1.2rem; }
.auth-card h1 { font-size: 1.5rem; } .auth-links { display: flex; justify-content: space-between; gap: 1rem; margin-top: 1rem; font-size: .9rem; flex-wrap: wrap; }
/* "Sign in", "Start free", "Forgot your password?" sit in a line of plain words: told apart by more than color. */
.auth-links a { text-decoration: underline; text-underline-offset: 2px; text-decoration-thickness: 1px; }
.dev-block { margin-top: 1.5rem; border: 2px dashed var(--accent); border-radius: var(--radius); background: var(--card); overflow: hidden; }
.dev-band { height: 1.6rem; background: repeating-linear-gradient(45deg, color-mix(in srgb, var(--accent) 12%, transparent) 0 8px, transparent 8px 16px); display: flex; align-items: center; justify-content: center; }
.dev-label { background: var(--card); font-size: .7rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; padding: 0 .6rem; border-left: 1px dashed var(--accent); border-right: 1px dashed var(--accent); display: inline-flex; gap: .4rem; align-items: center; line-height: 1.2rem; }
.dev-label .dot { width: .45rem; height: .45rem; border-radius: 50%; background: var(--ok); }
.dev-toggle { width: 100%; background: none; border: 0; font: inherit; font-weight: 600; text-align: left; padding: .6rem .9rem; cursor: pointer; color: var(--ink); display: flex; justify-content: space-between; }
.dev-toggle .chev { font-size: 1em; transition: transform .2s; } .dev-block.collapsed .dev-toggle .chev { transform: rotate(-90deg); }
.dev-body { display: grid; grid-template-rows: 1fr; transition: grid-template-rows .25s; } .dev-block.collapsed .dev-body { grid-template-rows: 0fr; } .dev-inner { overflow: hidden; }
.dev-row { display: grid; grid-template-columns: 6rem 1fr; gap: .8rem; width: 100%; text-align: left; padding: .6rem .9rem; border: 0; border-top: 1px solid var(--line); background: none; font: inherit; color: var(--ink); cursor: pointer; }
.dev-row:hover { background: var(--accent-soft); } .dev-name { font-weight: 600; } .dev-name code { font-size: .75em; } .dev-persona { color: var(--ink-2); font-size: .85rem; }
.dev-foot { padding: .6rem .9rem; font-size: .8rem; border-top: 1px solid var(--line); }

/* Marketing
   ────────────────────────────────────────────────────────────────────────────
   The page is a keyboard. Anything that means "a thing you press, or a step you
   take" carries a key's flat face and hard bottom edge, and nothing else casts a
   shadow, so shadow reads as physical depth rather than ambient decoration.
   Color is the app's own finger palette: the ten hues that teach which finger
   presses which key are the same ten that organize the page, which is why a key
   drawn in a marketing chip is the color it will be in the lesson. Type is two
   voices: Inter to read, JetBrains Mono for anything the product would print on
   a keycap or a readout. Sections are numbered on a rail, like a reference
   manual for a keyboard, which is what the course is. */

/* One finger, one hue. Set once here so a swatch, a chip and a keycap can all
   ask for --f instead of each carrying its own copy of the mapping. */
.finger-l5, .finger-r5 { --f: var(--f-l5); } .finger-l4, .finger-r4 { --f: var(--f-l4); }
.finger-l3, .finger-r3 { --f: var(--f-l3); } .finger-l2, .finger-r2 { --f: var(--f-l2); }
.finger-l1, .finger-r1 { --f: var(--f-l1); }

.mk-wrap { width: min(1180px, 100% - 2.5rem); max-width: none; margin-inline: auto; padding: 0; }
.mk-wrap.narrow { width: min(820px, 100% - 2.5rem); }
@media (max-width: 560px) { .mk-wrap, .mk-wrap.narrow { width: min(1180px, 100% - 1.8rem); } }

.mk-header { position: sticky; top: 0; z-index: 30; border-bottom: 1px solid var(--line); background: color-mix(in srgb, var(--paper) 90%, transparent); backdrop-filter: saturate(1.4) blur(10px); }
.mk-header .mk-wrap { display: flex; align-items: center; justify-content: space-between; gap: 1rem; height: 4rem; }
.mk-nav { display: flex; gap: .1rem; align-items: center; }
.mk-nav .nav-item { white-space: nowrap; font-size: .9rem; }
.mk-main { display: block; }
/* A short page (sign-in, /thanks) holds its footer to the bottom of the window
   rather than ending mid-window over an empty strip. */
.marketing-body { min-height: 100vh; min-height: 100dvh; display: flex; flex-direction: column; } .marketing-body > .mk-main { flex: 1 0 auto; }

.mk-band { padding: clamp(3rem, 7vw, 5.5rem) 0; scroll-margin-top: 4.5rem; }
.mk-band.alt { background: var(--paper-2); }

/* The rail: a numbered heading column beside the content, the way a manual sets
   out a section. It is what lets the FAQ and the legal pages use the full width
   without setting prose in a 1100px measure. */
.rail { display: grid; grid-template-columns: minmax(0, 19rem) minmax(0, 1fr); gap: clamp(2rem, 5vw, 4.5rem); align-items: start; }
.rail-side { position: sticky; top: 5.25rem; }
.rail-side h2, .plan h2, .mk-cta h2 { font-family: var(--mono); font-weight: 700; letter-spacing: -.045em; }
.rail-side h2 { font-size: clamp(1.3rem, 2.2vw, 1.72rem); margin-bottom: .55rem; }
.sect-n { display: inline-grid; place-items: center; width: 2.5rem; height: 2.5rem; margin: 0 0 1rem; border-radius: 9px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 4px; border-bottom-color: var(--key-edge); font-family: var(--mono); font-weight: 700; font-size: .85rem; color: var(--accent-text); }
.sect-p { color: var(--ink-2); font-size: .95rem; max-width: 32rem; margin: 0; }
@media (max-width: 960px) { .rail { grid-template-columns: 1fr; gap: 1.75rem; } .rail-side { position: static; } }

/* Hero */
.hero { background: var(--paper-2); padding: clamp(2.5rem, 6vw, 4.5rem) 0 clamp(3rem, 6vw, 5rem); scroll-margin-top: 4.5rem; }
.hero-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(2rem, 5vw, 4rem); align-items: stretch; }
.hero-copy { display: flex; flex-direction: column; justify-content: center; }
@media (max-width: 980px) { .hero-grid { grid-template-columns: 1fr; } }
.eyebrow { font-family: var(--mono); text-transform: uppercase; letter-spacing: .16em; font-size: .7rem; font-weight: 700; color: var(--muted); margin: 0 0 .9rem; }
.hero h1 { font-family: var(--mono); font-weight: 700; font-size: clamp(1.7rem, 4vw, 2.9rem); line-height: 1.16; letter-spacing: -.055em; margin-bottom: .7rem; }
.kcap-h { display: inline-grid; place-items: center; padding: 0 .3em .1em; margin: 0 .06em; border-radius: .18em; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: .12em; border-bottom-color: var(--key-edge); font-size: .9em; font-weight: 700; color: var(--accent-text); vertical-align: baseline; }
.hero .lead { max-width: 34rem; font-size: clamp(1rem, 1.5vw, 1.12rem); }
.hero-cta { display: flex; gap: .7rem; margin: 1.6rem 0 0; flex-wrap: wrap; }
.spec { display: flex; flex-wrap: wrap; gap: .35rem 1.5rem; font-family: var(--mono); font-size: .8rem; color: var(--muted); margin: 1.7rem 0 0; padding-top: 1.1rem; border-top: 1px solid var(--line); }
.spec b { color: var(--ink); font-size: .95rem; margin-right: .15rem; }
.spec .spec-free, .spec .spec-free b { color: var(--ok-ink); }
/* The home page's four facts need about 482px on one line. In a narrower column
   (a phone, or the two-column hero at 1024) they go two by two rather than three
   and one alone. */
.hero-copy { container: hero-copy / inline-size; }
@container hero-copy (max-width: 490px) { .spec.spec-four { display: grid; grid-template-columns: repeat(2, max-content); } }

/* A hero with no demo beside it: one column, centered, for the pages that lead with a picture. */
.hero-plain { padding-bottom: clamp(2rem, 4vw, 3rem); }
.hero-centered { text-align: center; align-items: center; }
.hero-centered .lead { max-width: 42rem; }
.hero-centered .spec { justify-content: center; }
/* Keeps a phrase whole so a heading breaks between thoughts, not wherever the width ran out. */
.nb { white-space: nowrap; }

/* Screenshots of the native app. The picture is the point, so the frame is a
   hairline and a shadow and nothing else: no fake device bezel around a shot
   that already has the real window chrome in it. */
.shot { margin: 0; }
.shot img { display: block; width: 100%; height: auto; border-radius: 14px; border: 1px solid var(--line); box-shadow: var(--shadow); background: var(--card); }
.shot figcaption { margin-top: .85rem; font-size: .92rem; color: var(--muted); line-height: 1.5; }
.shot figcaption b { color: var(--ink); }
.shot-wide { max-width: 62rem; margin: 0 auto 2.5rem; }
/* A shot standing in a rail column, where it is illustrating a paragraph rather
   than being the point of the page. Capped so a portrait device does not run a
   thousand pixels down the page beside four lines of copy. */
.shot-inline { max-width: 25rem; margin: 0 auto; }
/* An iPad next to an iPhone: two shapes that share nothing but a height. Sizing
   them by height rather than by column width is what keeps the pair level; on
   equal columns the phone runs half a screen below the tablet. */
.shots { --shot-h: clamp(22rem, 44vw, 38rem);
         display: grid; grid-auto-flow: column; gap: clamp(1.5rem, 4vw, 3.5rem);
         justify-content: center; align-items: start; max-width: 62rem; margin: 0 auto; }
.shots .shot img { height: var(--shot-h); width: auto; max-width: 100%; }
@media (max-width: 760px) {
  .shots { grid-auto-flow: row; gap: 2.5rem; }
  .shots .shot { max-width: 22rem; margin: 0 auto; }
  .shots .shot img { height: auto; width: 100%; }
}

/* The demo: the real keyboard and hands controllers, driven by demo_controller. */
.stage { margin: 0; display: grid; gap: .85rem; padding: 1.1rem; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 5px; border-bottom-color: var(--key-edge); border-radius: 16px; box-shadow: var(--shadow); }
.stage-cap { display: flex; align-items: center; gap: .45rem; font-family: var(--mono); font-size: .7rem; text-transform: uppercase; letter-spacing: .13em; color: var(--muted); }
.stage-cap .dot { width: .45rem; height: .45rem; border-radius: 50%; background: var(--ok); }
.stage-line { margin: 0; min-height: 3.4em; font-size: clamp(.95rem, 1.5vw, 1.2rem); line-height: 1.7; letter-spacing: -.01em; }
.stage-line .done { color: var(--ok-ink); } .stage-line .rest { color: var(--muted); }
.stage-line .cur { background: var(--accent-fill); color: var(--accent-ink); border-radius: 3px; }
.stage-kbd .key { height: 2rem; font-size: .68rem; }
.stage-foot { display: grid; grid-template-columns: 9.5rem 1fr; gap: 1rem; align-items: center; padding-top: .9rem; border-top: 1px solid var(--line); }
.stage-note { margin: 0; font-size: .82rem; color: var(--muted); }
@media (max-width: 480px) { .stage-foot { grid-template-columns: 1fr; } }

/* 01: the course, key by key */
.picker { border: 0; padding: 0; margin: 1.6rem 0 1.4rem; }
.picker legend { padding: 0; margin-bottom: .5rem; font-family: var(--mono); font-size: .68rem; text-transform: uppercase; letter-spacing: .13em; color: var(--muted); font-weight: 700; }
.picker-row { display: flex; flex-wrap: wrap; gap: .4rem; }
.picker label { display: inline-flex; align-items: center; padding: .42rem .8rem; border-radius: 8px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 3px; border-bottom-color: var(--key-edge); font-family: var(--mono); font-size: .8rem; font-weight: 600; color: var(--ink-2); cursor: pointer; }
.picker label:hover { border-color: var(--accent); color: var(--ink); }
.picker input:checked + label { background: var(--accent-fill); border-color: var(--key-edge-accent); color: var(--accent-ink); }
.picker input:focus-visible + label { outline: 3px solid var(--accent); outline-offset: 2px; }
.picker label:active { transform: translateY(2px); border-bottom-width: 1px; }
.legend { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: .3rem .9rem; font-size: .75rem; color: var(--muted); }
.legend li { display: flex; align-items: center; gap: .45rem; }
.legend .sw { width: .9rem; height: .9rem; border-radius: 3px; background: var(--f, var(--card)); border: 1px solid var(--line-2); flex: none; }

/* Without :has() the QWERTY ribbon is simply the one that shows, which is the
   right thing to degrade to: a complete course rather than an empty panel. */
.ribbon { display: none; gap: .7rem; }
.ribbon[data-layout="qwerty"] { display: grid; }
@supports selector(:has(*)) {
  .course-rail .ribbon { display: none; }
  .course-rail:has(#lay-qwerty:checked) .ribbon[data-layout="qwerty"],
  .course-rail:has(#lay-dvorak:checked) .ribbon[data-layout="dvorak"],
  .course-rail:has(#lay-colemak:checked) .ribbon[data-layout="colemak"] { display: grid; }
}
.cu { padding: .95rem 1.1rem; background: var(--card); border: 1px solid var(--line); border-radius: 10px; }
.cu.free { border-color: var(--ok); background: color-mix(in srgb, var(--ok-soft) 40%, var(--card)); }
.cu-head { display: flex; align-items: baseline; gap: .55rem; flex-wrap: wrap; }
.cu-head h3 { margin: 0; font-size: 1.02rem; letter-spacing: -.015em; }
.u-n { font-family: var(--mono); font-size: .7rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.u-t { margin-left: auto; font-family: var(--mono); font-size: .73rem; color: var(--muted); white-space: nowrap; }
.u-b { margin: .3rem 0 .75rem; color: var(--ink-2); font-size: .88rem; }
/* Balanced by public/balanced-chips.js, which narrows the list to the width that
   evens its rows; the chips stay the list's own <li> children. */
.chips, .free-keys { list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 0; padding: 0; }
.chip { display: flex; align-items: center; gap: .22rem; padding: .28rem .34rem; border-radius: 8px; background: var(--paper-2); border: 1px solid var(--line); }
.chip-word { padding: 0 .35rem; font-family: var(--mono); font-size: .72rem; font-weight: 600; color: var(--muted); white-space: nowrap; }
.kcap { display: inline-grid; place-items: center; min-width: 1.5rem; height: 1.5rem; padding: 0 .28rem; border-radius: 5px; background: var(--f, var(--card)); border: 1px solid var(--line-2); border-bottom-width: 2px; border-bottom-color: var(--key-edge); font-family: var(--mono); font-size: .75rem; font-weight: 700; color: var(--ink); }

.tag { display: inline-flex; align-items: center; gap: .25rem; padding: .12rem .45rem; border-radius: 999px; font-family: var(--mono); font-size: .66rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; white-space: nowrap; }
.tag-free { background: var(--ok-soft); color: var(--ok-ink); }
.tag-scored { background: var(--gold-soft); color: var(--gold-ink); }

/* 02: one lesson, exercise by exercise */
.ladder { list-style: none; margin: 0; padding: 0; }
.ladder li { display: grid; grid-template-columns: 2.5rem 1fr; gap: 1rem; padding: .9rem 0; border-top: 1px solid var(--line); align-items: start; }
.ladder li:first-child { border-top: 0; padding-top: 0; }
.rung { display: grid; place-items: center; width: 2.5rem; height: 2.5rem; border-radius: 8px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 3px; border-bottom-color: var(--key-edge); font-family: var(--mono); font-weight: 700; font-size: .85rem; color: var(--accent-text); }
.ladder h3 { display: flex; align-items: center; gap: .5rem; flex-wrap: wrap; margin: .25rem 0 .2rem; font-size: 1rem; }
.ladder p { margin: 0; color: var(--ink-2); font-size: .92rem; }
.after { margin: 1.3rem 0 0; padding-top: 1.1rem; border-top: 1px solid var(--line); color: var(--ink-2); font-size: .92rem; }

/* 03: stars and the speed ramp */
.stars-table { width: 100%; border-collapse: collapse; font-size: .93rem; }
.stars-table th { padding: 0 .6rem .6rem 0; text-align: left; border-bottom: 1px solid var(--line-2); font-family: var(--mono); font-size: .68rem; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.stars-table td { padding: .75rem .6rem .75rem 0; border-bottom: 1px solid var(--line); vertical-align: middle; }
.stars-table td:first-child { width: 7.5rem; white-space: nowrap; font-size: 1.05rem; }
.stars-table td:nth-child(2) { font-family: var(--mono); font-weight: 600; width: 6rem; }
.stars-table tr.pass td { background: var(--ok-soft); }
.stars-table tr.pass td:first-child { border-radius: 8px 0 0 8px; } .stars-table tr.pass td:last-child { border-radius: 0 8px 8px 0; }
.stars-table .tag { margin-left: .4rem; }
@media (max-width: 520px) {
  .stars-table td:first-child { width: 1%; font-size: .9rem; }
  .stars-table td:nth-child(2) { width: 1%; }
}
.plan-list span { text-wrap: balance; }
.ramp { margin-top: 2.2rem; }
.ramp-h { margin: 0 0 1rem; font-weight: 600; }
.ramp-bars { list-style: none; margin: 0; padding: 0; display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: .4rem; height: 9rem; }
.ramp-bars li { display: grid; grid-template-rows: 1fr auto; gap: .4rem; height: 100%; text-align: center; }
.ramp-bars .bar { align-self: end; height: var(--h); min-height: 1.5rem; display: grid; justify-items: center; align-items: start; padding-top: .25rem; border-radius: 7px 7px 3px 3px; background: var(--accent-soft); border: 1px solid var(--accent); border-bottom: 0; }
.ramp-bars .bar b { font-family: var(--mono); font-size: .72rem; color: var(--accent-text); }
.ramp-bars .lab { font-family: var(--mono); font-size: .68rem; color: var(--muted); }
.ramp-f { margin: .7rem 0 0; font-size: .78rem; color: var(--muted); }

/* 04: what comes with the lessons */
.kit { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 0 2.5rem; }
.kit li { display: grid; grid-template-columns: 2.6rem 1fr; gap: .9rem; padding: 1.05rem 0; border-top: 1px solid var(--line); align-items: start; }
.kit li:nth-child(-n+2) { border-top: 0; padding-top: 0; }
.kit .ico { width: 2.6rem; height: 2.6rem; padding: .55rem; border-radius: 9px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 3px; border-bottom-color: var(--key-edge); color: var(--accent); }
.kit h3 { margin: .15rem 0 .2rem; font-size: 1rem; }
.kit p { margin: 0; color: var(--ink-2); font-size: .91rem; }
@media (max-width: 720px) { .kit { grid-template-columns: 1fr; } .kit li:nth-child(2) { border-top: 1px solid var(--line); padding-top: 1.05rem; } }

/* The closing panel, and the one on the pricing page */
.mk-cta { display: flex; align-items: center; justify-content: space-between; gap: 1.25rem 2rem; flex-wrap: wrap; padding: clamp(1.5rem, 4vw, 2.4rem); border-radius: 16px; background: var(--ink); color: var(--paper); }
.mk-cta h2 { margin: 0; color: var(--paper); letter-spacing: -.02em; }
/* ⚠ Was a hardcoded #e4e7ee, which is a light grey. The panel inverts (its
   background is --ink and its text --paper), so in dark mode --ink resolves to a
   near-white and the panel turns LIGHT while this paragraph stayed light grey:
   unreadable. Invisible in light mode, which is why it survived. Tie it to the
   same token the panel's own text uses and it inverts with everything else. */
.mk-cta p { margin: .35rem 0 0; color: var(--paper); opacity: .82; font-size: 1.02rem; max-width: 42rem; }
.mk-cta .btn-row { margin: 0; }

/* Pricing */
.plans { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1.25rem; align-items: stretch; text-align: left; }
@media (max-width: 860px) { .plans { grid-template-columns: 1fr; } }
.plan { display: flex; flex-direction: column; gap: .2rem; border-color: var(--line-2); border-bottom-width: 5px; border-bottom-color: var(--key-edge); }
.plan .btn-row, .plan .plan-list:last-child { margin-top: auto; }
.plan .plan-list:last-child { padding-top: 1rem; }
.plan h2 { margin: 0 0 .5rem; font-size: 1.25rem; letter-spacing: -.02em; }
.plan .sub { margin: .55rem 0 0; color: var(--ink-2); font-size: .92rem; } .plan.full .sub { margin-bottom: 1rem; }
.plan > .price { margin: 0; }
.price { font-family: var(--mono); font-size: 2rem; font-weight: 700; letter-spacing: -.03em; line-height: 1; }
.price .per { white-space: nowrap; font-family: var(--sans); font-size: .9rem; font-weight: 500; color: var(--muted); margin-left: .15rem; }
.price-row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: .75rem 1.25rem; padding: 1.1rem 0; border-top: 1px solid var(--line); }
.price-row > div { flex: 1 1 9rem; }
.price-row .btn { flex: 0 0 auto; }
.price-row .note { font-size: .85rem; color: var(--muted); margin: .3rem 0 0; }
.plan-list { list-style: none; margin: 1rem 0 0; padding: 0; display: grid; gap: .5rem; }
.plan-list li { display: grid; grid-template-columns: 1.15rem 1fr; gap: .55rem; align-items: start; font-size: .93rem; }
.plan-list .ico { width: 1.15rem; height: 1.15rem; margin-top: .15rem; color: var(--ok); }
.plan-list .no .ico { color: var(--muted); }
.plan-list .no { color: var(--muted); }
.free-keys { margin: .9rem 0 0; }
.fine { font-size: .82rem; }

/* FAQ, as answers rather than nine closed drawers */
.qa { display: grid; gap: 2.2rem; }
.qa-group h2 { font-family: var(--mono); font-size: .72rem; font-weight: 700; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); padding-bottom: .6rem; border-bottom: 1px solid var(--line-2); margin-bottom: .2rem; }
.qa-item { padding: 1rem 0; border-bottom: 1px solid var(--line); }
.qa-item h3 { margin: 0 0 .3rem; font-size: 1.02rem; }
.qa-item p { margin: 0; color: var(--ink-2); font-size: .94rem; max-width: 46rem; }
.jump { list-style: none; margin: 1.4rem 0 0; padding: 0; display: grid; gap: .4rem; font-size: .88rem; }
.jump a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 3px; text-decoration-color: var(--line-2); }
.jump a:hover { color: var(--accent-text); text-decoration-color: currentColor; }

/* Legal */
.legal-body h2 { display: flex; align-items: baseline; gap: .6rem; margin: 2.2rem 0 .45rem; font-size: 1.08rem; scroll-margin-top: 5.5rem; }
.legal-body h2:first-of-type { margin-top: 0; }
.legal-body p { max-width: 44rem; color: var(--ink-2); }
.legal-list { max-width: 44rem; margin: 0 0 .6rem; padding-left: 1.2rem; color: var(--ink-2); } .legal-list li { margin: .2rem 0; }
.stamp { font-family: var(--mono); font-size: .78rem; color: var(--muted); margin-top: 1rem; }

/* Thanks */
.next-steps { list-style: none; margin: 1.5rem 0 0; padding: 0; display: grid; gap: .1rem; }
.next-steps li { display: grid; grid-template-columns: 2.5rem 1fr; gap: 1rem; padding: .85rem 0; border-top: 1px solid var(--line); align-items: start; }
.next-steps li:first-child { border-top: 0; }
.next-steps h3 { margin: .2rem 0 .15rem; font-size: 1rem; }
.next-steps p { margin: 0; color: var(--ink-2); font-size: .92rem; }

/* Footer */
.mk-footer { border-top: 1px solid var(--line); background: var(--paper-2); padding: 2.5rem 0 2rem; font-size: .9rem; }
.foot-top { display: flex; justify-content: space-between; gap: 1.5rem 2rem; flex-wrap: wrap; padding-bottom: 1.4rem; border-bottom: 1px solid var(--line); }
.foot-brand .brand { display: inline-flex; align-items: center; gap: .55rem; }
.foot-line { margin: .6rem 0 0; color: var(--muted); font-size: .85rem; max-width: 24rem; }
.foot-links { display: flex; gap: 1.4rem; flex-wrap: wrap; align-items: flex-start; }
.foot-links a { color: var(--ink-2); } .foot-links a:hover { color: var(--accent-text); }
.foot-bottom { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; padding-top: 1.2rem; color: var(--muted); font-size: .85rem; }
.foot-by a { color: var(--ink-2); text-decoration: underline; text-underline-offset: 2px; text-decoration-color: var(--line-2); }
.foot-by a:hover { color: var(--ink); text-decoration-color: currentColor; }
.foot-mail { display: inline-flex; align-items: center; gap: .4rem; color: var(--ink-2); }

/* Small screens: the wordmark is the first thing that can go, because the mark
   still says whose site this is and the nav has nowhere else to shrink to. */
@media (max-width: 760px) { .mk-nav .nav-course { display: none; } }
@media (max-width: 520px) {
  .mk-header .brand-name { display: none; }
  .mk-nav .nav-item { padding: .35rem .45rem; font-size: .85rem; }
}


/* Dashboard */
/* One column on a phone, in reading order. From 861px, three rows of pairs, each
   pair sharing its height: what to do next beside today's ring, the keys to work
   on beside the numbers, the recent runs beside the shortcuts. (The Continue card
   used to span two rows and center its content, leaving a band of empty card above
   it.) An ad, on the free tier, gets the full width under them. */
.dash-grid { display: grid; grid-template-columns: minmax(0, 1fr); gap: 1.25rem; }
@media (min-width: 861px) {
  .dash-grid { grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); }
  .dash-continue { grid-area: 1 / 1; } .dash-goal { grid-area: 1 / 2; }
  .dash-weak { grid-area: 2 / 1; } .dash-stats { grid-area: 2 / 2; }
  .dash-recent { grid-area: 3 / 1; } .dash-quick { grid-area: 3 / 2; }
  .dash-grid .ad { grid-area: 4 / 1 / 5 / -1; }
}
.dash-continue { display: flex; flex-direction: column; gap: .6rem; align-items: flex-start; padding: 2rem; background: linear-gradient(180deg, var(--card), color-mix(in srgb, var(--accent-soft) 45%, var(--card))); }
.dash-continue p { margin: 0; } .dash-continue .btn-row { margin-top: .6rem; }
@media (max-width: 480px) { .dash-continue { padding: 1.4rem; } .dash-continue .btn-row .btn { flex: 1 1 auto; } }
.dash-quick { display: flex; flex-direction: column; } .dash-quick .quick-grid { flex: 1; grid-auto-rows: 1fr; } .dash-quick .quick { justify-content: center; }
.stat-row.stat-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 1rem 1.25rem; margin: .5rem 0 1rem; }
.dash-title { font-size: 2.2rem; line-height: 1.05; } .dash-title .mono { font-family: var(--mono); color: var(--accent-text); }
.dash-goal { text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: .5rem; }
.ring { --pct: 0; width: 8.5rem; height: 8.5rem; border-radius: 50%; background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--paper-2) 0); display: grid; place-items: center; }
.ring-inner { width: 6.8rem; height: 6.8rem; border-radius: 50%; background: var(--card); display: flex; flex-direction: column; justify-content: center; } .ring-n { font-size: 2rem; font-weight: 800; line-height: 1; } .ring-l { font-size: .8rem; color: var(--muted); }
.dash-streak { display: inline-flex; align-items: center; gap: .35rem; font-size: 1.05rem; } .dash-streak .flame { color: var(--gold-ink); }
.stat-row { display: flex; gap: 1.5rem; flex-wrap: wrap; margin: .5rem 0; }
/* The tile row on Stats (eight) and Admin (six): a grid whose column count divides
   the count at every width, so no row is a full line and a leftover. */
.big-row { display: grid; grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 1.25rem 1rem; padding: 1.25rem; margin: 0 0 1.25rem; }
.big-row.six { grid-template-columns: repeat(6, minmax(0, 1fr)); }
.big-row .stat { align-items: center; text-align: center; min-width: 0; }
@media (max-width: 999px) { .big-row { grid-template-columns: repeat(4, minmax(0, 1fr)); } .big-row.six { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 480px) { .big-row, .big-row.six { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.heat-readout { min-height: 1.5em; margin: .5rem 0 0; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.on-touch { display: none; }
@media (hover: none), (pointer: coarse) { .on-hover { display: none; } .on-touch { display: inline; } }
.table.table-middle td { vertical-align: middle; } .progress-cell { width: 30%; }
.heat-readout + .two-col { margin-top: .75rem; }
.stat { display: flex; flex-direction: column; min-width: 4rem; } .stat-n { font-size: 1.7rem; font-weight: 800; line-height: 1.1; letter-spacing: -.02em; font-variant-numeric: tabular-nums; } .stat-n small { font-size: .55em; font-weight: 600; color: var(--muted); } .stat-l { font-size: .75rem; text-transform: uppercase; letter-spacing: .06em; color: var(--muted); font-weight: 600; } .stat-sub { font-size: .8rem; color: var(--accent-text); }
.quick-grid { display: grid; grid-template-columns: 1fr 1fr; gap: .6rem; } .quick { display: flex; flex-direction: column; align-items: center; gap: .2rem; padding: .8rem; border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); font-weight: 600; font-size: .9rem; } .quick .ico { color: var(--accent); } .quick:hover { background: var(--paper-2); text-decoration: none; }
.recent-list { list-style: none; padding: 0; margin: 0 0 .5rem; } .recent-list li { padding: .4rem 0; border-top: 1px solid var(--line); font-size: .92rem; } .recent-list li:first-child { border-top: 0; }
/* When, what, speed, accuracy, stars: fixed tracks so each column lines up
   down the list (catalog A2); under 480px they flow as one wrapped line. */
.recent-list li { display: grid; grid-template-columns: 8.5rem minmax(0, 1fr) 5rem 3rem 5.5rem; column-gap: .6rem; align-items: baseline; }
.rc-num { font-variant-numeric: tabular-nums; white-space: nowrap; } .rc-stars { white-space: nowrap; text-align: right; }
@media (max-width: 480px) {
  .recent-list li { grid-template-columns: minmax(0, 1fr) 5rem 5.2rem; grid-template-areas: "when when stars" "title wpm acc"; row-gap: .1rem; }
  .rc-when { grid-area: when; } .rc-title { grid-area: title; } .rc-stars { grid-area: stars; }
  .recent-list .rc-num { text-align: right; } .recent-list .rc-num:nth-of-type(3) { grid-area: wpm; } .recent-list .rc-num:nth-of-type(4) { grid-area: acc; }
}
.weak-keys { display: flex; gap: .5rem; flex-wrap: wrap; margin: .5rem 0 .8rem; } .weak-keys.sm { margin: .5rem 0 0; }
/* A phone: up to six keys in one row of six equal columns (they were five and
   one on /stats at 390), each as wide as the row allows up to its usual 3.2rem. */
@media (max-width: 480px) {
  .weak-keys:not(.sm) { display: grid; grid-template-columns: repeat(6, minmax(min-content, 3.2rem)); gap: .4rem; }
  .weak-keys:not(.sm) .keycap.big { min-width: 0; padding: 0 .15rem; }
}
/* The six keys inside the weak-keys practice card: one row of six, never five and one. */
.mode-card .weak-keys.sm { display: grid; grid-template-columns: repeat(6, minmax(0, 2rem)); gap: .35rem; }
.mode-card .weak-keys.sm .keycap { min-width: 0; margin: 0; padding: 0; }
.keycap { display: inline-flex; flex-direction: column; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; padding: 0 .5rem; border: 1px solid var(--line-2); border-bottom-width: 3px; border-radius: 6px; font-family: var(--mono); font-weight: 700; background: var(--card); margin-left: .25rem; }
.keycap.big { min-width: 3.2rem; height: 3.2rem; font-size: 1.1rem; margin: 0; } .keycap small { font-size: .65rem; color: var(--muted); font-weight: 500; }
.exercise-dots { display: flex; gap: .35rem; align-items: center; margin: .3rem 0; }
.dot-ex { width: .75rem; height: .75rem; border-radius: 50%; background: var(--paper-2); border: 1px solid var(--line-2); display: inline-block; } .dot-ex.done { background: var(--ok); border-color: var(--ok); } .dot-ex.current { box-shadow: 0 0 0 3px var(--accent-soft); border-color: var(--accent); }
a.dot-ex:hover { border-color: var(--accent); }
.star { color: var(--line-2); font-size: 1em; } .star.on { color: var(--gold); }

/* Lessons index */
.unit { margin-bottom: 2.4rem; }
.unit-num { display: inline-grid; place-items: center; width: 2.2rem; height: 2.2rem; border-radius: 7px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 3px; font-family: var(--mono); font-weight: 700; color: var(--accent-text); margin-right: .5rem; vertical-align: middle; }
/* Heading and blurb on the left, progress in a fixed column on the right, so the
   meta never wraps under the heading at some widths and not others. */
.unit-head { display: grid; grid-template-columns: minmax(0, 1fr) 12rem; align-items: end; gap: .5rem 1.5rem; margin-bottom: .8rem; }
.unit-head p { margin: 0; }
.unit-meta { display: flex; flex-direction: column; align-items: flex-end; gap: .3rem; }
.unit-progress { width: 100%; height: .45rem; background: var(--paper-2); border-radius: 999px; overflow: hidden; } .unit-progress-bar { height: 100%; background: var(--ok); }
/* A unit is one row of six on a wide screen (units of four and five leave the end
   of their row open rather than wrapping one card under), and two across below
   1000px, where an odd last card, always the unit's review, takes the full row. */
.lesson-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .7rem; }
@media (max-width: 999px) {
  .lesson-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .lesson-grid > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
.unit-locked { display: inline-flex; align-items: center; gap: .35rem; }
/* Below the heading on a narrow screen: the full width, read from the left. */
@media (max-width: 640px) { .unit-head { grid-template-columns: minmax(0, 1fr); } .unit-meta { align-items: stretch; } }
.upsell-band { display: flex; align-items: center; justify-content: space-between; gap: 1rem 1.5rem; flex-wrap: wrap; margin: -0.6rem 0 2.4rem; background: var(--gold-soft); border-color: color-mix(in srgb, var(--gold) 55%, var(--line)); }
.upsell-band h2 { font-size: 1.1rem; margin-bottom: .2rem; } .upsell-band p { margin: 0; color: var(--ink-2); max-width: 44rem; }
.lesson-card { position: relative; display: flex; flex-direction: column; gap: .15rem; padding: .85rem .9rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius-sm); color: var(--ink); min-height: 6.5rem; }
a.lesson-card:hover { border-color: var(--accent); text-decoration: none; }
.lesson-card.done { border-color: color-mix(in srgb, var(--ok) 50%, var(--line)); background: color-mix(in srgb, var(--ok-soft) 40%, var(--card)); }
.lesson-card.next { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.lesson-card.locked { background: var(--paper); border-style: dashed; border-color: var(--line-2); } a.lesson-card.locked:hover { border-color: var(--gold); } .lesson-card.locked .lesson-title { color: var(--ink-2); } .lesson-num { font-size: .7rem; font-weight: 700; color: var(--muted); } .lesson-title { font-weight: 700; font-family: var(--mono); text-wrap: balance; } .lesson-sub { font-size: .78rem; line-height: 1.35; }
.lesson-stars { margin-top: auto; font-size: .85rem; letter-spacing: .05em; } .lock { position: absolute; right: .7rem; top: .6rem; color: var(--muted); display: inline-flex; } .lesson-partial { position: absolute; right: .7rem; bottom: .6rem; }

/* Focus layout (lesson/test/practice/game pages) */
body.focus .focus-main { max-width: 1040px; margin: 0 auto; padding: 0 1rem 2rem; }
.focus-bar { display: flex; align-items: center; gap: 1.2rem; height: 3rem; font-size: .9rem; border-bottom: 1px solid var(--line); margin: 0 auto; max-width: 1040px; padding: 0 1rem; }
.focus-back { color: var(--ink-2); font-weight: 600; } .focus-crumb { color: var(--muted); } .focus-right { margin-left: auto; display: flex; align-items: center; gap: 1rem; }
.typing { display: flex; flex-direction: column; gap: .9rem; padding-top: 1.2rem; }
.typing-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 1.5rem; flex-wrap: wrap; }
.typing-kicker { text-transform: uppercase; letter-spacing: .08em; font-size: .72rem; font-weight: 700; color: var(--accent-text); }
.typing-title { font-size: 1.6rem; margin: .1rem 0 .2rem; } .typing-hint { color: var(--ink-2); margin: 0; max-width: 46rem; }
.typing-stats { display: flex; gap: 1.5rem; }
.typing-progress { height: .35rem; background: var(--paper-2); border-radius: 999px; overflow: hidden; } .typing-progress-bar { height: 100%; width: 0; background: var(--accent); transition: width .12s; }
.typing-stage { position: relative; }
.typing-text { background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.4rem 1.6rem; font-size: 1.55rem; line-height: 1.85; letter-spacing: .01em; white-space: pre-wrap; overflow-wrap: anywhere; max-height: calc(1.85em * 4 + 2.8rem); overflow: hidden; outline: none; scroll-behavior: smooth; cursor: text; user-select: none; }
.typing-text:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.typing-text.size-sm { font-size: 1.25rem; } .typing-text.size-lg { font-size: 1.9rem; }
.ch { border-radius: 3px; transition: background .08s; } .ch.ok { color: var(--ok-ink); } .ch.fixed { color: var(--ok-ink); text-decoration: underline; text-decoration-color: var(--gold); text-underline-offset: .2em; }
.ch.bad { color: var(--bad); background: var(--bad-soft); } .ch.bad.space { background: var(--bad); } .ch.was-wrong { color: var(--bad); }
.ch.cur { background: var(--accent-fill); color: var(--accent-ink); animation: blink 1.1s steps(2, start) infinite; } .ch.miss { animation: miss .16s; background: var(--bad-fill); color: #fff; }
@keyframes blink { to { background: transparent; color: inherit; } } @keyframes miss { 0% { transform: translateX(-2px); } 50% { transform: translateX(2px); } 100% { transform: none; } }
.typing-overlay { position: absolute; inset: 0; display: grid; place-items: center; background: color-mix(in srgb, var(--paper) 70%, transparent); backdrop-filter: blur(2px); border-radius: var(--radius); cursor: pointer; }
.overlay-card { background: var(--card); border: 1px solid var(--line-2); border-radius: var(--radius); padding: 1rem 1.4rem; text-align: center; box-shadow: var(--shadow); max-width: 30rem; }
.overlay-title { font-weight: 700; font-size: 1.1rem; } .overlay-sub { color: var(--muted); font-size: .9rem; margin-top: .2rem; }
.typing-result { display: grid; place-items: center; padding: .5rem 0; }
.typing.done .typing-text, .typing.done .typing-overlay, .typing.done .typing-guides { display: none; }
.result-inner { position: relative; background: var(--card); border: 1px solid var(--line-2); border-radius: var(--radius); padding: 1.4rem 1.8rem; box-shadow: var(--shadow); text-align: center; min-width: 22rem; max-width: 40rem; }
.result-stars { font-size: 2rem; letter-spacing: .1em; } .result-verdict { font-size: 1.3rem; font-weight: 700; margin: .2rem 0 .4rem; } .result-complete { color: var(--ok); font-weight: 600; margin-bottom: .4rem; }
.result-inner .stat-row { justify-content: center; } .result-inner .btn-row { justify-content: center; }
.new-badges { display: flex; flex-direction: column; gap: .5rem; margin: .8rem 0 .2rem; } .new-badge { display: flex; gap: .7rem; align-items: center; text-align: left; background: var(--gold-soft); border-radius: var(--radius-sm); padding: .5rem .8rem; } .new-badge > span { font-size: 1.6rem; }
.typing-guides { display: grid; grid-template-columns: 11rem 1fr; gap: 1rem; align-items: center; } @media (max-width: 760px) { .typing-guides { grid-template-columns: 1fr; } }
.hidden { display: none !important; }
.typing-foot { display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; } .typing-foot-left, .typing-foot-right { display: flex; gap: .8rem; align-items: center; }

/* Keyboard */
.keyboard { display: flex; flex-direction: column; gap: .3rem; padding: .6rem; background: var(--paper-2); border: 1px solid var(--line); border-radius: var(--radius); user-select: none; container-type: inline-size; }
.kb-row { display: flex; gap: .3rem; }
.key { --w: 1; flex: var(--w) 1 0; min-width: 0; height: 2.6rem; border-radius: 6px; background: var(--card); border: 1px solid var(--line-2); border-bottom-width: 3px; display: flex; flex-direction: column; align-items: center; justify-content: center; font-family: var(--mono); font-size: .8rem; font-weight: 600; color: var(--ink-2); line-height: 1; transition: background .1s, transform .05s; }
.key .k-up { font-size: .65rem; color: var(--muted); } .key.dead { font-size: .62rem; color: var(--muted); }
.keyboard:not(.no-fingers) .key.finger-l5, .keyboard:not(.no-fingers) .key.finger-r5 { background: var(--f-l5); } .keyboard:not(.no-fingers) .key.finger-l4, .keyboard:not(.no-fingers) .key.finger-r4 { background: var(--f-l4); }
.keyboard:not(.no-fingers) .key.finger-l3, .keyboard:not(.no-fingers) .key.finger-r3 { background: var(--f-l3); } .keyboard:not(.no-fingers) .key.finger-l2, .keyboard:not(.no-fingers) .key.finger-r2 { background: var(--f-l2); }
.keyboard:not(.no-fingers) .key.finger-l1, .keyboard:not(.no-fingers) .key.finger-r1 { background: var(--f-l1); }
.keyboard:not(.no-fingers) .key.dead { background: var(--card); }
.key.next { background: var(--accent-fill) !important; color: var(--accent-ink) !important; border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); transform: translateY(-1px); } .key.next .k-up { color: var(--accent-ink); }
.key.hit { background: var(--ok-fill) !important; color: #fff !important; } .key.miss { background: var(--bad-fill) !important; color: #fff !important; }
.keyboard.heat .key { background: var(--card); } .keyboard.heat .key.heat-5 { background: var(--ok-fill); color: #fff; } .keyboard.heat .key.heat-4 { background: color-mix(in srgb, var(--ok) 55%, var(--card)); } .keyboard.heat .key.heat-3 { background: var(--gold-soft); } .keyboard.heat .key.heat-2 { background: color-mix(in srgb, var(--bad) 45%, var(--card)); } .keyboard.heat .key.heat-1 { background: var(--bad-fill); color: #fff; }
@container (max-width: 560px) { .key { height: 2rem; font-size: .65rem; } .key .k-up { display: none; } }
.demo-kbd .key { height: 2.1rem; font-size: .7rem; }

/* Hands */
.hands { display: flex; flex-direction: column; align-items: center; gap: .2rem; } .hands-svg { width: 100%; max-width: 11rem; }
.hand path { fill: var(--paper-2); stroke: var(--line-2); stroke-width: 1.5; transition: fill .1s; } .hand path.palm { fill: var(--paper-2); }
.hand path.active { fill: var(--accent); stroke: var(--accent); } .hands-label { font-size: .8rem; color: var(--muted); min-height: 1.2em; text-align: center; }

/* Tests, practice, games, badges, log */
.test-grid, .mode-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; } @media (max-width: 800px) { .test-grid, .mode-grid { grid-template-columns: 1fr; } }
/* Practice's seven modes: four and three, the three centered, on a wide screen
   (it was three, three and Paragraphs alone); two across in between with the odd
   one taking the full row; one column on a phone. */
@media (min-width: 1001px) {
  .mode-grid.practice-modes { display: flex; flex-wrap: wrap; justify-content: center; }
  .practice-modes > .mode-card { flex: 0 0 calc((100% - 3rem) / 4); }
}
@media (min-width: 801px) and (max-width: 1000px) {
  .mode-grid.practice-modes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .practice-modes > :last-child:nth-child(odd) { grid-column: 1 / -1; }
}
/* Four test lengths: one row on a wide screen, two by two in between, then a column. */
.test-grid { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1000px) { .test-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .test-grid { grid-template-columns: 1fr; } }
.test-card, .mode-card { color: var(--ink); display: flex; flex-direction: column; gap: .3rem; } a.test-card:hover, a.mode-card:hover { border-color: var(--accent); text-decoration: none; }
/* A mode in the subscription: the locked lesson cards' dashed treatment, never
   opacity, which took its words to 3.25:1 (light) and 3.53:1 (dark). */
.mode-card.locked { background: var(--paper); border-style: dashed; border-color: var(--line-2); box-shadow: none; } a.mode-card.locked:hover { border-color: var(--gold); }
.test-min { font-size: 2.6rem; font-weight: 800; line-height: 1; } .test-min small { font-size: 1rem; color: var(--muted); margin-left: .2rem; } .test-name { font-weight: 600; }
.game-icon { color: var(--accent); display: inline-flex; margin-bottom: .3rem; }
.result-card { text-align: center; } .result-big { margin: .5rem 0; } .result-n { font-size: 4.5rem; font-weight: 900; line-height: 1; letter-spacing: -.03em; display: block; } .result-l { color: var(--muted); } .result-band { font-size: 1.1rem; color: var(--accent-text); margin-bottom: .5rem; } .result-card .stat-row { justify-content: center; } .result-card .btn-row { justify-content: center; }
.table { width: 100%; border-collapse: collapse; font-size: .92rem; } .table th { text-align: left; font-size: .75rem; text-transform: uppercase; letter-spacing: .05em; color: var(--muted); padding: .5rem .6rem; border-bottom: 1px solid var(--line); } .table td { padding: .55rem .6rem; border-bottom: 1px solid var(--line); vertical-align: top; } .table .num { text-align: right; } .row-actions { white-space: nowrap; }
.table .th-short { display: none; }
.seg { display: inline-flex; border: 1px solid var(--line-2); border-radius: 999px; padding: .2rem; background: var(--card); } .seg-item { padding: .3rem .8rem; border-radius: 999px; color: var(--ink-2); font-size: .85rem; font-weight: 600; } .seg-item.active { background: var(--accent-fill); color: var(--accent-ink); } .seg-item:hover { text-decoration: none; }
/* Each segment is a 44px target drawn as the same 30px pill: the link is 44px
   tall with 7px handed back by negative margins, and the active fill is a
   pseudo-element inset by those 7px, so the control looks exactly as before. */
.seg-item { position: relative; isolation: isolate; display: inline-flex; align-items: center; min-height: 44px; padding-block: 0; margin-block: -7px; }
.seg-item.active { background: none; }
.seg-item::before { content: ""; position: absolute; inset: 7px 0; z-index: -1; border-radius: 999px; }
.seg-item.active::before { background: var(--accent-fill); }
/* Twenty-four badges: six across, four, then two, so every row is full. */
.badge-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: .8rem; }
@media (max-width: 999px) { .badge-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (max-width: 639px) { .badge-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
.badge { display: flex; flex-direction: column; align-items: center; gap: .2rem; text-align: center; padding: 1rem .8rem; }
.badge-icon { display: grid; place-items: center; width: 3.5rem; height: 3.5rem; margin-bottom: .35rem; border-radius: 50%; background: var(--gold-soft); color: var(--gold-ink); }
.badge-title { font-weight: 700; } .badge-when { margin-top: auto; padding-top: .35rem; }
/* Not earned yet: the drawing goes quiet and the card flat; the words stay readable. */
.badge.locked { background: transparent; box-shadow: none; border-style: dashed; border-color: var(--line-2); }
.badge.locked .badge-icon { background: var(--paper-2); color: var(--muted); }
.log-day { margin-bottom: 1rem; } .log-date { font-size: 1rem; font-weight: 700; letter-spacing: 0; margin: 0 0 .5rem; }
.log-badge { display: flex; gap: .45rem; align-items: flex-start; } .log-badge .ico { flex: none; margin-top: .2em; color: var(--gold-ink); } .log-list { list-style: none; padding: 0; margin: 0; } .log-row { display: grid; grid-template-columns: 5rem 1fr; gap: .8rem; padding: .45rem 0; border-top: 1px solid var(--line); font-size: .93rem; } .log-time { color: var(--muted); font-variant-numeric: tabular-nums; }
.log-ended { font-size: .75rem; color: var(--muted); } .log-ended.quit { color: var(--bad-ink); } .log-ended.timeout { color: var(--accent-text); } .badge-row { background: var(--gold-soft); border-radius: 6px; padding: .45rem .4rem; margin-inline: -.4rem; }
/* The rest of a log row is a grid of fixed tracks (title, time taken, speed,
   accuracy, stars or score, how it ended), so each column lines up down the
   day (catalog A2). Under 640px the cells flow as one wrapped line. The badge
   row's tint reaches out past the text, so its time sits where the others do. */
.log-body { display: grid; grid-template-columns: minmax(0, 1fr) 4.5rem 5rem 3rem 5.5rem 6rem; column-gap: .75rem; align-items: baseline; }
.lg-title { min-width: 0; } .lg-num { font-variant-numeric: tabular-nums; white-space: nowrap; } .lg-extra { white-space: nowrap; }
/* On a phone each row is two lines on one grid: the time, the title and how
   it ended, then the numbers underneath, starting under the time. */
@media (max-width: 640px) {
  .log-row { grid-template-columns: 4rem 4.6rem 3rem minmax(0, 1fr); grid-template-areas: "time title title ended" "dur wpm acc extra"; column-gap: .5rem; row-gap: .1rem; }
  .log-row .log-body { display: contents; }
  .log-time { grid-area: time; } .lg-title { grid-area: title; } .log-body .log-ended { grid-area: ended; text-align: right; } .lg-extra { grid-area: extra; text-align: right; }
  .log-body .lg-num:nth-of-type(2) { grid-area: dur; } .log-body .lg-num:nth-of-type(3) { grid-area: wpm; } .log-body .lg-num:nth-of-type(4) { grid-area: acc; }
  .badge-row .log-badge { grid-column: 2 / -1; }
}
.profile-list { display: flex; flex-direction: column; gap: .7rem; } .profile-row { display: flex; align-items: center; gap: 1rem; } .profile-row.current { border-color: var(--accent); } .profile-body { flex: 1; } .profile-actions { display: flex; gap: .5rem; align-items: center; }
.profile-slot { display: inline-grid; width: 5rem; } .profile-slot > *, .profile-slot form .btn { width: 100%; justify-content: center; text-align: center; }
/* A status pill ("Current"). Scoped to a span: the onboarding goal and profile icon
   choices are labels with .choice.pill, and the bare class was painting all of them selected. */
span.pill { background: var(--accent-soft); color: var(--accent-text); font-size: .75rem; font-weight: 700; padding: .2rem .6rem; border-radius: 999px; }

.result-close { position: absolute; top: .4rem; right: .5rem; width: 2.2rem; height: 2.2rem; border: 0; background: none; font-size: 1.4rem; color: var(--muted); cursor: pointer; border-radius: 6px; } .result-close:hover { background: var(--paper-2); color: var(--ink); }

/* Ads (free tier only) */
.ad { display: flex; justify-content: center; margin: .5rem auto; max-width: 100%; overflow: hidden; }
.ad-placeholder { align-items: center; justify-content: center; flex-direction: column; border: 1px dashed var(--line-2); border-radius: var(--radius-sm); background: var(--paper-2); color: var(--muted); font-size: .85rem; max-width: 100%; }

/* Games */
.game { padding-top: 1.2rem; } .game-head { display: flex; gap: 2rem; margin-bottom: 1rem; }
.rain-field { position: relative; height: 26rem; background: var(--card); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.rain-start { position: absolute; inset: 0; display: grid; place-items: center; background: color-mix(in srgb, var(--paper) 70%, transparent); z-index: 2; }
.drop { position: absolute; left: 0; top: 0; font-size: 1.25rem; font-weight: 600; padding: .15rem .45rem; background: var(--paper-2); border: 1px solid var(--line-2); border-radius: 6px; will-change: transform; white-space: nowrap; }
.drop .hit-part { color: var(--ok); } .drop.popped { animation: pop .25s forwards; } .drop.missed { animation: fade .3s forwards; } .drop.shake { animation: miss .2s; }
@keyframes pop { to { transform: scale(1.6); opacity: 0; } } @keyframes fade { to { opacity: 0; } }
.game .typing-result { position: fixed; inset: 0; z-index: 60; display: grid; place-items: center; background: color-mix(in srgb, var(--paper) 78%, transparent); backdrop-filter: blur(3px); padding: 1rem; }
.rain-typed { margin-top: .6rem; font-size: 1.3rem; min-height: 1.6em; color: var(--accent-text); }
.sprint-track { display: flex; flex-direction: column; gap: .6rem; margin-bottom: 1rem; } .lane { display: grid; grid-template-columns: 4rem 1fr; align-items: center; gap: .6rem; } .lane-label { font-size: .8rem; font-weight: 700; color: var(--muted); }
.lane-bar { position: relative; height: 2.2rem; background: var(--paper-2); border-radius: 999px; border: 1px solid var(--line); } .runner { position: absolute; top: 50%; transform: translate(-50%, -50%); font-size: 1.4rem; transition: left .1s linear; left: 0; }

/* Charts */
.chart { width: 100%; height: auto; display: block; } .chart-grid { stroke: var(--line); stroke-width: 1; } .chart-tick { fill: var(--muted); font-size: 10px; font-family: var(--sans); } .chart-line { fill: none; stroke: var(--accent); stroke-width: 2.5; stroke-linejoin: round; }
.chart-area { fill: var(--accent); opacity: .12; } .chart-dot { fill: var(--accent); } .chart-label { fill: var(--ink); font-size: 12px; font-weight: 700; font-family: var(--sans); } .chart-bar { fill: var(--line-2); } .chart-bar.hit { fill: var(--ok); } .chart-goal { stroke: var(--accent); stroke-dasharray: 4 4; stroke-width: 1.5; }
.chart-empty { color: var(--muted); padding: 2rem 0; text-align: center; }

/* Admin. A wide table scrolls sideways inside its card on a phone, never the page. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.table-scroll > .table { min-width: 36rem; }
.lvl-error { color: var(--bad-ink); } .lvl-warn { color: var(--gold-ink); } pre { font-size: .75rem; white-space: pre-wrap; max-width: 30rem; }

/* A standing message inside a page, as opposed to .flash, which arrives and leaves. */
.notice { margin: 1rem 0 0; padding: .8rem 1rem; border: 1px solid var(--line); border-radius: 12px; background: var(--paper); font-size: .95rem; text-align: left; }
.notice strong { display: block; }
.notice-bad { border-color: var(--bad); }

/* Certificate. The greys are #5f6576, 5.9:1 on the white sheet (#7a8090 was 3.94:1). */
.print-body { background: #fff; color: #1b1f2a; } .certificate { max-width: 52rem; margin: 2rem auto; padding: 0 1rem; }
.cert-border { border: 10px double #2f6fed; padding: 3rem 2.5rem; text-align: center; background: #fff; }
.certificate { --accent: #2f6fed; --ink: #1b1f2a; }
.cert-brand { display: inline-flex; align-items: center; gap: .55rem; }
.cert-brand .brand-name { font-size: 1.5rem; }
.cert-foot { margin-top: 2rem; font-family: var(--brand-mono); font-size: .85rem; letter-spacing: .08em; color: #5f6576; } .cert-kicker { text-transform: uppercase; letter-spacing: .3em; font-size: .8rem; color: #5f6576; margin: 1.5rem 0 1rem; }
.cert-name { font-family: var(--serif); font-size: 3rem; font-weight: 600; margin-bottom: .5rem; } .cert-text { color: #4c5364; font-size: 1.1rem; }
.cert-wpm { font-size: 4rem; font-weight: 900; letter-spacing: -.03em; line-height: 1.1; margin: .4rem 0; } .cert-wpm span { display: block; font-size: 1rem; font-weight: 500; letter-spacing: .1em; text-transform: uppercase; color: #5f6576; }
.cert-date { margin-top: 1.5rem; font-size: 1rem; color: #4c5364; } .cert-band { margin-top: .4rem; font-weight: 700; color: #2f6fed; }
.cert-actions { text-align: center; margin-top: 1.5rem; }
/* The run Integrity would not vouch for: a single line, not a double border, so it never reads as an award. */
.cert-withheld { border: 1px solid var(--line); border-radius: 14px; }
.cert-withheld .cert-kicker { color: var(--bad-ink); }
.cert-why { list-style: none; margin: 1rem auto 1.5rem; padding: 0; max-width: 34rem; text-align: left; }
.cert-why li { padding: .6rem .9rem; background: #faf8f4; border: 1px solid var(--line); border-radius: 10px; margin-bottom: .5rem; }
@media print { .no-print { display: none !important; } .certificate { margin: 0; } body { background: #fff; } }


/* Phone width. A profile row's meta was wrapping a word a line beside its two
   buttons, a setting's note was squeezed into a four-line column beside its
   picker, and the on-screen keyboard ran off the right edge of a lesson. Each
   stacks instead of squeezing. (2026-09-26, the launch hardening pass.) */
@media (max-width: 480px) {
  .profile-row { flex-wrap: wrap; }
  .profile-body { flex-basis: calc(100% - 4.2rem); }
  .profile-actions { width: 100%; justify-content: flex-end; }
  .setting-row:has(.listbox) { flex-wrap: wrap; }
  .setting-row:has(.listbox) .listbox { width: 100%; }
  /* A table's first column (a date, a unit) keeps two lines at most: tighter cells
     give it the room it was losing to a five-line "Mon / Aug / 31 / 7:06 / PM". */
  .table th, .table td { padding-left: .35rem; padding-right: .35rem; }
  .table td:first-child { min-width: 5.75rem; }
  /* A long column heading over short numbers gives way to its abbreviation; a
     screen reader still hears the whole word. */
  .table .th-long { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
  .table .th-short { display: inline; }
  .typing-guides { overflow-x: auto; }
  .focus-crumb { display: none; }
}

/* Buttons side by side share one width, the widest label's, set here once
   (catalog A1): an inline grid of equal tracks sizes every track to the
   widest button. Last in the file, so it wins over a row's own display. Add
   btn-even-stack where the row would not fit a phone, and it becomes one
   full-width column under 480px. */
.btn-even { display: inline-grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: .6rem; width: fit-content; max-width: 100%; }
.btn-even > .btn, .btn-even > form, .btn-even > form > .btn { width: 100%; }
@media (max-width: 480px) { .btn-even.btn-even-stack { display: grid; grid-auto-flow: row; width: 100%; } }
