/* ============================================================
   THE FINGERPRINT — alternative design language ("sarah.html")
   A second route shown alongside the current page. Nothing in
   here is loaded by index.html, thanks.html or styles.css.

   Language: event poster. A pale blush field carrying inset panels,
   two dark bands and two blush ones, one very large condensed
   uppercase display face, bracketed calls to action.

   PALETTE: the locked colour spec of 25 August 2026. Seven colours
   plus white and three documented tints of them, and nothing else.
   The rules live in one block at the top of this file and in the
   ground classes under it; no rule further down picks a colour by
   hand. If a colour has to change, change the token.
   ============================================================ */

/* ---------- type ----------
   Display: Archivo variable (Omnibus-Type, SIL OFL) run at its
   narrow width and heaviest weight. Body: Newsreader variable,
   already self-hosted in this project under assets/fonts/. */
@font-face {
  font-family: "Newsreader";
  src: url("assets/fonts/recommended/Newsreader/Newsreader%5Bopsz,wght%5D.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Newsreader";
  src: url("assets/fonts/recommended/Newsreader/Newsreader-Italic%5Bopsz,wght%5D.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
}

/* ---------- tokens ---------- */
:root {
  --sans: "Archivo", "Archivo Narrow", "Helvetica Neue", Arial, sans-serif;
  --serif: "Newsreader", Georgia, "Times New Roman", serif;

  /* ================= THE LOCKED COLOUR SPEC =================
     Seven colours plus white, verbatim from the sales-page colour spec
     of 25 August 2026, and ONE derived tint — the one that document
     derives itself. Every role below is the role that document gives
     the colour, quoted. Nothing here was reassigned:

       near-black  "All body copy and headlines."
       pale blush  "Reading surface. Long-form copy sits here."
       blush       "Section bands. Near-black type only."
       ink blue    "Hero band, primary buttons, links."   (+ rules)
       tomato red  "Price, urgency, second button."
       yellow      "Highlights and badges. Near-black label only."
       raspberry   "Display type and graphics. Not a button colour."

     Two consequences worth stating because they shaped the page:

     Headlines are near-black. The accent colours do NOT get headings —
     tomato is the price, blue is the buttons and links, and the only
     colour allowed inside a heading is raspberry on the emphasised
     word, because display type is raspberry's stated job.

     Yellow is never a letterform. The spec sanctions it one way only,
     as a ground with a near-black label at 10.20:1, and its own table
     records white on yellow as a failure at 1.60:1. So every highlight
     on this page is a yellow BLOCK with near-black type in it, not a
     yellow word. */

  /* --- the seven, verbatim --- */
  --c-ink:     #241F1F;  /* warm near-black */
  --c-pale:    #FBEDF0;  /* pale blush      */
  --c-blush:   #EEADC0;  /* blush           */
  --c-blue:    #3956A8;  /* ink blue        */
  --c-tomato:  #AF271D;  /* tomato red      */
  --c-yellow:  #F3C846;  /* golden yellow   */
  --c-rasp:    #D34062;  /* raspberry       */
  --c-white:   #FFFFFF;

  /* NO DERIVED VALUES. The spec's "Left open" section says plainly
     "No muted text tone is defined — captions and small print run at
     full near-black in the preview", and offers #5A5253 only IF a
     lighter tone is wanted. It was taken, and then dropped: the small
     print is already set apart by being small, uppercase and tracked,
     so the grey was a ninth value doing a job the typography had
     already done — and it was the only value on the page belonging to
     neither the warm side of the palette nor the blue.

     Everything below is one of the eight above, or an alpha of one. */

  /* ================= THREE GROUNDS =================
     Pale blush is the page. Ink blue is the hero, the client plate and
     the twelve weeks. Blush is two bands. There is no fourth: near-black
     is type here and white is a label, which is all the spec gives them.

     Measured on the rendered page and checked against the spec's own
     proportions, which are stated as "roughly how much of the page each
     colour should hold". */

  --paper:    var(--c-pale);
  --ink:      var(--c-ink);
  --ground:   var(--c-blue);

  /* --- the working roles on the reading surface --- */
  --on-paper:      var(--c-ink);      /* 14.31:1 — copy AND headlines */
  --on-paper-soft: var(--c-ink);      /* 14.31:1 — the spec's own default */
  --on-ink:        var(--c-white);    /*  6.84:1 on ink blue */
  --on-ink-soft:   var(--c-pale);     /*  6.02:1 on ink blue */
  --ink-3:         var(--c-ink);

  --link:        var(--c-blue);    /* "Inline links: #3956A8 on #FBEDF0" */
  --accent-text: var(--c-blue);    /* eyebrows, rules, marks — 6.02:1 */
  --hot:         var(--c-tomato);  /* "Price, urgency" — 5.90:1 */
  --signal:      var(--c-blue);    /* the ground's mark colour: rules,
                                      ticks, bullets, bracket glyphs */
  --signal-ink:  var(--c-white);

  /* --- the highlight block ---
     "Badges and highlights: #241F1F on #F3C846", 10.20:1. This is the
     ONLY way yellow appears on the page. On the light field a yellow
     block is 1.40:1 against pale blush, under the 3:1 a non-text
     boundary needs, so it carries its own near-black edge. */
  --badge:      var(--c-yellow);
  --badge-ink:  var(--c-ink);

  /* --- the buttons, exactly as the spec pairs them ---
     "Primary button: #FFFFFF on #3956A8"  6.84:1
     "Secondary button: #FFFFFF on #AF271D"  6.71:1
     Hover darkens to near-black, which the spec names as the safe
     direction: "Darkening ink blue or tomato for hover only raises
     contrast against a white label." */
  --btn-bg:        var(--c-blue);
  --btn-ink:       var(--c-white);
  --btn-bg-hover:  var(--c-ink);
  --btn-ink-hover: var(--c-white);

  --gut: clamp(1.25rem, 4vw, 3.25rem);
  --inset: clamp(0.5rem, 1.6vw, 1.5rem);
  --shell: 1360px;
  /* A translucent ink rather than a solid: it takes its contrast from
     whatever it is drawn on, so one value works on pale blush, on
     white and on blush, and the flipped value below works on both
     dark grounds. No new hue either way. */
  --rule-color: rgba(36, 31, 31, 0.18);
  --rule: 1px solid var(--rule-color);

  /* ================= TYPE SCALE =================
     The colour system here was tokenised to the hue; the type was
     not. Counted on the rendered page: FORTY distinct computed font
     sizes at 1440. Display type earns its bespoke sizes — this is a
     poster, and a poster tunes each headline to its own line. The
     small end had no such excuse. One thing — a short uppercase
     tracked label — was being set at 0.68, 0.70, 0.72, 0.76, 0.78,
     0.80, 0.82, 0.84 and 0.85rem in different corners of the file.
     Nine sizes for one object, none of the differences intentional,
     all of them visible as a faint wrongness when two land near each
     other. Three rungs replace the nine. */
  --label-xs: clamp(0.68rem, 0.645rem + 0.18vw, 0.76rem);  /* badges, legal, tags */
  --label-s:  clamp(0.72rem, 0.68rem + 0.2vw, 0.82rem);    /* eyebrows, nav, sticky bar */
  --label-m:  clamp(0.8rem, 0.75rem + 0.24vw, 0.92rem);    /* the loudest small label */

  /* Reading sizes below the body. Same story, smaller cast. */
  --text-s:  clamp(0.9rem, 0.86rem + 0.2vw, 1rem);         /* captions, notes, fineprint */
  --text-l:  clamp(1.05rem, 0.98rem + 0.5vw, 1.3rem);      /* lifted paragraph */
  --text-xl: clamp(1.2rem, 1rem + 0.9vw, 1.65rem);         /* callout, pull quote */

  /* ================= SPACE SCALE =================
     Forty-plus distinct rem values across margin/padding/gap, with
     1.1, 1.15, 1.2 and 1.25rem all present and doing the same job.
     The section rhythm was already even (100.8px top and bottom on
     every panel) — it is the inside of the components that drifted. */
  /* Two ladders, because this page spaces at two very different
     orders. Inside a component the steps are small and every one of
     them gets used; between sections they are coarse and each is used
     once or twice as a clamp bound. Collapsing both into one list
     made the top end look arbitrary, which is how it got that way.

     Component — 4px to 64px: */
  --s0:  0.25rem;   /*  4 */
  --s1:  0.5rem;    /*  8 */
  --s2:  0.75rem;   /* 12 */
  --s3:  1rem;      /* 16 */
  --s4:  1.25rem;   /* 20 */
  --s5:  1.5rem;    /* 24 */
  --s6:  2rem;      /* 32 */
  --s7:  2.5rem;    /* 40 */
  --s8:  3rem;      /* 48 */
  --s9:  4rem;      /* 64 */

  /* Section — 80px to 240px, poster scale: */
  --sp-1: 5rem;     /*  80 */
  --sp-2: 6.5rem;   /* 104 */
  --sp-3: 8rem;     /* 128 */
  --sp-4: 10rem;    /* 160 */
  --sp-5: 12rem;    /* 192 */
  --sp-6: 15rem;    /* 240 */

  /* ================= MEASURE =================
     `ch` is not a character. It is the advance width of the digit
     ZERO, and in Newsreader that zero is 1.24× the average lowercase
     letter. So every `max-width: Nch` in this file was rendering 24%
     more text per line than the number in it claimed: `.prose` asked
     for 64 and served 79; `.prose--wide` asked for 72 and served 89.
     Measured on the rendered page, not inferred from the spec.

     The numbers below are stated in REAL characters and converted
     once, here. Nobody has to remember the ratio again — and nobody
     has to discover it a third time. */
  --measure-tight: 44ch;   /* ≈ 55 characters */
  --measure:       54ch;   /* ≈ 67 characters — the reading default */
  --measure-wide:  58ch;   /* ≈ 72 characters — the upper bound */
}

/* ---------- 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(--paper);
  color: var(--on-paper);
  font-family: var(--serif);
  font-size: clamp(1.0625rem, 1rem + 0.22vw, 1.1875rem);
  line-height: 1.62;
  font-variant-numeric: oldstyle-nums;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; }
h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul { padding: 0; list-style: none; }
button { font: inherit; }
::selection { background: var(--signal); color: var(--signal-ink); }

/* The focus ring carries its own contrast rather than reading the
   ground: a near-black stroke with a white halo inside it. The two
   are 16.27:1 apart, so whatever is behind them — pale blush, white,
   blush, ink blue, near-black, or a button mid-transition between two
   of those — one of the two is always visible.

   The alternative, flipping the ring per ground, fixed the static case
   and failed on the moving one: .nav__cta sits on the hero and turns
   white on hover, so hovering a focused button made a light ring
   vanish. Chasing every background that changes under a ring is a
   game you lose eventually. One rule, no context, nothing to keep in
   sync. The spec leaves focus open and asks only for 3:1 against both
   the control and the surface; this clears it on every ground the
   page has. */
:focus-visible {
  outline: 3px solid var(--c-ink);
  outline-offset: 3px;
  box-shadow: 0 0 0 3px var(--c-white);
  border-radius: 2px;
}
/* the pill and the plan buttons are already round; let the halo follow */
.nav__cta:focus-visible, .cta-solid:focus-visible, .stickybar .nav__cta:focus-visible {
  border-radius: inherit;
}

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  padding: 0; margin: -1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

.skip {
  position: absolute; left: var(--gut); top: -100px; z-index: 100;
  background: var(--signal); color: var(--signal-ink);
  padding: var(--s2) var(--s3); font-family: var(--sans);
  font-weight: 700; text-transform: uppercase; letter-spacing: 0.08em;
  font-size: var(--label-s); text-decoration: none;
}
.skip:focus { top: 1rem; }

/* ---------- display type ---------- */
.d {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  line-height: 0.86;
  letter-spacing: 0.004em;
  font-variant-numeric: lining-nums;
  text-wrap: balance;
}
/* ---- the ladder ----
   NINE of the eleven section headings on this page were .d--l at
   exactly 88px. Every section was shouting at the same volume for
   fifteen thousand pixels, so none of them was loud. Worse, the close
   — the last thing anyone reads and the only place the page actually
   asks for the sale — was .d--m, set SMALLER than the bio.

   Five rungs at roughly 1.6×, assigned by what a heading is doing in
   the argument rather than by which section it happens to sit in:
   216 the wordmark · 124 a peak · 80 a turn · 50 support · 30 a label.

   On a phone the clamps all bottom out and the ladder collapses — peak
   and major landed 5px apart, which is no ladder at all. The two
   minimums are set apart deliberately so the tiers still read at
   390px: 46 / 32, not 42 / 37. */
.d--xl   { font-size: clamp(3.5rem, 15.5vw, 13.5rem); line-height: 0.8; letter-spacing: -0.005em; }
.d--peak { font-size: clamp(2.9rem, 8.6vw, 8rem); line-height: 0.86; letter-spacing: -0.012em; }
.d--l    { font-size: clamp(2rem, 6vw, 5rem); }
.d--m    { font-size: clamp(1.6rem, 4vw, 3.1rem); }
.d--s    { font-size: clamp(1.35rem, 2.1vw, 1.85rem); line-height: 0.94; }

/* One or two words inside a display line carry the accent. Used
   sparingly — three times on the page, never twice in one view. */
.d .hl, .layer__type .hl { color: var(--accent-text); }

.eyebrow,
.ph-block__tag {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1.5;
  font-variant-numeric: lining-nums;
  color: var(--link);
}

.lede {
  font-size: clamp(1.25rem, 1.05rem + 0.85vw, 1.65rem);
  line-height: 1.45;
  color: var(--on-paper);
}

/* ---------- layout ---------- */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gut);
}
.shell--narrow { max-width: 940px; }

/* Panels sit inset with a margin all round, poster-plate style. */
.panel {
  background: var(--paper);
  color: var(--on-paper);
  margin-inline: var(--inset);
  padding-block: clamp(var(--s8), 7vw, var(--sp-2));
}
/* Every panel had identical padding, so the page had no pacing either
   — thirteen blocks of the same height in the same rhythm. Air now
   follows weight: the turns in the argument get room around them, the
   supporting sections get less and move faster. */
