/* judger.app: the landing page, the legal pages and whatever comes next all read from here.
 *
 * Every colour, radius and type role below is transcribed from app/src/theme/tokens.ts (crimson
 * variant D). tokens.ts stays the single source of truth (CLAUDE.md §6): when it moves, this moves.
 * Nothing in this file invents a value.
 *
 * Two rules that are not negotiable and are easy to break by accident:
 *   - the score is NEVER crimson. On paper it is ink; on a crimson field it is paper.
 *   - crimson owns whole regions. It is a field, not an accent sprinkled over a neutral page.
 */

/* ── Faces ──────────────────────────────────────────────────────────────────────────────────────
 * Self-hosted, subset to latin + latin-ext (60 kB for all four). No fonts.googleapis.com: a Google
 * font request would ship the visitor's IP to a third party and drag a consent banner behind it.
 * All three families are SIL OFL, so hosting them ourselves is squarely within the licence.
 * ascent/descent-override and size-adjust are measured from the real faces, so the fallback occupies
 * the same box as the webfont and swapping one for the other shifts nothing. */
@font-face {
  font-family: "Archivo Expanded";
  src: url("fonts/archivo-expanded-900.e9e808dd.woff2") format("woff2");
  font-weight: 900;
  font-display: swap;
  ascent-override: 87.8%;
  descent-override: 21%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("fonts/hanken-400.dc174b2e.woff2") format("woff2");
  font-weight: 400;
  font-display: swap;
  ascent-override: 100%;
  descent-override: 30.3%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Hanken Grotesk";
  src: url("fonts/hanken-700.580857c8.woff2") format("woff2");
  font-weight: 700;
  font-display: swap;
  ascent-override: 100%;
  descent-override: 30.3%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Plex Mono"; /* taste-skill-ignore mono: brand face, tokens.ts font.mono */
  src: url("fonts/plex-mono-500.16ef680d.woff2") format("woff2");
  font-weight: 500;
  font-display: swap;
  ascent-override: 102.5%;
  descent-override: 27.5%;
  line-gap-override: 0%;
}
/* Metric-matched stand-ins, one per face, so the box a line occupies before the webfont arrives is
 * the box it occupies after. Each is measured against Arial — the same family on Windows and macOS,
 * so the match holds on both — over the alphabet, digits and common punctuation rather than a single
 * glyph. size-adjust is targetAvgAdvance / arialAvgAdvance, and because the overrides are applied
 * before that scaling, each one is the target metric DIVIDED by size-adjust.
 *
 * Getting this wrong is not cosmetic. The display face previously borrowed the body face's stand-in,
 * whose ascent is 100% against Archivo Expanded's 87.8%: when the webfont swapped in, the line box
 * of an 88px headline shrank and the whole page jumped. It measured CLS 0.28 on roughly two loads
 * in five. */
@font-face {
  font-family: "Archivo Expanded Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 146.50%;
  ascent-override: 59.93%;
  descent-override: 14.33%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Hanken Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 101.18%;
  ascent-override: 102.1%;
  descent-override: 30.94%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Plex Mono Fallback"; /* taste-skill-ignore mono — stand-in for tokens.ts font.mono */
  src: local("Arial"), local("Helvetica Neue"), local("Helvetica");
  size-adjust: 106.16%;
  ascent-override: 96.55%;
  descent-override: 25.9%;
  line-gap-override: 0%;
}

:root {
  /* colour — tokens.ts `color` */
  --bg: #f7eeec;
  --surface: #fcf6f5;
  --text-primary: #1a1114;
  --text-body: #3a2a2d;
  --on-surface-muted: #574144;
  --text-muted: #7a5f63;
  --border: #e8dad7;
  --stitch: #c4adaa;
  --accent: #990011;
  --on-accent: #fcf6f5;
  --on-accent-muted: #f0c9cc;
  --cta-fill: #1a1114;
  --on-cta: #fcf6f5;
  --ink: #1a1114;
  /* tokens.ts `tint` */
  --photo-well: #efe3e0;
  --fade-far: #b39a9e;

  /* radius + space — tokens.ts `radius` / `space` */
  --r-tag: 14px;
  --r-card: 20px;
  --r-photo: 8px;
  --r-pill: 999px;
  --s-xs: 4px;
  --s-s: 8px;
  --s-m: 16px;
  --s-l: 24px;
  --s-xl: 40px;

  --display: "Archivo Expanded", "Archivo Expanded Fallback", system-ui, sans-serif;
  --body: "Hanken Grotesk", "Hanken Fallback", system-ui, sans-serif;
  --mono: "Plex Mono", "Plex Mono Fallback", ui-monospace, Menlo, monospace; /* taste-skill-ignore mono */

  /* Emil's curves. The built-in CSS easings are too weak to read as intentional. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);

  /* One rhythm for the whole page. Section gaps are always larger than anything inside a section. */
  --gap-section: clamp(80px, 11vw, 168px);
  --pad-x: clamp(20px, 5vw, 64px);
  --measure: 62ch;

  color-scheme: light;
  /* The page is one committed light world; it does not follow the OS into dark. */
}

