/*
 * GrailFox website.
 *
 * One stylesheet, five pages, no build step. Every rule below is transcribed by
 * hand from the approved export in `design-reference/GrailFoxWeb.dc.html`; the
 * line ranges in the comments are that file's, the way the mobile code cites
 * `GrailFox.dc.html:535–598`. Read the referenced lines before changing a rule.
 *
 * Tokens are transcribed from mobile/src/design/tokens.ts and must stay equal to
 * it — the site and the app are meant to read as one object. No colour may be
 * written anywhere below except in the :root block.
 *
 * The palette is written in rgb()/rgba() rather than hex, deliberately. The
 * stray-colour check in the plan is
 *
 *     grep -nE '#[0-9A-Fa-f]{3,8}' web/style.css | grep -v ':root' | ...
 *
 * which only drops the line that literally says `:root` — a hex token on its own
 * line would be reported as a stray colour. Writing the palette in rgb() makes
 * that check exact instead of approximate: any `#` in this file is, by
 * definition, a colour that escaped the token block. The channel values are
 * unchanged; each token carries the name of its key in tokens.ts, which is where
 * the hex originals live and stay — repeating them here would be a second copy
 * of the same fact, free to drift.
 */

/* Newsreader 500, latin subset, self-hosted. A font loaded from a third-party
   CDN sends every visitor's IP address to that provider, which is the request
   this whole site is built to avoid. Licence: fonts/OFL.txt (SIL OFL 1.1). */
@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('fonts/newsreader-500.woff2') format('woff2');
}

:root {
  /* Palette — tokens.ts `color`. */
  --ink: rgb(22, 19, 15);                    /* color.ink */
  --ink-button: rgb(27, 23, 18);             /* color.inkButton */
  --ink90: rgba(22, 19, 15, 0.90);
  --ink75: rgba(22, 19, 15, 0.75);
  --ink70: rgba(22, 19, 15, 0.70);           /* color.ink70 */
  --ink68: rgba(22, 19, 15, 0.68);
  --ink60: rgba(22, 19, 15, 0.60);
  --ink58: rgba(22, 19, 15, 0.58);
  --ink55: rgba(22, 19, 15, 0.55);           /* color.ink55 */
  --ink50: rgba(22, 19, 15, 0.50);
  --ink45: rgba(22, 19, 15, 0.45);
  --ink42: rgba(22, 19, 15, 0.42);           /* color.ink42 */
  --ink38: rgba(22, 19, 15, 0.38);
  --ink20: rgba(22, 19, 15, 0.20);
  --ink18: rgba(22, 19, 15, 0.18);
  --ink14: rgba(22, 19, 15, 0.14);
  --hairline: rgba(22, 19, 15, 0.09);        /* color.hairline */
  --hairline-soft: rgba(22, 19, 15, 0.07);
  --hairline-faint: rgba(22, 19, 15, 0.06);
  --canvas: rgb(251, 250, 248);              /* color.canvas */
  --surface: rgb(255, 255, 255);             /* color.surface */
  --fill: rgb(241, 238, 231);                /* color.fill */
  --muted: rgb(245, 242, 235);               /* color.muted */
  --amber: rgb(233, 169, 59);                /* color.amber */
  --amber-ink: rgb(138, 100, 16);            /* color.amberInk */
  --success: rgb(47, 122, 87);               /* color.success */
  --success-tint: rgb(231, 241, 235);        /* color.successTint */
  --success-ink: rgb(42, 107, 76);           /* successInk */
  --caution-dot: rgb(184, 134, 11);          /* caution.dot */
  --danger: rgb(176, 71, 59);                /* color.danger */

  /* Links — GrailFoxWeb.dc.html:16–17. Not an app token: the app has no links. */
  --link: rgb(165, 108, 18);
  --link-hover: rgb(126, 81, 11);

  /* Inside the device illustrations only. Nothing on the page itself may use
     these — they are the app's on-dark chrome, seen through a screenshot. */
  --device-black: rgb(0, 0, 0);
  --device-light: rgb(242, 242, 247);
  --camera-1: rgb(43, 39, 35);
  --camera-2: rgb(20, 18, 16);
  --camera-3: rgb(10, 9, 8);                 /* color.cameraBg */
  --on-dark: rgba(255, 255, 255, 0.92);
  --on-dark-label: rgba(255, 255, 255, 0.78);
  --on-dark-sub: rgba(255, 255, 255, 0.42);
  --on-dark-hairline: rgba(255, 255, 255, 0.15);
  --on-dark-sheen: rgba(255, 255, 255, 0.055);
  --on-dark-clear: rgba(255, 255, 255, 0);
  --home-dark: rgba(255, 255, 255, 0.70);
  --home-light: rgba(0, 0, 0, 0.25);

  /* The rarity-tinted striped placeholder that stands in for card art. It is the
     only card illustration on the site — CardArt.dc.html, mobile CardArt.tsx:24–27. */
  --art-bg: rgb(59, 55, 48);
  --art-secret-1: rgb(75, 68, 104);
  --art-secret-2: rgb(44, 39, 64);
  --art-secret-3: rgb(30, 27, 44);
  --art-illus-1: rgb(47, 90, 86);
  --art-illus-2: rgb(31, 63, 61);
  --art-illus-3: rgb(22, 48, 46);
  --art-holo-1: rgb(106, 83, 48);
  --art-holo-2: rgb(66, 52, 30);
  --art-holo-3: rgb(46, 37, 23);
  --art-common-1: rgb(74, 70, 64);
  --art-common-2: rgb(53, 50, 45);
  --art-common-3: rgb(40, 37, 33);

  --shadow-frame: 0 40px 80px rgba(0, 0, 0, 0.18), 0 0 0 1px rgba(0, 0, 0, 0.12);
  --shadow-sheet: 0 -12px 40px rgba(0, 0, 0, 0.30);
  --shadow-art: 0 1px 2px rgba(0, 0, 0, 0.22), 0 10px 26px rgba(0, 0, 0, 0.16);
  --shadow-seg: 0 1px 2px rgba(22, 19, 15, 0.09);

  --r-chip: 9px;
  --r-control: 11px;
  --r-button: 15px;
  --r-card: 18px;

  --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
  --s5: 20px; --s6: 24px; --s7: 32px; --s8: 40px;

  --shadow-card: 0 1px 2px rgba(22, 19, 15, 0.06);

  --sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --serif: 'Newsreader', Georgia, serif;
  --mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  --wrap: 1120px;

  /* Two viewport states, not a fluid scale: the design was approved at exactly
     1200 and 375 — GrailFoxWeb.dc.html:723–743. Desktop values here, phone
     values in the one media query at the foot of this block. */
  --hero-y: 76px;
  --sec-y: 92px;
  --band-y: 76px;
  --doc-y: 64px;
  --fs-hero: 58px;
  --fs-sub: 20px;
  --fs-band: 40px;
  --fs-section-serif: 42px;
  --fs-doc-title: 46px;
}