.panel--major { padding-block: clamp(var(--s9), 9vw, var(--sp-3)); }
.panel--quiet { padding-block: clamp(var(--s7), 5vw, var(--s9)); }
.panel + .panel { margin-top: var(--inset); }

/* Panels sit inset by default. The one that OPENS a page runs edge to
   edge instead, the way the hero does on the sales page — an inset
   band at the very top reads as a framed picture rather than as the
   page beginning. Used by the confirmation on thanks-v2.html. */
.panel--bleed { margin-inline: 0; }

.prose p + p { margin-top: 1.05em; }
.prose strong { font-weight: 700; }
.prose em { font-style: italic; }
.prose { max-width: var(--measure); }
.prose--wide { max-width: var(--measure-wide); }
.panel .prose a { color: var(--accent-text); text-decoration-thickness: 1px; text-underline-offset: 3px; }
.panel--dark .prose a { color: var(--link); }

.rule {
  height: 4px;
  background: var(--signal);
  width: 84px;
  border: 0;
}

/* ---------- buttons: bracketed, not boxed ---------- */
.cta {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  font-family: var(--sans);
  font-weight: 800;
  font-size: clamp(0.9rem, 0.84rem + 0.28vw, 1.05rem);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-decoration: none;
  color: var(--accent-text);
  padding: 0.55em 0;
  transition: color 0.25s ease, gap 0.25s ease;
}
.cta::before, .cta::after {
  content: "[";
  font-weight: 500;
  color: var(--signal);
  transition: transform 0.25s ease, color 0.25s ease;
}
.cta::after { content: "]"; }
.panel .cta::before, .panel .cta::after { color: var(--accent-text); }
.cta:hover { gap: 0.85em; }
.cta:hover::before { transform: translateX(-3px); }
.cta:hover::after { transform: translateX(3px); }

/* On any dark ground the label is white and only the brackets carry
   the ground's accent, which is the yellow on both of them. */
.panel--dark .cta, .hero .cta, .close .cta, .proof .cta { color: var(--paper); }
.panel--dark .cta::before, .panel--dark .cta::after,
.hero .cta::before, .hero .cta::after,
.close .cta::before, .close .cta::after,
.proof .cta::before, .proof .cta::after { color: var(--signal); }
.panel--dark .cta:hover,
.hero .cta:hover, .close .cta:hover, .proof .cta:hover { color: var(--signal); }
.panel .cta:hover { color: var(--c-ink); }

/* The one filled button on the page: the plan CTA on pricing. Same
   pill as everywhere else — it was a square block, a fourth button
   shape on a page that had just been reduced to one. */
.cta-solid {
  display: block;
  width: 100%;
  border-radius: 999px;
  text-align: center;
  font-family: var(--sans);
  font-weight: 800;
  font-size: 0.95rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-decoration: none;
  padding: var(--s3) var(--s3);
  background: var(--btn-bg);
  color: var(--btn-ink);
  border: 2px solid var(--btn-bg);
  transition: background 0.22s ease, color 0.22s ease, border-color 0.22s ease;
}
.cta-solid:hover { background: var(--btn-bg-hover); color: var(--btn-ink-hover); border-color: var(--btn-bg-hover); }
/* ============ THE PRIMARY ACTION ============
   The hero offered "Join the first cohort" and "Book a free chat first"
   in identical bracketed type. Two actions of very different value,
   rendered the same, so the page was asking the reader to choose
   without telling them which one it wanted. Across the page the
   primary action also had three different shapes — a bracket, a pill
   in the nav, a square block in pricing — so nothing taught the eye
   what "the button" looks like here.

   One primary from now on. It is INK BLUE with a white label, which is
   what the colour spec asks of a primary button — 6.84:1 on the label
   and 6.02:1 against the pale field behind it. On the two dark bands
   the blue would disappear into the ground, so there it becomes the
   golden yellow with a near-black label: 10.20:1 on the label, and
   4.29:1 against ink blue, over the 3:1 a filled shape needs.

   The bracket stays, demoted to what it is good at: the secondary,
   lower-commitment ask. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--sans);
  font-weight: 800;
  font-size: clamp(0.82rem, 0.76rem + 0.28vw, 0.98rem);
  text-transform: uppercase;
  letter-spacing: 0.1em;
  text-decoration: none;
  padding: 0.95em 1.9em;
  border-radius: 999px;
  border: 2px solid var(--btn-bg);
  background: var(--btn-bg);
  color: var(--btn-ink);
  font-variant-numeric: lining-nums;
  transition: background 0.22s ease, color 0.22s ease, border-color 0.22s ease;
}
.btn:hover { background: var(--btn-bg-hover); color: var(--btn-ink-hover); border-color: var(--btn-bg-hover); }
.btn--lg { font-size: clamp(0.92rem, 0.82rem + 0.5vw, 1.18rem); padding: 1.05em 2.3em; }

/* ---------- the outline button ----------
   The spec's eighth usage rule: "Outline button — #3956A8 border and
   label on #FBEDF0, 6.0:1". It had no implementation, while the hero's
   secondary action was a bracketed text link — a button style the
   palette spec does not contain, sitting next to two of its own that
   went unused.

   In the hero it inverts, exactly as the primary does: a blue border on
   ink blue is 1.0:1, so it becomes white border and white label at
   6.84:1. On the reading surface it is the pairing as written. */
.btn--outline {
  background: transparent;
  color: var(--btn-outline, var(--c-blue));
  border-color: var(--btn-outline, var(--c-blue));
}
.btn--outline:hover {
  background: var(--btn-outline, var(--c-blue));
  color: var(--btn-outline-ink, var(--c-white));
  border-color: var(--btn-outline, var(--c-blue));
}

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(var(--s3), 3vw, var(--s7));
  align-items: center;
}

/* ---------- placeholders ----------
   Golden yellow with a near-black label, which is the badge pairing
   the colour spec names: 10.20:1, and the only ground yellow is
   allowed to be. On the light field a yellow block is 1.40:1 against
   pale blush — under the 3:1 a non-text boundary needs — so it draws
   its own near-black edge rather than dissolving into the page.

   The word PLACEHOLDER is what makes these unmistakable, not the
   colour: it is printed by the inline mark and carried by the block
   label, and it must not be removed until the content replaces it.
   Pre-launch check: grep -i placeholder sarah-v2.html */
.ph-block {
  background: var(--c-yellow);
  color: var(--c-ink);
  outline: 2px solid var(--c-ink);
  padding: clamp(var(--s5), 2.8vw, var(--s6));
}
.ph-block p,
.ph-block .d,
.ph-block__list li,
.ph-block__list li::before { color: var(--c-ink); }

.ph-block__tag,
.panel--dark .ph-block__tag,
.hero .ph-block__tag {
  background: var(--c-ink);
  color: var(--c-white);
  padding: 0.4em 0.75em;
  align-self: flex-start;
}

/* the inline version, for a single unconfirmed value in a sentence */
.ph {
  background: var(--c-yellow);
  color: var(--c-ink);
  box-shadow: 0 0 0 1px var(--c-ink);
  padding: 0.1em 0.4em;
  font-weight: 700;
}
.ph::before { content: "PLACEHOLDER · "; }

.ph-block p + p { margin-top: 0.8em; }
.ph-block__tag { display: block; margin-bottom: var(--s2); }
.ph-block__list { margin-top: var(--s3); display: grid; gap: var(--s1); }
.ph-block__list li {
  position: relative;
  padding-left: var(--s6);
  max-width: var(--measure-wide);
}
.ph-block__list li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.55em;
  width: 1.1rem; height: 1.1rem;
  /* the ground's mark colour: ink blue on the reading surface, and
     near-black wherever it sits on a yellow badge */
  background: var(--signal);
  clip-path: polygon(14% 46%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 38% 70%);
}

/* ---------- floating nav pill ---------- */
.nav {
  position: absolute;
  z-index: 30;
  top: clamp(0.75rem, 1.8vw, 1.4rem);
  left: 50%;
  transform: translateX(-50%);
  width: min(calc(100% - var(--inset) * 2 - 1.5rem), calc(var(--shell) - 2rem));
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s1) var(--s1) var(--s1) var(--s5);
  border-radius: 999px;
  /* A pale blush pill on the ink blue hero: 6.02:1 as a boundary, and
     it puts the page's two grounds against each other at the very top
     instead of inventing a third value to float on. Near-black carries
     the labels at 14.31:1 and the CTA inside is the primary button,
     unchanged — blue with a white label, 6.02:1 against the pill. */
  background: var(--c-pale);
  color: var(--c-ink);
  --on-ink: var(--c-ink);
  --on-ink-soft: var(--c-ink);
  --signal: var(--c-blue);
  --signal-ink: var(--c-white);
  --btn-bg: var(--c-blue);
  --btn-ink: var(--c-white);
  --btn-bg-hover: var(--c-ink);
  --btn-ink-hover: var(--c-white);
}
.nav__brand {
  display: flex;
  align-items: center;
  gap: var(--s1);
  text-decoration: none;
  margin-right: auto;
}
.nav__mark {
  width: 20px; aspect-ratio: 240 / 300;
  background: var(--signal);
  -webkit-mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
}
.nav__word {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-size: 1.15rem;
  color: var(--c-ink);
}
.nav__links { display: flex; gap: clamp(var(--s3), 2.2vw, var(--s6)); margin-inline: auto; }
.nav__links a {
  font-family: var(--sans);
  font-weight: 600;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--on-ink-soft);
  text-decoration: none;
  transition: color 0.2s ease;
}
.nav__links a:hover { color: var(--signal); }
.nav__cta {
  font-family: var(--sans);
  font-weight: 800;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.11em;
  text-decoration: none;
  background: var(--signal);
  color: var(--signal-ink);
  padding: var(--s2) var(--s4);
  border-radius: 999px;
  white-space: nowrap;
  transition: background 0.2s ease, color 0.2s ease;
}
.nav__cta:hover { background: var(--c-white); color: var(--c-ink); }
@media (max-width: 860px) {
  .nav__links { display: none; }
  .nav { width: calc(100% - var(--inset) * 2 - 1rem); padding-left: var(--s3); }
  .nav__word { font-size: 1rem; }
  .nav__cta { padding: var(--s2) var(--s3); font-size: 0.7rem; }
}

/* ---------- announcement + sticky bar ---------- */
.announce {
  background: var(--signal);
  color: var(--signal-ink);
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  text-align: center;
  padding: var(--s2) var(--gut);
  font-variant-numeric: lining-nums;
  position: relative;
  z-index: 2;
}

.stickybar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s5);
  align-items: center;
  justify-content: space-between;
  padding: var(--s2) clamp(var(--s3), 4vw, var(--s7));
  /* The bar is TOMATO, not blue. What it carries is a date, a seat
     count and a button — that is the urgency line, which is half of
     what the spec gives this colour: "Price, urgency, second button."
     It was ink blue, which made blue the hero, both client plates AND
     the one element on screen at all times.

     White on tomato is 6.71:1, the spec's own secondary-button
     pairing; pale blush is 6.28:1 as the second tone. The pill stays
     white with a blue label so the thing you click is the colour it
     has been all page. It also bookends the announcement strip at the
     top, which is the same colour doing the same job. */
  background: var(--c-tomato);
  color: var(--c-white);
  --signal: var(--c-white);
  /* the pill's label is BLUE, not tomato: this bar's button is the same
     action as the nav's, and the thing you click should not change
     colour because of what it happens to be sitting on. Blue on white
     is 6.84:1; a blue PILL is impossible here, since blue on tomato is
     1.02:1 — so the pill inverts and the label carries the identity. */
  --signal-ink: var(--c-blue);
  --btn-bg: var(--c-white);
  --btn-ink: var(--c-blue);
  --btn-bg-hover: var(--c-pale);
  --btn-ink-hover: var(--c-blue);
  --on-ink-soft: var(--c-pale);
  /* The bar already had a 2px line across its top edge doing
     nothing but separating it from the page. On a 17,000px page —
     twenty screens on a phone — the one thing a reader has no way of
     knowing is how much is left, and not knowing is a reason to stop.
     So the line that was already there fills as you scroll. No new
     chrome: the same 2px, given a job. --sp is written by app.js. */
  border-top: 2px solid rgba(255, 255, 255, 0.22);
  background-image: linear-gradient(to right, var(--signal) 0 100%);
  background-repeat: no-repeat;
  background-size: calc(var(--sp, 0) * 100%) 2px;
  background-position: left top;
  transform: translateY(115%);
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}
.stickybar.is-visible { transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  /* the fill is information, not decoration, so it stays — it just
     stops being animated by the browser's own paint smoothing */
  .stickybar { transition: none; }
}
.stickybar__label {
  font-family: var(--sans);
  font-size: var(--label-s);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--on-ink-soft);
  font-variant-numeric: lining-nums;
}
.stickybar__label strong { color: var(--c-white); font-weight: 800; }
@media (prefers-reduced-motion: reduce) { .stickybar { transition: none; } }

/* On a 390×844 phone the bar was taking 140px — one sixth of the
   viewport — because the label wrapped to two lines and pushed the
   button onto a third row. A persistent CTA is worth a strip, not a
   shelf. The brand name is the part that can go: the bar is pinned
   to the page it belongs to, so it is the only thing on it that the
   reader already knows. What is left is the two facts that actually
   move someone — when it starts and how few seats there are. */
@media (max-width: 620px) {
  .stickybar {
    flex-wrap: nowrap;
    gap: var(--s3);
    padding: var(--s2) var(--s3);
  }
  .stickybar__brand, .stickybar__sep { display: none; }
  .stickybar__label {
    font-size: var(--label-xs);
    line-height: 1.25;
    letter-spacing: 0.04em;
  }
  .stickybar .nav__cta { flex: none; white-space: nowrap; }
}

