/* =====================================================================================
   Aff Tech Wiz — offer site design system
   Extracted from direction A ("footage-forward"), chosen by Tim 2026-07-27.
   Source of the direction: docs/superpowers/specs/2026-07-27-afftechwiz-offer-site-design-brief.md

   Register, in one line: a screening room. Light mode is a white wall with a black
   projection block on it; dark mode is the lights going down until the room *is* the
   screen. One saturated accent, sampled from the caption ink burned into the delivered
   ads. Hard cuts, no radius anywhere — the 9:16 crop is the page's only shape.

   ORGANISATION
     1  font          (self-hosted, inlined — zero external requests)
     2  tokens        (custom properties, light + dark)
     3  base + reset
     4  typography primitives
     5  layout        (.wrap, .band, .rail, dark-surface blocks)
     6  focus
     7  components    (.hero → .proof → .ladder → .math/.guarantee → .faq → .cta → form)
     8  reduced motion

   TWO CONVENTIONS WORTH KNOWING BEFORE EDITING
     - Every block-level component is self-sufficient: `.proof` alone carries its own
       max-width, gutter and vertical rhythm, so `<section class="proof">` is complete
       markup. Adding `.wrap` or `.band` on top is idempotent, never additive.
     - `.btn` is the shape and the voice; `.btn-primary` adds the accent fill. A bare
       `.btn` is a real, legible secondary button, not an unstyled one.
   ===================================================================================== */


/* =====================================================================================
   1 · FONT — Bebas Neue, SIL OFL 1.1, embedded as a data URI.
   Vendored from Tim's own Remotion pipeline (8.6KB woff2). Inlined rather than linked
   because the page must issue zero external requests: no CDN, no Google Fonts, no
   separate font file to 404. Body copy uses a system stack for the same reason.

   Usage rule carried from the direction: this face appears ONLY on claims at ≥28px.
   Small letterspaced Bebas is the cliché and does not appear anywhere on this site.
   ===================================================================================== */
@font-face{
  font-family:'Bebas Neue';
  font-style:normal;
  font-weight:400;
  font-display:block;
  src:url(data:font/woff2;base64,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) format('woff2');
}


/* =====================================================================================
   2 · TOKENS
   --signal does NOT change between light and dark. It is the product's ink — sampled
   from the yellow captions burned into the delivered ads — not the room's colour.
   ===================================================================================== */
:root{
  --paper:#FFFFFF;      /* page ground */
  --ink:#16130E;        /* body text, focus ring */
  --stage:#0B0A08;      /* the projection block: hero and the closing CTA sit on this */
  --signal:#F4E23A;     /* the one accent, committed to */
  --rule:#DEDCD6;       /* hairlines and input borders */
  --muted:#6B655B;      /* secondary copy */

  --seam:rgba(255,255,255,.24);   /* the hairline between hero panels */
  --field:#FFFFFF;                /* input ground */

  --display:'Bebas Neue','Haettenschweiler','Arial Narrow',sans-serif;
  --body:'Avenir Next','Avenir','Segoe UI Variable Text','Segoe UI',system-ui,sans-serif;

  --gut:clamp(1.25rem,5vw,5.5rem);   /* page gutter */
  --band:clamp(3.5rem,7vw,7rem);     /* vertical rhythm between sections */
  --maxw:1560px;

  --tint:rgba(244,226,58,.10);       /* --signal at 10%; used behind guarantees */
}

@media (prefers-color-scheme:dark){
  :root{
    --paper:#0B0A08;
    --ink:#F4F1E8;
    --stage:#000000;    /* the room goes past the block: dark mode is deliberate, not inverted */
    --rule:#2C2822;
    --muted:#968E82;
    --seam:rgba(255,255,255,.16);
    --field:#131109;
  }
}


/* =====================================================================================
   3 · BASE
   ===================================================================================== */
*,*::before,*::after{ box-sizing:border-box }
html{ -webkit-text-size-adjust:100% }

body{
  margin:0;
  background:var(--paper);
  color:var(--ink);
  font-family:var(--body);
  font-size:clamp(1rem,.94rem + .28vw,1.1875rem);
  line-height:1.55;
  overflow-x:hidden;          /* backstop; every grid child below also carries min-width:0 */
  -webkit-font-smoothing:antialiased;
}

img,video{ display:block; max-width:100% }
h1,h2,h3,h4,p,ol,ul,figure,fieldset{ margin:0 }
ol,ul{ padding:0; list-style:none }
fieldset{ border:0; padding:0; min-width:0 }
a{ color:inherit }


/* =====================================================================================
   4 · TYPOGRAPHY PRIMITIVES
   Every component that wants the display face declares it here in one grouped rule
   rather than each re-stating five properties. `.d` is the escape hatch for one-off
   markup; the component classes are self-sufficient without it.
   ===================================================================================== */
.d,
.hero-ask,
.claim,
.sec-head,
.mark,
.btn,
.ladder-name,
.ladder-price,
.math :where(b,strong),
.proof-axis :where(h2,h3),
.faq-item > summary,
.faq-item > :where(h2,h3),
.modal-step > :where(h2,h3){
  font-family:var(--display);
  font-weight:400;
  text-transform:uppercase;
  line-height:.86;
  letter-spacing:.004em;
  font-feature-settings:"kern" 1;
}

/* Headline scales. All floor at ~28px or above — below that the display face is banned. */
.claim{ font-size:clamp(1.75rem,3.3vw,2.9rem); max-width:16ch }
.sec-head{ font-size:clamp(1.9rem,4.4vw,3.6rem); margin-bottom:clamp(1.75rem,4vw,3.25rem) }

.lede{ font-size:clamp(1.06rem,1rem + .42vw,1.4rem); max-width:46ch }
/* A .lede wrapping more than one paragraph (a section's body copy, several sentences
   long) needs breathing room between them - same convention as .guarantee/.confirm below. */
.lede p + p{ margin-top:.9rem }
.micro{ color:var(--muted); font-size:.92rem; max-width:34rem }

/* Small uppercase labels are set in the BODY face, letterspaced. Uppercase *monospace*
   is the tool tell the brief bans; uppercase sans is not. */
