/* ═══════════════════════════════════════════════════════════════════════
   isjamesok? — landing page
   Tokens, type tiers, the blank device, crisis bar, stats, pillars,
   grid placements, grain and button states are lifted verbatim from
   isjamesok-brand-system-v4.html so they are not re-derived. Everything
   below the "SITE-SPECIFIC COMPONENTS" divider is new, built for this page.
   The "twice" ghost-text device and its --offset/--ghost tokens were
   removed in Patch 01 ("ask twice" → "ask openly") — see README.
   ═══════════════════════════════════════════════════════════════════════ */

@font-face{
  font-family:'Archivo';
  src:url('/fonts/archivo-variable-latin.woff2') format('woff2');
  font-weight:100 900;
  font-stretch:62% 125%;
  font-style:normal;
  font-display:swap;
}
@font-face{
  /* Metric-matched to Archivo's hhea ascent/descent (measured with fontTools),
     so the fallback occupies the same line-box height and swapping in the
     real face causes no vertical shift. Not width-matched — Archivo is a
     wider-set face than Arial and matching width would require inflating
     Arial past a legible size, trading a bigger defect for a smaller one. */
  font-family:'Archivo Fallback';
  src:local('Arial');
  ascent-override:87.8%;
  descent-override:21%;
  line-gap-override:0%;
}
@font-face{
  font-family:'Public Sans';
  src:url('/fonts/publicsans-variable-latin.woff2') format('woff2');
  font-weight:300 700;
  font-style:normal;
  font-display:swap;
}
@font-face{
  font-family:'Martian Mono';
  src:url('/fonts/martianmono-variable-latin.woff2') format('woff2');
  font-weight:100 800;
  font-stretch:75% 112.5%;
  font-style:normal;
  font-display:swap;
}

:root{
  /* GROUNDS — two kits */
  --late:  #0C0C0D;
  --early: #E9EBEC;

  /* THE SIGNAL — ONE HEX, for FILLS on either ground */
  --signal:  #5B2BE0;

  /* THE FIELD — the blank device only */
  --field: #8B6BFF;

  /* --fail's colour pair — the overprint device itself (--pass-b,
     --pass-ab) was removed in Patch 01; these two survive because --fail
     still uses them. */
  --pass-a:   #FF3F8E;
  --pass-a-d: #D6194F;

  /* SEMANTIC TOKENS — dark-kit defaults */
  --ground:     var(--late);
  --ink:        #F5F4F0;
  --ink-2:      #9E9C97;
  --rule:       #4A4A52;
  --rule-edge:  #5C5C66;
  --emphasis:   var(--ink);
  --underline:  var(--field);
  --focus:      var(--ink);
  --fail:       var(--pass-a);
  --btn-border: var(--ink);
  --surface-2:  #17171B;
  --signal-ink: #F5F4F0;   /* fixed text/border colour for fills on --signal, invariant across kits */

  /* TYPE */
  --display: 'Archivo', 'Archivo Fallback', system-ui, sans-serif;
  --sans:    'Public Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --mono:    'Martian Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* TYPE SCALE — nine steps */
  --step--3: clamp(0.62rem, 0.60rem + 0.08vw, 0.68rem);
  /* Was clamp(0.70rem, 0.68rem + 0.10vw, 0.76rem) = 11.27px on a phone, set
     uppercase and condensed — the tier that sits directly under most
     headings (Patch 22, Part 1.2). */
  --step--2: clamp(0.8125rem, 0.78rem + 0.14vw, 0.9375rem);
  /* Patch 22 raised --step--2 and left this alone, so step -2 came out
     larger than step -1 and the scale ran backwards — and the chips
     floored at -1 in Patch 22 §1.3 ended up smaller than the labels
     above them (Patch 24, Part 0.1). Verified: 9.92 < 13.00 < 14.11 <
     17.12 < 18.40 at 320px, and 10.75 < 14.50 < 15.90 < 19.00 < 23.20
     at 1440px. 14.11 @320 · 14.22 @390 · 14.83 @768 · 15.24 @1024 ·
     15.90 @1440 */
  --step--1: clamp(0.875rem, 0.85rem + 0.16vw, 1rem);
  /* Was clamp(0.94rem, 0.90rem + 0.20vw, 1.06rem), which crossed 16px only
     above an 800px viewport — so every phone got sub-16px running copy for
     an audience of men over 40. GDS ships 16/19. Do not lower this again
     (Patch 22, Part 1.1). 17.12px @320 · 17.36 @390 · 18.69 @768 · 19.00 @1024+ */
  --step-0:  clamp(1.0625rem, 1rem + 0.35vw, 1.1875rem);
  --step-1:  clamp(1.15rem, 1.05rem + 0.50vw, 1.45rem);
  --step-2:  clamp(1.5rem,  1.25rem + 1.25vw, 2.3rem);
  --step-3:  clamp(2rem,    1.4rem  + 3vw,    4rem);
  --step-4:  clamp(2.25rem, 1rem    + 6.6vw,  7rem);
  --step-5:  clamp(2.9rem,  0.2rem  + 13vw,   13rem);

  /* SPACING SCALE */
  --sp-1:0.25rem; --sp-2:0.5rem;  --sp-3:0.75rem; --sp-4:1rem;
  --sp-5:1.5rem;  --sp-6:2rem;    --sp-7:3rem;    --sp-8:4rem;
  --sp-9: clamp(3rem, 1.5rem + 5vw, 6rem);
  --sp-10:clamp(3.5rem, 2rem + 6vw, 8rem);

  --gutter: clamp(0.875rem, 0.5rem + 1.1vw, 2rem);
  --bleed:  clamp(1.5rem, 0.5rem + 4.2vw, 8.5rem);
  --crisis-h: 3.25rem;
  --hero-head-offset: 0px;   /* measured by site.js on the homepage */

  /* The space between the crisis bar and the wordmark, and the space below
     the last thing on a page. One pair of tokens because this gap was set
     in two unrelated places — --sp-9 on .hero, an inline padding-block on
     every other page's <main> — and drifted apart: 62px against 76px at
     390, 112px against 80px at 1440. Every page reads these now, so the
     opening is the same wherever you land. Patch 33. */
  --page-top: var(--sp-9);
  --page-bottom: var(--sp-10);
  --z-crisis: 500;

  /* Evidence grades. Deliberately NOT a red-amber-green scale: green as a
     pass-mark is the exact deflection this charity exists to name, and this
     is the third time it has re-entered the system. Weight and letter carry
     the grade; the only colour used is --fail, for refuted. */
  --grade-1: var(--ink);      /* strong    */
  --grade-2: var(--ink-2);    /* moderate  */
  --grade-3: var(--rule-edge);/* weak      */
  --grade-4: var(--signal);   /* contested */
  --grade-5: var(--fail);     /* refuted   */
}

/* SHORT AND WIDE — a phone in landscape (Patch 10).
   Every step on the spacing scale above --sp-8 is a clamp on vw, so
   rotating a phone hands an 844x330 viewport the vertical padding of an
   844px-wide desktop: --sp-9 resolves to 66px and --sp-10 to 83px, and
   the hero spends two thirds of the fold before the headline starts.
   Width is not the scarce dimension here, height is — so in landscape
   these two are capped against the height instead. Both are used only
   for padding-block, padding-top and margin-top (grepped), never for a
   horizontal gap, so re-deriving them against vh is safe. iPad
   landscape is 768px+ tall and never matches. */
@media (orientation:landscape) and (max-height:520px){
  :root{
    --sp-9:  clamp(1.25rem, 6vh, 2.75rem);
    --sp-10: clamp(1.5rem,  9vh, 3.5rem);
  }
}

/* GROUND RHYTHM — three --early bands on the homepage, and only three:
   the six-move index, the four pillars, the fork. The flip marks a
   register change (problem -> method -> ask), not a section break.
   Adding a fourth requires removing one. Patch 07, Part 0. */
.on-early{
  --ground:     var(--early);
  --ink:        #0C0C0D;
  --ink-2:      #5C5A55;
  --rule:       #B5B0A4;
  --rule-edge:  #A29C90;
  --field:      #5B2BE0;
  --emphasis:   var(--signal);
  --focus:      var(--signal);
  --fail:       var(--pass-a-d);
  --btn-border: var(--ink);
  --surface-2:  #DCDEE0;
  /* The grade tokens below are var(--ink) etc at :root, but a custom
     property's var() references resolve against the values in effect
     where it's DECLARED, not where it's used — so without redeclaring
     them here too, every evidence-grade chip on an --early section
     stayed locked to the --late ground's --ink (near-white), border
     effectively invisible against the light background it actually
     sits on. Re-declared so each one re-resolves against this ground's
     own tokens instead. */
  --grade-1: var(--ink);
  --grade-2: var(--ink-2);
  --grade-3: var(--rule-edge);
  --grade-4: var(--signal);
  --grade-5: var(--fail);
}

*, *::before, *::after{ box-sizing:border-box; margin:0; padding:0; }
/* The [hidden] attribute must always win over a component's own display
   rule (e.g. .btn{display:inline-flex}, .blank-actions{display:flex}) —
   same specificity as a single class, so without this an element JS sets
   hidden=true on can still render if any author rule sets its display.
   Caught empirically: #blank-actions rendered visible despite hidden. */
[hidden]{ display:none !important; }
html{ -webkit-text-size-adjust:100%; scroll-padding-top:calc(var(--crisis-h) + var(--sp-5)); }

body{
  background:var(--ground); color:var(--ink);
  font-family:var(--sans); font-size:var(--step-0);
  line-height:1.55; font-weight:400;
  -webkit-font-smoothing:antialiased;
  overflow-x:clip; hanging-punctuation:first;
}
@media (prefers-reduced-motion:no-preference){ html{ scroll-behavior:smooth; } }

/* ── GRAIN — fixed, never animated ──────────────────────────────── */
body::after{
  content:''; position:fixed; inset:0; z-index:400; pointer-events:none;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='128' height='128' filter='url(%23n)'/%3E%3C/svg%3E");
  background-size:128px 128px; mix-blend-mode:screen; opacity:.05;
}
.on-early::after{ mix-blend-mode:overlay; opacity:.11; }

/* ═══ STRUCTURE ═════════════════════════════════════════════════ */
.bleed{ padding-inline:var(--bleed); }
section{
  background:var(--ground); color:var(--ink); position:relative;
  border-top:1px solid var(--rule-edge); padding-block:var(--sp-10);
}
.grid{ display:grid; grid-template-columns:repeat(12,1fr); gap:var(--gutter); align-items:start; }
/* Section backgrounds, band rules and .c-full poster moments stay full-bleed
   (they're not in this list). The grid itself stops growing at 1560px so a
   62ch measure doesn't strand in a 2400px track on a wide monitor. */