@media (max-width: 767px) {
  :root {
    --hero-y: 40px;
    --sec-y: 56px;
    --band-y: 48px;
    --doc-y: 40px;
    --fs-hero: 34px;
    --fs-sub: 17px;
    --fs-band: 25px;
    --fs-section-serif: 28px;
    --fs-doc-title: 32px;
  }
}

*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font: 400 17px/1.45 var(--sans);
  letter-spacing: -0.01em;
  -webkit-font-smoothing: antialiased;
}

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

/* The design frames the site at 1200px with 40px gutters and an inner column of
   1120px — GrailFoxWeb.dc.html:730–731 and every `max-width:1120px` inside a
   section. box-sizing is border-box, so the gutters are added to --wrap here
   rather than eaten out of it. */
@media (min-width: 768px) {
  .wrap {
    max-width: calc(var(--wrap) + var(--s8) + var(--s8));
    padding: 0 var(--s8);
  }
}

@media (max-width: 767px) {
  .wrap { padding: 0 var(--s4); }
}

/* The document pages. `.doc` carries the vertical rhythm only — GrailFoxWeb.dc
   .html:375, `docPadY` at :739 — and leaves the horizontal gutter to `.wrap`,
   the way every home-page section does.

   A measure this narrow is the whole reason long legal text is readable at all,
   so the 68ch lives on `.doc-head` and `.doc-body`, which are the two blocks
   that actually carry prose. It cannot live on `.doc` itself: the design puts a
   sticky table of contents beside the text (:387, :442, :512) and a 68ch <main>
   leaves nowhere to put it. The rest of the template is under "Document pages"
   below. */
.doc { padding-top: var(--doc-y); }

/* Section label — GrailFoxWeb.dc.html:141, 247, 332, 356, 586. The design sets
   600 here; the type ramp at 781 names it "SECTION LABEL · SF 600 · 12/12 · +6%". */
.label {
  font-size: 12px; line-height: 16px; font-weight: 600;
  letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink42);
}
h2.label { margin: 0 0 var(--s7); }

.card {
  background: var(--surface);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  padding: var(--s5);
}

/* The export lays everything out with flex gaps and explicit margins, so where
   a <div> there became a <p> or an <h3> here the browser's default block
   margins have to go or the transcribed spacing is wrong. :where() keeps this
   at zero specificity, so every rule below still wins over it. */
:where(.bezel p, .bezel h3, .price-card h3, .price-card p,
       .step-head, .collection-lede, .footer-grid p) { margin: 0; }

/* Keyboard users must be able to see where they are. Never remove this.
   Ring transcribed from the export's global styles — GrailFoxWeb.dc.html:19. */
:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
a:focus-visible { border-radius: 3px; }

img, svg { max-width: 100%; height: auto; }

a { color: var(--link); text-decoration: none; }             /* :16 */
a:hover { color: var(--link-hover); }                        /* :17 */