.cap{
  margin-top:.55rem;
  font-size:clamp(.72rem,.7rem + .14vw,.85rem);
  color:var(--muted);
  letter-spacing:.06em;
  text-transform:uppercase;
}
/* The callout label above a hero ask ("FOR MEDIA-BUYING AGENCIES"). Its whole job is to let
   the right reader recognise themselves before they read a word of the pitch, so it sits
   ABOVE the thing it names rather than under it — which is the only thing this modifier
   changes about `.cap`: which side the space falls on. Same specificity as `.cap`, declared
   after it, so source order settles the margin. */
.eyebrow{ margin-top:0; margin-bottom:clamp(.45rem,1.1vw,.85rem) }

.bullets{ margin-top:clamp(1.25rem,3vw,2rem); display:grid; gap:.85rem; max-width:46ch }
.bullets li{
  position:relative;
  padding-left:1.6rem;
  font-size:clamp(.96rem,.92rem + .22vw,1.1rem);
  color:var(--muted);
}
.bullets li::before{                       /* a square, not a disc — nothing here is round */
  content:"";
  position:absolute; left:0; top:.62em;
  width:.7rem; height:.7rem;
  background:var(--signal);
}

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


/* =====================================================================================
   5 · LAYOUT
   ===================================================================================== */
.wrap{ max-width:var(--maxw); margin-inline:auto; padding-inline:var(--gut) }
.band{ padding-block:var(--band) }
.band--rule{ border-top:1px solid var(--rule) }

/* Asymmetric rail: claim left, evidence right. Nothing on the page is centred but the hero. */
.rail{
  display:grid;
  grid-template-columns:minmax(0,4fr) minmax(0,7fr);
  gap:clamp(1.75rem,4.5vw,5rem);
  align-items:start;
}
/* The conversion band inverts the ratio — there the form is the content and the clip is
   the sidebar. Without this the 9:16 clip caps out and leaves a dead column beside it. */
.rail--flip{ grid-template-columns:minmax(0,7fr) minmax(0,4fr) }
.rail > *{ min-width:0 }
@media (max-width:900px){
  .rail,.rail--flip{ grid-template-columns:minmax(0,1fr) }
}

/* ---- dark surfaces -------------------------------------------------------------------
   The hero and the closing CTA are the black projection block. Rather than writing
   `.hero .thing{color:white}` overrides for every nested component, they re-point the
   colour tokens. Anything placed inside — buttons, fields, rules, the focus ring —
   is then correct with no component-level special-casing at all.
   -------------------------------------------------------------------------------------- */
.hero,
.cta{
  --paper:var(--stage);
  --ink:#FFFFFF;
  --rule:rgba(255,255,255,.22);
  --muted:rgba(255,255,255,.74);
  --field:rgba(255,255,255,.06);
  background:var(--stage);
  color:#FFFFFF;
}


/* =====================================================================================
   6 · FOCUS
   The ink ring guarantees visibility on any ground; the yellow halo brands it. Yellow
   alone on paper is ~1.3:1 against white and would fail on its own.
   ===================================================================================== */
:where(a,button,input,select,textarea,summary,[tabindex]):focus-visible{
  outline:3px solid var(--ink);
  outline-offset:2px;
  box-shadow:0 0 0 7px rgba(244,226,58,.62);
  border-radius:0;
}


/* =====================================================================================
   7 · COMPONENTS
   ===================================================================================== */

/* ---- HERO ---------------------------------------------------------------------------
   The signature: one full-bleed rebuild that divides into three.
   -------------------------------------------------------------------------------------- */
.hero{
  position:relative;
  height:min(88vh,980px);
  min-height:430px;
  overflow:hidden;
  isolation:isolate;
}
@supports (height:1svh){ .hero{ height:min(88svh,980px) } }
@media (max-width:760px){
  .hero{ height:min(66svh,540px); min-height:400px }
}

.hero-panels{ position:absolute; inset:0; display:flex; gap:0; z-index:0 }
.hero-panel{ position:relative; flex:1 1 0; min-width:0; overflow:hidden }
.hero-panel + .hero-panel{ box-shadow:-1px 0 0 0 var(--seam) }   /* the seam, not a border */
.hero-panel > :where(video,img){
  width:100%; height:100%;
  object-fit:cover;
  object-position:center 44%;
}
/* The poster is painted as a background as well, so a frame is visible even where a
   renderer declines to show the <video poster> attribute. */
.hero-panel > video{
  background-color:var(--stage);
  background-position:center 44%;
  background-size:cover;
  background-repeat:no-repeat;
}

/* --- THE SPLIT -----------------------------------------------------------------------
   Pure CSS. There is no JS state anywhere in this animation, and that is the point.

   The RESTING value of flex-grow is 1, so three equal panels is the natural, default
   layout. The animation only BORROWS the collapsed state during its delay — that is what
   `animation-fill-mode: backwards` does — and hands it straight back. Consequences:

     · JS failing, being blocked, or never running cannot strand a visitor on one panel.
       The default state is already the finished state.
     · `prefers-reduced-motion: reduce` and narrow viewports never enter the rule at all,
       so they land on three panels with no fallback to write.
     · Both media queries re-evaluate on resize and on an OS motion-preference change,
       which a class stamped onto <html> once at parse time does not.

   `.js` records only that scripting exists (set by a one-line inline script). It asserts
   nothing about viewport or motion preference — the media queries judge those. Its
   absence is a correct state, not a degraded one.
   -------------------------------------------------------------------------------------- */
@media (min-width:760px) and (prefers-reduced-motion:no-preference){
  .js .hero-panel--b{ animation:hero-split 1050ms cubic-bezier(.19,.82,.2,1) 1500ms backwards }
  .js .hero-panel--c{ animation:hero-split 1050ms cubic-bezier(.19,.82,.2,1) 1650ms backwards }
}
@keyframes hero-split{ from{ flex-grow:0 } to{ flex-grow:1 } }
/* Panel A is never collapsed, so it plays uninterrupted straight through the divide. */

/* The delivered ads carry their own burned-in yellow captions at roughly 60% height. The
   panels are near-9:16 already, so object-position has almost no crop slack to move those
   captions with — the scrim does the work instead. It runs deep enough to sit the headline
   cleanly over that zone while leaving the upper frame bright.
   (The hero MEDIA is the pre-overlay render, which has no captions at all — see
   build_proof_assets.py. The scrim is belt-and-braces for contrast, and stays correct if a
   captioned clip is ever dropped in.) */