/* ── Reset ──────────────────────────────────────────────────────────────────────────────────── */
*,
*::before,
*::after {
  box-sizing: border-box;
}
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
}
body {
  margin: 0;
  background: var(--bg);
  color: var(--text-body);
  font-family: var(--body);
  font-size: 17px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img,
svg {
  max-width: 100%;
  display: block;
}
img {
  height: auto;
}
h1,
h2,
h3 {
  margin: 0;
  font-weight: 900;
  font-family: var(--display);
  color: var(--text-primary);
  letter-spacing: -0.03em;
  line-height: 0.92;
  text-wrap: balance;
}
p {
  margin: 0;
}
a {
  color: inherit;
  text-underline-offset: 0.18em;
  text-decoration-thickness: from-font;
}

/* The surfaces we did not draw still belong to the design. Leaving these at browser defaults is the
 * cheapest tell that a page was assembled rather than built. */
::selection {
  background: var(--accent);
  color: var(--on-accent);
}
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
.field-ink ::selection,
.field-accent ::selection {
  background: var(--on-accent);
  color: var(--accent);
}
.field-ink :focus-visible,
.field-accent :focus-visible {
  outline-color: var(--on-accent);
}

/* ── Type roles — transcribed from tokens.ts `textRole` ─────────────────────────────────────── */
/* Two lines from 480px up. Below that the hero headline sets in three — Archivo Expanded is a wide
 * face and "An honest verdict." cannot hold one phone line at any size worth setting it at. Three
 * lines is also exactly how this headline is set in our own App Store screenshots, so the small
 * screen matches what a visitor saw a moment earlier in the store. A declared deviation from the
 * two-line rule, not an accident. */
.display {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.4rem, 7.4vw, 5.5rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
}
.title {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.75rem, 5.2vw, 3.25rem);
  line-height: 0.95;
  letter-spacing: -0.03em;
}
.lead {
  font-size: clamp(1.0625rem, 2.4vw, 1.375rem);
  line-height: 1.5;
  color: var(--on-surface-muted);
  max-width: 34ch;
  text-wrap: pretty;
}
.body {
  max-width: var(--measure);
  text-wrap: pretty;
}
/* The care-label voice: the one place monospace is allowed, and it is allowed because this IS a
 * care label — a garment-tag utility line, not a costume for "technical". */
.mono {
  font-family: var(--mono); /* taste-skill-ignore mono — tokens.ts font.mono, the garment care-label voice */
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.accent-word {
  color: var(--accent);
}

/* ── Layout ─────────────────────────────────────────────────────────────────────────────────── */
.wrap {
  width: 100%;
  max-width: 1240px;
  margin-inline: auto;
  padding-inline: var(--pad-x);
}
section {
  padding-block: var(--gap-section);
}
/* A heading followed immediately by its own content does not need a second full gap under it. */
section > .wrap > .reveal:first-child + .step,
section > .wrap > .reveal:first-child + .faq {
  margin-top: var(--s-l);
}
.step:first-of-type {
  padding-top: var(--s-l);
}
.field-accent {
  background: var(--accent);
  color: var(--on-accent-muted);
}
.field-accent h2,
.field-accent h3 {
  color: var(--on-accent);
}
.field-ink {
  background: var(--ink);
  color: #c9bdbf;
}
.field-ink h2,
.field-ink h3 {
  color: var(--on-accent);
}
.field-surface {
  background: var(--surface);
}

/* ── Header ─────────────────────────────────────────────────────────────────────────────────── */
.site-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-m);
  padding-block: var(--s-l);
}
.wordmark {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.0625rem;
  letter-spacing: -0.02em;
  color: var(--text-primary);
  text-decoration: none;
}
.wordmark::before {
  content: "";
  width: 11px;
  height: 11px;
  background: var(--accent);
  flex: none;
}
.head-links {
  display: flex;
  gap: var(--s-l);
  font-size: 0.9375rem;
}
.head-links a {
  text-decoration: none;
  color: var(--on-surface-muted);
}
.head-links a:hover {
  text-decoration: underline;
}

/* ── Badge ──────────────────────────────────────────────────────────────────────────────────── */
/* Apple's own SVG, unmodified and unrecoloured, at its own aspect ratio. The Marketing Guidelines
 * set a minimum size and demand clear space around it; both are held here. */