/* ─────────────────────────────────────────────────────────────────────────────
   Header — GrailFoxWeb.dc.html:52–66
   ──────────────────────────────────────────────────────────────────────────── */

.site-header { border-bottom: 1px solid var(--hairline); }

.header-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s6);
  padding-top: var(--s5);
  padding-bottom: var(--s5);
}

.wordmark { display: flex; align-items: center; gap: 9px; color: var(--ink); }
.wordmark:hover { color: var(--ink); }
.wordmark-text {
  font-family: var(--serif);
  font-size: 21px;
  font-weight: 500;
  letter-spacing: -0.015em;
}

/* The mark is `assets/grailfox-mark.svg`, a copy of the app's master at
   mobile/assets/brand/grailfox-mark.svg — imported, never transcribed, so there
   is no second copy of the path data to drift. The prototype's rotated amber
   diamond (GrailFoxWeb.dc.html:54) was a stand-in from before brand delivered
   the mark; what the design fixes is the 26px rounded square around it.

   The master carries its own dark ground, so the container supplies only the
   corner radius — 26 × 0.308 ≈ 8px, the same ratio as mobile Wordmark.tsx:23.
   `overflow: hidden` is what rounds the corners; the master is a hard square by
   design and is not modified to fit. */
.mark {
  width: 26px; height: 26px; flex: none;
  border-radius: var(--s2);
  background: var(--ink-button);
  overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.mark img { display: block; width: 26px; height: 26px; max-width: none; }

.header-nav { display: flex; align-items: center; gap: var(--s5); }
.nav-link { font: 500 15px/1 var(--sans); color: var(--ink60); }
.nav-link:hover { color: var(--ink); }

/* The pre-launch call to action — spec §7, "a pill reading 'Coming to the App
   Store' … exists because the site must be live *before* the app is approved."

   The design export replaced that pill with Apple's badge and a transcription
   note saying to ship the badge without an `href` until release day
   (GrailFoxWeb.dc.html:679); the spec was never amended, and the export is
   wrong here. Apple's Marketing Guidelines license the badge as a link to a
   product page — an unlinked copy is the asset used outside the terms it comes
   with. It is also a lie told to a screen reader, which announces "Download on
   the App Store" and then finds nothing to activate. So until there is a URL,
   the site says what is true, in its own type. The badge returns on release
   day, inside an `<a href="https://apps.apple.com/…">`, and `web/check.sh`
   fails the build if the asset ever appears without that link on the line.

   Our own design, so no export line reference: a hairline pill in the site's
   sans, sized to the badge it stands in for (54px, 42px compact) so the layouts
   around it need no second set of numbers. The amber dot is the only colour, and
   is the app's accent. */
.pill {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin: 0;
  height: 54px;
  padding: 0 22px;
  border: 1px solid var(--ink20);
  border-radius: 999px;
  background: var(--surface);
  font: 500 15px/1.2 var(--sans);
  letter-spacing: -0.005em;
  color: var(--ink70);
}
.pill::before {
  content: "";
  width: 7px; height: 7px; flex: none;
  border-radius: 50%;
  background: var(--amber);
}
.pill-compact { height: 42px; padding: 0 16px; font-size: 14px; }

/* Apple's badge, used unmodified. Height is the only thing we set; the aspect
   ratio comes from the asset. Nothing references it while the app is
   unpublished — see `.pill` above — and these two lines are kept so that
   release day is one markup change rather than a markup change plus a guess at
   the sizing the layouts were built around. */
.badge { display: block; height: 54px; width: auto; }
.badge-compact { height: 42px; }

/* The design drops the header call to action on a phone so only one sits above
   the fold — GrailFoxWeb.dc.html:59 (`headerBadge: !phone`), :741. */
@media (max-width: 767px) {
  .header-nav .pill-compact,
  .header-nav .badge-compact { display: none; }
}

/* ─────────────────────────────────────────────────────────────────────────────
   Hero — GrailFoxWeb.dc.html:71–130
   ──────────────────────────────────────────────────────────────────────────── */

.hero { padding-top: var(--hero-y); }

.hero-row {
  display: flex;
  flex-wrap: wrap;
  gap: 48px;
  align-items: center;
  justify-content: space-between;
}

.hero-copy {
  flex: 1 1 420px;
  min-width: 0;
  max-width: 600px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 22px;
}

.hero-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--fs-hero);
  line-height: 1.06;
  letter-spacing: -0.03em;
  text-wrap: pretty;
}

.hero-sub {
  margin: 0;
  font: 400 var(--fs-sub)/1.5 var(--sans);
  color: var(--ink68);
  letter-spacing: -0.01em;
  text-wrap: pretty;
  max-width: 52ch;
}

.hero-note {
  margin: 0;
  font: 400 14.5px/1.5 var(--sans);
  color: var(--ink50);
  max-width: 46ch;
}

.hero-cta { margin: 6px 0 0; }

