/* Generated by scripts/vendor-fonts.mjs. Do not edit by hand.
 * Local copies of every font the app uses, latin subset only, so decks
 * keep their typography offline and no request ever leaves the device.
 */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(./fonts/manrope-bcbadccc.woff2) format('woff2');
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(./fonts/manrope-bcbadccc.woff2) format('woff2');
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(./fonts/manrope-bcbadccc.woff2) format('woff2');
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(./fonts/manrope-bcbadccc.woff2) format('woff2');
}

@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url(./fonts/manrope-bcbadccc.woff2) format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url(./fonts/newsreader-d3bcc2ce.woff2) format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url(./fonts/newsreader-c12324c4.woff2) format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url(./fonts/newsreader-c12324c4.woff2) format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url(./fonts/newsreader-c12324c4.woff2) format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url(./fonts/newsreader-c12324c4.woff2) format('woff2');
}

/* The marketing site's only stylesheet.
   ------------------------------------------------------------------------
   Hand-written, and deliberately sharing no code with the app: the app is a
   dark full-screen PWA shell and this is a document. What the two DO share is
   the palette and the two vendored families, so they read as one product.

   There is no build step. site/ is copied to dist-site/ by `npm run build:site`,
   so what you read here is what is served.

   Implements design.pen "Landing Page". Two deliberate deviations from it, both
   noted at the token that changes them: the faint grey, and the demo carousel's
   mechanism. */

:root {
  --bg: #15151A;
  --surface: #1E1E27;
  --deep: #191526;          /* the "why it's different" band */
  --band: #221F38;          /* violet-tinted panels: eyebrow pill, final CTA */
  --line: #31313E;
  --text: #F2F1F6;
  --soft: #A3A1B4;
  /* design.pen uses #6E6C80 here. It measures 3.6:1 on --bg, which fails AA for
     body text, and it is close to the #6B6980 the app itself replaced for
     exactly that reason (see the note beside C.faint in src/screens/ui.jsx).
     This is the app's audited replacement, at 6.1:1. */
  --faint: #9491AC;
  --violet: #8F86FF;

  /* Subject accents, lifted from TOPICS in src/content/catalog.jsx, each with
     the tinted chip the design puts its badge on. */
  --maths: #8F86FF;    --maths-dim: #221F38;
  --english: #E1567C;  --english-dim: #2C1A23;
  --thinking: #E08A3C; --thinking-dim: #2C2016;
  --time: #0FA98F;     --time-dim: #10241F;
  --games: #E8A013;    --games-dim: #2A2210;
  /* NOT the same hex as --english: that was the original choice (matching
     UNITS.Writing) and it collided exactly with Reading's own topic accent,
     since topic accents and UNITS colours are two independent palettes in
     this app (see src/content/catalog.jsx). #4A6FD4 is UNITS.Reading
     instead, reused because no TOPIC accent already uses it. Fixed
     2026-09-13. */
  --writing: #4A6FD4;  --writing-dim: #111A31;
  --neutral: #A3A1B4;  --neutral-dim: #26262F;

  --wrap: 1280px;
  --serif: 'Newsreader', Georgia, 'Times New Roman', serif;
  --sans: 'Manrope', system-ui, -apple-system, sans-serif;
}

* { box-sizing: border-box; margin: 0; }

html {
  -webkit-text-size-adjust: 100%; scroll-behavior: smooth;
  /* Not optional once .nav is sticky: without it every in-page anchor
     (#how, #why, #faq, and /selective's #writing) scrolls its target
     underneath the bar. Matches the bar's height plus a little air. */
  scroll-padding-top: 84px;
}

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  padding-bottom: env(safe-area-inset-bottom);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}

img, svg { display: block; }

a { color: var(--violet); }

.wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 22px; }

/* Headings are the serif. It is the one decision that changes the page's
   character most: the app is all Manrope, and a document wants a reading face
   at its top level. */
h1, h2, h3 { font-family: var(--serif); font-weight: 600; letter-spacing: -.01em; }

/* ------------------------------- nav ----------------------------------- */

/* Sticky, not fixed: the bar keeps its place in flow, so nothing below needs
   a compensating margin, and because a sticky element is positioned, the
   full-width dropdown panels resolve against IT rather than against the
   column, which is what lets them span the viewport. */
.nav {
  position: sticky; top: 0; z-index: 50;
  border-bottom: 1px solid var(--line); background: var(--bg);
}
.nav-inner {
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; padding-top: 18px; padding-bottom: 18px;
}

/* The wordmark is a lockup: the app's own four tiles beside the name, so this
   page, the installed icon and the home screen all read as one thing. The
   icon's backing square is --bg, so the inline SVG drops it and crops to the
   tiles, which lets them fill the box rather than float in padding. */
.mark {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--serif); font-size: 20px; font-weight: 600;
  color: var(--text); text-decoration: none; flex: none;
}

/* The nav is a LIST of destinations, which is what it is: a screen reader
   announces "list, seven items" and lets a user skip the whole thing as a
   unit, where seven loose anchors are seven unrelated announcements. Every
   list in here resets the marker and the UA's own indent. */