.badge {
  display: inline-block;
  line-height: 0;
  border-radius: 8px;
  transition: transform 160ms var(--ease-out);
}
.badge img {
  width: 168px;
  height: 56px;
}
@media (hover: hover) and (pointer: fine) {
  .badge:hover {
    transform: translateY(-2px);
  }
}
.badge:active {
  transform: scale(0.97);
}
.cta-row {
  display: flex;
  align-items: center;
  gap: var(--s-l);
  flex-wrap: wrap;
  margin-top: var(--s-l);
}
/* A flex child defaults to min-width:auto and so refuses to shrink below its own max-content width.
 * With a tracked-out mono line inside, that pushed the whole document wider than a 390pt screen and
 * cut the right edge off every section. These three lines are what keep the page from overflowing. */
.cta-row > *,
.fit-verdict > *,
.site-head > * {
  min-width: 0;
}

/* ── Hero ───────────────────────────────────────────────────────────────────────────────────── */
.hero {
  padding-top: clamp(20px, 3vw, 40px);
  padding-bottom: var(--gap-section);
}
.hero .display {
  /* Wide enough that "An honest verdict." holds one line from 480px up; the authored <br>
   * supplies the only break above that. */
  max-width: 20ch;
}
.hero .lead {
  margin-top: var(--s-l);
}
/* From 980px the hero is two columns: the argument on the left, the annotated fit on the right,
 * both inside the first screen. A hero whose photograph starts below the fold is a header with a
 * picture under it, and the photograph is the thing that demonstrates what this app does. */
/* One column, and the headline is the focal point of the first screen. The two-column version put
 * the photograph beside the headline and neither won: 52px type and a 24%-of-viewport picture read
 * as two medium things. Full-width type at 84px is unambiguous, and the fit follows immediately
 * under it rather than a screen later. */

/* The annotated fit. A real photograph, four pins on leader lines, one verdict assembling out of
 * them. This is the page's one live thing, and it is the product's own gesture: a tag naming a
 * garment, never the person wearing it. */
.fit {
  position: relative;
  margin-top: clamp(28px, 4vw, 48px);
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-l);
}
.fit-stage {
  position: relative;
  border-radius: var(--r-photo);
  overflow: hidden;
  background: var(--photo-well);
  aspect-ratio: 1008 / 1700;
  max-height: min(78vh, 760px);
  max-width: 560px;
}
/* Descendant, not child: the img sits inside <picture>, so `.fit-stage > img` matched nothing and
 * object-fit never applied. Harmless while the stage's aspect-ratio equals the file's, and a
 * distortion the moment max-height clips it. */
.fit-stage img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Each pin is a real <button>: keyboard reachable, 44px of hit area, and it announces its state. */
.pin {
  position: absolute;
  width: 44px;
  height: 44px;
  margin: -22px 0 0 -22px;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  z-index: 3;
}
.pin::after {
  content: "";
  position: absolute;
  inset: 50% auto auto 50%;
  width: 11px;
  height: 11px;
  margin: -5.5px 0 0 -5.5px;
  border-radius: 50%;
  background: var(--on-accent);
  outline: 1.5px solid var(--ink); /* a ring so the dot stays legible on any photograph */
  transition: transform 180ms var(--ease-out), background 180ms var(--ease-out);
}
.pin[aria-expanded="true"]::after {
  background: var(--accent);
  transform: scale(1.25);
}
@media (hover: hover) and (pointer: fine) {
  .pin:hover::after {
    transform: scale(1.25);
  }
}
.pin:active::after {
  transform: scale(0.97);
}

/* The tag itself, and the thread it hangs on. The thread draws itself from the pin outward — the
 * signature move, and the only elaborate one on the page. */