/* ─────────────────────────────────────────────────────────────────────────────
   Positioning band — GrailFoxWeb.dc.html:132–137
   ──────────────────────────────────────────────────────────────────────────── */

.band {
  margin-top: var(--sec-y);
  background: var(--muted);
  border-top: 1px solid var(--hairline-faint);
  border-bottom: 1px solid var(--hairline-faint);
  padding: var(--band-y) 0;
}

.band-quote {
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--fs-band);
  line-height: 1.2;
  letter-spacing: -0.025em;
  max-width: 20ch;
  text-wrap: pretty;
}

.band-sub {
  margin: 18px 0 0;
  font: 400 15.5px/1.55 var(--sans);
  color: var(--ink55);
  max-width: 56ch;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Sections — every one is `padding: secPadY padX 0` in the export
   ──────────────────────────────────────────────────────────────────────────── */

.section { padding-top: var(--sec-y); }

/* How it works — GrailFoxWeb.dc.html:139–169 */
.steps {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 36px var(--s8);
}

.step { display: flex; flex-direction: column; gap: 14px; }

/* The icons are transcribed path-for-path from :144, :152, :160 — they are the
   app's line style and are not redrawn. Only their colours moved into CSS. */
.step-icon { color: var(--ink); flex: none; }
.ico-accent { stroke: var(--amber); }
.ico-knockout { fill: var(--canvas); }

.step-head { display: flex; align-items: baseline; gap: 9px; }
.step-n {
  font: 600 15px/1 var(--sans);
  color: var(--amber);
  font-variant-numeric: tabular-nums;
}
.step-t { font: 600 19px/1.3 var(--sans); letter-spacing: -0.015em; }
.step-b {
  margin: 0;
  font: 400 15.5px/1.6 var(--sans);
  color: var(--ink60);
  max-width: 34ch;
}

/* "When we're not sure, we ask." — GrailFoxWeb.dc.html:171–233.
   wrap-reverse puts the frame left of the copy on one line, and the copy above
   the frame once it wraps, which is the order a phone should read in. */
.split {
  display: flex;
  flex-wrap: wrap-reverse;
  gap: 56px;
  align-items: center;
  justify-content: space-between;
}

.split-copy {
  flex: 1 1 380px;
  min-width: 0;
  max-width: 520px;
  display: flex;
  flex-direction: column;
  gap: var(--s5);
}

.split-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--fs-section-serif);
  line-height: 1.12;
  letter-spacing: -0.025em;
  text-wrap: pretty;
}

.split-body {
  margin: 0;
  font: 400 16.5px/1.65 var(--sans);
  color: var(--ink68);
  max-width: 52ch;
  text-wrap: pretty;
}

/* The one call to action, on its own — GrailFoxWeb.dc.html:235–242 */
.cta-row { display: flex; justify-content: center; }

/* Your collection — GrailFoxWeb.dc.html:244–328 */
.collection-row {
  display: flex;
  flex-wrap: wrap;
  gap: 56px;
  align-items: center;
  justify-content: space-between;
}

.collection-copy {
  flex: 1 1 360px;
  min-width: 0;
  max-width: 460px;
  display: flex;
  flex-direction: column;
  gap: 22px;
}

.collection-lede {
  margin: 0;
  font: 600 30px/1.2 var(--sans);
  letter-spacing: -0.028em;
  text-wrap: pretty;
}

.dot-list { list-style: none; margin: 0; padding: 0; }
.dot-list li {
  display: flex;
  gap: 13px;
  align-items: flex-start;
  padding: 15px 0;
  border-top: 1px solid var(--hairline);
  font: 400 16px/1.5 var(--sans);
  color: var(--ink70);
}
.dot-list li:last-child { border-bottom: 1px solid var(--hairline); }
.dot-list li::before {
  content: "";
  width: 5px; height: 5px; flex: none;
  margin-top: var(--s2);
  border-radius: 50%;
  background: var(--amber);
}

/* Pricing — GrailFoxWeb.dc.html:330–352 */
.price-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: var(--s4);
}