.grid,
.stats,
.pillars,
.evidence,
.doors,
.ask-openly-grid{
  max-width:1560px;
  margin-inline:auto;
}
.c-full{grid-column:1/-1} .c-head{grid-column:1/span 7} .c-side{grid-column:9/span 4}
/* .c-wide was 1/span 9, ending at line 10 — one track inside .c-side's own
   start at line 9, so any .c-wide + .c-side pair on the same row overlapped
   at every width above 700px (Patch 24, Part 1.2). */
.c-second{grid-column:8/span 5} .c-wide{grid-column:1/span 8}
/* .ev-flag, .flag and .capture-field all carry their own margin-top so
   they sit apart from a preceding sibling mid-flow. Grid items don't
   margin-collapse with their own children the way normal block flow
   does, so when one of them is the very first thing in one of these
   columns, straight after the .grid's own inline margin-top, that
   self-margin just adds a second, redundant gap on top of the first
   instead of doing anything — found on safeguarding.html (.ev-flag),
   partners.html and ask.html (.flag) and trustees.html (.capture-field
   via its wrapping .capture form). Zero it in exactly that case. */
:is(.c-head,.c-side,.c-second,.c-wide,.c-full) > .ev-flag:first-child,
:is(.c-head,.c-side,.c-second,.c-wide,.c-full) > .flag:first-child{
  margin-top:0;
}
:is(.c-head,.c-side,.c-second,.c-wide,.c-full) > .capture:first-child > .capture-field:first-child{
  margin-top:0;
}
/* The placement classes above are written against the twelve-column grid.
   Dropping to six columns without remapping them left .c-side (9/span 4),
   .c-second (8/span 5) and .c-wide (1/span 9) pointing at grid lines that
   don't exist at this breakpoint — so the browser appended implicit tracks,
   the six explicit 1fr columns collapsed to zero, and the whole 701–1080px
   range rendered with a ~110px headline column (the hero H1 stacked one
   word per line, "fine." colliding with the blank field beside it). Every
   class the 12-column set defines gets a 6-column equivalent here. */
@media (max-width:1080px){
  .grid{ grid-template-columns:repeat(6,1fr); }
  .c-head  { grid-column:1/span 4; }
  .c-side  { grid-column:5/span 2; }
  /* .c-second was 3/span 4 (tracks 3-6), overlapping .c-head's 1-4 on
     tracks 3-4 — the homepage's loudest band, dropping .c-second to row
     2 with two dead tracks above it. .c-wide was 1/span 5 (tracks 1-5),
     overlapping .c-side's 5-6 on track 5 (Patch 24, Part 1.2). */
  .c-second{ grid-column:5/span 2; }
  .c-wide  { grid-column:1/span 4; }
}
@media (max-width:700px){
  .grid{ grid-template-columns:repeat(4,1fr); }
  .c-head,.c-side,.c-second,.c-wide{ grid-column:1/-1; }
}

/* ═══ TYPE ══════════════════════════════════════════════════════ */
.kicker{
  font-family:var(--mono); font-size:var(--step--2); font-weight:500;
  text-transform:uppercase; letter-spacing:.08em; color:var(--ink-2);
  font-variation-settings:'wdth' 87.5;
  display:flex; align-items:baseline; gap:.9em;
  margin-top:0; margin-bottom:0;
}
/* Only when there is a number to put in it. attr() on a missing attribute
   resolves to the empty string rather than to nothing, so an unqualified
   ::before still generated a zero-width flex item — and the flex gap still
   applied to it, indenting every numberless kicker by .9em against an empty
   slot. Six of the twenty-one were numberless (/press, /privacy,
   /safeguarding, /accessibility, /contact, /trustees) and all six sat ~11px
   right of the wordmark above them. Patch 33. */
.kicker[data-n]::before{ content:attr(data-n); color:var(--emphasis); letter-spacing:0; }
/* These two margins collapse in normal flow, so the intended 40px rendered
   as 24px (max(16,24), not 16+24). Own the gap from one side only.
   Any element, not just h2/.d-head: the narrower selector left a kicker
   sitting flush against whatever else followed it — /ask's "take it with
   you" hard against its button row and "before you ask" against .terms,
   /evidence's kicker against its h1.d-poster. The kicker owns the gap
   below itself whatever comes next. */
.kicker + *{ margin-top:var(--sp-6); }
/* .kicker + * is (0,1,0), which beats a bare h2 at (0,0,1) but only ties
   .d-head's own margin-block at (0,1,0) and loses on source order — so
   the gap this rule exists to fix came back to 24px whenever the
   heading carried .d-head, which is most of them.

   The originally patched fix here was margin-top:0 on
   .kicker + .d-head/.kicker + h2 — checked empirically, that measured
   0px, not 32px: those selectors are MORE specific (0,2,0/0,1,1) than
   .kicker + * (0,1,0), so margin-top:0 doesn't just cancel .d-head's
   own margin-block, it also outranks and cancels .kicker + *'s sp-6 on
   the same element, wiping the gap entirely rather than restoring it.
   Setting the correct value directly on the higher-specificity
   selector sidesteps the cascade fight instead of trying to lose it on
   purpose (Patch 24, Part 3.2 — corrected during verification). */
.kicker + .d-head, .kicker + h2{ margin-top:var(--sp-6); }

h1,h2,h3{ text-box-trim:trim-both; text-box-edge:cap alphabetic; }

.d-poster, h1{
  font-family:var(--display); font-weight:900; font-size:var(--step-5);
  letter-spacing:-.038em; line-height:.95; font-variation-settings:'wdth' 112;
}
/* "get the emails" is the only .d-poster that's an h2, not a real page
   h1 — at --step-5 (poster scale, up to 13rem) it read as oversized for
   a closing CTA. Down one step. */
#capture-h{ font-size:var(--step-4); }
.d-head, h2{
  font-family:var(--display); font-weight:800; font-size:var(--step-3);
  letter-spacing:-.026em; line-height:1.02; font-variation-settings:'wdth' 100;
  margin-block:var(--sp-5) var(--sp-6);
}
.d-sub, h3{
  font-family:var(--display); font-weight:700; font-size:var(--step-2);
  letter-spacing:-.016em; line-height:1.05; font-variation-settings:'wdth' 100;
}
/* Patch 08, Part 4.3 — balance for headings (<=4 lines, evens the line
   lengths so a heading never breaks with a one-word orphan on its own
   line); .body/.lede already carry pretty (protects only the last
   line, right for running copy) — h2 had pretty too, the wrong one. */
.d-head, h2, .d-poster, h1, .d-sub, h3{ text-wrap:balance; }
.move p, .pillar .p-body{ text-wrap:pretty; }
.em{ color:var(--emphasis); text-decoration:underline; text-decoration-color:var(--underline);
  text-decoration-thickness:.07em; text-underline-offset:.12em; }
.on-early .em{ text-decoration:none; }

/* Was 34ch — about 39 characters, which only works for a hero strapline.
   Every section deck that needed two real sentences got written as .body
   instead, because .lede physically wouldn't hold it, and ended up at body
   size under a 64px headline. 48ch is ~55 characters at --step-1, a real
   deck measure (Patch 23). */
.lede{ font-size:var(--step-1); line-height:1.4; color:var(--ink-2); max-width:48ch; text-wrap:pretty; }
.body{ max-width:62ch; text-wrap:pretty; }
.body + .body{ margin-top:var(--sp-4); }
.body strong{ color:var(--ink); font-weight:600; }
.sm{ font-size:var(--step--1); color:var(--ink-2); }
.mono{ font-family:var(--mono); font-size:var(--step--1); font-variation-settings:'wdth' 87.5; }
.label{ font-family:var(--mono); font-size:var(--step--2); font-weight:500; letter-spacing:.08em;
  text-transform:uppercase; color:var(--ink-2); font-variation-settings:'wdth' 87.5; }
.lower{ text-transform:lowercase; }
code{ font-family:var(--mono); font-size:.88em; color:var(--emphasis); font-variation-settings:'wdth' 87.5; }

/* ═══ THE WORDMARK / THE BLANK ══════════════════════════════════ */
.wordmark{
  font-family:var(--display); font-weight:800; letter-spacing:-.035em; line-height:1;
  font-size:clamp(1.5rem, 1.2rem + 1vw, 2rem); font-variation-settings:'wdth' 100;
  display:inline; white-space:nowrap; text-transform:lowercase; color:var(--ink);
}
.wordmark .blank{
  display:inline-block; margin:0;
  color:var(--field);
  border-bottom:.1em solid currentColor; padding-bottom:.04em;
}
@media (max-width:600px){ .wordmark .blank{ border-bottom-width:max(2px,.12em); } }

/* ═══ THE QUESTIONS BUILT TO GET A NO ══════════════════════════
   Replaces the second-pass device (Patch 01). The argument was
   repetition; with "ask openly" the mechanism is the sentence's
   framing, so the display is a stack of the negatively-framed
   version against the one positively-framed line, each with its
   measured disclosure rate underneath. */
/* The left column (heading, framing line, McCabe note) is naturally much
   shorter than the four struck questions beside it — each is set at
   display scale, so the right column runs well past where the left one
   ends. On a wide screen that used to leave a tall, empty dark gap under
   the left column while the questions kept going. Pinning the left
   column instead keeps it in view alongside whichever question is on
   screen, releasing on its own once the row (i.e. the taller c-second
   column) runs out — which happens right at the next section, since the
   grid row's height is set by c-second. align-items:start on .grid
   already gives .c-head its own natural (short) height rather than
   stretching it, which is what leaves the sticky element room to move.
   Scoped to the width where the two columns are actually side by side
   under the original 12-column grid — below 1080px they're narrower and
   eventually stack, where a pinned heading would just be an annoyance. */
@media (min-width:1081px){
  .ask-sticky{ position:sticky; top:calc(var(--crisis-h) + var(--sp-7)); align-self:start; }
}
.no-lines{ display:flex; flex-direction:column; gap:var(--sp-4); }
/* Patch 04, C2 — this is meant to be the loudest band on the page; the
   four negative questions were sitting at the same --step-2 as any other
   .d-sub on the site, which didn't earn that. Bumping only these (not
   .d-sub itself) also clears .behind's 32px floor at every viewport
   width, which is what makes B4's "you alright?" placement valid. */
/* Struck through in --fail, the same correction device /evidence uses on
   a claim that doesn't survive checking (.correction .c-claim) — one
   visual language for "this is the thing we're telling you not to do",
   in both places it appears. The text also drops to --ink-2 (7.13:1, an
   already-verified pair) so the one question we do want keeps --ink and
   reads as the answer rather than a fifth option.
   Thickness is /evidence's 2px exactly. A first pass scaled it with the
   type (.045em) on the theory that --step-3 needs more than --step-1 —
   rendered, it read as a redaction rather than a correction and fought
   the words for attention. The words still have to be readable: the
   joke is in reading them. */