/* ---------- hero ---------- */
.hero {
  /* The press animation (thumb + imprint tokens that lived here) is
     archived in _archive/hero-press-animation/ — RESTORE.md has the
     exact pieces and where each goes. */
  position: relative;
  isolation: isolate;
  /* Flat ground. The photograph that used to fill this band has gone,
     and with it the duotone and the scrim that only existed to keep
     copy legible on top of it. */
  background: var(--ground);
  min-height: clamp(620px, 92vh, 940px);
  display: flex;
  /* Centred poster since 28 Aug: the press animation anchored a
     bottom-left composition; without it the band centres its lockup.
     The top padding clears the fixed nav pill. */
  align-items: center;
  overflow: hidden;
}
.hero__inner {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding: clamp(6rem, 12vh, 7.5rem) var(--gut) clamp(2.5rem, 6vh, 4rem);
}
.hero__eyebrow {
  margin-bottom: clamp(var(--s4), 3vw, var(--s6));
  position: relative;
  z-index: 3;
}

/* Kept after the press animation came out: the narrower measure gives
   the eyebrow its better break — "A 12-week group program / with
   Sarah Raanan". */
@media (max-width: 760px) {
  .hero__eyebrow { max-width: 74%; margin-inline: auto; }
}
.hero__title { margin: 0; }
.hero__the {
  display: block;
  font-family: var(--sans);
  font-weight: 500;
  font-stretch: 78%;
  font-variation-settings: "wdth" 78, "wght" 500;
  text-transform: uppercase;
  letter-spacing: 0.34em;
  font-size: clamp(0.85rem, 0.7rem + 0.75vw, 1.3rem);
  color: var(--paper);
  margin-bottom: clamp(var(--s1), 1vw, var(--s2));
}
.hero__bigwrap { display: block; position: relative; }
.hero__big { display: block; }
.hero__sub {
  margin-top: clamp(var(--s5), 3vw, var(--s6));
  max-width: 34ch;
  font-size: clamp(1.15rem, 1rem + 0.75vw, 1.55rem);
  line-height: 1.45;
  color: var(--paper);
}
/* Centred since the press animation came out: the wordmark anchored a
   left composition against the hand; alone, it reads as a poster and a
   poster sets its title in the middle. */
.hero__inner { text-align: center; }
.hero__sub { margin-inline: auto; }
.hero .cta-row { margin-top: clamp(var(--s5), 3.2vw, var(--s7)); justify-content: center; }
.hero__trust {
  margin-top: clamp(var(--s5), 2.6vw, var(--s6));
  font-family: var(--sans);
  font-size: var(--label-s);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--on-ink-soft);
  font-variant-numeric: lining-nums;
}
/* ---------- details strip ---------- */
.details {
  background: var(--paper);
  color: var(--on-paper);
  margin-inline: var(--inset);
  margin-top: var(--inset);
}
.details__grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
}
.details__item {
  padding: clamp(var(--s5), 3.2vw, var(--s7)) clamp(var(--s4), 2.4vw, var(--s6));
  display: block;
  border-right: var(--rule);
}
.details__item:last-child { border-right: 0; }
/* Four items, four of her colours, one each — repeated as a set
   rather than sprinkled, so it reads as a system. */
.details__item { border-top: 6px solid var(--item-hue, transparent); }

.details__label {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-xs);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--on-paper-soft);
  margin-bottom: var(--s1);
}
.details__value {
  font-family: var(--sans);
  font-weight: 800;
  font-stretch: 78%;
  font-variation-settings: "wdth" 78, "wght" 800;
  /* the value is the fact; it should be the size of a fact, not of a
     caption sitting next to a piece of clip art */
  font-size: clamp(1.15rem, 0.95rem + 0.85vw, 1.75rem);
  line-height: 1.06;
  text-transform: uppercase;
  letter-spacing: -0.005em;
  font-variant-numeric: lining-nums;
  margin-top: 0.12em;
}
.details__value .ph { font-stretch: normal; font-variation-settings: normal; }
.details__note {
  margin-top: 0.55em;
  margin-top: var(--s1);
  font-family: var(--sans);
  font-size: var(--text-s);
  line-height: 1.35;
  color: var(--on-paper-soft);
}

/* ---------- section heads ---------- */
.head { margin-bottom: clamp(var(--s6), 4vw, var(--s8)); }

/* Heading over lede over prose, eleven times, is what made the page
   read as one block repeated. On a major turn the lede now sits BESIDE
   the heading and rests on its last baseline, which gives the section
   a different silhouette and lets the headline run bigger without
   pushing the reading down the screen. */
@media (min-width: 900px) {
  .head--split {
    display: grid;
    grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
    column-gap: clamp(var(--s6), 4vw, var(--s9));
    align-items: end;
  }
  .head--split > .eyebrow { grid-column: 1 / -1; }
  .head--split > .lede { margin-top: 0; max-width: none; padding-bottom: 0.4em; }
}
.head .eyebrow { margin-bottom: clamp(var(--s2), 1.6vw, var(--s4)); }
.head .lede { margin-top: clamp(var(--s3), 2vw, var(--s5)); max-width: 46ch; }
.head--center { text-align: center; }
.head--center .lede { margin-inline: auto; }

/* ---------- testimonials ---------- */
.proof {
  margin-inline: var(--inset);
  margin-top: var(--inset);
  padding-block: clamp(var(--s8), 6vw, var(--sp-1));
  border-left: 5px solid var(--signal);
}
.proof__grid {
  display: grid;
  gap: clamp(var(--s5), 4vw, var(--s9));
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
  align-items: end;
  margin-top: clamp(var(--s3), 2vw, var(--s5));
}
@media (max-width: 900px) { .proof__grid { grid-template-columns: 1fr; align-items: start; } }
.proof__shout {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  line-height: 0.88;
  letter-spacing: 0.004em;
  font-size: clamp(2rem, 5.6vw, 4.5rem);
  color: var(--signal);
  max-width: 20ch;
}
.proof__quote {
  margin-top: clamp(var(--s4), 2.6vw, var(--s6));
  font-size: clamp(1.05rem, 0.98rem + 0.5vw, 1.3rem);
  line-height: 1.5;
  font-style: italic;
  color: var(--paper);
  max-width: 56ch;
}
.proof__attr {
  margin-top: clamp(var(--s3), 2.2vw, var(--s5));
}
.proof__name {
  font-family: var(--sans);
  font-weight: 800;
  font-size: 0.9rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--signal);
}
.proof__role {
  font-family: var(--sans);
  font-weight: 500;
  font-size: var(--label-s);
  letter-spacing: 0.04em;
  color: var(--on-ink-soft);
}

.quotes {
  display: grid;
  gap: var(--inset);
  /* a hard 300px minimum overflows a 320px phone once the shell's
     gutters are taken off — min() lets the column give way instead */
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  margin-top: clamp(var(--s6), 4vw, var(--s8));
  /* the cards had padding doing the vertical rhythm; with the box gone
     the grid has to do it, and rows need far more room than columns —
     a quote has to end before the next one starts */
  /* Widened once two of the cards took a yellow ground. The gold card
     bleeds outward by its own padding so its TEXT stays on the same
     edge as the plain cards, which means the yellow eats into this gap
     from one side. At the old 32-48px it left only 16px of clear
     ground between a yellow edge and the neighbouring card's text. */
  column-gap: clamp(var(--s7), 4vw, var(--s9));
  row-gap: clamp(var(--s8), 5vw, var(--sp-1));
}
.quote {
  /* was a 4px rule over each quote. Five stacked rules read as a tally,
     not as five people, so the card takes a surface instead.

     White against pale blush is only 1.14:1 — the two light grounds
     are close by design, and the spec is explicit that a boundary
     needs 3:1 to be seen. So the surface alone cannot carry the edge;
     a hairline does, and the surface makes it a card rather than a
     box. Both, or neither works. */
  /* NO BOX. Five outlined rectangles of near-identical size read as a
     wall of blurb — and the box was only ever there because the card
     had no surface of its own to sit on. White is not available (it is
     a label in this palette, not a ground) and the field cannot
     separate from itself.

     What separates them now is her own hand: the drawn squiggle under
     each pulled phrase, from her doodle set. Every quote starts with a
     bold phrase and a mark, which is a stronger entry point than an
     outline was. */
  background: transparent;
  border: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
}

/* Four quotes, not five — the headshots placeholder is gone, because
   Sarah is not supplying the photographs. Three-up left a ragged row of
   one; two-up makes it an even 2x2 at desktop. Below 1000px the
   auto-fit above still runs, so tablet and phone are untouched. */
@media (min-width: 1000px) {
  .quotes { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* The auto-fit grid above drops to one column on its own once the
   container can no longer hold two 300px cards side by side — measured
   at exactly 720px viewport and under (721px is already two-up; the
   number falls out of --gut and .quotes' own column-gap, both vw-based
   clamps, so re-measure if either token changes). In two columns the
   gold cards sit on the diagonal and are never adjacent. Stacked to
   one column, DOM order alone would read cream, gold, gold, cream —
   Estelle (gold, 2nd) sits directly above Justine (gold, 3rd). Tamara:
   "it should be cream, yellow, cream, yellow." CSS order swaps Justine
   and Leslie's VISUAL position only; the DOM and the reading/tab order
   both still run Alana, Estelle, Justine, Leslie — screen reader and
   keyboard users hear/reach the cards in that order regardless of
   which one sits where on screen. Not reordering the DOM was
   deliberate: the sighted alternation and the read-aloud order are two
   different things and only one of them was broken. */
@media (max-width: 720px) {
  .quotes .quote:nth-child(3) { order: 4; }
  .quotes .quote:nth-child(4) { order: 3; }
}

/* Two of the four take the yellow, on the diagonal. Losing the
   placeholder took the only yellow out of this section and left it
   reading as one long field of pale blush; this puts it back as
   emphasis rather than as review furniture.

   The bleed is padding plus an equal negative margin, so the quote's
   text stays on the same left edge as the heading above it and the
   yellow grows outward instead of pushing the words in. No two gold
   cards are adjacent, so only one side of any gap is ever pulled. */
.quote--gold {
  --gold-bleed: clamp(1rem, 1.6vw, 1.5rem);
  background: var(--c-yellow);
  padding: var(--gold-bleed);
  margin: calc(-1 * var(--gold-bleed));
}
/* The wall of five equal quotes had no entry point — same size, same
   weight, same grey italic, so the eye landed nowhere and the reader
   took none of it in. Each card now leads with a line lifted VERBATIM
   out of its own quote, at display size. Five phrases can be scanned;
   five paragraphs cannot. The full quote stays underneath, so nothing
   is hidden and nothing is summarised. */
.quote__pull {
  font-family: var(--sans);
  font-weight: 700;
  font-stretch: 84%;
  font-variation-settings: "wdth" 84, "wght" 700;
  font-size: clamp(1.15rem, 0.98rem + 0.68vw, 1.55rem);
  line-height: 1.16;
  letter-spacing: -0.008em;
  color: var(--on-paper);
  margin-bottom: 0.7em;
  text-wrap: balance;
  padding-bottom: 0.5em;
}
/* Her squiggle, from her own doodle set, masked rather than placed as
   an image — so recolouring it is a token change and it can never
   arrive in a hue the palette does not hold. Raspberry is the spec's
   "display type and GRAPHICS": 3.95:1 on pale blush, over the 3:1 a
   graphic needs. It underlines rather than bullets, which is what a
   pulled phrase wants.

   It used to anchor to .quote__pull itself — left:0 of the whole
   block, meaning it sat under whatever happened to open the line, not
   under the phrase that carries the point. Tamara: "underline should
   be under 'business sense' not 'sarah blew'." The mark now anchors to
   a span around the load-bearing phrase instead, so it travels with
   that phrase wherever the line wraps it. inline-block so the phrase
   moves as one unit if the pull wraps around it, rather than the mark
   splitting mid-phrase. */
.quote__pull-mark { position: relative; display: inline-block; }
.quote__pull-mark::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -0.56em;
  width: 100%;
  height: 20px;
  /* Tokenised, because this mark now appears on two grounds. Raspberry
     is 3.95:1 on the reading surface and clears the 3:1 a graphic
     needs — but only 2.81:1 on the yellow card, which fails. The badge
     ground below flips it to near-black; it must never be picked by
     hand here again. */
  background: var(--quote-mark, var(--c-rasp));
  -webkit-mask: url("assets/brand/doodles-95-blue_ai.png") no-repeat left bottom / 100% 100%;
  mask: url("assets/brand/doodles-95-blue_ai.png") no-repeat left bottom / 100% 100%;
}

.quote__text {
  font-size: 1.02rem;
  line-height: 1.55;
  font-style: italic;
  flex: 1;
}
.quote__attr { margin-top: var(--s4); }
.quote__name {
  font-family: var(--sans);
  font-weight: 800;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--accent-text);
}
.quote__role {
  font-family: var(--sans);
  font-weight: 500;
  font-size: var(--label-s);
  color: var(--on-paper-soft);
}

/* ---------- supporting blocks ---------- */
.clue {
  margin-block: clamp(var(--s6), 4vw, var(--s8));
  border: 1px solid var(--ink-3);
  border-left: 5px solid var(--on-dark-disp);
  padding: clamp(var(--s4), 2.6vw, var(--s6));
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  max-width: var(--measure);
}

.band {
  /* was a 3px rule across the section. A line to say "a new thing starts
     here" is the cheapest possible separator and it reads as filler.
     Space says it instead, and the pill is already a hard visual stop. */
  margin-top: clamp(var(--s8), 6vw, var(--sp-1));
  padding-top: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2) var(--s6);
  align-items: baseline;
  justify-content: space-between;
}
.band__label {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.16em;
  font-variant-numeric: lining-nums;
  color: var(--on-paper-soft);
}
/* This label lives on a dark band. White clears both of them —
   6.84:1 on ink blue and 16.27:1 on near-black — where the ground's
   accent would only clear one. */
.panel--dark .band__label,