.price-card {
  border: 1px solid var(--hairline);
  padding: var(--s6);
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.price-name { font: 600 17px/1.3 var(--sans); letter-spacing: -0.015em; }
/* The unit now carries "US price" as well as the period, because a bare figure
   is a claim about what the reader will be charged and the store decides that
   (index.html's pricing comment). At the 250px column the grid can produce,
   amount + unit no longer fit on one line, so the row wraps instead of
   overflowing the card; `line-height: 1` would collide once it does. */
.price-figure { display: flex; align-items: baseline; flex-wrap: wrap; gap: 2px 7px; }
.price-amount {
  font: 600 30px/1 var(--sans);
  letter-spacing: -0.03em;
  font-variant-numeric: tabular-nums;
}
.price-unit { font: 400 15px/1.35 var(--sans); color: var(--ink50); }
.price-body { margin: 6px 0 0; font: 400 14.5px/1.55 var(--sans); color: var(--ink60); }
.price-note {
  margin: var(--s4) 0 0;
  font: 400 13.5px/1.55 var(--sans);
  color: var(--ink45);
  max-width: 70ch;
}

/* Questions — GrailFoxWeb.dc.html:354–369. <details> needs no JavaScript and is
   open to search engines, which is the whole reason the design uses it. */
.faq-row { display: flex; flex-wrap: wrap; gap: var(--s8); }

.faq-row > h2.label {
  flex: 0 0 200px;
  margin: 0;
  padding-top: 22px;
}

.faq-list {
  flex: 1 1 520px;
  min-width: 0;
  max-width: 760px;
  border-top: 1px solid var(--hairline);
}

.faq-list details { border-bottom: 1px solid var(--hairline); }

.faq-list summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s5);
  padding: var(--s5) 0;
  cursor: pointer;
  list-style: none;
  font: 500 18px/1.4 var(--sans);
  letter-spacing: -0.015em;
}
.faq-list summary::-webkit-details-marker { display: none; }   /* :20 */

.chev { flex: none; transition: transform 0.18s ease; }        /* :21 */
.chev path { stroke: var(--ink45); }
.faq-list details[open] summary .chev { transform: rotate(180deg); }

@media (prefers-reduced-motion: reduce) {
  .chev { transition: none; }
}

.faq-list p {
  margin: 0 0 22px;
  font: 400 16px/1.65 var(--sans);
  color: var(--ink68);
  max-width: 64ch;
  text-wrap: pretty;
}

/* ─────────────────────────────────────────────────────────────────────────────
   Document pages — GrailFoxWeb.dc.html:374–427 privacy, 429–482 terms,
   484–537 support, 539–581 impressum
   ─────────────────────────────────────────────────────────────────────────────
   One template, four documents. Everything below is shared by all four; only
   the contact card (support) and the identification list (impressum) belong to
   a single page, and they say so.

   The rhythm is fixed by the design's own note at :685–689 — measure 68ch, body
   16.5/1.7, heading 20/1.35 with 40 above and 12 below, numbered so a clause can
   be cited. Changing any of those four numbers changes every legal page at once,
   which is the point of there being one template.
   ──────────────────────────────────────────────────────────────────────────── */

.doc-head { max-width: 68ch; margin: 0 0 var(--s8); }
.doc p.label { margin: 0 0 var(--s4); }

.doc-title {
  margin: 0;
  font-family: var(--serif);
  font-weight: 500;
  font-size: var(--fs-doc-title);
  line-height: 1.1;
  letter-spacing: -0.025em;
  text-wrap: pretty;
}

.doc-lede {
  margin: var(--s4) 0 0;
  font: 400 16px/1.6 var(--sans);
  color: var(--ink55);
  max-width: 60ch;
  text-wrap: pretty;
}

/* Draft banner — :381–384. It is on the page for exactly as long as the wording
   is placeholder, and removing it is the last step of the legal session, not a
   tidy-up. The amber dot is the same 5px mark as `.dot-list` and `.hint`. */
.doc-draft {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  max-width: 60ch;
  margin: 22px 0 0;
  padding: 13px 15px;
  background: var(--muted);
  border-radius: 13px;
  font: 400 14px/1.5 var(--sans);
  color: var(--ink58);
  text-wrap: pretty;
}
.doc-draft::before {
  content: "";
  width: 5px; height: 5px; flex: none;
  margin-top: 7px;
  border-radius: 50%;
  background: var(--amber);
}

/* Table of contents beside the text — :386–400 */
.doc-cols {
  display: flex;
  flex-wrap: wrap;
  gap: 56px;
  align-items: flex-start;
}

.doc-toc { flex: 0 0 190px; position: sticky; top: var(--s6); }
.doc-toc p.label { margin-bottom: 14px; }
.toc-links { display: flex; flex-direction: column; gap: 9px; }
.toc-links a { font: 400 14px/1.4 var(--sans); }

/* Sticky is a desktop affordance. Once the nav wraps above the text it is in a
   row of its own, and a sticky element there rides down over the paragraphs it
   is supposed to index. */
@media (max-width: 767px) {
  .doc-cols { gap: var(--s7); }
  .doc-toc { position: static; }
}

.doc-body { flex: 1 1 520px; min-width: 0; max-width: 68ch; }
.doc-body h2 {
  margin: var(--s8) 0 var(--s3);
  font: 600 20px/1.35 var(--sans);
  letter-spacing: -0.015em;
  scroll-margin-top: var(--s6);
}
.doc-body > :first-child { margin-top: 0; }
.doc-body p {
  margin: 0 0 var(--s4);
  font: 400 16.5px/1.7 var(--sans);
  color: var(--ink75);
  text-wrap: pretty;
}

/* Support's contact card — :493–509. Apple requires the support URL to give a
   user a real way to make contact, so this sits above everything else on the
   page and is reachable without scrolling on a phone. */