.no-line .d-sub{
  font-size:var(--step-3);
  color:var(--ink-2);
  text-decoration:line-through;
  text-decoration-color:var(--fail);
  text-decoration-thickness:2px;
}
.no-figure{ color:var(--ink-2); margin-top:var(--sp-1); }
.yes-line{ margin-top:var(--sp-6); }
/* The 38.1% figure used to be a small mono caption inside a signal-filled
   block. Patch 04 C2/D1 asks for the full .punct-scale treatment on the
   figure itself, carried by .knock rather than a block fill — a solid
   .yes-line fill would make an inline .knock invisible (signal on
   signal), so the fill moves from the container onto the word. */
.yes-line .yes-figure{
  margin-top:var(--sp-3); font-family:var(--display); font-weight:900;
  font-size:var(--step-3); letter-spacing:-.026em; line-height:1;
  font-variation-settings:'wdth' 112;
}
.op-note{ font-family:var(--mono); font-size:var(--step--1); color:var(--ink-2);
  max-width:46ch; font-variation-settings:'wdth' 87.5; }

/* ═══ BUTTONS ═══════════════════════════════════════════════════ */
.btns{ display:flex; flex-wrap:wrap; gap:var(--sp-3); align-items:center; }
.btn{
  font-family:var(--mono); font-size:var(--step--1); font-weight:500;
  letter-spacing:.06em; text-transform:uppercase; font-variation-settings:'wdth' 87.5;
  padding:var(--sp-4) var(--sp-5); border:1px solid transparent; border-radius:0;
  cursor:pointer; text-decoration:none; display:inline-flex; align-items:center; gap:.7em;
  transition:background .16s, color .16s, border-color .16s, translate .08s;
  min-height:44px;
}
.btn-1{ background:var(--signal); color:var(--signal-ink); border-color:var(--btn-border); }
.btn-1:hover{ background:var(--ink); color:var(--ground); border-color:var(--ink); }
/* On the light kit, inverting to --ink turns a violet button black on hover,
   which reads as a state change of kind rather than degree. Darken within
   the hue instead — re-derived at 8.63:1 against --signal-ink (patch cited
   7.4:1; still comfortably above AA at any size either way). */