.twocol {
  display: grid;
  gap: clamp(var(--s6), 4vw, var(--s9));
  /* Not even. The left column carries running prose and the right
     carries blocks, so at 1fr 1fr the left set to ~75 characters —
     wider than the measure the rest of the page reads at — and ran
     short while the blocks ran long. Both columns here lean the same
     way ("What's included" and "My promise to you"), so the same
     ratio corrects both: prose to a proper measure, blocks wider and
     therefore shorter. The heights closing is the consequence. */
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  align-items: start;
  /* movement-break scale, same as .band's own margin-top — a twocol
     always follows a distinct preceding block (the phases grid, the
     guarantee row), never a heading alone, so it reads as a new
     thought rather than a continuation. Was clamp(s7,5vw,s9), 64px at
     1440; too close to the phases grid below it. */
  margin-top: clamp(var(--s8), 6vw, var(--sp-1));
}
/* .twocol's margin-top is an INTERNAL separator — it puts air between
   whatever precedes it and the two columns ("What's included" after
   the phases; "What I guarantee" after the guarantee row). A first-child
   .twocol used to sit directly in .shell here and its margin collapsed
   straight through the shell's own padding — 128 + 64 = 192 where every
   other major panel opens at 128. Fixed properly by giving the section
   a heading and a guarantee row ABOVE the twocol, which is real content
   the section needed anyway, not a CSS workaround for a void. */

/* Scoped re-introduction of the fix the log already worked out once
   (25/26 Aug): when a .twocol is the section's own first flow child,
   its margin-top collapses straight through .shell (no padding of its
   own) and lands ON TOP of the section's padding-block instead of
   inside it — 128 + this margin, not 128. The "is this for you"
   section's twocol is back in that exact position now that the
   guarantee row moved out from above it. The section's own 128px
   padding already reads as the "generous headroom" the fix asked for;
   this modifier is what keeps a second helping of it from stacking on
   top. Not a blanket rule — only .twocol instances that open a section
   need it, so it stays a modifier rather than a :first-child selector. */
.twocol--open { margin-top: 0; }

/* Tamara: "i also want the this is for you/not for you to make more
   sense logically. not for u is currently bigger than the for u which
   i think send the wrong message." The base .twocol ratio (0.82fr /
   1.18fr) was built for the OTHER twocol on this page, where the right
   column carries the wider block ("What's included" / the tools box).
   Here both columns are `.ticks` lists and the base ratio just handed
   the extra width to the three-paragraph NOT column — the opposite of
   what five short affirmations against three long refusals should
   read as. Reversed and re-weighted toward "for you", scoped to this
   instance only so the "What's included" twocol is untouched. */
.twocol--fit { grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr); }

.stack { display: grid; gap: var(--inset); }
.twocol .ticks { margin-top: var(--s4); }
@media (max-width: 900px) { .twocol { grid-template-columns: 1fr; } }

.marmite-layer { margin-top: clamp(var(--s7), 5vw, var(--s9)); }
@media (min-width: 900px) {
  /* the print crosses the tail of the first line only, so the
     sentence underneath stays readable */
  .marmite-layer .layer__print { right: 7%; top: -16%; }
}
@media (min-width: 900px) {
  /* .close__layer rules removed with the layer itself — the prints
     they positioned no longer exist. Left behind they would be a
     template ghost: geometry describing content that is gone. */
}
.spread--flip .spread__art { order: 2; }
@media (min-width: 1025px) {
  /* The portrait ran taller than the bio and the gap GREW with the
     viewport — 244px at 1280, 363px at 1440. Widening the text column
     is what did it: fewer, longer lines make the prose shorter while
     a fixed-aspect photograph keeps scaling with its own column. Both
     caps below hold each side to a size it should have anyway, and the
     mismatch closes as a consequence rather than as the goal. */
  .spread--flip { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr); }
  .spread--flip .spread__art { order: 0; }
  /* 4:5 at 520px is still the largest photograph on the page. Past
     that it is only tracking the column. */
  .spread--flip .plate--portrait { max-width: 520px; }
  /* Her sentences are long; at the full column they set to ~72
     characters, over the measure the rest of the page reads at. */
  .spread--flip .prose { max-width: 30rem; }
}

/* ---------- pull quote ---------- */
.shout {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  line-height: 0.86;
  font-size: clamp(2.4rem, 8vw, 6.5rem);
  color: var(--signal);
  letter-spacing: 0.004em;
}
/* The shout is 104px of type, so it takes the section's accent the
   way every other display element here does — 5.90:1 in tomato on
   pale blush, 6.02 in blue. On a blush band it is near-black, because
   nothing else may run there. */
.panel:not(.panel--dark):not(.close)[data-accent] .shout { color: var(--accent); }

/* ---------- prints ----------
   Photographs appear as prints: one border weight, one caption
   treatment, one rotation value used in mirror. The tilt is a
   system, not an ornament — every print on the page is built
   from these two rules and nothing is tilted that is not a print. */
@media (prefers-reduced-motion: reduce) {
  .print { transition: none; }
  .print:hover { transform: rotate(var(--tilt)); }
}

/* ---------- type and image on the same layer ----------
   The light counterpart to the blue hero: near-black display type
   running the full measure with a photograph sitting over the
   letterforms. */
.layer {
  position: relative;
  isolation: isolate;
}
.layer__type {
  position: relative;
  z-index: 2;          /* the type sits above the photograph */
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  line-height: 0.82;
  letter-spacing: -0.008em;
  font-size: clamp(3.1rem, 13.4vw, 11.5rem);
  color: var(--on-paper);
  margin: 0;
}
.panel--dark .layer__type, .close .layer__type { color: var(--paper); }
.layer__print {
  width: clamp(160px, 22vw, 300px);
  margin: clamp(var(--s5), 3vw, var(--s6)) auto 0;
}
@media (min-width: 900px) {
  .layer { padding-block: clamp(var(--s5), 4vw, var(--s9)); }
  .layer__print {
    position: absolute;
    z-index: 2;
    margin: 0;
  }
  .layer__print--a { right: 2%; top: 0; }
}

/* ---------- fingerprint / marmite spread ---------- */
.spread {
  display: grid;
  gap: clamp(var(--s6), 4vw, var(--s9));
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  align-items: start;
}
.spread__art { position: relative; }
.spread__art .print { max-width: 420px; }

/* ---------- letting the prose breathe ----------
   Her copy already alternates long explanation with very short
   lines — "But it's still early." / "The bad habits haven't had time
   to set in stone." A single flat column was flattening a rhythm
   that is already in the writing. Nothing here changes a word: the
   short lines are given scale and air, and the long ones stop
   forming one unbroken left edge. */
.prose--airy { max-width: var(--measure); }
.prose--airy p { line-height: 1.72; }
.prose--airy p + p { margin-top: 1.9em; }

/* the short lines get to be statements rather than stubs */
.prose .beat {
  max-width: 26ch;
  text-wrap: balance;   /* no orphaned last word on a two-line beat */
  color: var(--beat-hue, inherit);
  font-family: var(--sans);
  font-weight: 700;
  font-stretch: 78%;
  font-variation-settings: "wdth" 78, "wght" 700;
  font-size: clamp(1.45rem, 1.05rem + 1.5vw, 2.35rem);
  line-height: 1.14;
  letter-spacing: -0.012em;
}
.prose--airy p.beat + p,
.prose--airy p + p.beat { margin-top: 2.5em; }
.prose--airy p.beat + p.beat { margin-top: 0.5em; }

/* Long runs set as two narrow columns rather than one tall one.
   The alternating indent this replaces was a rule applied every
   other paragraph — which reads as a pattern, not as rhythm. On
   thelonglunch.studio nothing runs wider than about 40% of the
   viewport, prose sits in pairs of narrow columns, and statements
   are a different SIZE rather than a different indent. */
.prose__cols > p { margin-top: 0; margin-bottom: 1.5em; }
.prose__cols > p:last-child { margin-bottom: 0; }
/* the statements need air on both sides of a column block — the
   p + p rules above no longer reach, the sibling is a div now */
.prose--airy > .beat + .prose__cols { margin-top: 2.1em; }
.prose--airy > .prose__cols + .beat { margin-top: 2.6em; }
.prose--airy > .prose__cols + .prose__cols { margin-top: 2.1em; }

@media (min-width: 900px) {
  .prose--airy { max-width: none; }
  .prose__cols {
    /* Column-width-first (`columns: 21rem 2`) let the block decide its
       own count, which sounds right and measured wrong. The gap was
       `clamp(2.5rem, 5vw, 5rem)` — it grows with the VIEWPORT, while the
       container is capped at .shell--narrow. Past about 1300px the gap
       is still growing and the container is not, so the gap eats the
       column budget from the inside: at 1440 the block had 736px and
       needed 744, and five of the seven runs on this page silently fell
       back to ONE column at 84–99 characters a line. Measured, not
       guessed. It also made the page read WORSE on a large monitor than
       on a small laptop, which is the tell.

       Fixed count, fixed gap. Two columns at every width this query
       covers, and the measure stops depending on the window. */
    columns: 2;
    column-gap: var(--s8);
    max-width: min(980px, 100%);
    font-size: 0.94em;
  }
  /* The bio sits in a ~540px grid cell, where two columns give 240px
     each — too narrow to read. That cell is the one place the block
     genuinely wants a single column, so it asks for one by name
     rather than relying on a width race it kept losing. */
  .prose__cols--single { columns: 1; max-width: var(--measure); }
  .prose__cols > p { break-inside: avoid; }
  /* the statement lines are the only full-measure things here */
  .prose--airy > p.beat { max-width: 24ch; }
}

/* ---------- the beats' air ----------
   The pair that turns the page toward the group ("...alone",
   "...on purpose") gets a movement-scale gap on every side. A drawn
   frame was tried here and removed — the log's 27 Aug entries have
   the history; do not re-add one. */
.beat-air { margin-block: clamp(2.75rem, 4.5vw, 4rem); }

/* ---------- where the rest of the palette lives ----------
   Golden yellow cannot be type on the light field at all — 1.40:1 on
   pale blush — and raspberry only clears at display size. So both
   earn their place as blocks and marks rather than as letterforms,
   and the text accents rotate by MEANING rather than by position.
   The two photo plates below are declared in the tail of this file
   with the rest of the emphasis map. */

/* ---------- the plate ----------
   Replaces the tilted print in the Marmite layer. Same instinct —
   a photograph sitting on top of the type — but squared off, larger,
   and framed by a flat block of one palette colour plus one mark from
   her own doodle set rather than by a Polaroid pastiche. It is
   absolutely positioned, so it can grow up into the paragraph above
   and down over the letterforms without the section getting taller. */
.plate {
  position: relative;
  display: block;
  margin: 0;
  /* One solid card rather than a photo sitting on an offset block.
     The offset produced two stepped corners along the bottom edge —
     the block's and the caption's — which read as a rendering fault
     rather than as a device. */
  background: var(--plate-block, var(--signal));
  /* The photograph runs flush to the plate's edges and the blush shows
     only as the caption bar beneath it. With a frame all round, the
     last glyph and a half of "MARMITE." crossed flat blush at 2.43:1 —
     raspberry needs 3:1 even at display size. Flush, the word crosses
     the photograph instead, which is what the composition was always
     about: type and image on the same layer. */
  padding: 0;
}
/* the photograph only — the doodle marks are also imgs inside .plate,
   and a bare `.plate img` outranks `.plate__mark` on specificity */
.plate img:not(.plate__mark) {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: auto;
  filter: grayscale(0.12) contrast(1.04) saturate(0.96);
}
.plate figcaption {
  position: relative;
  z-index: 1;
  margin-inline: 0;   /* the plate has no padding to bleed back out of */
  font-family: var(--serif);
  font-style: italic;
  font-weight: 600;
  font-size: clamp(1.05rem, 0.85rem + 0.72vw, 1.5rem);
  line-height: 1.15;
  color: var(--ink);
  background: var(--plate-block, var(--signal));
  text-align: center;
  padding: 0.55em 0.4em 0.6em;
}
/* Her own marks, breaking the edge of the plate. Decorative only.
   The drawings ship as peach PNGs, which is a hue the page no longer
   holds, so they are used as MASKS rather than as pictures: the
   artwork supplies the shape and the colour comes from the palette.
   One consequence worth knowing — recolouring one of these is now a
   token change, not a new export. */
.plate__mark {
  position: absolute;
  z-index: 2;
  pointer-events: none;
  width: var(--mark-w, 22%);
  height: auto;
  background: var(--mark-hue, var(--c-blue));
  -webkit-mask: var(--mark-src) no-repeat center / contain;
  mask: var(--mark-src) no-repeat center / contain;
}
/* A quarter-round from the kit, breaking out of the plate's top-right
   corner. It replaced her bolt, and before that a comma from the same
   kit — which had to go because a comma sitting beside body copy reads
   as punctuation, not as a mark. A quarter-round in a corner cannot be
   mistaken for a glyph.

   The colour still comes from --mark-hue, so the contrast reasoning is
   unchanged: the mark breaks out of a blush card onto the pale field
   and has to hold against both, and ink blue is 3.70:1 on blush and
   6.02:1 on pale blush. Yellow would have been 1.16 and 1.40. */
.plate__mark--spark {
  --mark-src: url("assets/kit/mark-corner.png");
  --mark-hue: var(--c-blue);
  --mark-w: 13%;
  aspect-ratio: 399 / 411;
  right: -5%;
  top: -5%;
  transform: rotate(0deg);
}

@media (min-width: 900px) {
  /* bigger, squarer, and straddling the paragraph above.
     position is restated here because .plate above sets relative at
     the same specificity and later in the file, which would win. */
  .marmite-layer .layer__print {
    position: absolute;
    /* under the display type, not over it: the words have to read */
    z-index: 1;
    margin: 0;
    width: clamp(260px, 31vw, 430px);
    right: 0;
    top: clamp(-15rem, -17vw, -7rem);
  }
}
@media (max-width: 899px) {
  .plate { width: min(78%, 340px); margin-inline: auto; }
  .plate__mark--point { --mark-w: 34%; left: -18%; }
}