.contact-card {
  border: 1px solid var(--hairline);
  padding: 28px;
  margin-bottom: 48px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 28px;
}
.contact-card p.label { margin: 0 0 10px; }
.contact-email { margin: 0; font: 500 19px/1.3 var(--sans); letter-spacing: -0.015em; }
.contact-name { margin: 0; font: 500 16px/1.5 var(--sans); }
.contact-note { margin: var(--s2) 0 0; font: 400 14px/1.55 var(--sans); color: var(--ink55); }

/* Impressum's identification list — :548–569. A reader has to find the address
   in about a second, which is why it is a list near the top and not prose. */
.imp-list {
  max-width: 640px;
  margin: 0 0 36px;
  padding: var(--s1) var(--s6);
  border: 1px solid var(--hairline);
}
.imp-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s1) var(--s6);
  padding: 18px 0;
  border-bottom: 1px solid var(--hairline);
}
.imp-row:last-child { border-bottom: 0; }
.imp-list dt { flex: 0 0 150px; line-height: 1.6; }
.imp-list dd { flex: 1 1 220px; margin: 0; font: 400 16.5px/1.6 var(--sans); }
.imp-note { color: var(--ink55); font-size: 15px; }
.imp-slot {
  font: 500 9.5px/1.6 var(--mono);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink38);
}

/* ─────────────────────────────────────────────────────────────────────────────
   Footer — GrailFoxWeb.dc.html:583–612
   ──────────────────────────────────────────────────────────────────────────── */

.site-footer {
  margin-top: var(--sec-y);
  border-top: 1px solid var(--hairline);
  padding: 44px 0 48px;
}

.footer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 36px var(--s8);
}

.footer-grid h2 { margin: 0 0 14px; }
.footer-links { display: flex; flex-direction: column; gap: 10px; }
.footer-links a,
.footer-contact a { font: 400 15px/1.4 var(--sans); }
.footer-operator { font: 400 15px/1.5 var(--sans); color: var(--ink70); }
.footer-contact { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.footer-meta { font: 400 13px/1.5 var(--sans); color: var(--ink45); margin: 18px 0 0; }
.footer-meta + .footer-meta { margin-top: var(--s2); max-width: 44ch; }

/* ─────────────────────────────────────────────────────────────────────────────
   Device illustrations — GrailFoxWeb.dc.html:84–129, 173–226, 264–326
   ─────────────────────────────────────────────────────────────────────────────
   Three screenshots of the app, drawn in HTML and CSS. The export imports a
   React component for the bezel (`ios-frame.jsx`); this site runs no JavaScript
   and no React, so the frame is rebuilt here from the same measurements:
   402 × 874, radius 48, a 126 × 37 dynamic island, a 139 × 5 home indicator.
   The screen is authored at full size and scaled down as one block, exactly as
   the export does at :86 and :723, so every inner measurement stays the design's.
   Prices inside a frame are illustration inside a product screenshot; no price
   appears as page content anywhere on this site — docs/RISKS.md R-01.
   ──────────────────────────────────────────────────────────────────────────── */

.device { flex: none; width: 330px; height: 717px; }
.device-inner {
  width: 402px; height: 874px;
  transform: scale(0.82);
  transform-origin: top left;
}

@media (max-width: 767px) {
  .device { width: 314px; height: 682px; }
  .device-inner { transform: scale(0.78); }
}

.bezel {
  position: relative;
  width: 402px; height: 874px;
  border-radius: 48px;
  overflow: hidden;
  background: var(--device-black);
  box-shadow: var(--shadow-frame);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}
.bezel--light { background: var(--device-light); }

.island {
  position: absolute;
  top: 11px; left: 50%;
  transform: translateX(-50%);
  width: 126px; height: 37px;
  border-radius: var(--s6);
  background: var(--device-black);
  z-index: 50;
}

.status {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 21px var(--s6) 19px;
  color: var(--device-black);
}
.status--dark { color: var(--surface); }
.status-time { font: 590 17px/22px var(--sans); }
.status-glyphs { display: flex; align-items: center; gap: 7px; }

.home-indicator {
  position: absolute;
  left: 50%; bottom: var(--s2);
  transform: translateX(-50%);
  width: 139px; height: 5px;
  border-radius: 100px;
  background: var(--home-dark);
  z-index: 60;
}
.bezel--light .home-indicator { background: var(--home-light); }

/* The camera surface behind a result sheet — :88, :177 */
.camera {
  position: absolute;
  inset: 0;
  background: radial-gradient(118% 74% at 50% 40%,
              var(--camera-1) 0%, var(--camera-2) 58%, var(--camera-3) 100%);
}

/* The result sheet — :89, :178 */
.sheet {
  position: absolute;
  left: 0; right: 0; bottom: 0; top: 60px;
  background: var(--canvas);
  border-radius: 22px 22px 0 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  box-shadow: var(--shadow-sheet);
}
.grabber {
  flex: none;
  width: 36px; height: 5px;
  margin: 9px auto 0;
  border-radius: 3px;
  background: var(--ink14);
}
.sheet-body { flex: 1; overflow: hidden; padding: 14px 22px var(--s5); }
.sheet-body--candidates { padding-top: var(--s4); }
.sheet-foot {
  flex: none;
  padding: var(--s3) 22px var(--s8);
  border-top: 1px solid var(--hairline-soft);
}
.sheet-cta {
  height: 52px;
  border-radius: var(--r-button);
  background: var(--ink-button);
  color: var(--canvas);
  display: flex; align-items: center; justify-content: center;
  font: 600 17px/1 var(--sans);
  letter-spacing: -0.01em;
}

/* Exact-match chip — :93 */
.chip-ok {
  display: flex; align-items: center; gap: 6px;
  width: max-content;
  margin: 0 auto var(--s4);
  height: 26px; padding: 0 11px;
  border-radius: 13px;
  background: var(--success-tint);
  font: 600 12px/1 var(--sans);
  color: var(--success-ink);
}
.chip-ok path { stroke: var(--success); }

.result-art { width: 150px; margin: 0 auto 18px; }
.result-name {
  text-align: center;
  font: 600 23px/1.22 var(--sans);
  letter-spacing: -0.025em;
}
.result-set {
  text-align: center;
  font: 400 14.5px/1.4 var(--sans);
  color: var(--ink50);
  margin: 5px 0 18px;
}

/* Estimated value card — :103 */
.value-card {
  background: var(--surface);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--r-card);
  padding: 18px 18px var(--s4);
}
.frame-label {
  font: 500 12px/1 var(--sans);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink42);
}
.value-figure {
  display: flex; align-items: baseline; gap: 9px; flex-wrap: wrap;
  margin-top: var(--s2);
}
.value-amount {
  font: 600 40px/1 var(--sans);
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
}
.value-cond { font: 400 14px/1.2 var(--sans); color: var(--ink50); }
.value-range { font: 400 13.5px/1.4 var(--sans); color: var(--ink50); margin-top: 7px; }
.value-rule {
  border: 0;
  height: 1px;
  background: var(--hairline-soft);
  margin: 14px 0 var(--s3);
}
.value-source { font: 400 12px/1.4 var(--sans); color: var(--ink38); margin-top: 11px; }