.tag {
  position: absolute;
  z-index: 2;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 13px;
  background: var(--surface);
  border-radius: var(--r-tag);
  /* Never wider than half the stage: two tags face each other across the figure and a long one
   * would otherwise cross the centre line or run off the edge on a phone. */
  max-width: 46%;
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.tag-name {
  font-family: var(--display);
  font-weight: 900;
  font-size: 0.9375rem;
  letter-spacing: -0.01em;
  color: var(--text-primary);
  line-height: 1.1;
}
.tag-note {
  font-family: var(--mono); /* taste-skill-ignore mono — tokens.ts font.mono, the garment care-label voice */
  font-weight: 500;
  font-size: 0.8125rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.tag[data-kind="fix"] .tag-note {
  color: var(--accent);
}
.thread {
  position: absolute;
  height: 1px; /* taste-skill-ignore hairline — the leader line IS the page's device */
  background: var(--surface);
  transform-origin: left center;
  z-index: 1;
  transition: transform 220ms var(--ease-out), opacity 220ms var(--ease-out);
}

/* With JS the tags wait for their pin. Without it they are simply all visible — the page never
 * depends on script to say what it is. `.js` is set on <html> by the inline bootstrap. */
.js .tag,
.js .thread {
  opacity: 0;
  pointer-events: none;
}
.js .tag {
  transform: translateY(6px) scale(0.97);
}
.js .thread {
  transform: scaleX(0);
}
.js .tag.is-open,
.js .thread.is-open {
  opacity: 1;
  pointer-events: auto;
}
.js .tag.is-open {
  transform: none;
}
.js .thread.is-open {
  transform: scaleX(1);
}

.fit-verdict {
  display: flex;
  align-items: baseline;
  gap: var(--s-m);
  flex-wrap: wrap;
}
/* 🔒 The score is ink here, never crimson — the same rule the app holds. */
.score {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3rem, 9vw, 4.75rem);
  line-height: 0.85;
  letter-spacing: -0.05em;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.score small {
  font-size: 0.42em;
  letter-spacing: -0.02em;
  color: var(--text-muted);
}
.field-accent .score,
.field-ink .score {
  color: var(--on-accent);
}



/* ── Steps ──────────────────────────────────────────────────────────────────────────────────── */
/* Three full-width bands, not a row of cards. Each alternates side and carries a real UI fragment. */
.step {
  display: grid;
  gap: var(--s-l);
  align-items: center;
  padding-block: clamp(32px, 6vw, 64px);
}
.step + .step {
  border-top: 1px dashed var(--stitch); /* taste-skill-ignore hairline — tokens.ts stitch, the tailoring seam */
}
.step-n {
  margin-bottom: var(--s-s);
}
.step h3 {
  font-size: clamp(1.5rem, 4vw, 2.25rem);
  margin-bottom: var(--s-m);
}
/* The interface fragments are capped rather than stretched. Their source is 934px wide -- the most
 * the App Store screenshot holds -- so a 320px slot on a DPR 3 phone is covered exactly, and a
 * wider slot would be upscaling small rendered UI text into mush. */
/* The interface fragments sit on the page as objects, so they are lit like objects. Three layers,
 * each with a real offset and a soft blur: a tight one that pins the card to the paper, a mid one
 * for its shape, and a wide soft one for the lift.
 *
 * The tint matters. Pure black on a warm paper ground reads cold and grey, like a filter applied
 * afterwards; tinting from the ink (#1A1114) keeps it looking like light falling in this room.
 *
 * The house style bans this on elements at rest, and that rule is usually right. This is a
 * deliberate exception, asked for, scoped to these three cards — and they genuinely do float. */
.step figure {
  margin: 0;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--photo-well);
  max-width: 320px;
  box-shadow: /* taste-skill-ignore shadow — deliberate, these cards float */
    0 1px 2px rgba(26, 17, 20, 0.07),
    0 8px 18px rgba(26, 17, 20, 0.07),
    0 26px 50px -12px rgba(26, 17, 20, 0.14);
}
@media (hover: hover) and (pointer: fine) {
  .step figure {
    transition: transform 320ms var(--ease-out), box-shadow 320ms var(--ease-out); /* taste-skill-ignore shadow */
  }
  .step:hover figure {
    transform: translateY(-3px);
    box-shadow: /* taste-skill-ignore shadow */
      0 1px 2px rgba(26, 17, 20, 0.07),
      0 12px 24px rgba(26, 17, 20, 0.08),
      0 34px 64px -12px rgba(26, 17, 20, 0.17);
  }
}
@media (min-width: 820px) {
  .step figure {
    max-width: 430px;
    justify-self: center;
  }
}
@media (min-width: 820px) {
  .step {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
    gap: var(--s-xl);
  }
  .step:nth-child(even) > figure {
    order: -1;
  }
}

/* ── Modes ──────────────────────────────────────────────────────────────────────────────────── */
.modes {
  display: grid;
  gap: var(--s-l);
  margin-top: var(--s-xl);
}
.mode h3 {
  font-size: 1.375rem;
  margin-bottom: var(--s-s);
}
.mode p {
  color: inherit;
  max-width: 40ch;
}
.quote {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(1.375rem, 3.6vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.03em;
  color: var(--on-accent);
  margin: 0;
  max-width: 20ch;
}
@media (min-width: 760px) {
  .modes {
    grid-template-columns: 1fr 1fr;
    gap: var(--s-xl);
  }
}

/* ── Duel ───────────────────────────────────────────────────────────────────────────────────── */
.duel {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--s-m);
  margin-top: var(--s-xl);
}
.duel figure {
  position: relative;
  margin: 0;
  border-radius: var(--r-photo);
  overflow: hidden;
  background: var(--photo-well);
}
.duel-win {
  position: absolute;
  left: var(--s-m);
  bottom: var(--s-m);
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 9px 13px;
  background: var(--surface);
  border-radius: var(--r-tag);
}

/* ── Archetypes ─────────────────────────────────────────────────────────────────────────────── */
.arch {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--s-m);
  margin-top: var(--s-xl);
}
.arch figure {
  margin: 0;
}
.arch img {
  border-radius: var(--r-photo);
  background: var(--photo-well);
}
.arch figcaption {
  margin-top: 10px;
}
@media (min-width: 760px) {
  .arch {
    grid-template-columns: repeat(4, 1fr);
  }
}