.hero-scrim{
  position:absolute; inset:0; z-index:1; pointer-events:none;
  background:
    linear-gradient(to top,   rgba(9,8,6,.95) 0%, rgba(9,8,6,.90) 26%, rgba(9,8,6,.72) 46%, rgba(9,8,6,.26) 66%, rgba(9,8,6,0) 84%),
    linear-gradient(to bottom,rgba(9,8,6,.60) 0%, rgba(9,8,6,0) 24%);
}
/* Must follow the base rule rather than sit in an earlier max-width block — same
   specificity, so source order decides. Each panel is ~125px on a phone, which crops any
   burned-in caption to its middle and repeats the fragment three times as noise directly
   under the headline. Sink that band nearly to black. */
@media (max-width:760px){
  .hero-scrim{
    background:
      linear-gradient(to top,   rgba(9,8,6,.985) 0%, rgba(9,8,6,.975) 44%, rgba(9,8,6,.90) 62%, rgba(9,8,6,.38) 80%, rgba(9,8,6,0) 94%),
      linear-gradient(to bottom,rgba(9,8,6,.55) 0%, rgba(9,8,6,0) 22%);
  }
}

.hero-inner{
  position:relative; z-index:2;
  height:100%;
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gut);
  padding-block:clamp(1.1rem,2.4vw,2.4rem) clamp(1.4rem,3.4vw,3.4rem);
  display:flex; flex-direction:column; justify-content:space-between;
}
.hero > .wrap{ padding-inline:0 }   /* .hero-inner already carries the gutter */

.mark{
  font-size:clamp(1.15rem,1.5vw,1.45rem);
  letter-spacing:.2em;                /* the one place letterspacing is this wide */
  line-height:1;
  color:var(--ink);
}

/* Sized so the longest word of the ask always sets on one line — a hyphen break mid-word
   is the single thing that kills a headline punched over moving footage. 15 characters of
   Bebas is ~6.3em, which fits the gutter-inset width at every breakpoint. */
.hero-ask{
  font-size:clamp(2.3rem,7.8vw,7.6rem);
  max-width:18ch;
}
.hero-ask em{ font-style:normal; color:var(--signal); display:block }

.hero-foot{
  margin-top:clamp(.9rem,2vw,1.6rem);
  display:flex; flex-wrap:wrap; align-items:center;
  gap:clamp(.75rem,2vw,1.6rem);
}
.hero-foot p{
  font-size:clamp(.9rem,.86rem + .2vw,1.05rem);
  color:rgba(255,255,255,.86);
  max-width:34ch;
}
.hero-note{
  align-self:flex-end;
  margin-top:clamp(.9rem,2vw,1.5rem);
  font-size:clamp(.76rem,.72rem + .16vw,.9rem);
  color:rgba(255,255,255,.72);
}
@media (max-width:600px){ .hero-note{ display:none } }


/* ---- BUTTONS ------------------------------------------------------------------------
   Hard cuts, no radius, echoing the 9:16 crop. The display face is permitted here because
   it lands at ~20px minimum and reads as a claim, not a label.

   `.btn` alone = secondary: the shape and the voice, drawn in a rule. It is a finished
   button, so markup that forgets the modifier still looks deliberate.
   `.btn.btn-primary` = the accent fill. This is the treatment direction A used for its
   one hero CTA, reproduced exactly.
   -------------------------------------------------------------------------------------- */
.btn{
  display:inline-block;
  font-size:clamp(1.25rem,1.1rem + .5vw,1.65rem);
  letter-spacing:.03em;
  line-height:1;
  padding:.72em 1.15em .58em;
  border:2px solid currentColor;
  border-radius:0;
  background:transparent;
  color:var(--ink);
  text-decoration:none;
  cursor:pointer;
  transition:transform 160ms ease, filter 160ms ease, background-color 160ms ease, color 160ms ease;
}
.btn:hover{ background:var(--ink); color:var(--paper); transform:translateY(-2px) }
.btn:active{ transform:translateY(0) }

.btn-primary{
  border-color:var(--signal);
  background:var(--signal);
  color:#16130E;                 /* fixed dark ink: yellow needs dark text in BOTH modes */
}
.btn-primary:hover{
  background:var(--signal);
  color:#16130E;
  filter:brightness(1.07);
}

.btn--wide{ width:100%; text-align:center }
.btn[disabled],.btn[aria-disabled="true"]{ opacity:.5; cursor:not-allowed; transform:none }
/* `display:inline-block` above out-specifies the UA stylesheet's `[hidden]{display:none}`,
   so a `.btn` shipped with the `hidden` attribute renders anyway — caught in the browser,
   where the no-JS Next button was fully visible despite carrying `hidden`. Same explicit
   override `.upload`, `.modal-step`, `.progress` and `.confirm` already carry. */
.btn[hidden]{ display:none }

/* `.btn--onscrim` = a secondary drawn ON the modal scrim rather than on a page surface.
   A bare `.btn` takes its colour from `--ink`, which is correct everywhere a surface has
   re-pointed the tokens (`.hero`, `.cta`) and wrong in a <dialog> appended to <body>,
   where `--ink` is the root's near-black and the ground behind it is rgba(9,8,6,.86) —
   legible in dark mode, all but invisible in light. Same fix as the dark surfaces in §5:
   re-point the tokens rather than special-case the component, so hover (ink ground, paper
   text) inverts correctly too. */
.btn--onscrim{
  --ink:#FFFFFF;
  --paper:var(--stage);
  color:#FFFFFF;
}


/* ---- PROOF --------------------------------------------------------------------------
   Three axes, one shell. A fourth axis is another `.proof-axis`; nothing about the
   container changes, and no breakpoint is keyed to the count. (Spec D4a: must hold three
   without a layout change — verified at 375px and 1280px with three axes present.)
   -------------------------------------------------------------------------------------- */
.proof{
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gut);
  padding-block:var(--band);
}

/* Same asymmetric ratio as `.rail`: the claim on the left, the evidence on the right.
   EXACTLY TWO grid children, always — `.proof-copy` (heading + lede) and the sheet. A third
   direct child is not a third column, it is auto-placed: the sheet gets bumped to row 2 and
   lands back in the NARROW column while a paragraph holds the wide one. That is precisely
   what happened while the heading and the lede sat here as separate children (448px of
   contact sheet beside a 783px paragraph at 1440), and it is why the heading/lede pair is
   wrapped in the partial rather than styled apart here. */