/* Condition segmented control — :112 */
.segmented {
  display: flex; gap: var(--s1);
  background: var(--fill);
  border-radius: 10px;
  padding: 3px;
  margin-top: 9px;
}
.segmented span {
  flex: 1;
  height: var(--s7);
  display: flex; align-items: center; justify-content: center;
  font: 600 12.5px/1 var(--sans);
  color: var(--ink50);
}
.segmented .is-on {
  border-radius: var(--s2);
  background: var(--surface);
  box-shadow: var(--shadow-seg);
  color: var(--ink);
}

/* Candidates screen — :181–:217 */
.cand-title { font: 600 22px/1.24 var(--sans); letter-spacing: -0.025em; margin-bottom: 5px; }
.cand-sub {
  font: 400 14.5px/1.45 var(--sans);
  color: var(--ink55);
  margin-bottom: 18px;
  text-wrap: pretty;
}
.cand-list { display: flex; flex-direction: column; gap: 9px; margin-bottom: 14px; }
.cand {
  display: flex; gap: 13px; align-items: center;
  padding: var(--s3);
  border-radius: var(--s4);
  background: var(--surface);
  border: 1.5px solid var(--hairline);
}
.cand.is-picked { border-color: var(--ink-button); }
.cand-art { width: 56px; flex: none; }
.cand-text { flex: 1; min-width: 0; }
.cand-print { font: 600 15.5px/1.25 var(--sans); letter-spacing: -0.015em; }
.cand-set { font: 400 13px/1.4 var(--sans); color: var(--ink50); margin-top: 3px; }
.cand-price {
  font: 500 13.5px/1 var(--sans);
  color: var(--ink70);
  margin-top: 6px;
  font-variant-numeric: tabular-nums;
}
.cand-radio {
  width: 21px; height: 21px; flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--ink18);
  display: flex; align-items: center; justify-content: center;
}
.cand.is-picked .cand-radio { border-color: var(--ink-button); background: var(--ink-button); }
.cand-radio path { stroke: var(--canvas); }

.hint {
  display: flex; align-items: flex-start; gap: 9px;
  padding: var(--s3) 14px;
  background: var(--muted);
  border-radius: 13px;
  font: 400 13px/1.45 var(--sans);
  color: var(--ink55);
  text-wrap: pretty;
}
.hint::before {
  content: "";
  width: 5px; height: 5px; flex: none;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--caution-dot);
}