/* Scoped to .nav-list, NOT to `.nav-links ul`: the dropdown's .menu-grid is
   also a ul inside .nav-links, and it carries .wrap, whose margin and 22px
   padding are what hold the panel's content to the same column as the rest of
   the page. A blanket reset here silently unpicked that and ran the panel
   edge to edge. */
.nav-list, .nav-sheet ul, .foot .meta { list-style: none; margin: 0; padding: 0; }
.nav-list { display: flex; align-items: center; gap: 30px; }
.nav-links a { color: var(--soft); font-size: 15px; font-weight: 500; text-decoration: none; }

/* The hamburger. A native details element, so it opens on click and on
   Enter, is announced as a disclosure, and needs no script. The cost is
   that an open sheet stays open until the summary is clicked again;
   accepted deliberately, because the alternative is the site's first
   piece of behavioural JavaScript. */
/* static, not relative: the sheet must hang off the BAR the way the desktop
   panel does, not off the icon. Relative here anchored it to the summary, so
   it started level with the X and cut across the nav's own bottom border,
   which then reappeared beside it. */
.nav-menu { display: none; position: static; }
.nav-menu > summary {
  list-style: none; cursor: pointer; padding: 8px; margin: -8px;
  display: flex; align-items: center;
}
.nav-menu > summary::-webkit-details-marker { display: none; }
.bars, .bars::before, .bars::after {
  display: block; width: 22px; height: 2px; border-radius: 2px;
  background: var(--text); content: "";
}
.bars::before { transform: translateY(-7px); }
.bars::after { transform: translateY(5px); }
.nav-sheet {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 40;
  padding: 10px 22px 18px;
  border-bottom: 1px solid var(--line);
  background: var(--bg); box-shadow: 0 20px 44px rgb(0 0 0 / .38);
}
/* display:block matters here: as flex children these anchors were blockified
   for free, and inside an <li> they are inline again, so their vertical
   padding stops affecting layout and the sheet collapses to a tight list. */
.nav-sheet a {
  display: block;
  color: var(--soft); font-size: 15px; font-weight: 500;
  text-decoration: none; padding: 10px 12px; border-radius: 9px;
}
/* The two link groups (Exams, Subjects) inside the hamburger sheet. A plain
   <b>, not a second nested <details>: the sheet is a flat list already open
   inside the summary a child just tapped, and a menu inside a menu would
   need its own keyboard handling this site has no script to give it. Bold
   text still reads correctly to a screen reader, it just carries no extra
   landmark. */
/* Each group in the sheet is a nested list with a label, not bold text
   floating between links: the label names the list for a screen reader
   (aria-labelledby) instead of being read as one more item in it. */
.sheet-label {
  display: block; padding: 14px 12px 2px; font-size: 12px; font-weight: 700;
  text-transform: uppercase; letter-spacing: .05em; color: var(--faint);
}
/* The column and its gap live on the lists, not on the panel: the panel's
   only child is now a single ul, so a gap there separates nothing. */
.nav-sheet ul { display: flex; flex-direction: column; gap: 2px; }
.nav-sheet ul ul { padding: 0; }

/* Same details mechanism as the hamburger, so the two behave alike and
   neither needs script. */
.menu { position: static; }
.menu > summary {
  list-style: none; cursor: pointer; color: var(--soft);
  font-size: 15px; font-weight: 500;
  display: inline-flex; align-items: center; gap: 7px;
}
.menu > summary::-webkit-details-marker { display: none; }

/* The collapse icon: a CSS chevron rather than an asset, so it inherits the
   summary's colour and needs nothing loaded. It reads [open] and nothing
   else, which means it is correct before nav.js runs, and stays correct if
   nav.js never arrives. */
.chev {
  width: 7px; height: 7px; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; border-radius: 1px;
  transform: translateY(-2px) rotate(45deg); transition: transform .18s ease;
}
.menu[open] > summary .chev { transform: translateY(2px) rotate(225deg); }

/* Absolute against .nav, so the panel spans the viewport; .menu-grid then
   holds its content to the same column as every other block on the page. */
.menu-panel {
  position: absolute; left: 0; right: 0; top: 100%; z-index: 40;
  border-bottom: 1px solid var(--line); background: var(--bg);
  box-shadow: 0 20px 44px rgb(0 0 0 / .38);
}
.menu-grid {
  list-style: none;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 6px; padding-top: 16px; padding-bottom: 22px;
}
/* The accent stripe is the same colour the subject carries everywhere else in
   the app, so the dropdown and the subject cards agree without a legend. */
.menu-grid a {
  display: block; padding: 13px 16px; border-radius: 12px;
  text-decoration: none; border-left: 3px solid transparent;
}
.menu-grid b { display: block; color: var(--text); font-size: 15px; font-weight: 600; }
.menu-grid span { display: block; margin-top: 3px; color: var(--faint); font-size: 13px; line-height: 1.5; }
.menu-grid .a-english { border-left-color: var(--english); }
.menu-grid .a-thinking { border-left-color: var(--thinking); }
.menu-grid .a-maths { border-left-color: var(--maths); }
.menu-grid .a-writing { border-left-color: var(--writing); }

/* The hamburger's three bars become an X while its sheet is open. Same
   [open]-only rule as the chevron, for the same reason. */