.on-early .btn-1:hover{ background:#4A22B8; color:var(--signal-ink); border-color:#4A22B8; }
/* border-color is ink-2, not rule-edge — rule-edge is ~2.3-3:1 and decorative
   band/row dividers are exempt from 1.4.11, but this border IS the required
   boundary of a real control, so it needs the ≥3:1 UI-component floor. */
.btn-2{ background:transparent; color:var(--ink); border-color:var(--ink-2); }
.btn-2:hover{ border-color:var(--ink); }
.btn:active{ translate:0 1px; }
.btn:focus-visible{ outline:2px solid var(--focus); outline-offset:3px; }
.btn:disabled{ opacity:.5; cursor:default; }

/* ═══ CRISIS BAR ════════════════════════════════════════════════ */
.crisis{
  position:sticky; top:0; z-index:var(--z-crisis);
  background:var(--ink); color:var(--ground);
  display:flex; flex-wrap:wrap; gap:var(--sp-4); align-items:center; justify-content:space-between;
  padding:var(--sp-3) var(--bleed); min-height:var(--crisis-h); font-size:var(--step-1);
}
.crisis .btn-crisis{
  background:var(--ground); color:var(--ink); border:1px solid var(--ground);
  border-radius:999px; text-transform:none; letter-spacing:.01em;
  padding:var(--sp-2) var(--sp-5); font-size:var(--step-0);
  flex-shrink:0; white-space:nowrap; /* default flex-shrink let the pill
    itself squeeze narrower than "Talk to someone tonight →" needs and
    wrap the words inside it — the row wrapping (flex-wrap above) is the
    intended fallback if space is tight, not the pill's own text. */
}
.crisis .btn-crisis:hover{ background:transparent; color:var(--ground); }
/* The condensed bar was scoped to portrait phones, but a landscape phone
   needs it more: at 740x320 the sentence and the pill were 16px too wide
   for the row, so the bar wrapped to two and took 109px — a third of the
   whole viewport, permanently, because it's sticky. nowrap here is what
   stops that. (Comma = OR; the `and` binds tighter.) */
@media (max-width:700px), (orientation:landscape) and (max-height:520px){
  .crisis{ flex-wrap:nowrap; align-items:center; gap:var(--sp-3); }
  .crisis-sentence{ flex:1 1 auto; min-width:0; }
  .crisis-sub{ display:block; font-size:var(--step--1); margin-top:.05em; }
  .crisis .btn-crisis{
    flex-shrink:0; flex-direction:column; align-items:center; gap:0;
    text-align:center; line-height:1.25; border-radius:var(--sp-3);
    padding:var(--sp-2) var(--sp-3); font-size:var(--step--1);
  }
}
/* The pill's flex-shrink:0 above claims its full natural width
   unconditionally, leaving whatever's left for the sentence — at 320px
   with --step-0 now 17px, that's not enough room, and the sentence
   wraps to three lines. Letting the pill shrink too shares the space
   instead (Patch 22, Part 1.5). */
@media (max-width:700px){
  .crisis .btn-crisis{ flex-shrink:1; min-width:0; }
}
/* Sharing space still wasn't enough at portrait phone widths at or below
   ~414px: the pill got squeezed until even "Talk to someone" wrapped in
   two, and the sentence had under 150px to work with — three lines
   total, a third of the viewport, permanently pinned there since the
   bar is sticky. A full column stack fixed the wrap but read as two
   full-width rows instead of one bar. Back to one row instead, sentence
   on the left and pill on the right as at every other width: "tonight"
   already dropped, and everything else — the pill's own padding, the
   bar's edge padding, the gap between them — pared back too, because
   at this width every pixel not spent on the two lines of text is a
   pixel that pushes them onto a third. */
@media (max-width:430px){
  .crisis{ padding-inline:var(--sp-3); gap:var(--sp-2); font-size:var(--step--1); }
  .crisis-sub{ font-size:var(--step--2); margin-top:.1em; }
  .crisis .btn-crisis{
    flex-shrink:0; flex-direction:row; align-items:center; gap:.25em;
    padding:var(--sp-1) var(--sp-2); font-size:var(--step--2); letter-spacing:0;
  }
  .cta-night{ display:none; }
}

/* ═══ STATS ═════════════════════════════════════════════════════ */
/* .stats declared no gap, so each .stat's own padding-inline:var(--gutter)
   was doing that job instead — which also pushed "91%" ~24px right of
   the heading above it, off the shared --bleed left edge. gap on the
   grid, padding-inline:0 on the item (Patch 24, Part 3.1). */
.stats{ display:grid; grid-template-columns:repeat(3,1fr); gap:0 var(--gutter); border-top:1px solid var(--rule); }
@media (max-width:820px){ .stats{ grid-template-columns:1fr; } }
.stat{ padding:var(--sp-6) var(--gutter) var(--sp-7); border-bottom:1px solid var(--rule); border-right:1px solid var(--rule); padding-inline:0; }
.stat:last-child{ border-right:0; }
@media (max-width:820px){ .stat{ border-right:0; padding-inline:0; } }
.stat .fig{ font-family:var(--display); font-weight:900; font-size:var(--step-4);
  line-height:.9; letter-spacing:-.04em; color:var(--ink); font-variation-settings:'wdth' 112; }
/* Patch 08, Part 2 tried stacking these two fractions vertically so they'd
   read as one figure (a third of referrals, three-quarters of deaths) —
   in practice that read as one number sitting on top of another, not as
   one figure. Side by side, same baseline, reads as the intended pair. */
.stat .fig-stack{ display:flex; flex-direction:row; align-items:baseline; gap:.2em; }
/* Archivo's font file has no glyph for U+2153 (⅓), so it silently fell
   back to a system font for that one character while ¾ (U+00BE, which
   Archivo does have) rendered correctly — the two "3"s the mismatch was
   spotted in were literally two different fonts. Built from plain
   digits instead and left to Archivo's own frac/numr/dnom OpenType
   features (confirmed present in the font file) to draw the diagonal
   fraction — guarantees both use the same glyphs, in the right font. */
.stat .fig-stack span{ font-variant-numeric:diagonal-fractions; }
/* 26ch is roughly a 30-character measure — at 1440px that's ~242px inside
   a 509px column, so the homepage's opening claim set as seven ragged
   lines. Widened (Patch 22, Part 1.6; the .stats--one selector the patch
   named no longer exists — it was removed as dead CSS earlier, so this
   applies directly to .stat .clm, its only real usage). */
.stat .clm{ margin-top:var(--sp-5); font-size:var(--step-0); max-width:44ch; }
.stat .src{ margin-top:var(--sp-3); font-family:var(--mono); font-size:var(--step--3);
  letter-spacing:.06em; color:var(--ink-2); text-transform:uppercase; font-variation-settings:'wdth' 87.5; }

/* ═══ PILLARS ═══════════════════════════════════════════════════ */
.pillars{ border-top:1px solid var(--rule); }
.pillar{ display:grid; grid-template-columns:minmax(3.5rem,max-content) 1fr 1fr;
  gap:var(--gutter); padding-block:var(--pb,var(--sp-6));
  border-bottom:1px solid var(--rule); align-items:start; }
@media (max-width:900px){
  .pillar{ grid-template-columns:minmax(2.5rem,max-content) 1fr; }
  .pillar .p-body{ grid-column:2; }
}
.pillar .num{ font-family:var(--display); font-weight:900; font-size:var(--n,var(--step-2));
  line-height:.8; letter-spacing:-.035em; color:var(--emphasis); font-variation-settings:'wdth' 112; }
.pillar .p-name{ display:block; font-family:var(--display); font-size:var(--nm,var(--step-2));
  font-weight:800; letter-spacing:-.024em; line-height:1; font-variation-settings:'wdth' 100; }
.pillar .p-sub{ font-family:var(--mono); font-size:var(--step--2); letter-spacing:.06em;
  text-transform:uppercase; color:var(--ink-2); margin-top:var(--sp-3); font-variation-settings:'wdth' 87.5; }
.pillar .p-body{ font-size:var(--step-0); color:var(--ink-2); max-width:44ch; }

/* ═══ TERMS — the COM-B component (Patch 03, A1) ═══════════════
   Same rule-divided construction as .pillar, no numeral column. */
.terms{ border-top:1px solid var(--rule); }
.term{ display:grid; grid-template-columns:1fr 1fr; gap:var(--gutter);
  padding-block:var(--sp-5); border-bottom:1px solid var(--rule); align-items:start; }
@media (max-width:700px){ .term{ grid-template-columns:1fr; } }
.term .t-name{ font-family:var(--display); font-weight:700; font-size:var(--step-2);
  letter-spacing:-.016em; line-height:1.05; font-variation-settings:'wdth' 100; }
.term .t-gloss{ font-size:var(--step-0); color:var(--ink-2); }

/* ═══ FLAGS (safety / callout blocks) ══════════════════════════ */
.flag{ border-left:3px solid var(--fail); padding:var(--sp-5) 0 var(--sp-5) var(--sp-5); margin-block:var(--sp-6); }
.flag--signal{ border-left-color:var(--signal); }

/* ═══ DISCLOSE — the <details> component (Patch 03) ══════════════
   Progressive disclosure without a modal: same content, in the DOM,
   indexable, keyboard-accessible, no JS required. The affordance is a
   mono +/− in the signal colour rather than a chevron — a chevron reads
   as accordion furniture, this reads as an editorial footnote. */
.disclose{ border-bottom:1px solid var(--rule); padding-block:var(--sp-5); }
.disclose > summary{
  display:flex; align-items:baseline; gap:var(--sp-4); cursor:pointer;
  min-height:24px;   /* SC 2.5.8 — the summary is the whole click target */
  font-family:var(--display); font-weight:700; font-size:var(--step-2);
  letter-spacing:-.016em; line-height:1.05; font-variation-settings:'wdth' 100;
  list-style:none;
}
.disclose > summary::-webkit-details-marker{ display:none; }
.disclose > summary::after{
  content:'+'; margin-left:auto; flex-shrink:0;
  font-family:var(--mono); font-weight:500; font-size:var(--step-0);
  color:var(--emphasis); font-variation-settings:'wdth' 87.5;
}
.disclose[open] > summary::after{ content:'\2212'; }
.disclose > summary:focus-visible{ outline:2px solid var(--focus); outline-offset:4px; }
/* .disclose > summary 26.1px (the primary control on /evidence, ~20
   instances), .ev-index a 38.1px, .footer-links a 20.07px — all under
   the 44px target-size floor (Patch 24, Part 2.3). min-height alone
   isn't enough on an inline or block element; display:flex +
   align-items makes the min-height actually apply to the click target
   rather than just the line box. (.site-nav a/button moved to its own
   expanded-hit-area rule below, so its visible size could shrink back
   to a tight highlight without losing the 44px target.) */
.footer-links a, .disclose > summary, .ev-index a{
  min-height:44px; display:flex; align-items:center;
}
/* .age-gate was already flex/align-items:center but stopped short of
   the floor (26.9px) — same fix, not in the patch's own snippet but
   named in its analysis. */
.age-gate{ min-height:44px; }
.disclose > *:not(summary){ margin-top:var(--sp-4); color:var(--ink-2); }
.disclose > *:not(summary):not(.win):not(.wk){ max-width:62ch; }

/* ═══ MISC ══════════════════════════════════════════════════════ */
.skip{ position:absolute; left:var(--bleed); top:0; z-index:600; background:var(--ink); color:var(--ground);
  padding:var(--sp-2) var(--sp-4); font-family:var(--mono); font-size:var(--step--1); translate:0 -150%; }
.skip:focus{ translate:0 0; }
@media (prefers-contrast:more){
  :root{ --ink-2:#D6D5D1; --rule:#7A7A85; --rule-edge:#9A9AA5; }
  .on-early{ --ink-2:#33322E; --rule:#7F7A6E; --rule-edge:#6A655B; }
}
@media (prefers-reduced-motion:reduce){
  *{ animation:none !important; transition:none !important; }
  /* Snapping moves the page without the reader asking. */
  html{ scroll-snap-type:none !important; }
}
/* A direct child of <body>, which is the only place a <footer> is mapped to
   the contentinfo landmark — nested inside <main> or a <section> Chrome
   computes it as `sectionfooter` and no screen reader offers it as the page
   footer. It was inside a section on the homepage and absent everywhere else,
   so the site had no contentinfo landmark at all (Patch 35).

   margin-inline, not padding-inline: as a body child the footer would
   otherwise run its background and top rule to the full width, where before
   it was inset by the bleed of the section holding it. The margin keeps the
   rule exactly where it was. */
footer{
  background:var(--ground); border-top:1px solid var(--rule-edge);
  padding-block:var(--sp-8) var(--sp-10); margin-inline:var(--bleed);
}
a{ color:inherit; text-decoration-thickness:1px; text-underline-offset:3px; }
/* A phone number must never break across a line. At 320-390px, 111 of them
   did — "0800 58 58 58" wrapping so the reader sees "0800 58" on one line and
   "58 58" on the next, in the crisis panel, on every page. A number you have
   to reassemble by eye is a number you can misdial, and the moment someone
   reads it is the worst possible moment for that. sms: too, for the same
   reason: "text 88247" is a number as much as a phrase. Patch 50. */
a[href^="tel:"], a[href^="sms:"]{ white-space:nowrap; }
/* An inline, JS-triggered action (e.g. "the crisis panel" mid-sentence)
   isn't a navigation link, so it shouldn't be an <a> — but it still
   needs to read as one, sitting inline in running prose. */
.link-btn{
  background:none; border:0; padding:0; margin:0; font:inherit; color:inherit;
  cursor:pointer; text-decoration:underline; text-decoration-thickness:1px;
  text-underline-offset:3px;
}
hr{ border:0; border-top:1px solid var(--rule); margin-block:var(--sp-7); }
/* Currently unused — the last call site went when band 03's heading became
   visible (Patch 16). Kept deliberately, same reasoning as the
   aria-disabled rules: it is the standard visually-hidden utility, and
   deleting it means a future class="sr-only" silently does nothing. */
.sr-only{ position:absolute; width:1px; height:1px; overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; }

/* ═══════════════════════════════════════════════════════════════
   SITE-SPECIFIC COMPONENTS — not in the brand-guide reference file
   ═══════════════════════════════════════════════════════════════ */

/* ── Header rail ─────────────────────────────────────────────── */
.site-header{
  display:flex; align-items:baseline; justify-content:space-between;
  gap:var(--sp-4); flex-wrap:wrap;
  /* horizontal inset comes from the parent .hero.bleed section already —
     padding-inline here would double it up against the H1 below. */
  padding-block:var(--sp-4);
}
.wordmark[href]{ text-decoration:none; }

/* ── Primary nav (Patch 05, §3; cut to three in Patch 09) — visible
   links, no hamburger. NN/g's own threshold: "if your site has 4 or
   fewer top-level nav links, display them as visible links." The fourth
   item was "talk to someone", which duplicated the crisis bar's own
   button — and that bar is position:sticky, so it is on screen at every
   scroll position, on every page, already. flex-wrap is what handles
   any width below one full row now, chips and all. ── */
.site-nav{
  display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-4);
  font-family:var(--display);
  /* Was --step--1, which put navigation ~3px BELOW running body copy at
     every width (14.11 vs 17.12 @320, 15.90 vs 19.00 @1440) — the chips
     read as a caption rather than the primary way around the site. At
     --step-0 the nav matches body copy and clears GDS's 16/19 floor.
     It costs a second row on phones, which is the right trade: two rows
     of legible navigation beat one row nobody can read. */
  font-size:var(--step-0);
  font-variation-settings:'wdth' 100; letter-spacing:-.01em;
  /* Row gap carries the expanded 44px hit areas below, not just the
     visible chips. A chip is ~28px at this size, so its target overhangs
     by ~8px top and bottom; anything under a 16px row gap puts two
     targets on top of each other and a tap near the edge of one fires
     the other. Measured at 320px before this change: rows 31px apart,
     targets overlapping by 13px, and the bottom probe on "home" landing
     on "about". --sp-5 puts the rows ~52px apart. */
  row-gap:var(--sp-5);
}
/* Plain coloured text, tight together, read as one run-on sentence
   rather than separate menu items — worst on mobile, where the nav
   wraps and loses even the wordmark's row to anchor it. Each item now
   gets .knock's own tight highlight — bold text, minimal padding,
   rather than a padded button-pill — with a real gap between items
   doing the work of separating them instead of generous padding. */
.site-nav a, .site-nav button{
  position:relative; /* anchors the expanded hit-area below */
  background:var(--signal); color:var(--signal-ink);
  border:0; margin:0; cursor:pointer;
  padding:0 .12em .04em; box-decoration-break:clone; -webkit-box-decoration-break:clone;
  font:inherit; text-decoration:none; text-transform:lowercase;
  white-space:nowrap; font-weight:700; /* after font:inherit — the shorthand resets weight too */
}
/* The tight highlight above is well under the 44px target-size floor
   (Patch 24, Part 2.3) — rather than pad the visible chip back out
   (which is the button-pill look this is specifically undoing), an
   invisible box extends the actual click/tap target to at least
   44x44 without changing what's on screen. Valid against SC 2.5.8:
   target size counts the hit area, not the visible decoration. */
.site-nav a::before, .site-nav button::before{
  content:''; position:absolute; top:50%; left:50%; translate:-50% -50%;
  width:max(100%, 44px); height:44px;
}
.site-nav a:hover, .site-nav button:hover{ background:var(--ink); color:var(--ground); }
.on-early .site-nav a:hover, .on-early .site-nav button:hover{ background:#4A22B8; color:var(--signal-ink); }
.site-nav a:focus-visible, .site-nav button:focus-visible{
  outline:2px solid var(--focus); outline-offset:2px;
}
/* The current page's chip inverts instead of just going bold — bold
   white-on-violet is a subtle difference to spot in a running row of
   identical chips; a different fill reads as "you're already here"
   at a glance. */
.site-nav a[aria-current="page"]{ background:var(--ink); color:var(--ground); font-weight:600; }

@media (max-width:700px){ .site-header{ padding-block:var(--sp-3); } }
/* Below 430px the four-item nav (home added) no longer holds one row at
   --step--1. Patch 12 shrank it to --step--3 to force one row back —
   9.92px primary navigation, trading legibility for a layout preference
   on the most-used viewport. A wrapped nav is not a defect; that was
   (Patch 22, Part 1.4). Now at --step-0 and left to wrap to two rows;
   the column-gap shrink still helps it sit tighter when it does. */
/* padding-block used to shrink here to hold one row at --step--3 — gone
   in Patch 22/24, and shrinking the chips' own padding on the narrowest
   screens is exactly backwards from what makes them read as separate
   items there, so only the gap between them tightens now.
   column-gap, not the gap shorthand: the shorthand sets both axes, so it
   was silently resetting the row gap to 8px at exactly the widths where
   this nav wraps — which is what put two 44px hit areas on top of each
   other and made a tap below "home" fire "about". */
@media (max-width:429px){
  /* --sp-2 left the four-item nav 3-6px over one row at 390px, so nine of
     the eleven pages wrapped on the commonest phone width while /index
     (three items) and /ask happened to fit. Six pixels is not worth a
     second row, and it is not worth shrinking the chips either — the
     padding is what makes them read as separate items. --sp-1 buys 12px,
     which clears it on every page with room. */
  .site-nav{ column-gap:var(--sp-1); }
}

/* ── Hero ─────────────────────────────────────────────────────── */
.hero{ padding-top:var(--page-top); }
/* Every page that is not the homepage. Replaces an inline
   `style="padding-block:var(--sp-8) var(--sp-10)"` repeated on ten files,
   which is why the homepage could drift away from them unnoticed. */
main.page{ padding-block:var(--page-top) var(--page-bottom); }
.hero-grid{ margin-top:var(--sp-6); position:relative; z-index:1; }
.site-header{ position:relative; z-index:1; }
/* Landscape phone — see the short-and-wide block near the tokens. These two
   have to sit after the declarations above, not with the token caps: a media
   query adds no specificity, so an earlier .hero rule would lose to a later
   one. --sp-6 here is a floor, not a reduction — the capped --sp-9 is
   already smaller. */
@media (orientation:landscape) and (max-height:520px){
  .hero-grid{ margin-top:var(--sp-4); }
  .site-header{ padding-block:var(--sp-2); }
}

/* ── The names cycling behind the hero (Patch 04, B3) ────────────
   A decorative, inert texture layer — never affects layout, so it
   sits at z-index 0 under the real content above, is aria-hidden
   and pointer-events:none, and is removed entirely (not just
   paused) under prefers-reduced-motion, per the hard requirement
   below rather than merely freezing it in place. */
.name-drift{ position:absolute; inset:0; z-index:0; overflow:hidden; pointer-events:none; }
.name-drift-item{
  position:absolute; top:0; left:0; will-change:transform, opacity;
  font-family:var(--display); font-weight:900; font-variation-settings:'wdth' 112;
  font-size:clamp(1.6rem, 1rem + 3.5vw, 3.5rem); line-height:1; letter-spacing:-.03em;
  text-transform:lowercase; color:var(--ink); white-space:nowrap;
}
/* Same underline device as .wordmark .blank, so a drifting "isXXXok?"
   reads as a ghost of the real thing rather than plain text that
   happens to share its shape. */
.name-drift-blank{
  /* currentColor, not --field — the parent's whole point is to sit at
     near-zero opacity, and swapping in a fixed accent colour here
     fails contrast at full opacity before the animation ever dims it. */
  display:inline-block;
  border-bottom:.1em solid currentColor; padding-bottom:.04em;
}
@media (prefers-reduced-motion:reduce){
  .name-drift{ display:none; }
}
/* The hero's own clamp, not the shared --step-5 — three stacked lines at
   step-5's ceiling (13rem/208px) run to ~1,300px tall and sink both CTAs
   below the fold, exactly the v2 defect the brief calls out. 9.5rem/152px
   at 1440px keeps headline + lede + both CTAs above the fold at 1440x850. */
.hero h1{ margin:0; font-size:clamp(2.75rem, 0.5rem + 9vw, 9.5rem); }
/* Patch 09, §3 — the hero's line gets its emphasis from the width axis
   rather than a second mark, on top of .behind. 118 is as far as it
   goes before the counters start closing up at 150px+. No opsz axis on
   Archivo, so wdth carries the optical-size job here as elsewhere. */
.hero h1{ font-variation-settings:'wdth' 118; }
@media (max-width:700px){ .hero h1{ font-variation-settings:'wdth' 112; } }
/* Direct-child selector only — this must stack the two top-level line
   spans, not any span nested deeper (e.g. .behind on "fine"). As a
   descendant selector this out-specificities .behind's own
   display:inline-block, forcing it block-level at the full column
   width, which orphans the trailing "." onto its own line below. */
.hero h1 > span{ display:block; }
/* Stagger only builds as a composition device across 3+ lines — on this
   two-line headline it just reads as a misaligned mistake. */
.hero h1:has(> span:nth-child(3)) > span + span{ margin-left:1.1em; }
@media (max-width:700px){ .hero h1 > span + span{ margin-left:0; } }
/* Patch 09, §1 — the hero gets one emphasis device, and it's .behind on
   "fine". .em used to sit on "that's the problem." with --field to fix
   Patch 07's 1.00:1 bug, but recolouring it just put a second violet
   device beside the ghost. Removed from the markup instead (the class
   is gone from the paragraph), so this rule has nothing left to match. */
/* Was an inline style on the markup until Patch 29, which is why the
   narrow-phone block below could not override it. */
.hero h1 + .d-sub{ margin-top:var(--sp-5); }
/* The one place the narrow 34ch measure is still right — it sits beside
   the blank field and wants to stay a short stack, not widen with the
   rest of the site's ledes (Patch 23, Part 1.1). */
.hero .lede{ margin-top:var(--sp-6); color:var(--ink-2); max-width:34ch; }
.hero .btns{ margin-top:var(--sp-6); }
@media (max-width:700px){
  /* Scaled to the screen rather than fixed, because this padding comes
     straight out of the first panel's height: the taller the phone, the
     more air the wordmark and nav can have under the crisis bar without
     costing the buttons their place on the floor. --sp-5 stays the floor,
     so no phone gets less than it had. */
  :root{ --page-top:clamp(var(--sp-5), 5.5vh, var(--sp-8)); }
  .hero-grid{ margin-top:var(--sp-4); }
  /* These were --sp-2 (8px) and --sp-3 (12px), tightened at some point to
     buy fold space. 8px under a subhead, above a 105px block of body copy,
     reads as a mistake rather than as pace — the whole hero looked
     compressed on a phone. Loosened to 16/24px. It costs 20px, and the
     side-by-side CTAs below give back ~62px, so the fold is better off
     than before. */
  .hero .lede{ margin-top:var(--sp-4); }
  .hero .btns{ margin-top:var(--sp-5); }

  /* ── Two screens, not one long scroll (mobile only) ─────────────
     The hook and the blank are the two things this page is for, and
     bunched into one scroll they competed. Each now gets a screen of
     its own: the headline block runs from under the nav to the bottom
     of the viewport with the CTAs sitting on the floor of it, and the
     name field is a second full screen below, vertically centred.

     100svh, not 100vh and not 100dvh. vh is the *large* viewport on iOS,
     so the panel would run under the address bar and put the CTAs
     off-screen. dvh was the first fix and caused a worse bug: it tracks
     the address bar live, so every time the bar hid or reappeared these
     two panels resized and the document lost 121px — measured — and
     every section below the hero jumped. svh is the *small* viewport,
     the one with the chrome at its largest, and it does not move when
     the bar retracts. So the CTAs are still never under the bar, and
     the page below the hero stops shifting under the reader. The cost
     is a strip of spare screen once the bar is gone, which is a good
     trade for a document height that holds still (Patch 34). */
  #hero .c-head{
    display:flex; flex-direction:column;
    min-height:calc(100svh - var(--crisis-h) - var(--hero-head-offset));
  }
  /* Where the slack goes. A single margin-top:auto on the buttons parked
     every spare pixel in one gap, which on a tall phone left the lede
     stranded a third of a screen above the CTAs. Split it instead, one
     part above the headline to two below the lede: the text block drops
     clear of the nav, the CTAs still land on the floor, and the empty
     space reads as composition rather than a missing paragraph. Grow
     factors, not auto margins — an auto margin eats the whole surplus
     before flex-grow gets a look in, so the two cannot be mixed. */
  #hero .c-head::before{ content:''; display:block; flex-grow:1; }
  #hero .c-head .lede{ flex-grow:2; }
  /* And a share below the buttons, so they lift off the very floor of the
     screen — flush against it they sit under the browser's own toolbar on
     iOS. A grow factor, not padding: padding would be owed whether or not
     the screen could spare it, and at 320px there is nothing to spare. A
     third share of nothing is nothing, so the shortest phones are left
     exactly as they were.

     Capped, because an uncapped share is 83px on a 390x844 and 117px on a
     Pro Max, which stops reading as a margin and starts reading as the
     buttons having come loose. Flexbox freezes an item at its max and
     hands the remainder back to the other two, so the cap costs the
     layout nothing. */
  #hero .c-head::after{ content:''; display:block; flex-grow:1.5; max-height:var(--sp-6); }
  /* This panel is landed on rather than started at, so it also has to
     undo html's scroll-padding-top: that parks a snap target --sp-5
     clear of the crisis bar, which is right for an anchored heading and
     wrong here — it left a --sp-5 sliver of the previous screen's
     buttons showing above the fold and pushed the panel's own foot the
     same distance below it. A negative scroll-margin cancels exactly
     that inset, so the panel lands flush under the bar and fills the
     rest of the screen precisely. */
  #hero .c-side{
    display:flex; flex-direction:column; justify-content:center;
    min-height:calc(100svh - var(--crisis-h));
    scroll-margin-top:calc(-1 * var(--sp-5));
  }
  #hero .c-side .blank-field{ margin-top:0; }

  /* Snap so each is a place you land rather than somewhere you stop
     halfway. proximity, never mandatory: mandatory refuses to rest
     between snap points, so on a phone short enough that a panel
     overflows its screen, the bottom of that panel becomes unreachable
     — and one of these panels holds the CTAs. proximity nudges when
     you're close and gets out of the way when you're not.

     One snap point, not two. Giving #hero itself one as well made the
     page snap on load at 320px — the top of the document is already a
     hard stop that scrolling up lands on, so the second target bought
     nothing and cost the wordmark 33px under the crisis bar. Only the
     homepage hero carries snap-align, so no other page is affected by
     the snap-type on html. */
  html{ scroll-snap-type:y proximity; }
  #hero .c-side{ scroll-snap-align:start; }
  /* The band after the hero is the third and last stop — from there the
     page is an ordinary scroll. Same negative scroll-margin as the name
     panel, so the native snap position and the one site.js computes are
     the same number rather than --sp-5 apart. */
  #hero + section{ scroll-snap-align:start; scroll-margin-top:calc(-1 * var(--sp-5)); }

  /* The two hero CTAs stacked, because they wanted 437px in a 341px column
     at 390px — and stacking cost 124px of height in the most valuable part
     of the page. Side by side instead: an equal half each, with the tight
     mono letter-spacing and the wide inline padding both pulled in, since
     at this width they are decoration that costs a whole row. flex:1 1 0
     with min-width:0 makes the two share the row exactly rather than
     sizing to their own text, so they stay the same width as each other
     whatever the labels say. min-height keeps the 44px target. */
  .hero .btns{ flex-wrap:nowrap; align-items:stretch; }
  .hero .btns .btn{
    flex:1 1 0; min-width:0;
    justify-content:center; text-align:center;
    padding-inline:var(--sp-3); letter-spacing:.02em;
    /* "Learn the six moves" can't hold one line in half a 390px row at
       any type size worth reading, so it wraps — balance makes it break
       as "learn the / six moves" rather than stranding one word. */
    text-wrap:balance;
  }
  /* The shared clamp's floor (2.75rem) bottomed out below ~400px and went
     flat, so every phone got the same 44px — which left "they look"
     occupying 222px of a 341px column at 390px and read as body copy in a
     headline's job, not as the poster the desktop hero is. Its own term
     down here, tracking width so it stays poster-scale on every phone:
     48px at 320, 58px at 390, 65px at 430. 15vw is ~90% of the largest
     size that keeps the longest authored line ("they look") on one line,
     measured per width rather than estimated — the 10% is headroom for
     the fallback face and for hinting differences off this machine. The
     4.5rem cap lands within 1px of the shared clamp's own value at the
     700px handover, so nothing jumps at the breakpoint. */
  .hero h1{ font-size:clamp(2.75rem, 15vw, 4.5rem); }
}

/* Landscape phone — the two panels are only panels when the screen is tall
   enough to hold one. Wide and short, .c-side is a good deal taller than the
   viewport, so a snap point on it means snapping back to a top you have just
   scrolled away from. Same threshold as the other short-and-wide caps. */
@media (orientation:landscape) and (max-height:520px){
  html{ scroll-snap-type:none; }
}

/* 320px, where the single screen is hardest won: the crisis bar wraps to
   109px and the nav to two rows, so 246px of the 568 is spoken for before
   the headline starts. Every gap in the hero comes in a step, which buys
   back the ~30px that decides whether the CTAs land above the fold. Kept
   to the gaps — the type itself stays at its size, since this is the width
   where shrinking it would do real damage. */
@media (max-width:359px){
  :root{ --page-top:var(--sp-1); }
  .site-header{ padding-block:var(--sp-2); }
  .hero-grid{ margin-top:var(--sp-1); }
  .hero h1 + .d-sub{ margin-top:var(--sp-2); }
  .hero .lede{ margin-top:var(--sp-2); }
  .hero .btns{ margin-top:var(--sp-2); }
}

/* Tuned so the input's underline lands on the H1's last baseline — see
   README, "the blank's baseline" — measured, not eyeballed, at 1440px. */
.blank-field{ display:flex; flex-direction:column; margin-top:clamp(3.5rem, 0.3rem + 6vw, 7rem); }
.blank-input-wrap{ position:relative; }
.blank-input{
  width:100%; background:none; border:0; border-bottom:.1em solid var(--field);
  color:var(--field); caret-color:var(--field);
  font-family:var(--display); font-weight:900; font-variation-settings:'wdth' 112;
  font-size:clamp(2rem, 1rem + 6vw, 5rem); letter-spacing:-.03em; line-height:1;
  padding:0 0 .1em; text-transform:lowercase; overflow:hidden;
}
/* Auto-shrink probe (Patch 04, B2) — identical font stack/weight/wdth to the
   real input, positioned off-screen so its offsetWidth can be measured
   without ever painting. Measuring the input itself doesn't work: it
   clips rather than reporting overflow. */
.blank-input-probe{
  position:absolute; left:0; top:0; visibility:hidden; white-space:pre; pointer-events:none;
  font-family:var(--display); font-weight:900; font-variation-settings:'wdth' 112;
  letter-spacing:-.03em; line-height:1; text-transform:lowercase;
}
.blank-input::placeholder{ color:var(--field); opacity:.75; }
.blank-input:focus-visible{ outline:2px solid var(--focus); outline-offset:6px; }
.blank-field .label{ margin-bottom:var(--sp-3); }
.blank-helper{ margin-top:var(--sp-3); }
.blank-actions{ display:flex; flex-wrap:wrap; gap:var(--sp-3); margin-top:var(--sp-5); }
#square-status{ margin-top:var(--sp-3); color:var(--ink-2); }

/* ── Caesura ──────────────────────────────────────────────────── */
/* Purple fill, matching .punct's treatment — this sits right after the
   origin band, which is also --late, so two black sections back to back
   otherwise. Same signal/signal-ink pair, same top rule colour. */
.caesura{
  /* Used to be a fixed min-height (78vh, capped at 640px) with the text
     grid-centred inside it — once the text dropped to --step-3 to match
     .punct, that fixed height was a lot more box than a step-3 line
     needs, which is what read as dead space above and below it. Padding
     instead, exactly .punct's formula, so the amount of space scales
     with the content the same way it does there. */
  padding:var(--sp-9) var(--bleed);
  background:var(--signal); color:var(--signal-ink);
  border-top:1px solid var(--signal);
}
.caesura p{
  font-family:var(--display); font-weight:800; font-size:var(--step-3);
  letter-spacing:-.026em; line-height:1.02; font-variation-settings:'wdth' 100;
  max-width:44ch; text-transform:lowercase;
}

/* ── Six moves — sticky-scroll narrative ─────────────────────── */
/* .moves-layout/.moves-rail/.moves-list removed (Patch 24, Part 1.1) —
   dead since Patch 05 moved the six-moves band to /ask, which uses
   .moves-full instead. Confirmed via grep: nothing in the markup
   references any of the three. The rail never got a 6-column remap
   and silently overlapped .moves-list across 701-1080px, which is
   what surfaced this as dead code worth checking rather than fixing. */
/* padding-block bumped 6->7 (Patch 07, §6.2): moves now each carry a
   .branch, and 32px between them read as too little for the added
   content. The patch's own note about protecting the homepage's .move
   instances is stale -- Patch 05 removed that band from the homepage
   entirely, so .move only renders on /ask now; changing the base rule
   directly is equivalent to scoping it there. */
.move{ display:grid; grid-template-columns:minmax(2.5rem,max-content) 1fr; gap:var(--gutter);
  padding-block:var(--sp-7); border-bottom:1px solid var(--rule); }
.move .num{ font-family:var(--display); font-weight:900; font-size:var(--step-2);
  color:var(--emphasis); line-height:.8; font-variation-settings:'wdth' 112; }
.move h3{
  font-family:var(--display); font-weight:600; font-size:var(--step-1);
  letter-spacing:-.008em; line-height:1.15; font-variation-settings:'wdth' 100;
  margin-bottom:var(--sp-2);
}
.move .sub{ font-family:var(--mono); font-size:var(--step--2); letter-spacing:.06em;
  text-transform:uppercase; color:var(--ink-2); margin-bottom:var(--sp-3); font-variation-settings:'wdth' 87.5; display:block; }
.move p{ color:var(--ink-2); max-width:48ch; }
.move em{ font-style:italic; color:var(--ink); }

/* ── Evidence — now a list of .disclose rows, see that component ── */
.evidence{ border-top:1px solid var(--rule); }

/* ── Get involved — four doors ───────────────────────────────── */
.doors{ border-top:1px solid var(--rule); }
.door{ display:grid; grid-template-columns:1fr; gap:var(--sp-4);
  padding-block:var(--sp-7); border-bottom:1px solid var(--rule); }
@media (min-width:701px){
  .door{ grid-template-columns:minmax(3.5rem,max-content) 1fr minmax(max-content,16ch);
    align-items:start; gap:var(--gutter); }
}
/* Patch 07, §3.2 — the fork reuses .pillar's numbered-row construction
   rather than defining its own. On --early (this band is now flipped,
   Part 0), --emphasis resolves to --signal, so the numerals come out
   violet without declaring a colour. */
.door .num{ font-family:var(--display); font-weight:900; font-size:var(--step-2);
  line-height:.8; letter-spacing:-.035em; color:var(--emphasis);
  font-variation-settings:'wdth' 112; }
.door .label{ padding-top:.3em; }
.door p{ color:var(--ink-2); max-width:48ch; }
/* The label is the door's own heading — it was sitting flush on the
   paragraph it introduces, in all four doors. */
.door .label + p{ margin-top:var(--sp-3); }
.door .btn{ justify-self:start; }
@media (min-width:701px){ .door .btn{ justify-self:end; } }

/* ── Email capture ───────────────────────────────────────────── */
.capture{ max-width:44ch; }
.capture-field{ margin-top:var(--sp-6); }
.capture-field label.label{ display:block; margin-bottom:var(--sp-2); }
.capture-row{ display:flex; flex-wrap:wrap; gap:var(--sp-3); }
.capture-row input[type="email"], .capture-row input[type="text"]{
  flex:1 1 16rem; min-width:0; background:none; border:1px solid var(--ink-2); color:var(--ink);
  font-family:var(--sans); font-size:var(--step-0); padding:var(--sp-4); border-radius:0;
  min-height:44px;
}
.capture-row input[type="email"]::placeholder, .capture-row input[type="text"]::placeholder{ color:var(--ink-2); }
.capture-row input[type="email"]:focus-visible, .capture-row input[type="text"]:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
.capture-row input[aria-invalid="true"]{ border-color:var(--fail); }
/* Honeypot — off-screen, not display:none (which most bots skip filling
   in), unreachable by keyboard and hidden from assistive tech. */
.hp-field{
  position:absolute; left:-9999px; width:1px; height:1px; overflow:hidden;
}
.age-gate{
  display:flex; align-items:center; gap:var(--sp-2); margin-top:var(--sp-4);
  color:var(--ink-2); cursor:pointer;
}
.age-gate input{ width:var(--sp-5); height:var(--sp-5); accent-color:var(--signal); flex-shrink:0; }
.age-gate input:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
.capture .consent{ margin-top:var(--sp-4); }
.capture .msg{ margin-top:var(--sp-3); font-family:var(--mono); font-size:var(--step--1);
  font-variation-settings:'wdth' 87.5; }
.capture .msg[data-tone="error"]{ color:var(--fail); }
.capture .msg[data-tone="success"]{ color:var(--ink); }
.capture .success-state{ border:1px solid var(--rule-edge); padding:var(--sp-6); max-width:44ch; }

/* ── Footer furniture ─────────────────────────────────────────── */
.footer-signpost{ border:1px solid var(--rule-edge); padding:var(--sp-6); max-width:70ch; }
/* Four short blocks, stacked on narrow screens. Two wide columns used to
   pair them up, but each column held two paragraphs of very different
   length, so the shorter pair left a block of dead space beneath it —
   one paragraph per column instead, so no single column runs much
   longer than its neighbours. Two columns as a tablet step, four once
   there's room for them without each getting too narrow to read. */
.footer-blocks{ margin-top:var(--sp-7); display:grid; grid-template-columns:1fr; gap:var(--sp-6); }
@media (min-width:701px){
  .footer-blocks{ grid-template-columns:1fr 1fr; gap:var(--sp-6) var(--sp-8); }
}
@media (min-width:1024px){
  .footer-blocks{ grid-template-columns:repeat(4,1fr); gap:var(--sp-4) var(--sp-6); }
}
.footer-blocks .footer-block{ margin-top:0; max-width:none; }
.footer-block{ max-width:62ch; margin-top:var(--sp-7); color:var(--ink-2); }
.footer-block strong{ color:var(--ink); }
/* Row gap --sp-2, not --sp-5. Each link carries a 44px hit box (see the
   target-size rule above) and only ~20px of that is ink, so a 24px gap put
   68px between one row of text and the next and the list read as four
   separate lines rather than one block. 8px brings the pitch to 52px. The
   boxes still never touch, so the 44px targets are untouched — this is the
   opposite of the Patch 26 nav bug, where the target came from a ::before
   and shrinking the gap overlapped it. Patch 41.

   Taken to zero in Patch 42. With a 44px target on every link the pitch
   cannot go below 44px without the targets overlapping each other, which is
   exactly the tap-the-wrong-link bug Patch 26 fixed in the nav. Zero gap is
   the floor: 44px pitch, 24px between one row of ink and the next, down from
   32px. Anything tighter has to come out of the 44px box itself. */
.footer-links{ margin-top:var(--sp-8); display:flex; flex-wrap:wrap; gap:0 var(--sp-6);
  list-style:none; font-family:var(--mono); font-size:var(--step--1); font-variation-settings:'wdth' 87.5; }
a[aria-disabled="true"]{ pointer-events:none; text-decoration:underline dotted; }
.footer-links a[aria-disabled="true"]{ color:var(--ink-2); }
.footer-tag{ margin-top:var(--sp-9); }

/* ── Crisis dialog ─────────────────────────────────────────────
   Rendered in the top layer, detached from any section it was
   opened from — carries its own .on-early class (in the markup)
   so every colour below comes from the token cascade, not a hex. */
dialog.crisis-dialog{
  background:var(--ground); color:var(--ink); border:0; border-radius:0;
  padding:0; max-width:min(90vw, 40rem); width:100%;
  /* vh resolves against iOS's large viewport, taller than the real
     window with the URL bar showing — dvh tracks the actual visual
     viewport so overflow-y actually engages when it should (Patch 24,
     Part 2.1). */
  max-height:min(85dvh, 48rem); overflow-y:auto;
  /* The global reset's margin:0 defeats the UA stylesheet's margin:auto
     centering, so position and centre it explicitly instead of relying
     on dialog's default fit-content-and-centre behaviour. */
  position:fixed; top:50%; left:50%; translate:-50% -50%; margin:0;
}
dialog.crisis-dialog::backdrop{ background:rgba(12,12,13,.7); }
/* --bleed scales with viewport, so inside a fixed max-width:40rem dialog
   the content got NARROWER as the screen got bigger — 559px@768 down to
   409px@2560 (43 characters, under the 45 floor). A fixed spacing token
   instead, since the dialog's width is already fixed (Patch 24, Part 3.3). */
.cd-inner{ padding:var(--sp-7) var(--sp-6); }
/* At 320x568 the dialog's own content runs to ~1885px tall in a ~460px
   window — Text SHOUT, Ring Samaritans, Call 111 and Close were the
   LAST elements, about four swipes down. Pins a reachable close
   control at the top so nobody in distress is ever trapped scrolling
   to find it; the full action row stays at the bottom too, for anyone
   who reads all the way through (Patch 24, Part 2.2). */
.cd-close-row{
  position:sticky; top:0; z-index:1;
  background:var(--ground); padding-block:var(--sp-3);
  display:flex; justify-content:flex-end;
}
.cd-item{ margin-top:var(--sp-6); }
.cd-item p{ margin-top:var(--sp-2); }
.cd-item a{ font-weight:700; text-decoration-color:var(--field); }
.cd-danger{ margin-top:var(--sp-6); font-weight:700; }
.cd-btns{ margin-top:var(--sp-7); display:flex; flex-wrap:wrap; gap:var(--sp-3); }

/* ═══ EVIDENCE PAGE (Patch 04, Part A) ═══════════════════════════
   /evidence — the whole map, on the site's own grid and tokens.
   Sticky index left, content right; collapses to a horizontal
   chip row above content below 1080px, matching .grid's own
   breakpoint so the two systems never disagree about layout. */
.ev-shell{ display:grid; grid-template-columns:15rem 1fr; gap:var(--sp-8); align-items:start; }
/* min-width:0 on both items — otherwise a grid item's auto-min-width is
   driven by its content's min-content size, and .tw table's min-width:38rem
   (nested many levels deep in .ev-content) forces the whole column track
   to at least 608px regardless of viewport, blowing out the mobile layout
   even though the table's own .tw wrapper scrolls correctly on its own. */
.ev-index, .ev-content{ min-width:0; }
.ev-index{
  position:sticky; top:calc(var(--crisis-h) + var(--sp-6)); align-self:start;
  border-right:1px solid var(--rule); padding-right:var(--sp-5);
  max-height:calc(100dvh - var(--crisis-h) - var(--sp-8)); overflow-y:auto;
}
.ev-index a{
  display:block; padding-block:var(--sp-2); padding-left:var(--sp-3);
  font-family:var(--mono); font-size:var(--step--1); color:var(--ink-2);
  text-decoration:none; border-left:2px solid transparent; text-transform:lowercase;
}
.ev-index a:hover{ color:var(--ink); }
.ev-index a:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
.ev-index a[aria-current="true"]{ color:var(--ink); border-left-color:var(--signal); font-weight:600; }
@media (max-width:1080px){
  .ev-shell{ grid-template-columns:1fr; }
  .ev-index{
    position:static; max-height:none; display:flex; flex-wrap:wrap; gap:var(--sp-2);
    border-right:0; border-bottom:1px solid var(--rule); padding:0 0 var(--sp-5);
  }
  /* These are navigation controls below 1080px, not decorative dividers, so
     --rule's 1.81:1 doesn't clear the 1.4.11 floor for a UI boundary.
     Same fix already applied to .btn-2. */
  .ev-index a{ border:1px solid var(--ink-2); padding:var(--sp-2) var(--sp-3); }
  .ev-index a[aria-current="true"]{ border-color:var(--signal); }
}

.ev-sec{ padding-block:var(--sp-8); border-bottom:1px solid var(--rule-edge); }
.ev-sec:first-of-type{ padding-top:0; }
.ev-sec > .lede, .ev-sec > .body{ max-width:70ch; }

.correction{ padding-block:var(--sp-7); border-bottom:1px solid var(--rule); display:grid;
  grid-template-columns:auto 1fr; gap:var(--sp-5); align-items:baseline; }
.correction:first-child{ padding-top:0; }
.correction .c-num{ font-family:var(--display); font-weight:900; font-size:var(--step-3);
  color:var(--emphasis); line-height:.9; }
.correction .c-claim{ font-family:var(--display); font-weight:700; font-size:var(--step-1);
  line-height:1.25; text-decoration:line-through; text-decoration-color:var(--fail);
  text-decoration-thickness:2px; color:var(--ink-2); }
.correction .c-body{ margin-top:var(--sp-3); font-size:var(--step-0); max-width:62ch; }
.correction .c-meta{ margin-top:var(--sp-4); display:flex; gap:var(--sp-4); flex-wrap:wrap;
  align-items:center; font-family:var(--mono); font-size:var(--step--2); text-transform:uppercase;
  letter-spacing:.06em; color:var(--ink-2); }
.correction .c-ourown{ color:var(--signal); border:1px solid var(--signal); padding:var(--sp-1) var(--sp-2); }
@media (max-width:700px){ .correction{ grid-template-columns:1fr; gap:var(--sp-2); } }

.tw{ overflow-x:auto; margin-block:var(--sp-5); border:1px solid var(--rule); }
/* min-width was blanket-applied and manufactured the very overflow the hint
   then advertised. Opt in per table instead — see the audit note above the
   markup for which tables actually earned .tw--wide. */
.tw table{ width:100%; border-collapse:collapse; font-size:var(--step--1); }
.tw--wide table{ min-width:38rem; }
.tw th, .tw td{ padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--rule); text-align:left; vertical-align:top; }
.tw thead th{ font-family:var(--mono); text-transform:uppercase; font-size:var(--step--2);
  letter-spacing:.05em; color:var(--ink-2); }