/* Collection screen — :268–:321 */
.screen {
  position: absolute;
  inset: 0;
  background: var(--canvas);
  display: flex;
  flex-direction: column;
}
.screen-body { flex: 1; overflow: hidden; padding: 62px var(--s5) 0; }
.screen-title {
  font: 600 34px/1.1 var(--sans);
  letter-spacing: -0.03em;
  margin-bottom: 18px;
}
.total-card {
  background: var(--surface);
  border: 1px solid var(--hairline-soft);
  border-radius: var(--s5);
  padding: 18px;
  margin-bottom: var(--s4);
}
.total-amount {
  font: 600 38px/1 var(--sans);
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  margin-top: 9px;
}
.total-meta { display: flex; align-items: center; gap: 9px; margin-top: 11px; }
.total-count { font: 400 14px/1 var(--sans); color: var(--ink55); }
.total-sep { width: 3px; height: 3px; border-radius: 50%; background: var(--ink20); }
.total-delta { font: 500 14px/1 var(--sans); color: var(--success-ink); }

.chips { display: flex; gap: 6px; margin-bottom: var(--s4); }
.chips span {
  height: 30px;
  display: flex; align-items: center;
  padding: 0 var(--s3);
  border-radius: 15px;
  background: var(--surface);
  border: 1px solid var(--ink14);
  color: var(--ink60);
  font: 500 13px/1 var(--sans);
}
.chips .is-on {
  background: var(--ink-button);
  border-color: var(--ink-button);
  color: var(--canvas);
}

.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s4) 14px; }
.tile-name { font: 500 13.5px/1.3 var(--sans); margin-top: var(--s2); letter-spacing: -0.01em; }
.tile-meta { display: flex; justify-content: space-between; gap: var(--s2); margin-top: 3px; }
.tile-set { font: 400 12px/1.3 var(--sans); color: var(--ink42); }
.tile-price {
  font: 600 12.5px/1.3 var(--sans);
  font-variant-numeric: tabular-nums;
}

.tabbar {
  flex: none;
  height: 82px;
  padding-top: 9px;
  background: var(--canvas);
  border-top: 1px solid var(--hairline);
  display: flex;
}
.tab {
  flex: 1;
  display: flex; flex-direction: column; align-items: center; gap: var(--s1);
  font: 500 10px/1 var(--sans);
  color: var(--ink38);
}
.tab svg { stroke: var(--ink38); fill: none; }
.tab .knockout { fill: var(--canvas); }
.tab.is-on { color: var(--ink); font-weight: 600; }
.tab.is-on svg { stroke: var(--ink); }
.tab.is-on .tab-fill { fill: var(--ink90); }

/* ─────────────────────────────────────────────────────────────────────────────
   Card art — CardArt.dc.html, mirrored from mobile/src/components/CardArt.tsx
   ─────────────────────────────────────────────────────────────────────────────
   A rarity-tinted striped placeholder. There is no trading-card artwork on this
   site and there never will be — docs/RISKS.md R-09, docs/BRAND.md.
   ──────────────────────────────────────────────────────────────────────────── */

.card-art {
  position: relative;
  width: 100%;
  aspect-ratio: 63 / 88;
  border-radius: 5.5%;
  overflow: hidden;
  background-color: var(--art-bg);
  background-image:
    repeating-linear-gradient(135deg,
      var(--on-dark-sheen) 0 5px, var(--on-dark-clear) 5px 11px),
    linear-gradient(158deg, var(--art-common-1) 0%, var(--art-common-2) 58%, var(--art-common-3) 100%);
  box-shadow: var(--shadow-art);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 5px;
  padding: 10px;
  text-align: center;
}
.card-art--secret {
  background-image:
    repeating-linear-gradient(135deg,
      var(--on-dark-sheen) 0 5px, var(--on-dark-clear) 5px 11px),
    linear-gradient(158deg, var(--art-secret-1) 0%, var(--art-secret-2) 58%, var(--art-secret-3) 100%);
}
.card-art--illustration {
  background-image:
    repeating-linear-gradient(135deg,
      var(--on-dark-sheen) 0 5px, var(--on-dark-clear) 5px 11px),
    linear-gradient(158deg, var(--art-illus-1) 0%, var(--art-illus-2) 58%, var(--art-illus-3) 100%);
}
.card-art--holo {
  background-image:
    repeating-linear-gradient(135deg,
      var(--on-dark-sheen) 0 5px, var(--on-dark-clear) 5px 11px),
    linear-gradient(158deg, var(--art-holo-1) 0%, var(--art-holo-2) 58%, var(--art-holo-3) 100%);
}
.card-art::after {
  content: "";
  position: absolute;
  inset: 5.5%;
  border: 1px solid var(--on-dark-hairline);
  border-radius: 3.5%;
  pointer-events: none;
}
.card-art-name {
  font: 500 9.5px/1.35 var(--mono);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--on-dark-label);
  text-wrap: pretty;
}
.card-art-sub {
  font: 400 8.5px/1.3 var(--mono);
  letter-spacing: 0.05em;
  color: var(--on-dark-sub);
}