.proof-axis{
  display:grid;
  grid-template-columns:minmax(0,4fr) minmax(0,7fr);
  gap:clamp(1.75rem,4.5vw,5rem);
  align-items:start;
  padding-block:clamp(2rem,4.5vw,3.75rem);
  border-top:1px solid var(--rule);
}
.proof-axis > *{ min-width:0 }
@media (max-width:900px){ .proof-axis{ grid-template-columns:minmax(0,1fr) } }

/* Plain markup inside an axis gets the right treatment without extra classes. The `~ p`
   rule below is what sets the heading-to-lede distance now that the two are siblings inside
   `.proof-copy` and no longer collect the axis grid's much larger `gap`. */
.proof-axis :where(h2,h3){ font-size:clamp(1.75rem,3.3vw,2.9rem); max-width:16ch }
.proof-axis :where(h2,h3) ~ p{
  margin-top:clamp(.85rem,1.6vw,1.15rem);
  color:var(--muted);
  font-size:clamp(.96rem,.92rem + .22vw,1.08rem);
  max-width:40ch;
}

.proof-index{
  font-family:var(--display);
  font-size:clamp(1.6rem,2.2vw,2.2rem);
  line-height:1;
  color:var(--muted);
  margin-bottom:.5rem;
  display:flex; align-items:center; gap:.55rem;
}
.proof-index i{ width:.6rem; height:.6rem; background:var(--signal); font-style:normal; flex:none }
/* The `.proof-axis--pending` / `.proof-pending` rules that used to sit here are gone with
   the markup: an axis with no assets is not rendered at all (make_offer_site.py, PROOF_AXES).
   A dashed "examples land here once a client run is ready to show" panel, on the block
   carrying the page's whole credibility load, advertised having no clients. */


/* ---- CONTACT SHEET -------------------------------------------------------------------
   `.sheet` is the grid, `.sheet-cell` one frame in it. Three columns at every width: on a
   phone that is three ~105px verticals, which is small but legible and — more importantly
   — keeps the "three rebuilds" claim visually true at 375px. Dropping to one column would
   turn the proof into a slideshow.

   A `.sheet` row rendered under the claim "one ad in, three rebuilds out" must be three
   rebuilds of the SAME source ad. build_proof_assets.py stamps a `source` key on every
   manifest clip and exposes group_by_source() for exactly this; build the row from one
   group and it cannot mix.

   Six cells per axis, so three columns is two rows. The `.sheet--dense` 3:4 variant that
   used to live here is gone with the reason for it: it existed because the persona axis
   sampled nine cells out of twenty-four and nine full-height verticals ran the band past
   1300px. The axes now ship six named clips each (build_proof_assets.py), both fit as 9:16
   in two rows, and one crop for the whole page is the point — the 9:16 frame is the only
   shape this site has.
   -------------------------------------------------------------------------------------- */
.sheet{
  display:grid;
  grid-template-columns:repeat(3,1fr);
  gap:clamp(.4rem,1vw,.85rem);
}
.sheet > *{ min-width:0 }

.sheet-cell{
  position:relative;
  display:block;
  width:100%;
  margin:0; padding:0;
  border:0; border-radius:0;
  background:var(--stage);
  aspect-ratio:9/16;
  overflow:hidden;
  cursor:pointer;
  appearance:none;              /* the cell is often a <button>; strip the UA chrome */
  color:inherit;
  font:inherit;
}
.sheet-cell > :where(video,img){ width:100%; height:100%; object-fit:cover; display:block }
.sheet-cell--static{ cursor:default }

/* The cell's label ("Wooden table, potted plant", "Bathroom mirror, serum") is the whole
   reason the grid is readable as evidence rather than as decoration: it names the scene, so
   a visitor scanning the row sees WHAT changed between two cells rather than counting them.
   (It used to read "Ad 02 / rebuild 1" and "Presenter 01" — a counter tells a reader how
   many cells there are, which they can already see.)
   It has to be an overlay — the media fills the cell to its edges (height:100%) and the
   cell is `overflow:hidden`, so a label left in normal flow is pushed past the bottom edge
   and clipped away to nothing. Taken out of flow, it also stops adding to the cell's
   scrollHeight, which is what made every cell report as overflowing.

   Typography is `.cap`'s exact recipe — body face, small, letterspaced, uppercase — because
   that is already this site's small-label voice, and uppercase *monospace* is the tool tell
   the brief bans. The ground is the hero scrim's near-black in miniature, for the same
   reason the hero has one: the frame behind is an arbitrary video still that may be a bright
   curtain or a dark sofa, so the label carries its own contrast instead of hoping.
   `pointer-events:none` keeps the whole cell one click target for the play handler. */
.sheet-cell > span{
  position:absolute;
  left:0; right:0; bottom:0;
  z-index:1;
  pointer-events:none;
  padding:1.5em .55em .45em;
  font-family:var(--body);
  font-size:clamp(.62rem,.58rem + .18vw,.8rem);
  line-height:1.2;
  letter-spacing:.06em;
  text-transform:uppercase;
  text-align:left;
  color:#FFFFFF;
  text-shadow:0 1px 2px rgba(9,8,6,.9);
  background:linear-gradient(to top,rgba(9,8,6,.94) 0%,rgba(9,8,6,.82) 38%,rgba(9,8,6,0) 100%);
}


/* ---- PLAYER -------------------------------------------------------------------------
   One clip shown at size — the whole deliverable, on its own. Same crop and same ground as
   a sheet cell, capped so a 9:16 clip cannot grow taller than a screen.
   -------------------------------------------------------------------------------------- */
.player{
  position:relative;
  display:block;
  width:100%;
  max-width:26rem;
  margin:0; padding:0;
  border:0; border-radius:0;
  background:var(--stage);
  aspect-ratio:9/16;
  overflow:hidden;
  appearance:none;
  color:inherit;
  font:inherit;
}
.player > :where(video,img){ width:100%; height:100%; object-fit:cover; display:block }
.player + .cap{ max-width:26rem }


/* ---- LADDER -------------------------------------------------------------------------
   Rows on a rail, not tiles. The brief bans bento stat-tile collages; a price ladder read
   top to bottom is also simply easier to compare than four boxes side by side.
   -------------------------------------------------------------------------------------- */
.ladder{ border-top:1px solid var(--rule) }

.ladder-tier{
  display:grid;
  grid-template-columns:minmax(6.5rem,1.1fr) minmax(0,3fr) minmax(5rem,.9fr) minmax(6rem,1fr);
  gap:clamp(.5rem,2vw,2rem);
  align-items:baseline;
  padding-block:clamp(1.05rem,2.2vw,1.5rem);
  border-bottom:1px solid var(--rule);
}
/* The ROW is body face. Only the tier name and the price take the display face — putting
   it on `.ladder-tier` would inherit condensed uppercase into the description columns and
   turn a readable table into a wall of caps. */