/* ── Price ──────────────────────────────────────────────────────────────────────────────────── */
.price-card {
  margin-top: var(--s-xl);
  padding: clamp(24px, 5vw, 48px);
  background: var(--surface);
  border-radius: var(--r-card);
  max-width: 660px;
}
.price-big {
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.5rem, 8vw, 4rem);
  line-height: 0.9;
  letter-spacing: -0.04em;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}

/* ── FAQ ────────────────────────────────────────────────────────────────────────────────────── */
.faq {
  margin-top: var(--s-xl);
  max-width: 760px;
}
.faq details {
  padding-block: var(--s-l);
  border-top: 1px dashed var(--stitch); /* taste-skill-ignore hairline — tokens.ts stitch, the tailoring seam */
}
.faq details:last-of-type {
  border-bottom: 1px dashed var(--stitch); /* taste-skill-ignore hairline — tokens.ts stitch */
}
.faq summary {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.125rem;
  letter-spacing: -0.015em;
  color: var(--text-primary);
  cursor: pointer;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: var(--s-m);
  align-items: center;
}
.faq summary::-webkit-details-marker {
  display: none;
}
.faq summary::after {
  content: "";
  flex: none;
  width: 13px;
  height: 13px;
  border-right: 2px solid var(--accent);
  border-bottom: 2px solid var(--accent);
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 200ms var(--ease-out);
}
.faq details[open] summary::after {
  transform: rotate(225deg) translate(-3px, -3px);
}
.faq details p {
  margin-top: var(--s-m);
  max-width: var(--measure);
  text-wrap: pretty;
}

/* ── Footer ─────────────────────────────────────────────────────────────────────────────────── */
.site-foot {
  padding-block: var(--gap-section) var(--s-xl);
}
.foot-tag {
  display: inline-flex;
  flex-direction: column;
  gap: var(--s-m);
  padding: clamp(24px, 4vw, 40px);
  background: var(--surface);
  border-radius: var(--r-tag);
  max-width: 560px;
}
.foot-legal {
  font-size: 0.875rem;
  color: var(--text-muted);
  line-height: 1.7;
}
.foot-legal a {
  color: var(--on-surface-muted);
}
.field-ink .foot-tag {
  background: #241a1d;
}
.field-ink .foot-legal {
  color: #9c8d90;
}
.field-ink .foot-legal a {
  color: #c9bdbf;
}

/* ── Legal pages (privacy, terms) ───────────────────────────────────────────────────────────── */
/* The same world, set for long-form reading. The body of those documents is generated from the
 * canonical markdown and is not styled per-element here beyond rhythm and measure. */
.legal {
  padding-block: var(--s-xl) var(--gap-section);
}
.legal main {
  max-width: 68ch;
  margin-inline: auto;
}
.legal h1 {
  font-size: clamp(2rem, 6vw, 3rem);
  margin-bottom: var(--s-l);
}
.legal h2 {
  font-size: clamp(1.25rem, 3.2vw, 1.625rem);
  margin-top: var(--s-xl);
  margin-bottom: var(--s-m);
  line-height: 1.1;
}
.legal h3 {
  font-size: 1.125rem;
  margin-top: var(--s-l);
  margin-bottom: var(--s-s);
}
.legal p,
.legal li {
  margin-bottom: var(--s-m);
  text-wrap: pretty;
}
.legal ul,
.legal ol {
  padding-left: 1.25em;
}
.legal hr {
  border: 0;
  border-top: 1px dashed var(--stitch); /* taste-skill-ignore hairline — tokens.ts stitch, the tailoring seam */
  margin-block: var(--s-xl);
}
.legal table {
  width: 100%;
  border-collapse: collapse;
  margin-bottom: var(--s-l);
  font-size: 0.9375rem;
  display: block;
  overflow-x: auto;
}
.legal th,
.legal td {
  text-align: left;
  padding: 10px 14px;
  border-bottom: 1px solid var(--border);
  vertical-align: top;
}
.legal th {
  font-family: var(--display);
  font-weight: 900;
  color: var(--text-primary);
}
.legal code {
  font-family: var(--mono);
  font-size: 0.875em;
  background: var(--surface);
  padding: 0.1em 0.35em;
  border-radius: 4px;
}
.legal a {
  color: var(--accent);
}