.bars, .bars::before, .bars::after { transition: transform .18s ease, background .18s ease; }
.nav-menu[open] .bars { background: transparent; }
.nav-menu[open] .bars::before { transform: translateY(0) rotate(45deg); }
.nav-menu[open] .bars::after { transform: translateY(-2px) rotate(-45deg); }

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-menu { display: block; }
}

/* ------------------------------ buttons -------------------------------- */

.btn {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 15px 26px; border-radius: 12px;
  background: var(--violet); color: #15151A;
  font-size: 16px; font-weight: 700; text-decoration: none;
  flex: none;
}
.btn.sm { padding: 11px 20px; font-size: 15px; }
.btn.lg { padding: 16px 32px; font-size: 18px; }
.btn.ghost {
  background: var(--surface); color: var(--text);
  border: 1.5px solid var(--line);
}
.btn .arrow { width: 18px; height: 18px; }

/* ------------------------------- hero ---------------------------------- */

.hero { padding: 64px 0 80px; }
.hero-grid { display: grid; gap: 56px; align-items: center; grid-template-columns: 1fr; }
@media (min-width: 1040px) { .hero-grid { grid-template-columns: 1fr 526px; } }

.hero-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 24px; }

.pill {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 7px 13px; border-radius: 20px;
  background: var(--band); color: var(--violet);
  font-size: 13px; font-weight: 600;
}
.pill svg { width: 14px; height: 14px; }

h1 { font-size: clamp(34px, 6vw, 56px); line-height: 1.04; letter-spacing: -.02em; }
.lede { font-size: clamp(17px, 2.2vw, 19px); color: var(--soft); line-height: 1.55; max-width: 34ch; }

.cta-row { display: flex; flex-wrap: wrap; gap: 14px; }

.ticks { display: flex; flex-wrap: wrap; gap: 18px; list-style: none; padding: 0; }
.ticks li { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 500; color: var(--faint); }
.ticks svg { width: 15px; height: 15px; color: var(--time); }

/* --------------------------- the demo carousel -------------------------- */

/* design.pen shows this as a two-slide carousel with working arrows and dots.
   It is built from radio inputs and labels rather than script: the only
   JavaScript on this site is migration plumbing, and a disclosure widget is not
   worth breaking that. Radios also come with keyboard support and a screen
   reader announcement for free, which a div-based carousel would have to be
   given by hand. */
/* min-width: 0 is load-bearing, not tidying. .demo is a grid item, so its
   automatic minimum size is min-content, and the track's min-content is the
   sum of its slides: four cards at flex-basis 100% each. At two slides that
   still fitted a phone and nothing showed; at four it pushed .demo to 664px
   inside a 390px viewport, scrolled the whole page sideways, and stretched
   the hero's text column with it. Caught by measuring at 390px, not by eye:
   the card itself looks right either way because the viewport clips it. */
.demo { display: flex; flex-direction: column; gap: 18px; min-width: 0; }
.demo-r { position: absolute; width: 1px; height: 1px; opacity: 0; }

.demo-viewport {
  overflow: hidden; border-radius: 22px;
  box-shadow: 0 24px 50px -12px #00000073;
}
.demo-track { display: flex; transition: transform .35s ease; }
#demo-2:checked ~ .demo-viewport .demo-track { transform: translateX(-100%); }
#demo-3:checked ~ .demo-viewport .demo-track { transform: translateX(-200%); }
#demo-4:checked ~ .demo-viewport .demo-track { transform: translateX(-300%); }