.ladder-tier > *{ min-width:0 }
.ladder-name{
  font-size:clamp(1.35rem,1.2rem + .6vw,1.9rem);
  line-height:1;
  display:flex; align-items:center; gap:.5rem;
}
.ladder-name i{ width:.55rem; height:.55rem; background:var(--signal); flex:none; font-style:normal }
.ladder-what{ color:var(--muted); font-size:clamp(.95rem,.91rem + .2vw,1.06rem) }
.ladder-when{ color:var(--muted); font-size:clamp(.88rem,.85rem + .16vw,.98rem) }
.ladder-price{
  font-size:clamp(1.35rem,1.2rem + .6vw,1.9rem);
  line-height:1;
  font-variant-numeric:tabular-nums;
  text-align:right;
}
.ladder-price small{ font-size:.62em }
.ladder-note{ grid-column:2 / -1; color:var(--muted); font-size:.9rem; margin-top:.4rem }

/* The per-rung next step. It lives INSIDE `.ladder-price` rather than as a fifth grid child:
   the brief is "under the price", and .ladder-tier is a four-column auto-placed grid, so a
   sibling would land in the next row's first column and shove `.ladder-note` down with it.
   Nested, it needs the price cell's display face and uppercase explicitly turned back off -
   the display face is banned below ~28px and this is ~13px. Subtle by construction: --muted
   text and the default underline, never a .btn, because a button on every rung would put five
   filled controls against the page's one primary CTA. */
.ladder-cta{
  display:block;
  margin-top:.5rem;
  font-family:var(--body);
  font-weight:400;
  text-transform:none;
  letter-spacing:normal;
  line-height:1.3;
  font-size:.82rem;
  color:var(--muted);
  text-underline-offset:.2em;
}
.ladder-cta:hover{ color:var(--ink) }

/* The lead tier is washed, not boxed — a border would make it a bento tile. */
.ladder-tier--lead{ background:linear-gradient(to right,rgba(244,226,58,.16),rgba(244,226,58,0) 62%) }

@media (max-width:760px){
  .ladder-tier{ grid-template-columns:1fr auto; row-gap:.3rem }
  .ladder-price{ order:2 }
  .ladder-what{ grid-column:1 / -1; order:3 }
  .ladder-when{ grid-column:1 / -1; order:4 }
  .ladder-note{ grid-column:1 / -1; order:5 }
}


/* ---- THE TWO ACCENT CARDS: MATH + GUARANTEE -----------------------------------------
   These two sit one under the other at the foot of the ladder and carry the page's two
   strongest claims — what it costs against the alternative, and what happens if you hate
   the work. They used to be a left rule with loose <p>s hanging off it, which read as
   afterthoughts (Tim, desktop, 2026-07-28). They are now ONE card shape used twice, sized
   the same and bordered the same, so the section ends on two objects rather than on some
   spare paragraphs.

   ON THE FULL BORDER. The old note here said tinted-not-bordered, "on this page a full box
   reads as a badge". That still holds for a BADGE — a small boxed claim with a number in it,
   the thing the brief bans. It does not describe a panel with a heading and three rows: the
   border is what makes the rows read as one comparison instead of three sentences, and
   half-cards (accent rule, no frame) beside a real card is what made these look unfinished
   in the first place. Same tokens as everywhere else: --rule for the frame, --signal for the
   accent edge, --tint for the row we want read. No new colour, no radius. THE FRAME STAYS.

   ON THE WIDTH — the fix, 2026-07-29. They carried `max-width:46rem` and so stopped 560px
   short of every other block on the page. Measured at 1440: `.proof-axis`, `.sec-head`,
   `.ladder`, `.ladder-tier` and `.faq-item` all sit at x:72 spanning 1296px; these two sat
   at x:72 spanning 736px, with nothing to their right. Not a deliberate narrow measure — a
   block that ran out. They read as stranded (Tim, 1440, 2026-07-29).

   Derived from the reference sites rather than invented. Every one of them gives a
   comparison or a statement block the FULL content column, measured at 1440 on 2026-07-29:
     · brandpush.co   — the conversion reference. Content container 1170px; the pricing /
                        comparison table is 1200px, the widest thing on the page, and it is
                        bordered (1px #EDEDED). Their PROSE narrows to 975px — but centred
                        inside the container, never left-aligned and short. So: a comparison
                        may be framed, and it takes the whole column.
     · superside.com  — the closest structural analogue: a "vs. the alternatives" strip.
                        Rows are 1311px against a 1216px container — full width, no outer
                        frame, each row separated by a 1px hairline at 10% opacity, and only
                        the row you are meant to leave with given its own ground. That is
                        already this block's own logic (`.math-row--here` + --tint); what it
                        does not do anywhere is narrow the strip.
     · mccann.com     — restraint. The entire homepage carries exactly ONE bordered element,
                        the `HELLO@MCCANN.COM` CTA (2px, radius 0). Content blocks are
                        full-bleed bands and air. A border there means "this is a control".
     · vaynermedia.com— content column 1200px at x:120; borders again only on buttons (2px,
                        radius 0). Rhythm comes from headings owning the full column and
                        alternating alignment, not from insetting blocks.
     · delacruz.com   — statement lines run 1395px of a 1440 viewport, each separated by a
                        1px full-width top rule, alternating left/right/centre.
   Across the five, a comparison or statement block sits at 83–97% of the viewport. Ours was
   at 51%. Full content column puts it at 90%, inside that band and flush with the ladder
   rungs directly above it — which is the alignment that makes it read as the end of that
   table rather than as a leftover. Brandpush is the one that settles frame-vs-no-frame:
   it is the only reference whose job is converting a stranger, and its comparison is both
   full-width AND bordered. So the frame stays and the ceiling goes.
   -------------------------------------------------------------------------------------- */
.math,
.guarantee{
  border:1.5px solid var(--rule);
  border-left:5px solid var(--signal);
}
/* Both cards are flush siblings — of the last ladder rung above and of each other — and
   neither the rung nor the section supplies a gap. Measured at 1440 before this rule: 0px
   between the last rung's bottom rule and the math card's top border, and 0px between the
   two cards, so the three read as one long box with a seam in it rather than as a row, a
   card and a card. Framing them is what made the gap load-bearing. */