.tw td.num, .tw th.num{ text-align:right; font-family:var(--mono); font-variation-settings:'wdth' 87.5; }
.tw tbody tr:last-child td{ border-bottom:0; }
.tw-hint{ font-family:var(--mono); font-size:var(--step--2); color:var(--ink-2); margin-bottom:var(--sp-2);
  display:none; }              /* JS reveals it only if it's true */
.tw[data-overflows="true"] .tw-hint{ display:block; }
/* These are the boundary of a real, focusable control (once JS marks a
   table overflowing, below), not a decorative divider — same 1.4.11
   reasoning already applied to .btn-2. */
.tw:focus-visible{ outline:2px solid var(--focus); outline-offset:2px; }
.disclose .tw{ max-width:none; }

.chip{ display:inline-block; font-family:var(--mono); font-size:var(--step--3); font-weight:600;
  text-transform:uppercase; letter-spacing:.05em; padding:var(--sp-1) var(--sp-2); border:1px solid var(--ink-2); color:var(--ink);
  white-space:nowrap; }
.g-strong   { border-color:var(--grade-1); border-width:2px; font-weight:700; }
.g-moderate { border-color:var(--grade-2); }
.g-weak     { border-color:var(--grade-3); }
.g-contested{ border-color:var(--grade-4); }
.g-refuted  { border-color:var(--grade-5); }
.g-none     { border-color:var(--rule); border-style:dashed; }