/* ---------- the turn ----------
   One statement, its kicker, and the promise it sets up. The statement
   runs to the full shell so it stops ending in dead space; the kicker
   hangs off its last line rather than starting a new block; the promise
   is lifted out of body size and indented away from both, so the eye
   reads statement → warning → payoff instead of three paragraphs. */
.turn { margin-top: clamp(var(--s6), 4vw, var(--s8)); }
.turn__statement { max-width: 18ch; }
.turn__kicker {
  margin-top: clamp(var(--s3), 1.8vw, var(--s5));
  font-family: var(--sans);
  font-weight: 700;
  font-stretch: 84%;
  font-variation-settings: "wdth" 84, "wght" 700;
  font-size: clamp(1.15rem, 0.95rem + 0.9vw, 1.75rem);
  line-height: 1.18;
  max-width: 22ch;
  color: var(--on-paper);
  text-wrap: balance;
}
.turn__promise {
  margin-top: clamp(var(--s7), 5vw, var(--sp-1));
  font-size: var(--text-l);
  line-height: 1.5;
  max-width: var(--measure);
  color: var(--on-paper);
}
.turn__promise strong { font-weight: 700; }

@media (min-width: 900px) {
  /* the statement and its kicker share a baseline band: the kicker sits
     to the right of the last line rather than under the whole block */
  .turn {
    display: grid;
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
    column-gap: clamp(var(--s6), 4vw, var(--s9));
    align-items: end;
  }
  .turn__kicker { margin-top: 0; padding-bottom: 0.5em; }
  /* the promise steps in from the left edge — it is an answer, and it
     should not start on the same axis as the question */
  .turn__promise { margin-inline-start: 38%; }
}

/* ---------- numbered steps: the row variant ---------- */

/* --- the row ---
   Three parallel steps read as a sequence side by side and as a list
   when they stack.

   The first attempt hung them on vertical dividers, and measured
   wrong: each fingerprint sat at `mark left offset 0` — flush against
   its column's left edge, which is directly against the previous
   column's rule — with 332px of empty space on its other side. Every
   mark was jammed into a line it had nothing to do with. The rule
   itself was a tint of a hue the page no longer holds.

   Dividers are the wrong device anyway: they cut vertical space that
   is not being contested. What the three steps need is a common
   BASELINE — the fingerprints sit on it the way a press sits on
   paper, which is the metaphor the whole page is built from, and each
   one is centred over its own segment so nothing is jammed against
   anything. The line breaks at the column gaps, so the three read as
   three. */
@media (min-width: 860px) {
  /* .steps--row and .steps score the same, and .steps { gap: 0 } is
     declared further down the file, so the bare class loses the gap on
     source order. Doubled up so the row wins on its own terms. */
  .steps.steps--row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: clamp(var(--s6), 4.5vw, var(--s9));
    border: 0;
  }
  .steps--row .step {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 0;
    padding: 0;
    border: 0;
  }
  /* the press, centred over its own segment */
  .steps--row .step__mark {
    width: clamp(4.6rem, 6.2vw, 6.6rem);
    margin-inline: auto;
    margin-bottom: clamp(var(--s3), 1.4vw, var(--s4));
  }
  .steps--row .step__num { font-size: clamp(2rem, 3vw, 3rem); }
  /* the paper it presses onto */
  .steps--row .step p {
    margin: 0;
    padding-top: clamp(var(--s3), 1.4vw, var(--s4));
    max-width: none;
  }
}

/* The row variant shares one rule across all three steps, so the rule
   itself cannot be per-step; the numerals above it still are, and they
   read --step-hue with the rest of them at the foot of this file. */
.steps--row { --step-rule: var(--c-blue); }

/* ---------- numbered steps ---------- */

.steps {
  display: grid;
  gap: 0;
  counter-reset: step;
}
.step {
  display: grid;
  grid-template-columns: clamp(4.5rem, 9vw, 7.5rem) minmax(0, 1fr);
  gap: clamp(var(--s3), 2.5vw, var(--s6));
  padding-block: clamp(var(--s5), 3vw, var(--s7));
  border-bottom: var(--rule);
  /* Was baseline, which pinned the numeral's baseline to the FIRST
     line of the paragraph — and because the numeral is five times
     the body size, all of its mass then hung above the text and read
     as unaligned. Centred against the whole paragraph instead. */
  align-items: center;
}

/* The step marker: the number sitting in the middle of a fingerprint,
   the same mark the nav and the hero use. */
.step__mark {
  position: relative;
  display: grid;
  place-items: center;
  width: clamp(3.6rem, 7.4vw, 5.6rem);
  aspect-ratio: 240 / 300;
}
.step__mark::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--step-hue, var(--accent-text));
  opacity: 0.28;
  -webkit-mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
}

.step__num {
  position: relative;
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  /* smaller than before: it now sits inside the mark rather than
     standing in for one */
  font-size: clamp(1.6rem, 3.4vw, 2.6rem);
  line-height: 1;
  color: var(--step-hue, var(--accent-text));
  font-variant-numeric: lining-nums;
}
.step p { max-width: 56ch; }

/* ---------- F.I.N.D. phases ---------- */
.phases {
  display: grid;
  gap: var(--inset);
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-top: clamp(var(--s6), 4vw, var(--s8));
}
/* four across only when four fit; 2x2 rather than an orphaned card */
@media (max-width: 1240px) { .phases { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 560px) { .phases { grid-template-columns: 1fr; } }
/* These were filled boxes stretched to equal height over four unequal
   paragraphs, so two of the four carried about 145px of empty fill and
   read as unfinished rather than as designed.

   They are the same OBJECT as the three steps further up the page — a
   sequence laid across the width — so they now use the same grammar:
   a column under its own rule, sized by its own content. Unequal
   lengths then read as what they are, four different amounts to say,
   rather than as four boxes someone forgot to fill. Two sections doing
   one job in one visual language. */
.phase {
  color: var(--on-paper);   /* the ground decides; this section is light now */
  padding: clamp(var(--s4), 2vw, var(--s5)) clamp(var(--s5), 2.4vw, var(--s6)) 0 0;
  display: flex;
  flex-direction: column;
}
.phases { align-items: start; }
.phase__weeks {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-xs);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--on-dark-disp);   /* yellow, 4.29:1 on the blue band */
  font-variant-numeric: lining-nums;
}
.phase__name {
  margin: var(--s1) 0 var(--s3);
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  font-size: clamp(2rem, 3.4vw, 2.9rem);
  line-height: 0.88;
  /* the ground decides, like every other heading: white on ink blue,
     near-black on the reading surface. It was pinned to pale blush,
     which is legal at 6.02 but made these four the only headings on
     the band that were not white. */
  color: var(--on-paper);
}

.phase p:last-child { font-size: 1rem; line-height: 1.55; color: var(--on-paper); }

/* ---------- lists ---------- */
.ticks { display: grid; gap: clamp(var(--s3), 1.8vw, var(--s4)); margin-top: var(--s5); }
.ticks li {
  position: relative;
  padding-left: var(--s6);
  max-width: var(--measure-wide);
}
.ticks li::before {
  content: "";
  position: absolute;
  left: 0; top: 0.55em;
  width: 1.1rem; height: 1.1rem;
    /* the ground's mark colour: ink blue on the reading surface,
     near-black on a yellow badge */
  background: var(--signal);
  clip-path: polygon(14% 46%, 0 60%, 40% 100%, 100% 22%, 86% 8%, 38% 70%);
}

.crosses li::before {
  background: var(--hot);
  clip-path: polygon(20% 0, 50% 30%, 80% 0, 100% 20%, 70% 50%, 100% 80%, 80% 100%, 50% 70%, 20% 100%, 0 80%, 30% 50%, 0 20%);
}

/* ---------- the NOT-for-you column: stepped down a rung ----------
   Same demotion the five tools got ("The five tools stepped down a
   rung", 27 Aug): a hairline box, since white is a label in this
   palette and never a surface, and body type a half-step under the
   list beside it. Her heading stays untouched — same `d d--s` scale
   as "This is for you if:" — the demotion is in the box and the body
   only, so the reader still sees two headings of equal weight and one
   list that's visibly the secondary read. Scoped to this column only;
   `.crosses`' tomato marks (5.90:1) are untouched. */
.not-for-you {
  border: var(--rule);
  padding: clamp(var(--s5), 2.6vw, var(--s7));
  align-self: start;
}
.not-for-you .ticks li { font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.05rem); }

/* the three-item guarantee row. It used to sit alongside the five-plus-
   three "for you if / not for you if" lists in a twocol, where three
   short items next to eight left roughly 380px of pale blush hanging
   under the shorter column — the same void the portrait and "What's
   included" sections had, both times fixed by giving the block the
   width its content actually needs rather than padding a number.
   A row of three, full width, is that fix here: it needs one line each
   instead of a half-empty column. */
@media (min-width: 860px) {
  .ticks--row {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    column-gap: clamp(var(--s6), 4vw, var(--s8));
  }
}

/* ---------- pricing ---------- */
.plans {
  display: grid;
  gap: var(--inset);
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  margin-top: clamp(var(--s6), 4vw, var(--s8));
}
/* Three equal boxes with hairline borders is the single most generic
   pattern on the internet, and it did not belong to the rest of this
   page — everything else here is either an unbordered panel or a soft
   pill. The boxes are gone. What separates the plans now is what
   actually differs about them: the recommended one is a near-black
   plate with its price in golden yellow, the other two are white
   cards, and the recommended one is physically taller because it is
   the one being recommended. */
.plan {
  /* a card needs both a surface and an edge here: the two light
     grounds are 1.14:1 apart, so the surface alone cannot be seen. */
  /* The card is the page's own paper with an edge drawn round it, NOT
     a white panel. White is not a surface in this palette: it appears
     in the spec only as "White label" and as "#FFFFFF on" a colour,
     it is absent from the proportion list, and the off-white surface
     role is already taken by name — "Pale blush, 60 to 70%, reads as
     warm off-white". A white card was me inventing a role the document
     had already assigned. The edge does the separating. */
  background: var(--c-pale);
  color: var(--on-paper);
  border: 1px solid rgba(36, 31, 31, 0.28);
  padding: clamp(var(--s5), 2.8vw, var(--s7)) clamp(var(--s5), 2.6vw, var(--s6));
  display: flex;
  flex-direction: column;
}
@media (min-width: 760px) {
  /* the recommendation is made by the layout, not only by a label */
  .plans { align-items: start; }
  .plan--featured { margin-block: calc(-1 * var(--s5)); padding-block: clamp(var(--s7), 4.4vw, var(--sp-1)); }
}
.plan__tag {
  font-family: var(--sans);
  font-weight: 800;
  font-size: var(--label-xs);
  text-transform: uppercase;
  letter-spacing: 0.14em;
  background: var(--ink);
  color: var(--signal);
  padding: 0.35em 0.7em;
  align-self: flex-start;
  margin-bottom: var(--s3);
  font-variant-numeric: lining-nums;
}
/* keeps the three plan names on one line across the row */
.plan__tag--ghost { visibility: hidden; }
.plan__name {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: var(--on-paper-soft);
}
/* the featured card's own type is set with the rest of that card, in
   the emphasis map at the foot of this file */
.plan__price {
  margin: var(--s1) 0 var(--s0);
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  font-size: clamp(3rem, 6vw, 4.5rem);
  line-height: 0.88;
  letter-spacing: -0.01em;
  font-variant-numeric: lining-nums;
}
/* Archivo's condensed dollar sits hard against the first figure */
.plan__cur { margin-right: 0.045em; }
.plan__per {
  font-size: 0.3em;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.plan__terms {
  font-size: 0.98rem;
  color: var(--on-paper-soft);
  margin-bottom: var(--s5);
  flex: 1;
}
.plan--featured .plan__terms { color: var(--ground); }

.fineprint {
  margin-top: clamp(var(--s6), 4vw, var(--s8));
  display: grid;
  gap: var(--s2);
  max-width: var(--measure-tight);
}
@media (min-width: 900px) {
  /* it was one narrow column with the entire right half of the section
     empty beside it. Two columns, and it sits under the plans it
     explains rather than trailing off the bottom-left. */
  .fineprint {
    max-width: none;
    columns: 2;
    column-gap: clamp(var(--s7), 5vw, var(--sp-1));
    display: block;
  }
  .fineprint p { break-inside: avoid; margin-bottom: 0.9em; max-width: 46ch; }
  .fineprint__lead { column-span: all; margin-bottom: 1.1em; }
}
.fineprint p { font-size: 1rem; color: var(--on-paper-soft); }
.fineprint strong { color: var(--on-paper); }
.fineprint__lead {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.92rem !important;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--on-paper) !important;
}

/* ---------- FAQ ---------- */
.faq { margin-top: clamp(var(--s5), 3vw, var(--s7)); }

/* Nine questions in one column ran 1,094px with roughly a third of the
   section empty beside them. Two columns halve the run and use the
   width — split in the markup, because every CSS-only version shares
   either the rows or the flow, and opening one answer then moves
   something the reader did not touch. */
@media (min-width: 1000px) {
  .faq {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--s2);
    align-items: start;
  }
  .faq__body p { max-width: 46ch; }
}
/* nine hairlines down a column is the same tally problem. Each question
   gets a surface, an edge and a gap instead. */
.faq__item {
  /* The card is the page's own paper with an edge drawn round it, NOT
     a white panel. White is not a surface in this palette: it appears
     in the spec only as "White label" and as "#FFFFFF on" a colour,
     it is absent from the proportion list, and the off-white surface
     role is already taken by name — "Pale blush, 60 to 70%, reads as
     warm off-white". A white card was me inventing a role the document
     had already assigned. The edge does the separating. */
  background: var(--c-pale);
  border: 1px solid rgba(36, 31, 31, 0.22);
  padding: 0 clamp(var(--s4), 2vw, var(--s5));
  margin-bottom: var(--s2);
}
.faq__col { display: grid; align-content: start; }
.faq__item summary {
  list-style: none;
  cursor: pointer;
  padding: clamp(var(--s3), 2.2vw, var(--s5)) var(--s8) clamp(var(--s3), 2.2vw, var(--s5)) 0;
  position: relative;
  font-family: var(--sans);
  font-weight: 700;
  font-stretch: 84%;
  font-variation-settings: "wdth" 84, "wght" 700;
  font-size: clamp(1.05rem, 0.95rem + 0.4vw, 1.35rem);
  line-height: 1.25;
  transition: color 0.2s ease;
}
.faq__item summary::-webkit-details-marker { display: none; }
/* the hover colour follows the ground: blue on the light field,
   yellow on either dark band */