.math{ margin-top:clamp(1.5rem,3.5vw,2.5rem) }
.math + .guarantee{ margin-top:clamp(1rem,2.4vw,1.6rem) }

/* ---- MATH ---------------------------------------------------------------------------
   A comparison strip: one row per option, the who on the left and the money on the right,
   the "Here" row tinted. Any <b>/<strong> in a figure cell is a display figure at the same
   scale as `.ladder-price` directly above it — same page, same kind of row, same size — so
   the markup stays plain and the numbers keep interpolating from OFFER.md.
   -------------------------------------------------------------------------------------- */
.math{
  color:var(--muted);
  font-size:clamp(.98rem,.94rem + .22vw,1.12rem);
}
.math > *{
  padding:clamp(.75rem,1.7vw,1.05rem) clamp(.9rem,2vw,1.35rem);
  border-bottom:1px solid var(--rule);
}
.math > :last-child{ border-bottom:0 }

.math-row{
  display:grid;
  grid-template-columns:minmax(0,auto) minmax(0,1fr);
  gap:.25rem clamp(1rem,2.5vw,2rem);
  align-items:baseline;
}
/* The row the reader is meant to leave with. Tint plus full-ink text, no second accent. */
.math-row--here{ background:var(--tint); color:var(--ink) }
.math-figure{ text-align:right }
/* The closing sentence is prose, not a row, so it keeps a measure while the rows spend the
   full column. 56ch is the same measure `.faq-item`'s body copy already uses — the other
   place on this page where sentences sit inside a full-width block. */
.math-foot{ max-width:56ch }
.math :where(b,strong){
  font-size:clamp(1.35rem,1.2rem + .6vw,1.9rem);
  line-height:1;
  color:var(--ink);
  font-variant-numeric:tabular-nums;
}

@media (max-width:760px){
  /* Same collapse as `.ladder-tier`: label over figure, both reading from the left edge.
     A right-aligned figure under a left-aligned label is two ragged edges and no column. */
  .math-row{ grid-template-columns:minmax(0,1fr) }
  .math-figure{ text-align:left }
}


/* ---- GUARANTEE ----------------------------------------------------------------------
   The named-guarantee panel (spec §5/§6). The NAME is the heading — a guarantee you can
   quote back at us has to be findable in one glance, and a bold sentence opener is not.
   Body face at body scale: the display face is banned below ~28px, and a 28px condensed
   caps heading twice inside one tinted panel is a shout, not a promise.

   The PANEL spans the content column with everything else (see the width note above); its
   SENTENCES keep a measure, because a promise set 1296px wide is ~150 characters a line and
   nobody finishes it. Same split every reference makes — brandpush's comparison table runs
   1200px while its prose holds 975, superside's rows run 1311px while its statement copy
   caps at 1064. 56ch is `.faq-item`'s measure, already in use for body copy inside a
   full-width block on this page.
   -------------------------------------------------------------------------------------- */
.guarantee{
  padding:clamp(1rem,2.2vw,1.35rem) clamp(1.1rem,2.4vw,1.5rem);
  background:var(--tint);
  color:var(--muted);
  font-size:clamp(.96rem,.92rem + .22vw,1.08rem);
}
.guarantee > p{ max-width:56ch }
.guarantee > h3{
  font-family:var(--body);
  font-size:clamp(1.02rem,.98rem + .3vw,1.2rem);
  font-weight:600;
  line-height:1.25;
  color:var(--ink);
}
.guarantee :where(strong,b){ color:var(--ink); font-weight:600 }
.guarantee > * + *{ margin-top:.45rem }
/* A second named guarantee starts a new promise, not a new paragraph of the same one. */
.guarantee > * + h3{ margin-top:clamp(.9rem,2vw,1.2rem) }


/* ---- TESTIMONIAL --------------------------------------------------------------------
   The client-proof slot (spec §9.4). NOTHING ON THE SITE USES THIS YET, deliberately: there
   are no clients to quote, and an empty credibility block is worse than none at all (see
   _testimonial() in make_offer_site.py, and the same call already recorded for the reserved
   third proof axis). It is here so the first real quote is a copy edit — a `## testimonial`
   section in a page's deck — rather than a layout decision made in a hurry.

   Built entirely from what the page already has: the accent left rule of `.guarantee`, the
   `.lede` measure and scale, and `.cap` on the attribution. It sits in the evidence column
   of a `.rail`, so it inherits the same claim-left / proof-right shape as every other
   section and needs no width of its own.
   -------------------------------------------------------------------------------------- */
.testimonial{ display:grid; gap:clamp(1.1rem,2.5vw,1.75rem) }
.testimonial blockquote{
  margin:0;
  max-width:46ch;
  padding-left:clamp(.9rem,2vw,1.4rem);
  border-left:5px solid var(--signal);
  font-size:clamp(1.06rem,1rem + .42vw,1.4rem);
}
/* `cite` is italic by UA default; nothing else on this page is. */
.testimonial cite{ display:block; font-style:normal }


/* ---- FAQ ----------------------------------------------------------------------------
   Works three ways with no JS: as a plain list of `<div class="faq-item">` with an h3 and
   a p (a single question shown open — a lone accordion reads as filler), or as
   `<details class="faq-item">` once there are enough of them to be worth collapsing.
   -------------------------------------------------------------------------------------- */
.faq{
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gut);
  padding-block:var(--band);
}

/* Every item carries its own rule, including the first: the list reads as a set of rows
   rather than as one question with a stack under it. */
.faq-item{ border-top:1px solid var(--rule); padding-block:clamp(1.5rem,3.5vw,2.5rem) }

.faq-item > :where(h2,h3),
.faq-item > summary{
  font-size:clamp(1.75rem,3.6vw,3rem);
  max-width:24ch;
}
.faq-item > summary{
  cursor:pointer;
  list-style:none;
  display:flex; align-items:flex-start; justify-content:space-between; gap:1.5rem;
}
.faq-item > summary::-webkit-details-marker{ display:none }
/* A square that becomes a bar when open. No rotation, no chevron — same vocabulary as the
   bullet squares, and it still reads correctly with animation switched off. */
.faq-item > summary::after{
  content:"";
  flex:none;
  width:.85rem; height:.85rem;
  margin-top:.35em;
  background:var(--signal);
  transition:height 160ms ease;
}
.faq-item[open] > summary::after{ height:.2rem; margin-top:.68em }