.win, .wk{ padding-block:var(--sp-4); border-bottom:1px solid var(--rule); }
.win-head{ display:flex; justify-content:space-between; gap:var(--sp-3); flex-wrap:wrap; align-items:baseline; }
.win-name{ font-weight:600; }
.win-age{ font-family:var(--mono); font-size:var(--step--2); color:var(--ink-2); }
.win-note{ margin-top:var(--sp-2); color:var(--ink-2); max-width:70ch; }
.win-src{ margin-top:var(--sp-2); font-family:var(--mono); font-size:var(--step--3); color:var(--ink-2); }

.phase{ border-bottom:1px solid var(--rule); }
.phase summary{ padding-block:var(--sp-4); }
/* .disclose > summary is a flex row (so the +/− marker can sit hard right).
   The phase summaries put three blocks straight into that row — age, title,
   strap — which laid them side by side, each with flex's default
   min-width:auto, so none could shrink and the section pushed the page 18px
   wide at 320px. One shrinkable wrapper instead: the three stack inside it
   as intended, and the marker keeps its row. */
.phase .ph-txt{ min-width:0; }
.phase .ph-age{ font-family:var(--mono); font-size:var(--step--2); color:var(--ink-2); display:block; margin-bottom:var(--sp-1); }
.phase .ph-strap{ display:block; font-family:var(--sans); font-weight:400; font-size:var(--step-0); color:var(--ink-2); margin-top:var(--sp-2); }
.finding{ margin-top:var(--sp-5); }
.finding .f-claim{ font-weight:700; color:var(--ink); max-width:62ch; }
/* No flex-wrap plus nowrap chips meant a long chip row fell off the right
   edge, and body{overflow-x:clip} meant it did so with no scrollbar to
   reveal it — the grade itself was what got lost (Patch 24, Part 0.2). */