.faq__item summary:hover { color: var(--accent-text); }
.faq__item summary::after {
  content: "+";
  position: absolute;
  right: 0.35rem; top: 50%;
  transform: translateY(-50%);
  font-weight: 500;
  font-size: 1.6em;
  line-height: 1;
  color: var(--signal);
  -webkit-text-stroke: 1px var(--ink);
  transition: transform 0.25s ease;
}
.faq__item[open] summary::after { transform: translateY(-50%) rotate(45deg); }
.faq__body { padding-bottom: clamp(var(--s4), 2.2vw, var(--s5)); }
.faq__body p { max-width: var(--measure-wide); }

/* ---------- close ---------- */
.close {
  position: relative;
  text-align: center;
  /* was clamp(--sp-1, 13vw, --sp-4) on top — 160px at full size, which
     was clearance for a photo card that hung above the wordmark. With
     the reprise gone that is just a hole above the headline. */
  /* the band carries the vertical air now; the section only has to
     hold the chat line under it */
  padding-block: 0 clamp(var(--s7), 5vw, var(--s9));
}
.close__fp {
  position: absolute;
  left: 50%; top: 50%;
  transform: translate(-50%, -50%);
  width: clamp(260px, 46vw, 620px);
  aspect-ratio: 240 / 300;
  background: var(--signal);
  opacity: 0.055;
  -webkit-mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  pointer-events: none;
}
.close__inner { position: relative; }
.close__spots {
  margin-top: var(--s3);
  font-family: var(--sans);
  font-weight: 800;
  font-size: var(--label-m);
  text-transform: uppercase;
  letter-spacing: 0.24em;
  color: var(--signal);
  font-variant-numeric: lining-nums;
}
.close .cta-row { justify-content: center; margin-top: clamp(var(--s6), 3.5vw, var(--s8)); }
/* The close headline is now 128px. A 16px bracketed link under it read
   as an afterthought — and it is the only place on the page that asks
   for the sale. Same form, scaled to the moment it belongs to; the
   brackets grow with it because they are set in em. */
.close .cta { font-size: clamp(1.05rem, 0.9rem + 0.7vw, 1.5rem); letter-spacing: 0.12em; }
.close .cta::before, .close .cta::after { font-weight: 400; }
.close__spots { font-size: clamp(0.8rem, 0.72rem + 0.4vw, 1.05rem); }
.close__chat { margin-top: clamp(var(--s5), 3vw, var(--s7)); }
.close__chat a {
  color: var(--signal);
  /* exempt as an inline link, but 17px is a mean target on a phone —
     padding buys height without moving the line it sits in */
  padding-block: 0.35em;
}

/* ---------- footer ---------- */
/* The footer was once coloured for a DARK ground while sitting on the
   light one — the wordmark was the paper colour on the paper colour,
   1:1, literally invisible, and it is the brand name. Every value
   below is stated against the ground it is actually on. Nothing here is a taste
   call; the component was reading from the wrong half of the token
   table. Re-pointed at the on-paper set. */
.footer {
  border-top: 1px solid var(--ink-3);
  /* The sticky bar is fixed to the bottom and is showing by the time
     anyone reaches the footer, so it was sitting permanently on top
     of the last line — the copyright and her own domain. Reserve its
     height. Measured at 73px desktop / 65px mobile; 5.5rem clears
     both with room for the two-line wrap at very small widths. */
  padding-block: clamp(var(--s7), 5vw, var(--s9)) calc(clamp(var(--s7), 5vw, var(--s9)) + var(--sp-1));
  color: var(--on-paper-soft);
  font-size: var(--text-s);
}
.footer__grid {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s5) var(--s7);
  align-items: flex-start;
  justify-content: space-between;
}
.footer__brand { display: flex; align-items: center; gap: var(--s3); }
.footer__mark {
  width: 32px; aspect-ratio: 240 / 300;
  background: var(--signal);
  -webkit-mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
}
.footer__wordmark {
  font-family: var(--sans);
  font-weight: 900;
  font-stretch: 62%;
  font-variation-settings: "wdth" 62, "wght" 900;
  text-transform: uppercase;
  font-size: 1.5rem;
  letter-spacing: 0.02em;
  color: var(--on-paper);
}
.footer__meta {
  color: var(--hot);   /* urgency, same as the five band labels */
  font-family: var(--sans);
  font-size: var(--label-s);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-variant-numeric: lining-nums;
}
.footer__nav { display: flex; flex-wrap: wrap; gap: var(--s1) var(--s3); align-items: center; }
.footer__nav a { color: var(--on-paper-soft); }
.footer__nav a:hover { color: var(--accent-text); }
.footer__legal { margin-top: var(--s5); font-size: var(--text-s); display: flex; flex-wrap: wrap; gap: var(--s1) var(--s4); align-items: center; }
/* the icon is 22x22 and it is a standalone control, so WCAG 2.5.8's
   inline-link exception does not cover it. The glyph stays its drawn
   size; the target around it does not. */
.footer__social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  margin: -11px;
  color: var(--on-paper-soft);
}
.footer__social svg { width: 22px; height: 22px; }
.footer__social:hover { color: var(--accent-text); }

/* ---------- toast ---------- */
.toast {
  position: fixed;
  left: 50%; bottom: 5.5rem;
  transform: translateX(-50%);
  z-index: 60;
  width: min(30rem, calc(100vw - 2rem));
  background: var(--paper);
  color: var(--on-paper);
  border: 2px solid var(--ink);
  border-left: 6px solid var(--signal);
  padding: var(--s3) var(--s8) var(--s3) var(--s4);
  font-size: 0.98rem;
  box-shadow: 0 18px 45px rgba(63, 15, 6, 0.45);
}
.toast a { color: var(--accent-text); }
.toast__close {
  position: absolute;
  top: 0.35rem; right: 0.5rem;
  background: none; border: 0;
  font-size: 1.5rem; line-height: 1;
  cursor: pointer; color: var(--on-paper-soft);
  padding: var(--s0) var(--s1);
}
.toast__close:hover { color: var(--ink); }

/* ---------- reveal ---------- */
@media (prefers-reduced-motion: no-preference) {
  .reveal {
    opacity: 0;
    transform: translateY(18px);
    transition: opacity 0.7s cubic-bezier(0.22, 1, 0.36, 1), transform 0.7s cubic-bezier(0.22, 1, 0.36, 1);
  }
  .is-live .reveal { opacity: 1; transform: none; }
  .is-live .reveal:nth-child(2) { transition-delay: 0.07s; }
  .is-live .reveal:nth-child(3) { transition-delay: 0.14s; }
  .is-live .reveal:nth-child(4) { transition-delay: 0.21s; }

  .hero .reveal { opacity: 0; transform: translateY(22px); }
  body.is-loaded .hero .reveal { opacity: 1; transform: none; }
  body.is-loaded .hero .reveal:nth-child(2) { transition-delay: 0.1s; }
  body.is-loaded .hero .reveal:nth-child(3) { transition-delay: 0.22s; }
  body.is-loaded .hero .reveal:nth-child(4) { transition-delay: 0.34s; }
  body.is-loaded .hero .reveal:nth-child(5) { transition-delay: 0.44s; }
}

/* ---------- responsive ---------- */
@media (max-width: 1024px) {
  .spread { grid-template-columns: 1fr; }
  .spread__art { max-width: 460px; }
  .details__grid { grid-template-columns: repeat(2, 1fr); }
  .details__item:nth-child(2n) { border-right: 0; }
  .details__item:nth-child(-n + 2) { border-bottom: var(--rule); }
}

@media (max-width: 760px) {
  .hero { min-height: 0; }
  .hero__inner { padding-top: clamp(var(--sp-3), 34vh, var(--sp-6)); }
  .hero__sub { max-width: none; }
  /* On the phone the portrait fills the frame, so the press sits
     small in the top corner and steps back rather than crossing
     Sarah's face. */
  /* The press is anchored to the word, so it follows the wordmark
     down to the phone on its own, and on a flat ground it has
     nothing to compete with. */
  .cta-row { gap: var(--s1) var(--s5); }
  .step { grid-template-columns: 1fr; gap: var(--s0); }
  .step__num { font-size: 2.4rem; }
  .proof { border-left-width: 4px; }
}

@media (max-width: 520px) {
  .details__grid { grid-template-columns: 1fr; }
  .details__item { border-right: 0; border-bottom: var(--rule); }
  .details__item:last-child { border-bottom: 0; }
  .plan__price { font-size: 2.9rem; }
}

/* Archivo variable may not carry a width axis in older engines;
   the narrow fallback keeps the poster proportion either way. */
@supports not (font-variation-settings: "wdth" 62) {
  .d, .shout, .step__num, .phase__name, .plan__price,
  .footer__wordmark, .details__value, .hero__the {
    font-family: "Archivo Narrow", "Archivo", "Helvetica Neue", Arial, sans-serif;
  }
}

/* ---------- collisions, found by _tools/collide.js ----------
   Two were real: the photo card sat on two lines of the paragraph
   above it, and the arrow sat on a line below. The third — the thumb
   over the nav — was a false positive: the nav is already
   position:absolute with z-index 30 and paints above it. Overriding
   its position here dropped it into the hero's flex row and broke
   the whole hero, so there is deliberately no .nav rule. */

@media (min-width: 900px) {
  /* The card overlaps the display type (which paints above it) but
     must not reach the paragraphs above. Capping the whole section
     was the wrong lever — it squashed every column here to ~284px.
     Shortening the card's rise is the right one. */
  .marmite-layer .layer__print { top: clamp(-5rem, -5vw, -2.5rem); }
  /* room under the type for the arrow, which is ~1.4x its own width tall */
  .marmite-layer { padding-bottom: clamp(var(--sp-3), 13vw, var(--sp-5)); }
  /* lone paragraphs have no neighbour to pair into columns, so they
     need their own measure — .prose--airy releases max-width so the
     column blocks can be wide, and these were running the full shell */
  .prose--airy > p:not(.beat) { max-width: 42ch; }
  /* max-width without an auto margin does not centre a block, it just
     narrows it and leaves it at the left — so the spots line and the
     chat line sat left of a centred heading. The decorative layer used
     to fill that space, which is how it went unnoticed. */
  .close__inner p:not(.beat) { max-width: 44ch; margin-inline: auto; }
}

/* the arrow belongs to the layer, not the card: it starts under the
   word and points up at her, in the space the padding above creates */
/* The drawn arrow runs tail top-right to head bottom-left. It was sitting
   at the bottom-left of the block pointing further left, away from
   everything — an ornament aimed at nothing. Turned 180deg the tail is at
   the bottom-left and the head points UP AND RIGHT, so it now leaves the
   end of "be Marmite." and lands on the photograph of her holding the jar,
   which is the thing the line is talking about. */

/* ================= THE THREE GROUNDS =================
   THIS BLOCK LIVES AT THE FOOT OF THE FILE ON PURPOSE.

   It used to sit near the top, above every component it colours — and
   because a ground rule and a component rule are usually the same
   specificity (.details--band vs .details), the component won on source
   order and the ground silently lost. That happened three times in one
   day: the essentials strip stayed pale, the hero would not take its
   height, and the client plate would not take its padding. Each was
   patched with a restatement further down, which is a workaround for a
   file that was in the wrong order.

   Grounds are the last word on colour, so they are last in the file.
   Only the emphasis map below may override them.

   Each ground re-states only the roles that change on it, so no rule
   above has to know what it is sitting on.

   --signal is the ground's MARK colour: the rules, ticks, bullets and
   bracket glyphs. On the reading surface that is ink blue, which is
   the spec's own list for blue — "hero, buttons, rules". On ink blue
   it is white; on a blush band it is near-black, because those are the
   only things legal on each. */

/* the reading surface — the default, declared in :root above */

/* --- ink blue: the masthead ---
   The twelve weeks used to be the second blue band, and it was the
   longest run of body copy on the page. The spec puts long-form copy on
   pale blush, so it moved there, and blue fell to 7% of the page — half
   its budget.

   What blue holds instead is what the spec's own preview shows it
   holding: the top of the page. The hero, the four essentials under it
   and the client quote are one blue masthead — a headline, four short
   facts and a quote, none of it long-form — and then the page opens
   into the reading field and stays there.

   Below, this is the old comment, and it still governs what may sit on
   the colour:

   "Hero band: #FFFFFF on #3956A8", 6.84:1. Pale blush is the secondary
   tone at 6.02:1, so the band is not all white and no tint is invented
   to get there. Raspberry is 1.52:1 here and tomato 1.02:1, so neither
   may appear on this ground at all — the only highlight available is a
   yellow BLOCK with a near-black label, which is what the F.I.N.D.
   marks are. */
.panel--blue, .hero, .proof {
  background: var(--c-blue);
  color: var(--c-white);
  --on-paper: var(--c-white);
  --on-paper-soft: var(--c-pale);
  --on-ink: var(--c-white);
  --on-ink-soft: var(--c-pale);
  --link: var(--c-white);
  --accent-text: var(--c-white);
  --ink-3: var(--c-pale);
  --signal: var(--c-white);
  --signal-ink: var(--c-blue);
  --hot: var(--c-white);
  /* blue on blue would vanish, so the button inverts: white pill with a
     blue label, 6.84:1 both ways */
  --btn-bg: var(--c-white);
  --btn-ink: var(--c-blue);
  --btn-bg-hover: var(--c-pale);
  --btn-ink-hover: var(--c-blue);
  --btn-outline: var(--c-white);        /* 6.84:1 — blue on blue is 1.0 */
  --btn-outline-ink: var(--c-blue);
  --rule-color: rgba(255, 255, 255, 0.32);
}