.faq-item > :where(h2,h3) ~ *,
.faq-item > summary ~ *{
  margin-top:clamp(.9rem,2vw,1.3rem);
  max-width:56ch;
  color:var(--muted);
  font-size:clamp(1rem,.96rem + .3vw,1.2rem);
}


/* ---- CTA ----------------------------------------------------------------------------
   The closing conversion band: the projection block again, full-bleed, at the foot of the
   page. It re-points the colour tokens (see §5), so a form, a guarantee and a player
   dropped inside it are all correct with no overrides.
   -------------------------------------------------------------------------------------- */
.cta{
  padding:var(--band) var(--gut);
}
.cta > *{ max-width:var(--maxw); margin-inline:auto }
.cta > .wrap{ padding-inline:0 }     /* the band already carries the gutter */


/* ---- FORM ---------------------------------------------------------------------------
   `.field` is one label + control pair. `.confirm` is the state the form is replaced by.
   -------------------------------------------------------------------------------------- */
.form{ display:grid; gap:clamp(.85rem,1.8vw,1.15rem); max-width:34rem }

/* The two lines under the claim button: what it costs you to click, and the way out for
   someone who would rather talk or write. Restates the 34rem measure the same way `.form`
   above does, and for the same reason — `.cta > *` sets `max-width:var(--maxw)` on every
   direct child, so both have to be declared after that rule to win on source order.
   -------------------------------------------------------------------------------------- */
.cta-foot{
  max-width:34rem;
  margin-top:clamp(1.1rem,2.4vw,1.6rem);
}

/* …and both opt OUT of the `margin-inline:auto` that `.cta > *` hands every child. That
   rule is right for the full-width children (it centres the --maxw column on a wide screen)
   and wrong for the two narrow ones: a 34rem block inside a 1152px band gets centred while
   the heading, the lede and the claim button above it all start at the gutter. Measured at
   1280: the button at x=64 and the microcopy that belongs to it at x=368, reading as two
   unrelated things. §5's own note — "nothing on the page is centred but the hero" — is the
   rule; this is the one place that had drifted from it. */
.cta > .form,
.cta > .cta-foot{ margin-inline:0 }
.cta-foot p + p{ margin-top:.5rem }
.cta-foot a{ color:var(--ink); text-underline-offset:.2em }

.field > label{
  display:block;
  font-size:.83rem;
  letter-spacing:.02em;
  color:var(--muted);
  margin-bottom:.35rem;
}
.field :where(input,select,textarea){
  width:100%;
  font-family:var(--body);
  font-size:1.02rem;
  line-height:1.4;
  color:var(--ink);
  background:var(--field);
  border:1.5px solid var(--rule);
  border-radius:0;
  padding:.82rem .9rem;
  appearance:none;
}
.field textarea{ min-height:7rem; resize:vertical }
/* The select arrow is drawn with two gradients rather than an SVG data URI: it inherits
   currentColor, so it stays correct in light, dark and on the dark bands, and it adds no
   bytes and no request. */
.field select{
  background-image:
    linear-gradient(45deg,transparent 50%,currentColor 50%),
    linear-gradient(135deg,currentColor 50%,transparent 50%);
  background-position:calc(100% - 1.15rem) 1.32rem,calc(100% - .8rem) 1.32rem;
  background-size:.36rem .36rem,.36rem .36rem;
  background-repeat:no-repeat;
  padding-right:2.4rem;
}
.field :where(input,select,textarea):hover{ border-color:var(--muted) }
.field input::placeholder,.field textarea::placeholder{ color:var(--muted); opacity:.72 }
.field > small{ display:block; margin-top:.35rem; color:var(--muted); font-size:.82rem }
/* Invalid state is carried on the wrapper, so it can be set before the control is touched
   and does not fight :invalid firing on an empty required field at first paint. */
.field[data-invalid] :where(input,select,textarea){ border-color:var(--signal); border-width:2px }
.field[data-invalid] > small{ color:var(--ink) }

/* ---- OPTIONAL DISCLOSURE -------------------------------------------------------------
   The six fields that help us deliver and follow up, folded behind one line. The visual
   job is hierarchy: name and email are the ask, this is an aside, and it has to read as an
   aside BEFORE it is opened — hence the muted body-face summary against the display-face
   submit button under it, and the word "Optional" on the closed line rather than inside.

   Built from `<details>`, so it works with scripting off. The marker is the FAQ's square-
   becomes-a-bar, reused deliberately: the page has one disclosure vocabulary and this is
   it. Every colour is a token, because this block renders on two different grounds — the
   dark `.cta` band without JS, and the light `.modal-step` panel inside the dialog with it.
   -------------------------------------------------------------------------------------- */
.more{ border-block:1px solid var(--rule) }
.more > summary{
  cursor:pointer;
  list-style:none;
  display:flex; align-items:center; gap:.75rem;
  padding-block:.9rem;
  color:var(--muted);
  font-size:.95rem;
}
.more > summary::-webkit-details-marker{ display:none }
.more > summary::after{
  content:"";
  flex:none;
  width:.8rem; height:.8rem;
  background:var(--signal);
  transition:height 160ms ease;   /* neutralised by the reduced-motion catch-all in §8 */
}
.more[open] > summary::after{ height:.2rem }
.more:hover > summary{ color:var(--ink) }
/* Pushed to the right edge, not centred between the two: the question is the control's
   label and the flag is a property of it, so they must not read as two equal items. */
.more-flag{
  margin-left:auto;
  font-size:.78rem;
  letter-spacing:.06em;
  text-transform:uppercase;       /* body face — uppercase MONOSPACE is the banned tell */
}
.more-body{
  display:grid;
  gap:clamp(.85rem,1.8vw,1.15rem);
  padding-bottom:clamp(1.1rem,2.4vw,1.4rem);
}


/* ---- UPLOAD -------------------------------------------------------------------------
   The second way to satisfy step 1: the file goes browser -> Google directly, so the page
   has to show its own progress — nothing else will. Built from parts already here: the
   file control is a `.field` like every other control, the bar is the seam-thin rule in
   `--signal`, and it inherits the re-pointed tokens inside `.cta` and inside the modal
   with no overrides. The whole block ships [hidden] and is revealed by site.js, so these
   rules never apply to a page without JS.
   -------------------------------------------------------------------------------------- */
.upload{ display:grid; gap:.5rem }
.upload[hidden]{ display:none }