.finding .f-chips{ margin-top:var(--sp-3); display:flex; gap:var(--sp-2); flex-wrap:wrap; }
.finding .f-ev{ margin-top:var(--sp-2); }
.finding .f-cite{ margin-top:var(--sp-2); font-family:var(--mono); font-size:var(--step--3); }
.finding .f-limit{ margin-top:var(--sp-2); border-left:2px solid var(--fail); padding-left:var(--sp-3); }
/* --step--3 renders at 9.92px on a phone — five px smaller than the prose
   it qualifies, on the page whose whole purpose is showing the working.
   --step--3 stays in the token set for genuinely incidental marks; nothing
   a reader needs may use it. Floored these four at --step--1 (Patch 22,
   Part 1.3) — placed after all four's own definitions so this wins the
   cascade regardless of source order above. Uppercase at chip size also
   closed the counters, so that comes off too. */
.chip, .stat .src, .win-src, .finding .f-cite{ font-size:var(--step--1); }
.chip{ text-transform:none; }
/* nowrap plus no flex-wrap on the parent is what let a long chip row push
   the grade chip off the right edge with no scrollbar to reveal it
   (Patch 24, Part 0.2 — paired with .finding .f-chips{flex-wrap:wrap}). */
.chip{ white-space:normal; }

.gap-item{ padding-block:var(--sp-4); border-bottom:1px solid var(--rule); }
.gap-item .gap-age{ font-family:var(--mono); font-size:var(--step--2); color:var(--ink-2); }
.gap-item h3{ font-family:var(--display); font-weight:700; font-size:var(--step-0); margin-top:var(--sp-2); color:var(--ink); }
.gap-item h3 + p{ margin-top:var(--sp-2); }
.gap-item .gap-fix{ margin-top:var(--sp-3); border-left:2px solid var(--signal); padding-left:var(--sp-3); }