/* The essentials strip is the third blush surface: four one-line
   captions, no paragraph, no link, no coloured figure — so it is legal
   where a prose section would not be. It sits directly under the hero,
   and it is blush rather than blue because two navy blocks stacked read
   as one block that failed to end. Blue, pink, then the reading field. */
/* The masthead's own geometry, stated with its ground rather than away
   from it. The hero holds a screen — it is the page's first impression.
   The two client plates carry the air the blush bands do, because a
   quote is display type and this is the ground that can hold it. */
.hero { min-height: 100svh; display: flex; flex-direction: column; justify-content: center; }
.proof { padding-block: clamp(var(--s9), 9vw, var(--sp-3)); }

/* --- golden yellow: the badge object ---
   The badge is a ground and it never said so, which is how a tomato
   cross ended up on it at 2.43:1. Only near-black may be TYPE here
   (10.20); for a mark, near-black or ink blue (4.29) clear the 3:1 a
   non-text shape needs and nothing else does — tomato is 2.43 and
   raspberry 2.50. So the badge inverts every accent it inherits. */
.ph-block, .ph, .clue, .plan--featured, .find__k--4, .quote--gold {
  --on-paper: var(--c-ink);
  --on-paper-soft: var(--c-ink);
  --on-ink: var(--c-ink);
  --on-ink-soft: var(--c-ink);
  --link: var(--c-ink);
  --accent-text: var(--c-ink);
  --hot: var(--c-ink);
  --signal: var(--c-ink);
  --signal-ink: var(--c-yellow);
  /* her squiggle under each pulled phrase: raspberry is 2.81:1 here,
     under the 3:1 a graphic needs, so on this ground it is near-black */
  --quote-mark: var(--c-ink);
}

/* --- blush: three surfaces, two of them bands ---
   "Section bands. Near-black type only." And, from the watch-notes:
   "Body copy never goes on full blush … keep #EEADC0 for hero and band
   headlines; run paragraphs on #FBEDF0."

   So a blush band is only ever as tall as the HEADLINE it carries. Both
   bands started out as whole sections, which put four paragraphs and a
   link on blush; the prose is back on the reading surface and the band
   is the statement alone. The button is the one other thing in one, and
   it is legal: a blue block on blush is 3.70:1, over the 3:1 a non-text
   boundary needs, and the white label on it is 6.84:1.

   Blush against pale blush is 1.62:1, far under the 3:1 a boundary
   needs, so the band draws its own edges. */
.band-blush, .details--band {
  background: var(--c-blush);
  color: var(--c-ink);
  --on-paper: var(--c-ink);          /* 8.81:1 */
  --on-paper-soft: var(--c-ink);
  --on-ink: var(--c-ink);
  --on-ink-soft: var(--c-ink);
  --link: var(--c-ink);
  --accent-text: var(--c-ink);
  --hot: var(--c-ink);
  --ink-3: var(--c-ink);
  --signal: var(--c-ink);
  --signal-ink: var(--c-blush);
  --rule-color: rgba(36, 31, 31, 0.34);
  border-top: 2px solid var(--c-ink);
  border-bottom: 2px solid var(--c-ink);
}

/* --- and the two BANDS' own geometry ---
   Only the bands take this. The essentials strip shares the colour and
   nothing else: it is a four-column strip of facts, not a statement, so
   a screenful of air around it would be absurd.

   The band's height is air rather than copy, which is the only way to
   spend the 8-10% the spec gives blush while obeying its other rule,
   that paragraphs never run on it. At headline height the two bands
   held 4% of the page.

   Padding alone could not hold that at both ends: a narrow viewport
   makes the page far TALLER while a vw-based band gets SHORTER, so at
   390 the same rule gave blush 2.4% against 9.2% at 1440. The floor is
   a screenful instead. Both values are page-settable, because the
   spec's percentages are calibrated to the sales page and the
   three-screen confirmation page needs much less. */
.band-blush {
  padding-block: var(--band-pad, clamp(var(--s8), 9vw, var(--sp-4)));
  min-height: var(--band-min, 76vh);
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  overflow: hidden;
}
/* on a phone the page is a third taller again and the viewport a third
   shorter, so one screenful is no longer 8% of it — the band runs a
   little over a screen there, which on a phone is what a band IS */
@media (max-width: 700px) {
  .band-blush { min-height: var(--band-min-sm, 74vh); }
}

/* the confirmation page: a real band, but the smallest that still reads
   as one. Measured in the log rather than asserted. */
[data-page="thanks"] {
  --band-pad: clamp(var(--s5), 2.6vw, var(--s7));
  --band-min: 0px;
  --band-min-sm: 0px;
}

.band-blush > .turn { margin-top: 0; }
/* The honesty section's own band is not the section's first child —
   it follows a prose block, the way a beat or a CTA band follows one
   elsewhere. Nothing gave it that separation: .band-blush has no
   margin of its own (the close section's copy needs none, opening
   flush against padding-block:0), so this one sat against the prose
   above it with only line-height between them. Same movement-break
   scale as .band's own margin-top, scoped so the close section's
   band-blush is untouched. */
.band-blush--turn { margin-top: clamp(var(--s8), 6vw, var(--sp-1)); }
/* The page's own motif, on the one band big enough to need it: 1,700px
   of flat colour with nothing in it but type. Pseudo-element, so no
   markup and no request — the SVG is already loaded for the nav. */
.panel--print { position: relative; overflow: hidden; }
.panel--print > * { position: relative; z-index: 1; }
.panel--print::before {
  content: "";
  position: absolute;
  right: -6%;
  top: 50%;
  transform: translateY(-50%);
  width: clamp(320px, 42vw, 720px);
  aspect-ratio: 240 / 300;
  background: var(--c-white);
  opacity: 0.07;
  -webkit-mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  mask: url("assets/fingerprint-simple.svg") no-repeat center / contain;
  pointer-events: none;
  z-index: 0;
}

.panel--dark {
  border-top: 1px solid transparent;
  border-bottom: 1px solid transparent;
}
.panel--flush { padding-block: 0; }

/* ================= THE EMPHASIS MAP =================
   Every rule below is one of the spec's own usage lines. Nothing here
   invents a role for a colour.

     HEADLINES AND BODY   near-black, on every ground it is legal on
     THE EMPHASISED WORD  raspberry — "display type", 3.95:1, and
                          display clears at 3:1. Never at body size.
     LINKS, RULES, MARKS  ink blue, 6.02:1
     PRICE AND URGENCY    tomato, 5.90:1
     HIGHLIGHTS, BADGES   a yellow BLOCK with a near-black label,
                          10.20:1. Never a yellow letterform.
     BLUSH BANDS          near-black, and nothing else may enter.

   data-accent no longer names a hue. It names the GROUND, because on
   this palette the ground is what decides everything. */

[data-accent="ink"]    { --accent: var(--c-ink);   --accent-2: var(--c-rasp); }
[data-accent="onblue"] { --accent: var(--c-white); --accent-2: var(--c-white); }
.band-blush[data-accent], .band-blush    { --accent: var(--c-ink);   --accent-2: var(--c-ink); }

/* headings, and the one word inside them that may take a colour */
[data-accent] .d--l,
[data-accent] .d--m,
[data-accent] .shout,
[data-accent] .layer__type   { color: var(--accent); }
[data-accent] .d .hl,
[data-accent] .layer__type .hl { color: var(--accent-2); background: none; padding-inline: 0; }

/* eyebrows and small labels take the ground's mark colour */
[data-accent] .eyebrow     { color: var(--accent-text); }
/* "Price, URGENCY, second button." Tomato had the price and nothing
   else, so it appeared exactly twice on the whole page. These five
   lines are the urgency — the date and the seat count, next to every
   mid-page button — and on pale blush tomato is 5.90:1 at any size.
   On the blue grounds --hot is white and on a blush band near-black,
   so the role travels and the colour does not have to. */
[data-accent] .band__label { color: var(--hot); }
[data-accent] .rule        { background: var(--signal); }
[data-accent] .proof__shout { color: var(--accent); }

/* ---------- the highlight block ----------
   "Badges and highlights: #241F1F on #F3C846." Four things on this page
   are highlights and all four are the same object: the clue block (the
   "how well do you understand your competitors" question), the
   recommended plan, every placeholder, and the plan tags. On the light
   field a yellow block is
   1.40:1 against pale blush, so it carries a near-black edge; on ink
   blue it is 4.29:1, over the 3:1 a block needs, and carries none. */
.clue {
  background: var(--badge);
  color: var(--badge-ink);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}
.clue {
  border: 2px solid var(--c-ink);
  padding: clamp(var(--s5), 3vw, var(--s7));
}
.clue p, .clue em, .clue strong { color: var(--c-ink); }
.panel:not(.panel--blue) .clue { border-color: var(--c-ink); }

/* ---------- links, rules and marks: ink blue ---------- */
.panel:not(.panel--blue) .prose a,
.panel:not(.panel--blue) .faq__item summary::after { color: var(--c-blue); }
.faq__item summary { color: var(--on-paper); }
.faq__item summary::after { color: var(--signal); }

/* the three step numerals and the fingerprints under them are graphics,
   which is raspberry's other stated job. One colour for all three: the
   only other accent legal at this size on pale blush is tomato, and
   tomato is the price. */
.step:nth-child(n) { --step-hue: var(--c-rasp); }
.step__num { color: var(--step-hue, var(--accent-text)); }
.step__mark::before { background: var(--step-hue, var(--accent-text)); }
.panel--blue .step:nth-child(n) { --step-hue: var(--c-white); }
.steps--row .step__num { color: var(--step-hue, var(--accent-text)); }

/* ---------- the beats: raspberry ----------
   Sarah stepping out of the explanation to say something straight to
   the reader — "Most people can't answer that.", "That's where I come
   in.", "Here's what I mean…", the two that turn the page toward the
   group, and the revenue line in Why me. One rhetorical device, so one
   colour; colouring some of them would make the colour mean nothing.

   Raspberry is the spec's "display type" and at 37.6px / 700 these are
   display: 3.95:1 on pale blush, over the 3:1 large type has to clear.
   Same reasoning as the step numerals above, and the same constraint —
   tomato is the price and cannot be borrowed for emphasis.

   Scoped to the beat rule's own selector on purpose. One more place
   carries class="beat" outside .prose — the USD line in the pricing
   fineprint — so it never took the beat styling and must not take the
   colour either: the fineprint line is 16px regular, which needs
   4.5:1 and raspberry only reaches 3.95. It stays near-black by not
   matching. */
.prose .beat { --beat-hue: var(--c-rasp); }
.panel--blue .prose .beat { --beat-hue: var(--c-white); }

/* The four marks over the essentials strip are rules. On blush only
   near-black clears the 3:1 a mark needs — blue is 3.70 and tomato
   3.63, raspberry 2.43 — so all four are near-black and the strip reads
   as one object. The four-colour key lives on the phases, where it
   means something, rather than here where it was decoration. */
.details__item:nth-child(n) { --item-hue: var(--c-blue); }
.details--band .details__item:nth-child(n) { --item-hue: var(--c-ink); }

/* ---------- price and urgency: tomato ---------- */
.plan__price { color: var(--c-tomato); }          /* 5.90:1 */
.panel--blue .plan__price { color: var(--c-white); }
.plan--featured .plan__price { color: var(--c-ink); }  /* on the yellow block */

/* ---------- secondary type ---------- */
.panel:not(.panel--blue) .details__label,
.panel:not(.panel--blue) .details__note,
.panel:not(.panel--blue) .phase__weeks,
.panel:not(.panel--blue) .proof__role,
.panel:not(.panel--blue) .quote__role { color: var(--on-paper-soft); }
.panel--blue .details__note,
.panel--blue .proof__role,
.panel--blue .quote__role,
.panel--blue .phase__weeks,
.proof .proof__role { color: var(--on-ink-soft); }
.quote__pull { color: var(--on-paper); }
.panel--blue .quote__pull { color: var(--c-white); }

/* ---------- the two photo plates ----------
   The Marmite mount is pale blush with a near-black edge, so the
   raspberry word crossing it keeps its 3.95:1 the whole way — on a
   blush mount those last two letters would drop to 2.43. The portrait
   mount takes raspberry, which is the spec's "graphics" and the one
   block of it on the page; its caption is near-black at 3.63:1, and
   the caption is display-size italic, so 3:1 is the bar it has to
   clear. */
.plate, .plate--portrait { --plate-block: var(--c-blush); --plate-ink: var(--c-ink); border: 0; }
.plate figcaption { color: var(--plate-ink, var(--c-ink)); }

/* ---------- the recommended plan ----------
   It is a badge, so it is the badge object: a yellow block with
   near-black type. Its button stays ink blue with a white label —
   blue on yellow is 4.29:1, over the 3:1 a filled shape needs. */
.plan--featured {
  background: var(--c-yellow);
  color: var(--c-ink);
  border-color: var(--c-ink);
  --btn-bg: var(--c-blue);
  --btn-ink: var(--c-white);
  --btn-bg-hover: var(--c-ink);
  --btn-ink-hover: var(--c-white);
}
.plan--featured .plan__name,
.plan--featured .plan__terms { color: var(--c-ink); }
.plan--featured .plan__tag { background: var(--c-ink); color: var(--c-white); }
.plan__tag { background: var(--c-yellow); color: var(--c-ink); }

/* ---------- anything still sitting on ink blue ---------- */
.panel--blue .d--l,
.panel--blue .d--m,
.panel--blue .phase p,
.panel--blue .prose p { color: var(--c-white); }
.panel--blue .prose a { color: var(--c-white); text-decoration-thickness: 2px; }