.field input[type="file"]{ padding:.55rem .6rem; cursor:pointer }
/* The picker button is the secondary `.btn` treatment, drawn in a rule — squared off like
   everything else on the page, rather than the browser's default rounded chip. */
.field input[type="file"]::file-selector-button{
  font:inherit;
  font-size:.9rem;
  margin-right:.8rem;
  padding:.4rem .8rem;
  color:var(--ink);
  background:transparent;
  border:1.5px solid var(--ink);
  border-radius:0;
  cursor:pointer;
  transition:background .12s,color .12s;
}
.field input[type="file"]::file-selector-button:hover{ background:var(--ink); color:var(--paper) }

.upload-status{ font-size:.86rem; color:var(--muted) }
.upload-status[hidden]{ display:none }
.upload-status[data-state="done"],
.upload-status[data-state="error"]{ color:var(--ink) }
.upload-status[data-state="error"]{ border-left:3px solid var(--signal); padding-left:.6rem }

.progress{ height:.4rem; background:var(--rule); overflow:hidden }
.progress[hidden]{ display:none }
.progress > i{
  display:block;
  height:100%;
  width:0;
  background:var(--signal);
  transition:width .18s linear;   /* neutralised by the reduced-motion catch-all in §8 */
}

.confirm{
  max-width:34rem;
  /* /thanks/ is a page whose whole body is this panel, so it needs the page's own vertical
     rhythm around it - without this the tinted block bleeds off the top of the viewport and
     the confirmation reads as a fragment of something larger. Harmless where `.confirm`
     appears inside a flow (margins collapse into the surrounding rhythm). */
  margin-block:var(--band);
  padding:1.1rem 1.25rem;
  border-left:5px solid var(--signal);
  background:var(--tint);
}
.confirm :where(strong,b){ font-weight:600 }
/* Was `p + p`, which spaced the paragraphs and left the heading welded to the first one the
   moment /thanks/ grew a heading and a hidden booking line (spec §9.3). Every child, so a
   line added to that page later is spaced without anyone remembering this rule exists. */
.confirm > * + *{ margin-top:.6rem }
.confirm > .claim + *{ margin-top:clamp(.8rem,2vw,1.1rem) }
.confirm[hidden]{ display:none }


/* ---- MODAL --------------------------------------------------------------------------
   `.modal` is the overlay; `.modal-step` is one panel of a multi-step flow inside it, and
   the steps not currently showing carry [hidden]. Works as a plain <div class="modal"> the
   page toggles, or as <dialog class="modal"> driven by showModal().
   -------------------------------------------------------------------------------------- */
.modal{
  position:fixed; inset:0; z-index:60;
  display:grid; place-items:center;
  padding:clamp(.75rem,3vw,2rem);
  background:rgba(9,8,6,.86);
  overflow:auto;
  overscroll-behavior:contain;
}
.modal[hidden]{ display:none }

dialog.modal{
  width:100%; height:100%;
  max-width:none; max-height:none;
  border:0;
  color:var(--ink);
}
dialog.modal:not([open]){ display:none }   /* .modal's display:grid would otherwise win */
dialog.modal::backdrop{ background:rgba(9,8,6,.86) }

.modal-step{
  width:min(34rem,100%);
  max-height:100%;
  overflow:auto;
  padding:clamp(1.25rem,4vw,2.25rem);
  background:var(--paper);
  color:var(--ink);
  border:1px solid var(--rule);
  border-radius:0;
}
.modal-step[hidden]{ display:none }
.modal-step > :where(h2,h3){ font-size:clamp(1.75rem,4vw,2.6rem) }
/* Rendered only when the author supplies the attribute — an unlabelled step gets no
   invented chrome. Body face, not monospace. */
.modal-step[data-step]::before{
  content:"Step " attr(data-step);
  display:block;
  margin-bottom:.55rem;
  font-size:.78rem;
  letter-spacing:.14em;
  text-transform:uppercase;
  color:var(--muted);
}
.modal-step > * + *{ margin-top:clamp(.9rem,2vw,1.2rem) }
.modal-step .form{ max-width:none }


/* ---- PROSE ---------------------------------------------------------------------------
   Utility pages that are genuinely just text (/privacy). One measure, one rhythm, and
   subheads in the BODY face: the display face is reserved for claims at ≥28px (§1), and a
   privacy policy has no claims in it — setting "What we collect" in Bebas would shout a
   section that exists to be calm and read once. The h1 keeps `.claim` because it is the
   page's title, not a subhead.
   -------------------------------------------------------------------------------------- */
.prose{ max-width:64ch; padding-block:var(--band) }
.prose > * + *{ margin-top:1rem }
.prose h2{
  font-family:var(--body);
  font-weight:600;
  font-size:1.05rem;
  line-height:1.35;
  margin-top:clamp(1.9rem,4vw,2.6rem);
}
.prose ul{ display:grid; gap:.7rem }
.prose li{ position:relative; padding-left:1.4rem; color:var(--muted) }
.prose li::before{                         /* the page's square bullet, at list scale */
  content:"";
  position:absolute; left:0; top:.62em;
  width:.55rem; height:.55rem;
  background:var(--signal);
}
.prose p{ color:var(--muted) }
.prose .claim + p{ color:var(--ink) }      /* the plain-English summary, at full contrast */
.prose :where(strong,b){ color:var(--ink); font-weight:600 }
.prose a{ color:var(--ink); text-decoration:underline; text-underline-offset:.2em }


/* ---- FOOTER -------------------------------------------------------------------------- */
.foot{
  max-width:var(--maxw);
  margin-inline:auto;
  padding-inline:var(--gut);
  padding-block:clamp(2rem,4vw,3rem);
  border-top:1px solid var(--rule);
  display:flex; flex-wrap:wrap; gap:1rem 2rem;
  align-items:baseline; justify-content:space-between;
  color:var(--muted);
  font-size:.9rem;
}
.foot .mark{ color:var(--ink) }


/* =====================================================================================
   8 · REDUCED MOTION
   The hero split is already excluded at its source (§7) rather than being started and then
   neutralised here. This block is the catch-all for every other transition on the page —
   button lifts, the FAQ marker, field borders — and for anything added later that forgets.
   ===================================================================================== */
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{
    animation-duration:.001ms !important;
    animation-iteration-count:1 !important;
    transition-duration:.001ms !important;
    scroll-behavior:auto !important;
  }
}