.q-item{ padding-block:var(--sp-4); border-bottom:1px solid var(--rule); display:grid;
  grid-template-columns:2rem 1fr; gap:var(--sp-3); }
.q-item .q-n{ font-family:var(--mono); color:var(--ink-2); }
.q-item .q-t{ font-weight:600; color:var(--ink); }
.q-item .q-why{ display:block; margin-top:var(--sp-2); font-weight:400; color:var(--ink-2); }

.ev-flag{ border-left:3px solid var(--fail); padding:var(--sp-5) 0 var(--sp-5) var(--sp-5); margin-block:var(--sp-6); max-width:70ch; }
.ev-flag.good{ border-left-color:var(--signal); }
.ev-flag h3, .ev-flag h2{ font-family:var(--display); font-weight:700; font-size:var(--step-1); margin-bottom:var(--sp-2); }
.ev-decl{ border:1px solid var(--rule-edge); padding:var(--sp-6); max-width:70ch; margin-top:var(--sp-6); }
/* 70ch was ~75 characters at the old ~17px body; at 19px (Patch 22) it's
   ~84, past the 75 upper bound. Placed after all six's own definitions
   so this wins the cascade regardless of source order above (Patch 24,
   Part 0.3). */
.ev-sec > .lede, .ev-sec > .body, .win-note, .ev-flag, .ev-decl,
.footer-signpost{ max-width:62ch; }

/* ═══ PUNCT — the one bold colour moment (Patch 04, C1) ═══════════
   A third ground value between --late and --early, used exactly twice,
   once inside each long run, so a ground flip keeps meaning "register
   change" rather than "next section". */
.punct{
  background:var(--signal); color:var(--signal-ink);
  padding:var(--sp-9) var(--bleed);
  border-top:1px solid var(--signal);
}
.punct p{
  font-family:var(--display); font-weight:800; font-size:var(--step-3);
  letter-spacing:-.026em; line-height:1.02; font-variation-settings:'wdth' 100;
  max-width:30ch; text-transform:lowercase;
  /* The markup reuses .d-head for this paragraph's type styles, but
     .d-head also carries its own margin-block for when it's a normal
     heading — stacking inside .punct's own padding and adding ~56px
     .punct never intended. .punct's padding is meant to be the only
     spacing control here, same as .caesura. */
  margin-block:0;
}

/* ═══ KNOCK — the knockout highlight (Patch 04, D1) ════════════════
   Same device as the wordmark's one-colour master: a signal fill behind
   a word, inline. One per band, maximum; never in the Quiet register or
   the crisis panel; never on a statistic except the one exception noted
   at its call site (38.1% — the figure *is* the ask, not the data). */
.knock{
  background:var(--signal); color:var(--signal-ink);
  padding:0 .12em .04em; box-decoration-break:clone;
  /* At display sizes the H1's line-height:.95 lets the fill of one line
     overlap the fill of the line above. Clip the box to the cap height
     rather than the line box so stacked knocks can never touch. */
  -webkit-box-decoration-break:clone;
}
.hero h1 .knock, .d-poster .knock{ padding-block:0; }
/* Signal on signal is 1.00:1. If a .knock ever lands inside a .punct
   panel, fail loudly rather than rendering an invisible word. */
.punct .knock{ outline:3px solid var(--fail); background:none; color:var(--fail); }
/* Patch 08, Part 4.1 — the knock is a display device (--step-2 and up).
   At body size it reads as a highlighter pen, not a typographic mark,
   which cheapens the one mark the system can't recover once spent.
   Guard it the same way as the .punct nesting ban above. */
.body .knock, .clm .knock, .sm .knock, .mono .knock, .op-note .knock{
  outline:3px solid var(--fail); background:none; color:var(--fail);
}

/* ═══ BEHIND — the offset word (Patch 04, D2) ══════════════════════
   Deflection words only (fine / alright / good / not too bad), display
   sizes only, three uses on the page maximum. Full opacity, not a tint —
   a tint composites to a drop shadow, which this system otherwise bans. */
.behind{ position:relative; display:inline-block; isolation:isolate; }
.behind::before{
  content:attr(data-word) / "";
  position:absolute; left:0; top:0; z-index:-1;
  white-space:pre; width:max-content;
  color:var(--fail);
  translate:.06em .06em;
  user-select:none;
}
/* Patch 09, §2 — an offset dot has no edge to double, so it reads as a
   second dot rather than off-register ink; the trailing full stop must
   sit outside the span. data-word is hand-typed and will drift, so fail
   loudly on a punctuation-only value rather than trust the markup. This
   only catches a span with no other content — see the patch's own §6
   check (grep every data-word) for the real guarantee. */
.behind:not(:has(*)):is([data-word="."],[data-word=","],[data-word="?"],[data-word="!"]){
  outline:3px solid var(--fail);
}

/* ═══ /ASK — the method's own page (Patch 05, §1) ══════════════════ */

/* .move already exists (homepage six-moves band) and is reused as-is
   for the full moves list here — this just gives the standalone list
   (not inside the sticky .moves-layout rail) the same top rule. */
.moves-full{ border-top:1px solid var(--rule); }

/* The "if..." branch nested inside a .move — one per move, the
   biggest content addition on this page. 2px signal rule, mono
   label, everything at --step--1 so it reads as a footnote to the
   move above it, not a seventh move. */
.branch{
  margin-top:var(--sp-5); padding-left:var(--sp-4);
  border-left:2px solid var(--signal); font-size:var(--step--1);
}
.branch .b-label{
  display:block; font-family:var(--mono); font-weight:600;
  text-transform:lowercase; letter-spacing:.03em; color:var(--ink-2);
  margin-bottom:var(--sp-2); font-variation-settings:'wdth' 87.5;
}
.branch p{ color:var(--ink-2); max-width:48ch; }
.branch strong{ color:var(--ink); }

/* The three safety tiers inside #if-frightens — rule-divided rows,
   not a table (a table implies sortable/comparable data; this is a
   sequence to read top to bottom). */
.tiers{ border-top:1px solid var(--rule); margin-top:var(--sp-5); }
.tier{ padding-block:var(--sp-4); border-bottom:1px solid var(--rule); }
.tier:last-child{ border-bottom:0; }
.tier .t-label{ font-weight:700; margin-bottom:var(--sp-3); }

/* ── Print it — a same-origin, dependency-free "PDF" (§1.6). Hidden
   on screen; @media print swaps the whole page for this one sheet,
   sized for A4, pure black-on-white regardless of --late/--early. ── */
#print-sheet{ display:none; }
@media print{
  body > *:not(#print-sheet){ display:none !important; }
  html, body{ background:#fff; }
  #print-sheet{
    display:block; background:#fff; color:#000;
    font-family:var(--sans); font-size:11pt; line-height:1.35;
    padding:14mm; max-width:210mm; margin:0 auto;
  }
  #print-sheet h1{
    font-family:var(--display); font-weight:900; font-size:22pt;
    letter-spacing:-.02em; margin-bottom:6pt; text-transform:lowercase;
  }
  #print-sheet .p-intro{ font-size:11pt; color:#000; margin-bottom:12pt; }
  #print-sheet .p-move{ margin-top:8pt; }
  #print-sheet .p-safety{ margin-top:14pt; border-top:1px solid #000; padding-top:10pt; }
  #print-sheet .qr-wrap{ margin-top:16pt; display:flex; align-items:center; gap:10pt; }
  #print-sheet .qr-wrap svg{ width:28mm; height:28mm; }
  #print-sheet .qr-label{ font-family:var(--mono); font-size:9pt; }
}

/* ═══ /PARTNERS — five roles, none of them filled (Patch 06, §6) ═══
   CSS given verbatim in the patch; same construction as .pillar. */
.roles{ border-top:1px solid var(--rule); }
.role{ display:grid; grid-template-columns:minmax(3.5rem,max-content) 1fr 1fr;
  gap:var(--gutter); padding-block:var(--sp-7);
  border-bottom:1px solid var(--rule); align-items:start; }
@media (max-width:900px){
  .role{ grid-template-columns:minmax(2.5rem,max-content) 1fr; }
  .role .role-detail{ grid-column:2; }
}
.role .num{ font-family:var(--display); font-weight:900; font-size:var(--step-2);
  line-height:.8; letter-spacing:-.035em; color:var(--emphasis);
  font-variation-settings:'wdth' 112; }
.role .who{ font-family:var(--mono); font-size:var(--step--2); letter-spacing:.06em;
  text-transform:uppercase; color:var(--ink-2); margin-top:var(--sp-3);
  font-variation-settings:'wdth' 87.5; }
.role[data-filled] .who{ color:var(--emphasis); }
/* Both of these set a full sentence — .role .who runs to 80 characters on
   /partners, .correction .c-meta sets full citations — in all caps.
   Uppercase reads fine for a short label; past four or five words it turns
   into caps noise (Patch 22, Part 1.2). */
.role .who, .correction .c-meta{ text-transform:none; letter-spacing:.02em; }
.role dt{ font-family:var(--mono); font-size:var(--step--2); letter-spacing:.08em;
  text-transform:uppercase; color:var(--ink-2); margin-top:var(--sp-4);
  font-variation-settings:'wdth' 87.5; }
.role dd{ font-size:var(--step-0); max-width:48ch; margin-top:var(--sp-2); }