.qcard {
  flex: 0 0 100%;
  background: var(--surface); border: 1px solid var(--line); border-radius: 22px;
  padding: 26px;
  display: flex; flex-direction: column; gap: 18px;
}
.qcard-head {
  display: flex; align-items: center; justify-content: space-between;
  font-size: 12.5px; font-weight: 600; color: var(--faint);
}
.qcard-head .lesson { display: flex; align-items: center; gap: 8px; color: var(--soft); }
.qcard-head .swatch { width: 9px; height: 9px; border-radius: 3px; background: var(--violet); }
.qcard q, .qcard .q-stem {
  font-family: var(--serif); font-size: 20px; font-weight: 500;
  line-height: 1.35; color: var(--text); quotes: none;
}
.opts { display: flex; flex-direction: column; gap: 9px; list-style: none; padding: 0; }
.opts li {
  padding: 12px 14px; border-radius: 11px;
  background: #191920; border: 1px solid var(--line);
  font-size: 15px; color: var(--soft);
  display: flex; align-items: center; gap: 10px;
}
.opts li .key { color: var(--faint); font-weight: 700; font-size: 13px; min-width: 1em; }
.opts li.picked { border-color: var(--time); background: #10241F; color: var(--text); }
.opts li.wrong { border-color: var(--english); background: #2B161C; color: var(--text); }
.note {
  border-radius: 11px; padding: 13px 15px;
  font-size: 14px; line-height: 1.5;
}
.note.hint { background: var(--games-dim); color: #E9C77A; }
.note.explain { background: #2B161C; border: 1px solid var(--english); color: var(--soft); }
.note.explain b { color: var(--text); display: block; margin-bottom: 4px; font-weight: 700; }

.demo-controls { display: flex; align-items: center; justify-content: center; gap: 16px; }
.demo-arrow {
  width: 42px; height: 42px; border-radius: 21px;
  display: flex; align-items: center; justify-content: center;
  background: var(--surface); border: 1px solid var(--line); color: var(--faint);
  cursor: pointer;
}
.demo-arrow svg { width: 18px; height: 18px; }
.demo-dots { display: flex; align-items: center; gap: 7px; }
.demo-dots label {
  width: 7px; height: 7px; border-radius: 4px; background: var(--line);
  cursor: pointer; transition: width .2s ease, background .2s ease;
}
#demo-1:checked ~ .demo-controls .demo-dots label[for="demo-1"],
#demo-2:checked ~ .demo-controls .demo-dots label[for="demo-2"],
#demo-3:checked ~ .demo-controls .demo-dots label[for="demo-3"],
#demo-4:checked ~ .demo-controls .demo-dots label[for="demo-4"] {
  width: 22px; background: var(--violet);
}

/* A label cannot change which radio it points at, so each arrow is three
   labels in one slot and only the one that steps from HERE is shown. The slot
   keeps its size either way, so the dots stay put on the first and last
   slides where one arrow has nothing to point at. */
.demo-slot { width: 42px; height: 42px; flex: none; display: block; }
.demo-slot .demo-arrow { display: none; }
#demo-1:checked ~ .demo-controls .next label[for="demo-2"],
#demo-2:checked ~ .demo-controls .prev label[for="demo-1"],
#demo-2:checked ~ .demo-controls .next label[for="demo-3"],
#demo-3:checked ~ .demo-controls .prev label[for="demo-2"],
#demo-3:checked ~ .demo-controls .next label[for="demo-4"],
#demo-4:checked ~ .demo-controls .prev label[for="demo-3"] { display: flex; }

/* The arrow that carries you forward is the filled one, except on the last
   slide where forward does not exist and back is the only move left. */
#demo-1:checked ~ .demo-controls .next label,
#demo-2:checked ~ .demo-controls .next label,
#demo-3:checked ~ .demo-controls .next label,
#demo-4:checked ~ .demo-controls .prev label { background: var(--violet); border-color: var(--violet); color: #15151A; }

/* Focus has to be visible on the radio's LABEL, since the radio itself is
   clipped to a pixel. */
.demo-r:focus-visible ~ .demo-controls .demo-dots label[for="demo-1"],
.demo-r:focus-visible ~ .demo-controls .demo-dots label[for="demo-2"],
.demo-r:focus-visible ~ .demo-controls .demo-dots label[for="demo-3"],
.demo-r:focus-visible ~ .demo-controls .demo-dots label[for="demo-4"] { outline: 2px solid var(--violet); outline-offset: 3px; }

.demo-cap { font-size: 14px; color: var(--faint); text-align: center; line-height: 1.45; }

/* ------------------------------ sections ------------------------------- */

.section { padding: 88px 0; }
.band { background: var(--surface); padding: 80px 0; }
.band-deep { background: var(--deep); padding: 88px 0; }

.section-head { display: flex; flex-direction: column; align-items: center; gap: 13px; text-align: center; margin-bottom: 40px; }
.eyebrow { font-size: 13px; font-weight: 700; letter-spacing: .12em; color: var(--violet); }
/* The "why it is different" section carries its eyebrow AS its heading, so the
   section is not three h3 cards hanging under the previous section's h2. An h2
   rather than a hidden heading, because the visible title and the real title
   should be the same words. These declarations only undo what an h2 would
   otherwise inherit: `.section-head h2` and the serif `h1, h2, h3` rule both
   outrank a bare `.eyebrow`, so without this the label renders 40px and serif. */
.section-head h2.eyebrow { font-family: inherit; font-size: 13px; line-height: inherit; margin: 0; }
.section-head h2 { font-size: clamp(28px, 4.4vw, 40px); line-height: 1.12; }
.section-head .sub { font-size: 17px; color: var(--soft); line-height: 1.55; max-width: 62ch; }

.grid { display: grid; gap: 22px; grid-template-columns: 1fr; }
@media (min-width: 700px) { .grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1040px) { .grid.three { grid-template-columns: repeat(3, 1fr); } }
@media (min-width: 860px) { .grid.two { grid-template-columns: repeat(2, 1fr); } }

/* ------------------------------- cards --------------------------------- */

.card {
  background: var(--bg); border: 1px solid var(--line); border-radius: 18px;
  padding: 26px; display: flex; flex-direction: column; gap: 14px;
}
/* On the tinted band the card is the page colour; everywhere else it is the
   raised one. Inverting them is what keeps the bands from reading as one flat
   sheet of dark. */
.section .card, .band-deep .card { background: var(--surface); }

/* The Kit section's beta tag and small print. The tag sits inside the h2 so
   it travels with the line when the heading wraps on a phone. */
.beta {
  display: inline-block; vertical-align: middle; margin-left: 10px;
  padding: 3px 10px 4px; border-radius: 20px;
  background: var(--band); color: var(--violet);
  font-family: inherit; font-size: 13px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase;
  position: relative; top: -4px;
}
.kit-face { width: 72px; height: 72px; border-radius: 21px; box-shadow: 0 6px 24px rgba(0, 0, 0, .35); }
.kit-note { margin-top: 28px; text-align: center; color: var(--soft); font-size: 14px; line-height: 1.55; }

/* The thanks page's key panel. The key itself is the one thing on the page a
   buyer needs, so it is large, monospaced and easy to copy by eye or by hand. */
.keybox {
  margin: 8px 0 32px; padding: 28px 24px; text-align: center;
  background: var(--surface); border: 1px solid var(--line); border-radius: 16px;
}
.keybox-status { margin: 0; color: var(--soft); font-size: 16px; }
.keybox-label { margin: 0 0 10px; color: var(--soft); font-size: 13px; letter-spacing: .04em; text-transform: uppercase; }
.keybox-key {
  margin: 0; font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: clamp(24px, 6vw, 34px); font-weight: 700; letter-spacing: .06em;
  color: var(--text); word-break: break-all;
}
.keybox-sub { margin: 12px 0 0; color: var(--soft); font-size: 14px; }

/* The top-up-miss notice: calm, not a warning. A quiet brand-coloured rule on
   the left is enough to draw the eye without reading as an error, which it
   is not, the purchase is fine either way. */
.keybox-notice {
  margin-top: 20px; padding: 14px 16px; text-align: left;
  background: var(--bg); border: 1px solid var(--line); border-left: 3px solid var(--violet);
  border-radius: 10px; color: var(--soft); font-size: 14px; line-height: 1.6;
}
.keybox-notice p { margin: 0; }
.keybox-notice p + p { margin-top: 8px; }
.keybox-notice strong { color: var(--text); }

.badge {
  width: 46px; height: 46px; border-radius: 13px;
  display: flex; align-items: center; justify-content: center;
  background: var(--tint, var(--band)); flex: none;
}
.badge svg { width: 26px; height: 26px; }
.card h3 { font-size: 21px; }
/* Four of the six subject-grid cards link to that subject's own page. The
   anchor inherits the heading colour rather than taking the global link
   violet, so a linked card and an unlinked one (Games, Against the Clock)
   still read as the same kind of thing at a glance. */
.card h3 a { color: inherit; text-decoration: none; }
.card p { color: var(--soft); font-size: 15px; line-height: 1.5; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; padding: 0; margin-top: auto; }
.chips li {
  padding: 5px 10px; border-radius: 7px;
  background: var(--surface); border: 1px solid var(--line);
  font-size: 12px; font-weight: 500; color: var(--faint);
}
.band .chips li { background: var(--bg); }

/* the two big "how it works" halves */
.card.wide { padding: 34px; gap: 18px; }
.card.wide .badge { width: 52px; height: 52px; border-radius: 14px; }
.card.wide h3 { font-size: 25px; }
.card.wide p { font-size: 16.5px; line-height: 1.6; }
.tag {
  align-self: flex-start; padding: 7px 12px; border-radius: 8px;
  background: var(--tint, var(--band)); color: var(--accent, var(--violet));
  font-size: 14px; font-weight: 600;
}
/* Two pills on one line under each wide card: the SCALE of the thing beside
   what it does. A row rather than two stacked tags, because stacked they read
   as a list of features and the number is not one. Wraps on a narrow phone
   instead of overflowing the card. */
/* margin-top:auto so both cards land their pills on the same baseline even
   though one paragraph is longer, the same trick .chips already uses on the
   subject cards. Without it the two rows sit at different heights and the
   pair reads as misaligned rather than as a set. */
.tags { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; align-self: flex-start; margin-top: auto; }
.tags .tag { align-self: auto; }
/* The count is filled rather than tinted, so the eye lands on the number
   first. Dark ink on the card's own accent, which is a light violet or a mid
   orange here, both comfortably readable against #16161B. */
.tag.count { background: var(--accent, var(--violet)); color: #16161B; font-weight: 800; }

/* the two smaller ones below them */
.card.row { flex-direction: row; align-items: flex-start; gap: 18px; padding: 24px; }
.card.row .badge { width: 44px; height: 44px; border-radius: 12px; }
.card.row h3 { font-family: var(--sans); font-size: 18px; font-weight: 800; letter-spacing: 0; }
.card.row .txt { display: flex; flex-direction: column; gap: 5px; }

/* --------------------- why it's different ------------------------------ */

.quote {
  font-family: var(--serif); font-weight: 500;
  font-size: clamp(24px, 3.4vw, 38px); line-height: 1.3;
  /* An em measure rather than ch or px, so the quote keeps the same two or
     three lines at every size the clamp produces. */
  text-align: center; max-width: 24em; margin: 0 auto;
}
.band-deep .card { background: #FFFFFF14; border-color: #FFFFFF1A; padding: 30px; }
.band-deep .card p { color: #FFFFFFB3; font-size: 16px; line-height: 1.6; }
.band-deep .badge { background: var(--violet); width: 48px; height: 48px; border-radius: 12px; }
.band-deep .badge svg { color: #15151A; }

/* --------------------------- privacy strip ----------------------------- */

.strip { border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); }
.strip ul {
  display: flex; flex-wrap: wrap; justify-content: space-between; gap: 20px 28px;
  list-style: none; padding: 32px 0; margin: 0;
}
.strip li { display: flex; align-items: center; gap: 12px; font-size: 16px; font-weight: 600; }
.strip .tick {
  width: 28px; height: 28px; border-radius: 14px; flex: none;
  display: flex; align-items: center; justify-content: center;
  background: var(--english-dim); color: var(--english);
}
.strip .tick svg { width: 16px; height: 16px; }

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

/* Native <details>, so this folds with no JavaScript. Crawlers and answer
   engines read the closed content normally: it is in the DOM either way. */
.faqs { max-width: 860px; margin: 0 auto; }
.faq { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: baseline; gap: 12px;
  padding: 18px 0; cursor: pointer; list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
/* A chevron built from a rotated square: no icon font, no extra request. */
.faq summary::before {
  content: ""; flex: none;
  width: 7px; height: 7px; margin-top: 6px;
  border-right: 2px solid var(--violet); border-bottom: 2px solid var(--violet);
  transform: rotate(-45deg); transition: transform .15s ease;
}
.faq[open] summary::before { transform: rotate(45deg); }
.faq summary h3.q { font-family: var(--sans); font-size: 17px; font-weight: 700; letter-spacing: 0; margin: 0; }
.faq p { color: var(--soft); margin: 0 0 18px 19px; font-size: 16px; }
.faq p + p { margin-top: 12px; }

/* ------------------------------ final CTA ------------------------------ */

.cta-band {
  background: var(--band); border-radius: 28px;
  padding: 64px 32px; text-align: center;
  display: flex; flex-direction: column; align-items: center; gap: 24px;
}
.cta-band h2 { font-size: clamp(28px, 4.6vw, 46px); line-height: 1.2; max-width: 18ch; }
.cta-band .sub { color: var(--soft); font-size: 18px; }
.cta-band .url { color: var(--faint); font-size: 15px; font-weight: 500; }

/* -------------------------------- footer -------------------------------- */

footer { border-top: 1px solid var(--line); }
/* Longhands, not `padding: 34px 0`. This element carries .wrap as well, and
   the shorthand resets .wrap's horizontal gutter to zero, which put the logo
   hard against the edge of the screen. Anything sharing an element with .wrap
   has to add vertical padding this way; check-site.mjs now enforces it. */
.foot {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 20px 40px; padding-top: 34px; padding-bottom: 18px;
}
.foot .brand { display: flex; flex-direction: column; gap: 10px; }
.foot .brand p { color: var(--faint); font-size: 14px; }
.foot .meta { display: flex; flex-wrap: wrap; align-items: center; gap: 26px; font-size: 14px; font-weight: 500; }
.foot .meta a { color: var(--soft); text-decoration: none; }

/* The Facebook link is an icon on a row of its own, hard right. As text it
   read as a fifth site link beside Pricing and Privacy, which it is not: it
   leaves the site. An icon-only link has no accessible name, so the anchor
   carries the label and the svg is hidden from the reader rather than
   announced as a graphic. */
/* Two things on this row now, one at each end: the domain reads as a
   signature at the left, the icon as the way out at the right. The row had
   been the icon alone, which left it looking like something had gone
   missing. */
.foot-social {
  display: flex; align-items: center; justify-content: space-between;
  padding-bottom: 34px;
}
.foot-social .url { color: var(--faint); font-size: 14px; font-weight: 500; }
.foot-social .social { display: inline-flex; color: var(--soft); }

/* The closing call to action on the section and hub pages. The button sat
   tight under its line of copy and read as part of the sentence rather than
   as the thing to tap. Centring lives here rather than in five inline
   styles. */
.page-cta { text-align: center; }
.page-cta .cta-row { justify-content: center; margin-top: 24px; }

/* -------------------------------- hover -------------------------------- */

/* On a touchscreen a hover state sticks after a tap, so a card would look
   pressed when it is not. Gated exactly as the app gates its own. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { filter: brightness(1.08); }
  .nav-links a:hover, .foot .meta a:hover { color: var(--text); }
  .menu > summary:hover { color: var(--text); }
  .menu-grid a:hover { background: var(--surface); }
  .foot-social .social:hover { color: var(--text); }
  .faq summary:hover h3.q { color: var(--violet); }
  .card h3 a:hover { color: var(--violet); }
  .demo-arrow:hover { color: var(--text); }
  .card.link:hover { border-color: var(--violet); }
}

/* Anything focusable gets a visible ring. The dark palette makes the browser
   default almost invisible. */
a:focus-visible, summary:focus-visible, label:focus-visible {
  outline: 2px solid var(--violet); outline-offset: 3px; border-radius: 4px;
}

/* ------------------------------ documents ------------------------------ */

/* Privacy and the 404 share the nav and footer but not the landing page's
   grid: they are prose, so they take a reading measure inside the wide wrap. */
.doc { max-width: 44rem; margin: 0 auto; padding: 56px 0 40px; }
.doc h1 { font-size: clamp(30px, 5.5vw, 44px); line-height: 1.1; }
.doc .lede { max-width: none; margin-top: 14px; }
.doc h2 { font-size: 23px; margin-top: 46px; }
.doc p { color: var(--soft); margin-top: 12px; }
.doc p strong, .doc li strong { color: var(--text); font-weight: 700; }
.doc ul { margin-top: 12px; padding-left: 22px; color: var(--soft); }
.doc li { margin-top: 6px; }
.doc .btn { margin-top: 30px; }

/* The 404 is one short block, so it sits in the middle of the screen rather
   than hanging off the top of an otherwise empty page. */
.doc.center { text-align: center; padding: 96px 0 120px; }
.doc.center .lede { margin-left: auto; margin-right: auto; }

/* ------------------------------- pricing -------------------------------- */

/* Four tiers need their own column count: .grid.three would orphan the fourth
   on a row of its own. Two across from 700px, four from 1100px, because four
   price columns below that squeeze the tier names onto three lines each. */
@media (min-width: 1100px) { .grid.four { grid-template-columns: repeat(4, 1fr); } }

/* A tier is a .card with a fixed running order: name, price, line, list, then
   the button pinned to the bottom so all four buttons align however much the
   lists differ in length. */
.tier { gap: 10px; }
.tier h3 { font-family: var(--sans); font-size: 17px; font-weight: 800; letter-spacing: 0; }
.tier .price {
  font-family: var(--serif); font-size: 40px; font-weight: 600;
  line-height: 1.05; color: var(--text);
}
.tier .price small { font-family: var(--sans); font-size: 14px; font-weight: 600; color: var(--faint); }
.tier .who { color: var(--text); font-weight: 600; font-size: 15.5px; line-height: 1.45; }
.tier p { font-size: 14.5px; }
.tier .act { margin-top: auto; padding-top: 18px; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }

/* The disabled buy button. A real <button disabled>, not a styled span: it is
   announced as unavailable rather than merely looking it, and it cannot be
   tabbed to and pressed. The free tier keeps a live <a> instead, because a
   greyed-out control on the one thing that works today would be a lie. */
.tier .btn[disabled] {
  background: var(--surface); color: var(--faint);
  border: 1.5px solid var(--line); cursor: not-allowed;
}
.soon {
  padding: 5px 10px; border-radius: 20px;
  background: var(--band); color: var(--violet);
  font-size: 12.5px; font-weight: 700; letter-spacing: .04em;
}

/* The prose blocks on the pricing page. Same job as .doc, but usable INSIDE a
   .section: .doc carries its own page padding, which would double up against
   the section's. Centred rather than left, or a 46rem column strands itself
   against the 1280px wrap with half the page empty beside it. */
.prose { max-width: 46rem; margin: 0 auto; }
/* .lede is 34ch for the hero, where it sits beside the demo. In a full-width
   prose column that is a third of the measure and reads as a broken line. */
.prose .lede { max-width: none; margin-top: 14px; }
.prose h2 { font-size: 23px; margin-top: 46px; }
.prose > h2:first-child { margin-top: 0; }
.prose p { color: var(--soft); margin-top: 12px; }
.prose p strong, .prose li strong { color: var(--text); font-weight: 700; }
.prose ul { margin-top: 12px; padding-left: 22px; color: var(--soft); }
.prose li { margin-top: 7px; }
.prose.page-head { padding: 56px 0 8px; }

/* The Kit section's way forward, between the cards and the small print. Its own
   rule rather than .cta-row because it is centred under a full-width grid,
   where the hero's left-aligned row would hang off one edge. */
.kit-cta { margin-top: 32px; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.kit-cta .url { font-size: 14px; color: var(--faint); }

/* --------------------- the paid extras section -------------------------- */

/* This section carries two paid features rather than one, so the small tag
   above each card is what tells a parent which of the three they are reading
   about and whether it costs anything. Same .tag as the "how it works" cards,
   sized down: there it is the last line of a big card, here it is a label
   above a title. */
.tag.sm { padding: 4px 10px; border-radius: 7px; font-size: 12px; font-weight: 700; letter-spacing: .04em; }
/* .kit-face was sized to sit over the whole section. It is a card badge now,
   so it takes the badge's own box and drops the shadow, which only read
   against the page and not against a card. */
.kit-face.sm { width: 46px; height: 46px; border-radius: 13px; box-shadow: none; }
/* .beta is dimensioned for an h2. Inside a card's h3 it needs to come down a
   step or it outweighs the name it is qualifying. */
.card h3 .beta { margin-left: 8px; padding: 2px 8px 3px; font-size: 11.5px; top: -2px; }

/* The card that says what the paid features will NOT do. Full width under the
   three, and green-bordered, because a parent who reads one card of four
   should read this one. */
.honest { margin-top: 22px; border-color: #0FA98F59; background: var(--time-dim); }
.honest p { font-size: 16px; }

.extras-cta { margin-top: 30px; display: flex; flex-direction: column; align-items: center; gap: 18px; text-align: center; }
.extras-cta .fine { color: var(--soft); font-size: 14.5px; line-height: 1.55; max-width: 58ch; }
/* The hero's .cta-row is left-aligned under left-aligned copy. Here it sits
   under a centred column, and on a phone the two buttons wrap onto separate
   lines, where flex-start would leave them hanging off one edge. */
.extras-cta .cta-row { justify-content: center; }

/* ----------------------- marked from a photo ---------------------------- */

/* Copy beside a mockup, rather than the centred .section-head the rest of the
   page uses: the picture is the argument here, and a centred heading over it
   would leave the two reading as separate sections. */
.split { display: grid; gap: 44px; align-items: center; grid-template-columns: 1fr; }
@media (min-width: 960px) { .split { grid-template-columns: 1fr 380px; } }
.split-copy { display: flex; flex-direction: column; align-items: flex-start; gap: 18px; }
.split-copy h2 { font-size: clamp(28px, 4.4vw, 40px); line-height: 1.12; }
.split-copy > p { color: var(--soft); font-size: 17px; line-height: 1.55; max-width: 48ch; }
/* The hero's ticks are three short phrases along one row. These are sentences
   under a narrower column, so they stack rather than wrap raggedly. */
.ticks.stack { flex-direction: column; align-items: flex-start; gap: 11px; }
/* Top-aligned, not centred: these wrap to two lines on a phone, and a tick
   floating beside the middle of a two-line sentence reads as unattached. */
.ticks.stack li { align-items: flex-start; font-size: 15.5px; color: var(--soft); }
.ticks.stack svg { margin-top: 5px; }

/* The mockup is drawn here rather than exported as an image: it stays crisp at
   any width, costs no download, and cannot go stale while the screen it
   depicts is still being built. It is also why there is still no JavaScript on
   this site outside the migration plumbing.
   min-width: 0 for exactly the reason .demo carries it: a grid item's
   automatic minimum size is min-content, and the three counts tiles would
   refuse to shrink below their own width and push a phone sideways. */
.shot {
  min-width: 0; justify-self: center; width: 100%; max-width: 380px;
  background: #0E0E13; border: 1px solid var(--line);
  border-radius: 30px; padding: 11px;
  box-shadow: 0 24px 50px -12px #00000073;
}
.shot-screen {
  background: var(--bg); border-radius: 21px; padding: 18px 15px 20px;
  display: flex; flex-direction: column; gap: 13px;
}
.shot-bar { display: flex; align-items: center; gap: 8px; font-size: 12.5px; font-weight: 700; color: var(--soft); }
.shot-bar svg { width: 15px; height: 15px; color: var(--violet); flex: none; }
.shot-file { font-family: var(--serif); font-size: 19px; font-weight: 600; color: var(--text); line-height: 1.2; }

.shot-counts { display: flex; gap: 8px; list-style: none; padding: 0; margin: 2px 0 2px; }
.shot-counts li {
  flex: 1 1 0; min-width: 0; padding: 11px 6px 10px; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--line); text-align: center;
}
.shot-counts b { display: block; font-family: var(--serif); font-size: 25px; font-weight: 600; color: var(--text); line-height: 1.05; }
.shot-counts span { display: block; margin-top: 4px; font-size: 11px; line-height: 1.25; color: var(--faint); }

.shot-item {
  border-radius: 13px; padding: 12px 13px; border: 1px solid var(--line);
  background: var(--surface); display: flex; flex-direction: column; gap: 7px;
}
/* A slip and a hand-back are different events and must not look alike: the
   first is marked, the second deliberately is not. */
.shot-item.slip { border-color: var(--english); background: #2B161C; }
.shot-item.ask { border-color: var(--games); background: var(--games-dim); }
.shot-q { display: flex; align-items: center; gap: 9px; font-size: 15px; font-weight: 700; color: var(--text); }
.shot-mark {
  width: 20px; height: 20px; border-radius: 10px; flex: none;
  display: flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 800; line-height: 1;
}
.shot-item.slip .shot-mark { background: var(--english); color: #15151A; }
.shot-item.ask .shot-mark { background: var(--games); color: #15151A; }
.shot-note { font-size: 12.5px; line-height: 1.45; color: var(--soft); }
.shot-link {
  align-self: flex-start; padding: 5px 10px; border-radius: 7px;
  background: var(--band); color: var(--violet); font-size: 11.5px; font-weight: 700;
}

/* ------------------ the pricing page's parents' side -------------------- */

/* The homepage's stacked ticks sit in a left-aligned column beside the phone
   mockup. Here they are a short pair under a centred .section-head, so they
   take a column of their own: centring them one item at a time would leave
   the two ticks on different left edges, which reads as two stray lines
   rather than as a list. */
.ticks.centred { width: fit-content; max-width: 100%; margin: 0 auto; }

/* The hero's .pill, under centred copy rather than at the left edge of the
   hero column. It is inline-flex, so it needs a row to centre inside. */
.pill-row { margin-top: 28px; display: flex; justify-content: center; }
.pill-row .pill { line-height: 1.5; text-align: center; }

/* The green "honest bit" card again, this time closing the credits
   explainer. Restated at .band-deep's own weight rather than reordered:
   `.band-deep .card` outranks a bare `.honest` on specificity, so without
   this the panel would silently come out the band's grey, and the one card
   on the page meant to be found would look like every other. */
.band-deep .card.honest { background: var(--time-dim); border-color: #0FA98F59; }
.prose .card.honest { margin-top: 30px; }
.prose .card.honest p { margin-top: 0; color: var(--soft); font-size: 16px; }