/* ── Motion ─────────────────────────────────────────────────────────────────────────────────── */
/* Section parts rise in once, staggered. The content is visible by default and the reveal class is
 * only ever added by script, so a failed script can never leave the page blank. */
.js .reveal > * {
  opacity: 0;
  transform: translateY(20px);
}
.js .reveal.is-in > * {
  opacity: 1;
  transform: none;
  transition: opacity 520ms var(--ease-out), transform 520ms var(--ease-out);
}
.js .reveal.is-in > :nth-child(2) {
  transition-delay: 70ms;
}
.js .reveal.is-in > :nth-child(3) {
  transition-delay: 140ms;
}
.js .reveal.is-in > :nth-child(4) {
  transition-delay: 210ms;
}
.js .reveal.is-in > :nth-child(5) {
  transition-delay: 280ms;
}

/* Reduced motion means fewer and gentler, not none: the fades stay, the travel goes. */
@media (prefers-reduced-motion: reduce) {
  .js .reveal > * {
    transform: none;
  }
  .js .reveal.is-in > * {
    transition: opacity 240ms ease;
  }
  .tag,
  .thread,
  .pin::after,
  .badge,
  .faq summary::after {
    transition-duration: 1ms !important;
  }
  .js .tag {
    transform: none;
  }
  .js .thread {
    transform: none;
    opacity: 0;
  }
  .js .thread.is-open {
    opacity: 1;
  }
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--ink);
  color: var(--on-cta);
  padding: 12px 18px;
  z-index: 99;
  border-radius: 0 0 var(--r-tag) 0;
}
.skip:focus {
  left: 0;
}
.vh {
  position: absolute;
  width: 1px;
  height: 1px; /* taste-skill-ignore hairline — the screen-reader-only box, not a rule */
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* The mono tone is derived for the paper ground; on the two dark fields it falls to ~3:1, so it is
 * re-tinted from the field's own foreground rather than left as a grey that cannot be read. */
.field-ink .mono {
  color: #a8989b;
}
.field-accent .mono {
  color: var(--on-accent-muted);
}

/* ── Utilities ──────────────────────────────────────────────────────────────────────────────── */
/* Vertical rhythm and the two type variants that were otherwise one-off inline sizes. Keeping them
 * named holds the page to a scale instead of letting every section invent its own. */
.stack-m {
  margin-top: var(--s-m);
}
.stack-l {
  margin-top: var(--s-l);
}
.stack-xl {
  margin-top: var(--s-xl);
}
.field-accent .stack-xl.mono {
  color: var(--on-accent-muted);
}
.body-lg {
  font-size: 1.125rem;
}
.fine {
  font-size: 0.875rem;
  color: var(--text-muted);
}
.title-sm {
  font-size: clamp(1.5rem, 4vw, 2.25rem);
}
.per {
  font-size: 0.34em;
  letter-spacing: 0;
  color: var(--text-muted);
}

/* The photograph keeps the headline's left edge: a centred picture under left-aligned type opens a
 * hole on the left that reads as a mistake. The verdict takes the room beside it, at the top, so it
 * lands in the first screen instead of at the foot of a 700px-tall row. */
@media (min-width: 900px) {
  .fit {
    grid-template-columns: minmax(0, auto) minmax(0, 1fr);
    align-items: start;
    justify-items: start;
    gap: var(--s-xl);
  }
  .fit-verdict {
    display: block;
    padding-top: var(--s-s);
  }
  .fit-verdict .mono {
    margin-top: var(--s-s);
  }
}

/* Pin and tag positions. These live here rather than on the elements because the site's CSP sets
 * style-src 'self', which blocks inline style= attributes as well as <style> blocks -- with them in
 * the markup every pin and tag collapsed into the corner of the photograph, silently. */
.pin--shirt { left: 42%; top: 18%; }
.pin--belt  { left: 53%; top: 35%; }
.pin--jeans { left: 45%; top: 62%; }
.pin--boots { left: 52%; top: 92%; }

.tag--shirt { left: 2%;  top: 9%;  }
.tag--belt  { right: 2%; top: 30%; }
.tag--jeans { left: 2%;  top: 55%; }
.tag--boots { right: 2%; top: 84%; }

/* ── Centred layout ─────────────────────────────────────────────────────────────────────────────
 * The page was built left-aligned, with the type hanging off one edge for the whole scroll. This
 * layer centres it instead: headings, the hero block and the calls to action sit on the page's
 * centre line, while anything long enough to actually read keeps its left edge and is centred as a
 * block. Centred ragged-right prose is hard to read past a couple of lines, so the two behaviours
 * are deliberately different.
 *
 * It lives at the end, after every rule it overrides, so the cascade needs no !important. */

/* The reading measure for long-form text: narrower than the old 62ch, which is what makes a
 * centred block feel composed rather than stranded. */
:root {
  --measure-read: 640px;
}

/* ── Hero ──────────────────────────────────────────────────────────────────────────────────── */
.hero > .wrap {
  text-align: center;
}
.hero .display {
  margin-inline: auto;
}
.hero .lead {
  margin-inline: auto;
  max-width: 38ch;
}
/* Badge under the text, caption under the badge: a column, not a row. On the left-aligned version
 * the caption sat beside the badge, which centring would have left visually off-axis. */
.hero .cta-row {
  flex-direction: column;
  align-items: center;
  gap: var(--s-m);
}

/* ── The annotated fit ─────────────────────────────────────────────────────────────────────── */
/* One centred column at every width: the photograph on the page's centre line, the score beneath
 * it. The desktop rule that put them side by side with the stage flush left is undone here. */
.fit {
  grid-template-columns: minmax(0, 1fr);
  justify-items: center;
  text-align: center;
}
/* width:100% is load-bearing, not decoration. `.fit` is a grid, and centring it gave the stage
 * both `justify-items: center` on the parent and `margin-inline: auto` here -- either one alone
 * turns a grid item off `stretch` and onto shrink-to-fit. Shrink-to-fit means the width comes from
 * the content, and the only in-flow content is an <img> sized `width: 100%`, which has no width of
 * its own until the file arrives. So the stage measured 0x0 until the photograph loaded, which
 * made `aspect-ratio` reserve nothing, and the whole page below the hero sat 625px too high and
 * then dropped. Measured CLS 0.28, on about a quarter of production loads and every slow one.
 *
 * A definite width restores the reservation: the box is the column's width (capped at 560) from
 * the first layout, aspect-ratio gives it its height, and the photograph can take as long as it
 * likes. `margin-inline: auto` keeps it centred once max-width binds. */
.fit-stage {
  width: 100%;
  margin-inline: auto;
}
.fit-verdict {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s-s);
  padding-top: 0;
}
@media (min-width: 900px) {
  .fit {
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    align-items: start;
  }
  .fit-verdict {
    display: flex;
  }
}