/* ================= F.I.N.D. =================
   Four letters, four colours, and the same four carry down into the four
   phase cards — so the acronym is a key to the cards rather than a word
   sitting on its own.

   Each letter is a BLOCK with the letter knocked out of it, not a
   coloured letterform, because that is the only way all four can be
   legal: yellow may never be a letterform at all, and raspberry is
   display-only. As blocks every one clears:

     F   white on ink blue      6.84:1
     I   white on tomato        6.71:1
     N   white on raspberry     4.49:1  (large only — 80px and 46px here)
     D   near-black on yellow  10.20:1

   And each block against the pale blush behind it: 6.02, 5.90 and 3.95
   all clear the 3:1 a filled shape needs; yellow is 1.40 and does not,
   which is why its keyline can never come off. */
.find { white-space: nowrap; }
/* No keylines on any key — Tamara's call, 28 Aug: "honestly try it
   without the black... i dont like the outlines." The yellow block is
   1.40:1 against pale blush, but the near-black letter on it (10.20:1)
   is what actually carries the key, and the audit does not treat a
   glyph-sized block as a boundary surface — checks stay at zero. A
   deliberate call, not an oversight; do not quietly re-add edges. */
.find__k {
  display: inline-block;
  background: var(--find-bg);
  color: var(--find-ink, var(--c-white));
  padding: 0.02em 0.12em 0.06em;
  margin-inline: 0.02em;
}
.find__k--1 { --find-bg: var(--c-blue); }
.find__k--2 { --find-bg: var(--c-tomato); }
.find__k--3 { --find-bg: var(--c-rasp); }
.find__k--4 { --find-bg: var(--c-yellow); --find-ink: var(--c-ink); }

/* in a card the letter opens a word, so the block tightens around it */
.phase__name .find__k { padding-inline: 0.08em; margin-inline: 0 0.04em; }

/* and the card's own rule takes the same colour, so the key reads
   without the reader having to match letterforms */
.phase:nth-child(1) { --phase-hue: var(--c-blue); }
.phase:nth-child(2) { --phase-hue: var(--c-tomato); }
.phase:nth-child(3) { --phase-hue: var(--c-rasp); }
.phase:nth-child(4) { --phase-hue: var(--c-yellow); }
.phase { border-top: 6px solid var(--phase-hue, var(--rule-color)); }

/* ---------- the client plate, on ink blue ----------
   The pull-line is display type and stays on the blue. The QUOTE is
   not: at ~300 characters it is a paragraph, and the spec puts
   long-form copy on the reading surface. The spec's own preview does
   put short copy on this ground — two lines under the wordmark — but
   that is a lede, not four sentences of reversed italic serif.

   So the quote sits in a white card ON the plate: near-black at
   16.27:1, on a surface the spec's contrast table clears, and the
   plate keeps its ground. */
.proof .proof__shout,
.proof .eyebrow { color: var(--c-white); }
.proof .proof__quote {
  background: var(--c-pale);
  color: var(--c-ink);
  padding: clamp(var(--s4), 2.4vw, var(--s6));
  margin-top: clamp(var(--s3), 2vw, var(--s5));
}
.proof .proof__attr {
  background: var(--c-pale);
  color: var(--c-ink);
  margin-top: 0;
  padding: 0 clamp(var(--s4), 2.4vw, var(--s6)) clamp(var(--s4), 2.4vw, var(--s6));
}
.proof .proof__name { color: var(--c-ink); }
.proof .proof__role { color: var(--c-ink); }

/* ---------- the two blush bands ----------
   Near-black type only. The button is the one exception and it is
   legal: an ink blue block on blush is 3.70:1, over the 3:1 a non-text
   boundary needs, and the white label on it is 6.84:1. It stays blue
   so the thing you click is the colour it has been all page. */
/* inside a band: near-black, and nothing else */
.band-blush .d,
.band-blush .d--l,
.band-blush .d--m,
.band-blush .d .hl,
.band-blush .shout,
.band-blush .layer__type,
.band-blush .layer__type .hl,
.band-blush .turn__kicker,
.band-blush .eyebrow,
.band-blush .cta,
.band-blush .close__spots { color: var(--c-ink); }
.band-blush .cta::before, .band-blush .cta::after { color: var(--c-ink); }
.close__fp { background: var(--c-ink); }

/* the chat line now sits on the reading surface, below the band, so its
   link is an ordinary inline link again — "#3956A8 on #FBEDF0", 6.02:1.
   On blush it would have been 3.70 and the spec's own watch-note says
   not to put it there. */
.close { text-align: center; }
.close__chat {
  color: var(--on-paper);
  /* it was running the full shell at 1440 — a 95-character measure,
     centred, which wrapped one word onto a second line */
  max-width: var(--measure-tight);
  margin-inline: auto;
}
.close__chat a { color: var(--c-blue); }

.band-blush .btn,
.band-blush .cta-solid {
  --btn-bg: var(--c-blue);
  --btn-ink: var(--c-white);
  --btn-bg-hover: var(--c-ink);
  --btn-ink-hover: var(--c-blush);
}

/* The word above the wordmark takes the badge — the one legal way
   yellow appears, near-black on it at 10.20:1. Without it the hero was
   entirely white on blue: the biggest moment on the page and the only
   one with no colour in it at all. A block this small is well under
   yellow's budget and it plants the colour before the F.I.N.D. marks
   pick it up again later. */
.hero__the {
  /* display: table, not inline-block — an inline-block here rides the
     h1's own 0.8-line-height line box (216px type), which parks ~140px
     of leading above the tag. A table shrink-wraps without joining
     that line box. */
  display: table;
  margin-inline: auto;
  background: var(--c-yellow);
  color: var(--c-ink);
  padding: 0.14em 0.5em 0.18em;
  margin-bottom: clamp(var(--s2), 1.2vw, var(--s3));
}

/* ---------- the hero ----------
   "Hero band: #FFFFFF on #3956A8." The wordmark is white, not yellow:
   the spec sanctions yellow one way only, as a ground with a near-black
   label, and records white on yellow as a failure at 1.60:1. A yellow
   wordmark would be a letterform, which is the one thing it is never
   asked to be. */
.hero .d--l, .hero .d--m { color: var(--c-white); }
.hero .eyebrow, .hero__trust { color: var(--c-pale); }
.hero__big { color: var(--c-white); }

/* the announcement strip is urgency, which is tomato, with the white
   label the spec pairs with it — 6.71:1 */
.announce { background: var(--c-tomato); color: var(--c-white); }

/* ---------- the portrait's hand-cut mount ----------
   Her portrait was a plain rectangle with a blush caption bar under it.
   A photo frame is the one place on this page a graphic element has an
   obvious job, so the mount from the asset kit goes here rather than
   being sprinkled somewhere it would read as clutter.

   The opening is deliberately IRREGULAR, so the photograph cannot sit
   behind the ring — its corners would show. It is masked to a
   silhouette cut from the same artwork and the ring paints over the
   top. The mask is grown 11px so the photo tucks UNDER the ring and no
   seam of pale blush can appear between them.

   frame-01 is the wobbly oval. frame-06 crops her least on paper (0.77
   against the photograph's 0.80) but its ring is so thick at this size
   that the black swallowed the picture. The oval carries a tighter crop
   and looks far better doing it.

   The mask is grown by 55px rather than a few, which is what makes the
   ring read as a mount instead of a slab: the photograph eats into the
   drawn border, leaving about a quarter of the artwork showing.

   The ring is a ::after and NOT a background with the image behind it —
   a negative z-index would push the photograph behind the section's own
   background and it would vanish entirely. */
.plate--portrait .plate__mount {
  position: relative;
  aspect-ratio: 560 / 914;
}
.plate--portrait .plate__mount img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  -webkit-mask: url("assets/kit/portrait-blue-hole.png") no-repeat center / contain;
  mask: url("assets/kit/portrait-blue-hole.png") no-repeat center / contain;
}
.plate--portrait .plate__mount::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: url("assets/kit/portrait-blue-ring.png") no-repeat center / contain;
}
/* The plate's blush block would show as a rectangle behind the oval's
   cut corners, so this plate's surface is the page itself. The caption
   loses its blush bar for the same reason: a hard rectangle butted
   against a hand-cut curve reads as the old frame left behind. It sits
   as plain type under the mount instead. */
.plate--portrait { background: transparent; }
.plate--portrait figcaption {
  background: transparent;
  padding-inline: 0;
  padding-top: 0.9em;
  /* the mount is symmetrical, so a left-aligned caption reads as a
     leftover from the old rectangle. It centres on the oval instead,
     and takes the oval's width rather than the column's. */
  text-align: center;
  max-width: 100%;
  font-size: clamp(1.15rem, 0.9rem + 0.85vw, 1.6rem);
}

/* ---------- the Sherlock card ----------
   The detective conceit gets its evidence photo at the line that sets it
   up — "Claude is your forensics lab, and you're the lead detective."
   Same mechanism as the portrait mount: a hand-cut mount from the kit,
   the photograph masked to the frame's own silhouette, the ring painted
   by ::after so it stacks above the photo on source order alone (no
   negative z-index — that bug is documented on the portrait mount).
   A different frame from the kit than the portrait uses, so the two
   photo objects on the page read as two instances of one system rather
   than the same mount twice. No caption: the surrounding prose already
   explains the photograph; the alt text carries it for a screen reader. */
.detective { position: relative; }
.clue-card {
  display: block;
  margin: clamp(1.75rem, 8vw, 2.5rem) auto 0;
  width: min(62%, 260px);
}
.clue-card .plate__mount { position: relative; }
.clue-card .plate__mount img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(0.12) contrast(1.04) saturate(0.96);
}
.clue-card .plate__mount::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
}
@media (min-width: 900px) {
  /* leaves room to the right of the two-column prose for the card to
     sit in, the way the Marmite print sits over its paragraph */
  .detective .prose__cols { max-width: 620px; }
  .clue-card {
    position: absolute;
    top: 0.1em;
    right: 0;
    margin: 0;
    width: clamp(200px, 17vw, 280px);
    transform: rotate(-2deg);
  }
}
/* frame-01 (the wobbly blue oval, the portrait mount's own frame) was
   rendered here too and rejected: reusing the portrait's exact frame
   for a second photo on the same page makes the mount read as one
   repeated template rather than a system with two members. frame-06
   (ink) was "too heavy at portrait scale" per the portrait mount's own
   log entry — the near-black ring swallowed the picture there — but at
   this card's ~210px width the thick ring reads as a proper evidence
   mount and the tighter crop it forces (0.77 wide-to-tall) suits a
   close-up on the eye and the glass. */
.clue-card--ink .plate__mount { aspect-ratio: 650 / 840; }
.clue-card--ink .plate__mount img {
  -webkit-mask: url("assets/kit/sherlock-ink-hole.png") no-repeat center / contain;
  mask: url("assets/kit/sherlock-ink-hole.png") no-repeat center / contain;
}
.clue-card--ink .plate__mount::after {
  background: url("assets/kit/sherlock-ink-ring.png") no-repeat center / contain;
}

/* ---------- the five tools ----------
   Replaces the placeholder list. One kit shape, repeated five times in
   the one colour it already carries (ink blue) — a family in the sense
   of one repeated mark, not five different shapes or colours, which is
   the scattered-pebbles failure the plan rules out. It REPLACES the
   bullet the .ticks pattern would otherwise draw here, the same
   replaces-not-adds doctrine the photo mounts use. */
/* The block is a breakdown of ONE bullet in the list beside it, so it
   sits a full step below that list in the hierarchy: an eyebrow-scale
   label instead of display type, body-scale names, and a hairline box —
   the only edge this ground offers (white is a label, not a surface). */
.tools-box {
  border: var(--rule);
  padding: clamp(var(--s5), 2.6vw, var(--s7));
  align-self: start;
}
.tools__label {
  font-family: var(--sans);
  font-weight: 700;
  font-size: var(--label-s);
  text-transform: uppercase;
  letter-spacing: 0.2em;
  line-height: 1.5;
  color: var(--accent-text);
  margin: 0;
}
.tools { display: grid; gap: clamp(var(--s5), 2.2vw, var(--s6)); margin-top: var(--s5); }
.tools__item { position: relative; padding-left: var(--s6); }
.tools__mark {
  position: absolute;
  left: 0;
  top: 0.3em;
  width: 1.05rem;
  height: 1.05rem;
  background: var(--signal);
  -webkit-mask: url("assets/kit/tool-mark-blue.png") no-repeat center / contain;
  mask: url("assets/kit/tool-mark-blue.png") no-repeat center / contain;
}
.tools__name {
  font-family: var(--sans);
  font-weight: 800;
  font-stretch: 80%;
  font-variation-settings: "wdth" 80, "wght" 800;
  font-size: clamp(1rem, 0.95rem + 0.25vw, 1.15rem);
  line-height: 1.1;
  color: var(--on-paper);
  margin: 0 0 0.3em;
}
.tools__desc {
  margin: 0;
  color: var(--on-paper);
  font-size: clamp(0.95rem, 0.9rem + 0.2vw, 1.05rem);
}

/* ---------- the litany ----------
   A different device from the beats and the prose columns around it —
   a stacked list of short lines rather than an aside or a paragraph.
   Same italic Newsreader voice the .clue block already uses; kept off
   raspberry deliberately, because that colour already means "Sarah
   stepping outside the explanation" (the beats) and giving the same hue
   to a second device would make it mean nothing. */
.litany {
  margin-block: clamp(var(--s5), 3vw, var(--s7));
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.05rem, 1rem + 0.4vw, 1.25rem);
  line-height: 1.5;
  color: var(--on-paper);
  max-width: var(--measure);
}
.litany p { margin: 0; }
.litany p + p { margin-top: 0.35em; }

/* ---------- legal.html ---------- */
.legal__header { padding-block: clamp(var(--s5), 3vw, var(--s7)); }
.legal__header .nav__brand { display: inline-flex; }
.details__note + .prose { margin-top: clamp(var(--s6), 4vw, var(--s8)); }
.prose h3.d--s {
  margin-top: 1.9em;
  margin-bottom: 0.5em;
}
.prose > p:first-child,
.prose > h3:first-child { margin-top: 0; }