/* ── Section headings and the blocks under them ────────────────────────────────────────────── */
.title {
  text-align: center;
  margin-inline: auto;
  max-width: 18ch;
}
/* Long-form text: centred as a block, left-aligned inside it. */
.body,
.faq,
.price-card,
.modes .mode p {
  max-width: var(--measure-read);
  margin-inline: auto;
  text-align: left;
}
section > .wrap > .reveal > .lead {
  margin-inline: auto;
  text-align: center;
}

/* ── Sections that carried their own alignment ─────────────────────────────────────────────── */
.modes {
  text-align: center;
}
.modes .mode p {
  text-align: center;
  max-width: 34ch;
}
.quote {
  margin-inline: auto;
  text-align: center;
}
.field-ink > .wrap > .mono,
.field-accent > .wrap > .reveal > .mono {
  text-align: center;
}
.arch figcaption,
.duel + .mono,
.duel ~ .mono {
  text-align: center;
}
/* The step bands keep their two-column shape on desktop but centre their own text column, and
 * stack centred on a phone. */
.step {
  text-align: center;
}
.step .body {
  margin-inline: auto;
}
.step figure {
  margin-inline: auto;
}
@media (min-width: 820px) {
  .step {
    text-align: left;
  }
  .step .body {
    margin-inline: 0;
  }
}

/* ── Price ─────────────────────────────────────────────────────────────────────────────────── */
.price-card {
  text-align: center;
}
.price-card .body {
  text-align: left;
}
.price-card .cta-row {
  justify-content: center;
}

/* ── Footer ────────────────────────────────────────────────────────────────────────────────── */
.site-foot .wrap {
  text-align: center;
}
.foot-tag {
  display: flex;
  align-items: center;
  margin-inline: auto;
}
.foot-legal {
  margin-inline: auto;
  max-width: var(--measure-read);
}

/* ── Legal pages ───────────────────────────────────────────────────────────────────────────── */
/* Their headings follow the same rule; the clauses themselves stay left-aligned and keep the wider
 * measure a legal document needs. */
.legal h1 {
  text-align: center;
}

/* A section lead is a single supporting sentence, so give it room to sit on one or two lines.
 * At the body measure it broke into three centred ragged lines, which reads as a stanza. */
section > .wrap > .reveal > .lead {
  max-width: 46ch;
}

/* ── The in-app escape panel (bio pages only) ──────────────────────────────────────────────── */
/* TikTok, Instagram and Facebook open links in their own webview, and the App Store will not open
 * from in there: the hop either does nothing or stops on "Cannot Complete Action". go.js hides the
 * whole page and shows this instead, which asks for the three taps that lead out of the webview.
 * Served hidden, so a page with no JavaScript keeps the ordinary hero.
 *
 * It is the site's ink field rather than its cream one, and that is the one deliberate departure:
 * the arrow and the card have to be the loudest things a visitor has ever seen on this domain,
 * because they are competing with a host app's own chrome for attention. `.field-ink` is already
 * in the palette, so this is a field the site owns, not a new world. */
.go-escape {
  position: fixed; /* taste-skill-ignore fixed — a full-screen interstitial, nothing behind it is reachable */
  inset: 0;
  z-index: 10;
  overflow-y: auto;
  display: grid;
  align-content: start;
  padding: clamp(164px, 25vh, 240px) var(--pad-x) var(--s-xl);
  background: var(--ink);
}
.go-escape[hidden] {
  display: none; /* beats the grid above, which would otherwise keep a hidden section's box */
}
.go-inner {
  width: 100%;
  max-width: 28rem;
  margin-inline: auto;
  text-align: center;
}

/* The arrow points out of the page at the host app's own ··· button, which sits above our viewport
 * in the webview's chrome. Fixed to the corner it is pointing at, so a scroll cannot part them.
 * The loop is there to read as drawn by a hand rather than placed by a layout. */
.go-arrow {
  position: fixed; /* taste-skill-ignore fixed — it points at a fixed piece of someone else's UI */
  top: 4px;
  right: 2px;
  width: clamp(132px, 38vw, 188px);
  color: var(--on-accent);
  pointer-events: none;
  z-index: 11;
  animation: go-arrow-nudge 1.6s var(--ease-in-out) infinite alternate;
}
/* A nudge along the arrow's own direction, not a pulse: it should read as pointing harder, not as
 * blinking. Four pixels is the whole move. */
@keyframes go-arrow-nudge {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(5px, -5px, 0);
  }
}

/* The wordmark, on the one dark field it ever appears on, with the glow that gives it a middle to
 * sit in. Not a link here: the only thing worth tapping on this page is the way out. */
.go-logo {
  position: relative;
  display: grid;
  place-items: center;
  margin: 0 0 var(--s-l);
}
.go-logo::before {
  content: "";
  position: absolute;
  width: 17rem;
  height: 9.5rem;
  border-radius: 50%;
  /* A glow is a soft light source and a flat colour cannot be one. The only gradient on the site,
   * and it falls off to nothing. */
  background: radial-gradient(ellipse at center, rgba(153, 0, 17, 0.34), rgba(153, 0, 17, 0) 72%); /* taste-skill-ignore gradient */
  filter: blur(14px); /* taste-skill-ignore blur — the glow is the point */
}
.go-escape .wordmark {
  position: relative;
  font-size: clamp(1.75rem, 7vw, 2.25rem);
  color: var(--on-accent);
  gap: 14px;
}
.go-escape .wordmark::before {
  width: 18px;
  height: 18px;
}

.go-escape h1 {
  color: var(--on-accent);
}
.go-escape .lead {
  margin: var(--s-m) auto 0;
  max-width: 26ch;
  color: #c9bdbf; /* taste-skill-ignore palette — .field-ink's own body colour, on the ink field */
}

/* Cream on ink: the card is the instruction, and it should look like a card handed to you rather
 * than another paragraph of the page. */
.go-steps {
  list-style: none;
  margin: var(--s-l) 0 0;
  padding: clamp(18px, 4.5vw, 24px);
  background: var(--surface);
  border-radius: var(--r-card);
  text-align: left;
  color: var(--text-body);
}
.go-steps li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-m);
  align-items: center;
  line-height: 1.45;
}
.go-steps li + li {
  margin-top: var(--s-m);
}
.go-steps strong {
  color: var(--text-primary);
}
.go-step-n {
  display: grid;
  place-items: center;
  width: 30px;
  height: 30px;
  border-radius: var(--r-pill);
  background: var(--photo-well);
  color: var(--accent);
  font-family: var(--mono); /* taste-skill-ignore mono — tokens.ts font.mono, the care-label voice */
  font-weight: 500;
  font-size: 0.875rem;
}

/* The header is hidden in an in-app browser: the wordmark moves into the panel, and the legal
 * links are not what anyone is here for. */
.head-links[hidden],
[data-go-head][hidden] {
  display: none;
}
