/* Hinter — single stylesheet. Tokens first, then layout, then components.
   Source of truth for the look: design/Hinter.dc.html (Claude Design export).
   Structure (2026-08-22): nav → hero → offer band → where you are (statement + climb) → the deck → case panel → fit columns → sign-off → footer → the skill modal.
   Motion: every scroll-in pre-state hangs off html.m-on (set in <head>) and lifts on .is-in (one observer at the end of index.html),
   so no JS, no IntersectionObserver or reduced motion all render the finished page. The reduced-motion block at the end only quiets hover/UI transitions.
   The ladder and the founder letter are parked in archive/next-and-founder.html. */

@font-face {
  font-family: "Recursive";
  font-style: normal;
  font-weight: 300 1000;
  font-display: swap;
  src: url("assets/fonts/recursive.woff2") format("woff2");
}

:root {
  /* palette */
  --bg: #F7F5F0;
  --ink: #191713;
  --ink-2: #575246;
  --ink-3: #6B655A;
  --muted: #776F62;        /* 4.55:1 on cream, 4.96 on white */
  --line: #E5DFD3;
  --line-card: #E9E4DA;
  --line-btn: #D9D2C4;
  --white: #FFFFFF;
  --dark: #171512;
  --dark-muted: #8A8478;
  --dark-text: #A9A296;
  --dark-line: #4A453C;
  --accent: #FF4D2E;
  --accent-text: #C8301A;   /* the accent at small-text size: 4.95:1 on cream, where #FF4D2E is 3.03 */

  /* type — one family, Recursive, at three axis positions.
     Weight is driven by font-weight only; never put "wght" in font-variation-settings (it would override it). */
  --sans: "Recursive", system-ui, -apple-system, "Segoe UI", sans-serif;
  --mono: "Recursive", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  --fv-display: "MONO" 0, "CASL" 0;        /* headlines, buttons, nav, logo, statement, row titles */
  --fv-prose: "MONO" 0, "CASL" 0.28;       /* body copy — the slightly casual voice */
  --fv-instrument: "MONO" 1, "CASL" 0;     /* eyebrows, labels, meta, time markers */

  /* layout */
  --wrap: 1180px;
  --gutter: 32px;
  --section-gap: 112px;
}

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-variation-settings: var(--fv-prose);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}
a { color: inherit; text-decoration: none; transition: color .15s ease, background .15s ease, filter .15s ease, border-color .15s ease; }
a:hover { color: var(--accent); }
/* one focus ring for the whole page: ink, 3px off the box; cream where it sits on a dark ground.
   Inputs and the select keep their own (border + glow, in the modal block). */
a:focus-visible, button:focus-visible { outline: 2px solid var(--ink); outline-offset: 3px; }
.link-underline:focus-visible, .footer a:focus-visible, .nav-links a:not(.btn):focus-visible, .logo:focus-visible { border-radius: 2px; }
.offer a:focus-visible, .card-dark a:focus-visible { outline-color: var(--bg); }
::selection { background: var(--accent); color: var(--white); }
h1, h2, h3, p, dl, dd { margin: 0; }
h1, h2, h3, .btn, .logo, .nav-links, .link-underline,
.statement-text { font-variation-settings: var(--fv-display); }
main [id] { scroll-margin-top: 72px; }   /* the sticky nav's height; anchors land under it, not behind it */

/* ---------- primitives ---------- */
.wrap { max-width: var(--wrap); margin: 0 auto; padding-left: var(--gutter); padding-right: var(--gutter); }
.mono { font-family: var(--mono); font-variation-settings: var(--fv-instrument); }
.acc { color: var(--accent); }
.logo { font-size: 20px; font-weight: 700; letter-spacing: -0.02em; }
.logo:hover { color: var(--ink); }
.logo-sm { font-size: 17px; }
.dot { width: 7px; height: 7px; border-radius: 999px; background: var(--accent); display: inline-block; }

.btn {
  display: inline-block;
  padding: 15px 28px;
  border-radius: 999px;
  font-size: 16px;
  font-weight: 600;
  line-height: 1;
}
.btn-primary { background: var(--accent); color: var(--ink); }   /* ink on the orange: 5.41:1 */
.btn-primary:hover { filter: brightness(0.92); color: var(--ink); }
/* the press: no further dimming — brightness(0.86) drops the ink label to 4.24:1 — an inset edge instead */
.btn-primary:active { filter: brightness(0.92); box-shadow: inset 0 2px 0 rgba(25,23,19,0.22); }
.btn-ghost { border: 1px solid var(--line-btn); color: var(--ink); }
.btn-ghost:hover { background: var(--white); color: var(--ink); }
.btn-sm { padding: 10px 20px; font-size: 15px; }

.cta-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.eyebrow { display: flex; align-items: flex-start; gap: 10px; font-family: var(--mono); font-variation-settings: var(--fv-instrument); font-size: 12px; letter-spacing: 0.12em; color: var(--muted); }
.eyebrow .dot { flex: none; margin-top: 3.5px; }
.label { font-size: 12px; letter-spacing: 0.12em; color: var(--muted); }
.meta { font-size: 12px; color: var(--muted); letter-spacing: 0.06em; }

/* phone tap targets: a 44px band behind the small links and the nav pill, centred on the text, no wider than it.
   Nothing visible changes; the hero's link sits 22px under the button when it wraps, so the 11px of overhang never reaches it. */
.link-underline, .logo, .nav .btn-sm { position: relative; }
.link-underline::before, .logo::before, .nav .btn-sm::before {
  content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 44px; transform: translateY(-50%);
}

/* ---------- nav ---------- */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: rgba(247,245,240,0.94);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.nav-inner { padding-top: 18px; padding-bottom: 18px; display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.nav-links { display: flex; align-items: center; gap: 28px; font-size: 15px; font-weight: 500; }
.nav-links a:not(.btn) { color: var(--ink-2); }
.nav-links a:not(.btn):hover { color: var(--ink); }

/* ---------- 1. hero ---------- */
.hero { position: relative; overflow: clip; background: radial-gradient(900px 520px at 82% -10%, rgba(255,77,46,0.08), transparent 60%); }
.hero-inner { position: relative; padding-top: 120px; padding-bottom: clamp(72px, 10vh, 112px); display: flex; flex-direction: column; gap: 32px; }
/* the words sit above the spray: the dots are laid out to miss the headline, but the h1 reflows with
   the viewport and text should never be the thing that loses. */
.hero-inner > :not(.spray) { position: relative; }
.hero h1 {
  font-size: clamp(48px, 6.2vw, 84px);
  font-weight: 320;
  letter-spacing: -0.03em;
  line-height: 1.02;
  max-width: 1000px;
  text-wrap: balance;
}
.lead { font-size: 20px; line-height: 1.55; color: var(--ink-2); max-width: 580px; text-wrap: pretty; }
.hero .cta-row { margin-top: 8px; gap: 22px; }
.hero .link-ink { color: var(--ink-2); border-bottom-color: var(--line-btn); transition: color .15s ease, border-color .15s ease; }
.hero .link-ink:hover { color: var(--accent); border-bottom-color: currentColor; }
.hero .link-ink .arr { display: inline-block; transition: transform .2s cubic-bezier(.2,.7,.2,1); }
.hero .link-ink:hover .arr { transform: translateY(3px); }
.nowrap { white-space: nowrap; }

/* the load beat — the wordmark's period and the eyebrow's dot come up ink and turn accent a beat after
   the fonts are in (html.is-loaded, two frames later). Scoped to the eyebrow's dot so the modal's never transitions. */
html.m-on:not(.is-loaded) .logo .acc { color: var(--ink); }
html.m-on:not(.is-loaded) .eyebrow .dot { background: var(--ink); }
html.m-on .logo .acc { transition: color .45s ease .25s; }
html.m-on .eyebrow .dot { transition: background-color .45s ease .25s; }

/* The spray — the headline's period throws a hundred marks into the hero's empty right half, ten of
   them winners. The dots are written by the inline script at the end of index.html, seeded, so the
   scatter is the same on every load. They fly on transform and opacity only: nothing here relayouts,
   and it plays once and then rests. Anchored to the right of the wrap with a bleed that grows with
   the margin, so the origin lands on the period at every width the block is shown at. */
.spray {
  position: absolute; z-index: 0; pointer-events: none;
  top: 0; bottom: 0; left: 0;
  right: calc(-1 * clamp(0px, (100vw - var(--wrap)) / 2, 84px));
}
.sp {
  position: absolute; width: 4px; height: 4px; border-radius: 999px;
  background: rgba(25,23,19,0.32);
  animation: spray 1.9s cubic-bezier(.16,.84,.3,1) backwards;   /* backwards, not both: a finished-but-filling layer re-rasterises the text above it */
}
.sp.win { width: 7px; height: 7px; background: var(--accent); }
@keyframes spray {
  from { opacity: 0; transform: translate(var(--dx), var(--dy)) scale(0.25); }
  to { opacity: 1; transform: none; }
}
/* below this the hero has no empty half to throw into — the lead already fills the width */
@media (max-width: 1099px) { .spray { display: none; } }

/* ---------- 2. the offer — the free skill, one full-bleed dark band.
   The skill sits in a ruled frame with its name stamped through the top rule, fieldset-legend
   style. The name is written in normal case in the HTML and uppercased here, so swapping the
   skill is one edit in one place. ---------- */
.offer { background: var(--dark); color: var(--dark-text); border-top: 1px solid var(--dark); }
.offer-inner {
  padding-top: 96px; padding-bottom: 96px;
  display: grid; grid-template-columns: 5fr 7fr; gap: 72px; align-items: stretch;
}
.offer-lead { display: flex; flex-direction: column; gap: 26px; align-items: flex-start; }
.offer h2 {
  font-size: clamp(30px, 3.3vw, 44px);
  font-weight: 400;
  letter-spacing: -0.03em;
  line-height: 1.08;
  color: var(--bg);
  text-wrap: balance;
}
.offer p { font-size: 17px; line-height: 1.6; color: var(--dark-text); text-wrap: pretty; max-width: 460px; }
.offer p strong { color: var(--bg); font-weight: 550; }
.offer .cta-row { margin-top: 6px; }
.offer .btn-primary:hover { filter: brightness(1.08); }   /* on the dark band a dimmed button reads pressed; lift instead */
.offer .btn-primary:active { filter: brightness(1.08); }

/* "All we ask" — a label stamped above the line, set off by a rule instead of living
   inline in the paragraph flow, so the one thing we ask of the reader reads as its own beat. */
.offer-ask {
  padding-top: 26px; border-top: 1px solid var(--dark-line);
  align-self: stretch; max-width: 460px;
  display: flex; flex-direction: column; gap: 6px;
}
.offer-ask-label { font-size: 13px; letter-spacing: 0.16em; text-transform: uppercase; color: var(--dark-text); }
.offer-ask-line { font-size: 17px; line-height: 1.6; color: var(--bg); text-wrap: pretty; }

/* Stretched to match the lead column's height (copy length now varies), the label
   stays pinned at the top like a card header and the points fan out to fill the
   frame rather than sitting stranded in a short box with dead air beside it. */
.skill-frame {
  position: relative; border: 1px solid var(--dark-line); padding: 54px 40px 0;
  display: flex; flex-direction: column;
}
.skill-name {
  position: absolute; top: -13px; left: 28px;
  background: var(--dark); padding: 0 16px;
  font-size: 21px; letter-spacing: 0.13em; line-height: 1;
  text-transform: uppercase; color: var(--bg);
}
.skill-points { margin: 0; padding: 0; list-style: none; flex: 1; display: flex; flex-direction: column; }
/* Rows bleed to the frame's edges like the partner row below, so every divider runs border to border. */
.skill-points li {
  display: grid; grid-template-columns: 46px 1fr; gap: 4px;
  padding: 32px 40px; margin: 0 -40px; border-top: 1px solid var(--dark-line); align-items: start;
}
.skill-points li:first-child { padding-top: 0; padding-bottom: 32px; border-top: 0; }
.skill-point-n { font-size: 13px; letter-spacing: 0.1em; line-height: 1.5; padding-top: 4px; color: var(--accent); }
.skill-point-text { font-size: 19px; line-height: 1.5; color: var(--bg); }   /* 20px wraps rows 01 and 02 at 1280 */
/* Two columns: the frame's top sits on the h2's box top, which puts the stamp's cap-line above the
   h2's. 16px down and the two cap-lines share a line; stretch keeps the frame's foot on the button's. */
@media (min-width: 901px) { .skill-frame { margin-top: 16px; } }
/* Bleeds to the frame's edges (negative margin cancels the frame's own padding) so the
   rule and the row both run the full width, same trick the deck cards use for card-spec. */
.skill-partner {
  margin: 0 -40px; padding: 24px 40px; border-top: 1px solid var(--dark-line);
  display: flex; align-items: center; gap: 18px;
  font-size: 15px; line-height: 1.4; color: var(--dark-text);
}
.partner-logo { display: inline-flex; align-items: center; gap: 8px; font-weight: 600; letter-spacing: -0.01em; color: var(--bg); }
.partner-logo svg { width: 18px; height: 18px; flex: none; }

/* motion — the frame boots. On scroll-in the top rule draws left to right, the other three sides
   fade in behind it and the stamp prints; then rows 01/02/03 and the partner row arrive in
   sequence: the divider draws, the numeral lights accent, the copy rises 6px. Every rule that
   "draws" is a 1px pseudo on top of the real border, which stays in layout and only changes
   colour, so nothing moves. --d is the reveal's batch stagger, --t each row's place in the boot.
   The "All we ask" rule does the same draw-and-print on its own. */
html.m-on .skill-frame { --boot: calc(var(--d, 0s) + .6s); transition: border-color .5s ease calc(var(--d, 0s) + .45s), border-top-color 0s linear calc(var(--d, 0s) + .7s); }
html.m-on .skill-points li, html.m-on .skill-partner, html.m-on .offer-ask { position: relative; }
html.m-on .skill-frame::before, html.m-on .skill-points li::before, html.m-on .skill-partner::before, html.m-on .offer-ask::before {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 1px;
  background: var(--dark-line); transform-origin: left;
  transition: transform .55s cubic-bezier(.2,.7,.2,1) calc(var(--t) - .08s);
}
html.m-on .skill-frame::before { left: -1px; right: -1px; transition: transform .7s cubic-bezier(.2,.7,.2,1) var(--d, 0s); }
html.m-on .skill-points li:first-child::before { display: none; }
html.m-on .skill-name { transition: opacity .12s ease calc(var(--d, 0s) + .1s); }
html.m-on .skill-points li:nth-child(1) { --t: calc(var(--boot) + .05s); }
html.m-on .skill-points li:nth-child(2) { --t: calc(var(--boot) + .30s); }
html.m-on .skill-points li:nth-child(3) { --t: calc(var(--boot) + .55s); }
html.m-on .skill-partner { --t: calc(var(--boot) + .80s); }
html.m-on .skill-points li, html.m-on .skill-partner { transition: border-top-color 0s linear calc(var(--t) + .47s); }   /* the real rule takes over once the pseudo has drawn */
html.m-on .skill-point-n, html.m-on .skill-point-text, html.m-on .skill-partner > * {
  transition: opacity .45s ease var(--t), transform .55s cubic-bezier(.2,.7,.2,1) var(--t);
}
html.m-on .skill-point-n { transition: opacity .45s ease var(--t), transform .55s cubic-bezier(.2,.7,.2,1) var(--t), color .35s ease calc(var(--t) + .25s); }
html.m-on .offer-ask { --t: calc(var(--d, 0s) + .08s); transition: border-top-color 0s linear calc(var(--t) + .47s); }
html.m-on .offer-ask-label { transition: opacity .12s ease calc(var(--t) + .3s); }
/* pre-states: only under m-on, so without JS or with reduced motion the band renders finished */
html.m-on .skill-frame:not(.is-in) { border-color: transparent; }
html.m-on .skill-frame:not(.is-in) .skill-points li, html.m-on .skill-frame:not(.is-in) .skill-partner, html.m-on .offer-ask:not(.is-in) { border-top-color: transparent; }
html.m-on .skill-frame:not(.is-in)::before, html.m-on .skill-frame:not(.is-in) li::before, html.m-on .skill-frame:not(.is-in) .skill-partner::before, html.m-on .offer-ask:not(.is-in)::before { transform: scaleX(0); }
html.m-on .skill-frame:not(.is-in) .skill-name, html.m-on .offer-ask:not(.is-in) .offer-ask-label { opacity: 0; }
html.m-on .skill-frame:not(.is-in) :is(.skill-point-n, .skill-point-text, .skill-partner > *) { opacity: 0; transform: translateY(6px); }
html.m-on .skill-frame:not(.is-in) .skill-point-n { color: var(--dark-muted); }

/* ---------- 3. where you are — question, bridge, then the climb (a scale, not a numbered list) ---------- */
.statement { border-top: 1px solid var(--line); }
.statement-inner {
  padding-top: 96px; padding-bottom: 56px;
  display: grid; grid-template-columns: 3fr 9fr; gap: 32px; align-items: start;
}
.statement .label { padding-top: 12px; }
.stmt-col { display: flex; flex-direction: column; gap: 28px; }
.statement-text {
  font-size: clamp(30px, 3.1vw, 44px);
  font-weight: 350;
  line-height: 1.22;
  letter-spacing: -0.02em;
  max-width: 880px;
  text-wrap: pretty;
}
.statement-text strong { font-weight: 550; }
.statement-text .stmt-ask { display: block; color: var(--accent); }
.bridge {
  font-size: 19px;
  line-height: 1.5;
  color: var(--ink);
  max-width: 640px;
  text-wrap: pretty;
}

.climb { padding-top: 24px; padding-bottom: 0; }
.climb-head {
  position: relative;
  display: flex; justify-content: space-between; align-items: baseline; gap: 24px;
  border-top: 1px dashed var(--line-btn); padding-top: 11px; margin-bottom: 40px;
}
.climb-head .more { font-size: 11px; letter-spacing: 0.12em; color: var(--ink-3); }
.more-arrow { display: inline-block; }   /* turns with the rail under 900 */
/* the five stops sit on one line: each stop owns the segment that runs through the gutter to the next dot,
   the dot stays the ::before. Subgrid keeps the stage / h3 / p rows straight across the columns; the row gap
   is restated because a subgrid would otherwise inherit the 22px column gap as its row gap. */
.stops { position: relative; display: grid; grid-template-columns: repeat(4, 1fr) 1.3fr; grid-template-rows: auto auto auto; gap: 9px 22px; }
.stop { position: relative; display: grid; grid-template-rows: subgrid; grid-row: span 3; gap: 9px; padding-top: 23px; }
.stop::before { content: ""; position: absolute; top: -4px; left: 0; z-index: 2; width: 9px; height: 9px; border-radius: 9px; background: var(--ink); }
.stop-line { position: absolute; top: 0; left: 0; height: 1px; width: calc(100% + 22px); background: var(--ink); transform-origin: 0 50%; }
.stop:nth-child(4) .stop-line { width: 100%; }   /* stops at the break */
.stop .stage { font-size: 10.5px; letter-spacing: 0.11em; color: var(--ink); }
.stop h3 { font-size: 16.5px; font-weight: 600; letter-spacing: -0.01em; line-height: 1.28; text-wrap: pretty; }
.stop p { font-size: 13.5px; line-height: 1.5; color: var(--ink-2); text-wrap: pretty; }
.stop-next { margin-left: 34px; }
.stop-next::before { background: var(--accent); }
.stop-next .stop-line { background: var(--accent); width: 100%; }
/* the break: a dashed accent jump across the 56px gap (22 gutter + 34 offset) */
.stop-jump {
  position: absolute; top: 0; right: 100%; width: 56px; height: 1px;
  background: repeating-linear-gradient(90deg, var(--accent) 0 5px, transparent 5px 9px);
  transform-origin: 0 50%;
}
.stop-next .stage { color: var(--accent-text); }   /* the h3 stays ink: 16.5px/600 orange on cream is 3.03:1 */

/* motion — the statement label prints and "Does your AI?" turns accent. Once the climb is in view the dashed
   rule draws left to right, its labels print, then the stops light up one after another: dot, line, copy.
   --d is each stop's place in the sequence; --sx/--sy let the rail draw the line down instead of across. */
html.m-on .statement-inner:not(.is-in) .label { opacity: 0; }
html.m-on .statement-inner:not(.is-in) .stmt-ask { color: var(--ink); }
html.m-on .statement-inner .label { transition: opacity .12s ease; }
html.m-on .statement-inner .stmt-ask { transition: color .45s ease .35s; }

html.m-on .climb-head { border-top-color: transparent; }   /* the real rule hides, the pseudo draws it */
html.m-on .climb-head::before {
  content: ""; position: absolute; left: 0; right: 0; top: -1px; bottom: 0;   /* same box as the head, so the dashes phase the same */
  border-top: 1px dashed var(--line-btn);
  clip-path: inset(0 100% 0 0); transition: clip-path .9s cubic-bezier(.4,0,.2,1);
}
html.m-on .climb.is-in .climb-head::before { clip-path: inset(0 0 0 0); }
html.m-on .climb:not(.is-in) .climb-head > span { opacity: 0; }
html.m-on .climb-head > span { transition: opacity .12s ease; }
html.m-on .climb-head .more { transition-delay: .7s; }   /* prints when the rule reaches it */

.stop { --d: 0s; }
.stop:nth-child(2) { --d: .4s; }
.stop:nth-child(3) { --d: .8s; }
.stop:nth-child(4) { --d: 1.2s; }
.stop:nth-child(5) { --d: 1.88s; }   /* the jump takes a beat longer than a gutter */
html.m-on .climb:not(.is-in) .stop::before { transform: scale(0); }
html.m-on .climb:not(.is-in) .stop-line,
html.m-on .climb:not(.is-in) .stop-jump { transform: scale(var(--sx, 0), var(--sy, 1)); }
html.m-on .climb:not(.is-in) .stop .stage,
html.m-on .climb:not(.is-in) .stop h3,
html.m-on .climb:not(.is-in) .stop p { opacity: 0; transform: translateY(6px); }
html.m-on .stop::before { transition: transform .28s cubic-bezier(.2,.9,.3,1.3) var(--d); }
html.m-on .stop-line { transition: transform .36s cubic-bezier(.4,0,.2,1) calc(var(--d) + .08s); }
html.m-on .stop-jump { transition: transform .3s linear calc(var(--d) - .22s); }   /* lands before the accent dot pops */
html.m-on .stop .stage, html.m-on .stop h3, html.m-on .stop p {
  transition: opacity .38s ease calc(var(--d) + .05s), transform .38s ease calc(var(--d) + .05s);
}
/* the accent stop arrives in ink and turns accent once its line is in (.44s after --d) */
html.m-on .climb:not(.is-in) .stop-next::before, html.m-on .climb:not(.is-in) .stop-next .stop-line { background: var(--ink); }
html.m-on .climb:not(.is-in) .stop-next .stage { color: var(--ink); }
html.m-on .stop-next::before { transition: transform .28s cubic-bezier(.2,.9,.3,1.3) var(--d), background-color .3s ease calc(var(--d) + .44s); }
html.m-on .stop-next .stop-line { transition: transform .36s cubic-bezier(.4,0,.2,1) calc(var(--d) + .08s), background-color .3s ease calc(var(--d) + .44s); }
html.m-on .stop-next .stage {
  transition: opacity .38s ease calc(var(--d) + .05s), transform .38s ease calc(var(--d) + .05s), color .3s ease calc(var(--d) + .44s);
}

/* ---------- sections (shared) ---------- */
.section { padding-top: var(--section-gap); display: flex; flex-direction: column; gap: 48px; }
.section h2 { font-size: 44px; font-weight: 400; letter-spacing: -0.025em; line-height: 1.1; text-wrap: balance; }   /* one size for the offer, statement, deck and case heads */
.section h3 { font-size: 20px; font-weight: 600; }
.section p { font-size: 15.5px; line-height: 1.6; color: var(--ink-2); text-wrap: pretty; }

/* ---------- 4. what we build — the deck. Heading row inside the wrap; the track bleeds to the right edge
   and starts flush with the wrap's left gutter (the padding-left expression = .wrap's margin + gutter).
   Cards are ruled frames with the name stamped through the top rule, the skill frame's device. ---------- */
.build { gap: 36px; }
.build-head { width: 100%; display: grid; grid-template-columns: 4fr 8fr; gap: 48px; align-items: end; }   /* width: the section column centres its children; without it the head shrink-wraps and floats off the gutter */
.build-head-r { display: flex; justify-content: space-between; align-items: end; gap: 24px; }
.build-intro { max-width: 420px; font-size: 16px; }
.deck-ctl { display: flex; align-items: center; gap: 18px; flex: 0 0 auto; }
/* the rail is a scrubber: six muted ticks are the track, one accent thumb glides with the scroll and lands on a tick at each snap */
.deck-rail { position: relative; display: flex; gap: 5px; }
.deck-rail i { display: block; width: 20px; height: 2px; background: var(--muted); opacity: .38; }
.deck-rail::after {
  content: ""; position: absolute; left: 0; top: 0; width: 20px; height: 2px; background: var(--accent);
  transform: translateX(calc(var(--p, 0) * 125px));   /* 125 = rail width (145) minus one tick; six cards, hardcoded */
}
.deck-btns { display: flex; gap: 8px; }
.deck-btn {
  width: 44px; height: 44px; border-radius: 999px; border: 1px solid var(--line-btn); background: transparent; color: var(--ink);
  cursor: pointer; display: grid; place-content: center; font: inherit; font-size: 18px; line-height: 1;
  transition: background .15s ease, border-color .15s ease, opacity .2s ease, transform .12s ease;
}
.deck-btn:hover { background: var(--white); border-color: var(--ink); }
.deck-btn:active { transform: scale(.94); }
/* nothing further this way */
.deck-btn[aria-disabled="true"] { opacity: .28; cursor: default; }
.deck-btn[aria-disabled="true"]:hover { background: transparent; border-color: var(--line-btn); }
/* card width: three cards plus ~96px of the fourth at every desktop width, so the peek always reads as "there's more", never as a clipped sliver */
.deck {
  --deck-left: max(var(--gutter), calc((100% - var(--wrap)) / 2 + var(--gutter)));
  --deck-left-vw: max(var(--gutter), calc((100vw - var(--wrap)) / 2 + var(--gutter)));   /* same thing in vw, usable inside --card */
  --card: clamp(340px, calc((100vw - var(--deck-left-vw) - 60px - 96px) / 3), 420px);   /* 60 = the three gaps before the fourth card */
  overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -webkit-overflow-scrolling: touch;
  scroll-padding-left: var(--deck-left);
}
.deck::-webkit-scrollbar { display: none; }
/* right padding = what is left of the viewport after one card at the left edge, so the last card can become the current one */
.deck-track {
  display: flex; gap: 20px; width: max-content;
  padding: 12px max(var(--gutter), calc(100% - var(--card) - var(--deck-left))) 4px var(--deck-left);
}
.card {
  scroll-snap-align: start; position: relative; flex: 0 0 var(--card); min-height: 330px;
  border: 1px solid var(--line-btn); padding: 46px 32px 30px; background: var(--bg);
  display: flex; flex-direction: column; gap: 16px;
}
.card-name {
  position: absolute; top: -9px; left: 22px; background: var(--bg); padding: 0 10px;
  font-size: 12px; letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink); line-height: 1;
}
.build .card h3 { font-size: 27px; font-weight: 500; letter-spacing: -0.02em; line-height: 1.15; text-wrap: balance; }
.build .card p { font-size: 15.5px; line-height: 1.55; }
.card-spec {
  margin-top: auto; display: grid; grid-template-columns: 36px 1fr; row-gap: 8px; column-gap: 14px;
  font-size: 12.5px; letter-spacing: 0.03em; line-height: 1.45; color: var(--ink-2);
  border-top: 1px dashed var(--line-btn); padding-top: 16px;
  min-height: 100px; align-content: start;   /* the dashed rule sits at one height on every card */
}
.card-spec dt { color: var(--muted); letter-spacing: 0.12em; font-size: 11px; padding-top: 2px; }
.card-dark { background: linear-gradient(var(--bg) 0 4px, var(--dark) 4px); border-color: transparent; }
/* the stamp straddles the top edge, so the dark fill starts 4px down (the strip above it is page-coloured) and the stamp stays a cream/ink label like its siblings */
.card-dark .card-name { background: var(--bg); color: var(--ink); }
.build .card-dark h3 { color: var(--bg); }
.build .card-dark p { color: var(--dark-text); }
.card-dark .link-underline { margin-top: auto; align-self: flex-start; }

/* motion */
/* cards settle: rise 22px and fade, 70ms apart, once, off the one is-in the shared observer puts on the deck (--d = its place in the batch) */
html.m-on .deck:not(.is-in) .card { opacity: 0; transform: translateY(22px); }
.card { transition: opacity .6s cubic-bezier(.2,.7,.2,1), transform .6s cubic-bezier(.2,.7,.2,1), border-color .25s ease; transition-delay: var(--d, 0ms); }
.card:nth-child(2) { transition-delay: calc(var(--d, 0ms) + 70ms); }
.card:nth-child(3) { transition-delay: calc(var(--d, 0ms) + 140ms); }
.card:nth-child(4) { transition-delay: calc(var(--d, 0ms) + 210ms); }
.card:nth-child(5) { transition-delay: calc(var(--d, 0ms) + 280ms); }
.card:nth-child(6) { transition-delay: calc(var(--d, 0ms) + 350ms); }
/* the current card takes the ink frame and the accent stamp, so the frame travels as you scrub */
.card .card-name { transition: color .25s ease; }
.card.is-current .card-name { color: var(--accent-text); }
.card.is-current { border-color: var(--ink); }
/* right-edge fade: says "continues" without a hard clip; lifts when the last card is current */
@property --fade { syntax: "<length>"; inherits: false; initial-value: 80px; }
.deck {
  --fade: 80px;
  -webkit-mask-image: linear-gradient(90deg, #000 calc(100% - var(--fade)), transparent 100%);
          mask-image: linear-gradient(90deg, #000 calc(100% - var(--fade)), transparent 100%);
  transition: --fade .35s ease;
}
.deck.at-end { --fade: 0px; }
/* under 1100 the 340px card floor leaves 2.7 cards in view and the fade would sit on the third card's headline; a clean clip reads better */
@media (max-width: 1099px) { .deck { --fade: 0px; -webkit-mask-image: none; mask-image: none; } }
/* drag with a mouse (touch already swipes natively) */
.deck { cursor: grab; }
.deck.is-dragging { cursor: grabbing; scroll-snap-type: none; user-select: none; }
.deck.is-dragging .card { pointer-events: none; }

/* ---------- 5. one project — a ruled frame (the deck card's device, at full width), the head on top,
   four figures under it, then the story as three columns read left to right: before → after ---------- */
.case {
  position: relative;
  /* white sheet, ink frame: the 5px cream strip at the top keeps the stamp on page colour, the way .card-dark does it */
  background: linear-gradient(var(--bg) 0 5px, var(--white) 5px); border: 1px solid var(--ink); border-radius: 0; box-shadow: none;
  padding: 60px 56px 56px;
  display: flex; flex-direction: column; gap: 52px;
}
/* the label stamped through the top rule — .card-name's move, same offsets */
.case-stamp {
  position: absolute; top: -7px; left: 22px; background: var(--bg); padding: 0 10px;
  font-size: 12px; letter-spacing: 0.13em; color: var(--ink); line-height: 1;
}
.case-head { display: flex; flex-direction: column; gap: 18px; }
.case-head h2 { max-width: 26ch; }   /* size comes from .section h2 */
.case-meta { font-size: 12px; letter-spacing: 0.08em; color: var(--muted); }
/* one line until the phone: the <br> goes, a drawn "·" takes its place, and the second half never breaks on its own */
.case-meta br { display: none; }
.case-meta span { white-space: nowrap; }
.case-meta span::before { content: " · "; }
/* the ledger: 4 figures over 3 columns, the same 1px rule over each so the two rows rhyme */
.case-ledger { margin: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 40px; }
.case-ledger div { position: relative; display: flex; flex-direction: column; gap: 5px; padding-top: 14px; }
.case-ledger dt { font-variation-settings: var(--fv-display); font-size: 24px; font-weight: 500; letter-spacing: -0.02em; line-height: 1.1; }
.case-ledger dd { font-size: 11px; letter-spacing: 0.1em; color: var(--muted); }
.case-cols { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 40px; }
.case-col { position: relative; padding-top: 22px; display: flex; flex-direction: column; gap: 14px; }
.case-ledger div::before, .case-col::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: var(--line); transform-origin: left center;
}
.case-col p { font-size: 16.5px; }
/* "what changed" is the only accent in the block */
.case-col-changed::before { background: var(--accent); }
.case-col-changed .label { color: var(--accent-text); }
.case-col-changed p { color: var(--ink); }
/* motion — the stamp prints, then the rules draw left to right and the text under each settles:
   the ledger first, then the three columns. --t is each item's place in the sequence. */
html.m-on .case:not(.is-in) .case-stamp { opacity: 0; }
html.m-on .case:not(.is-in) .case-ledger div::before, html.m-on .case:not(.is-in) .case-col::before { transform: scaleX(0); }
html.m-on .case:not(.is-in) .case-ledger div > *, html.m-on .case:not(.is-in) .case-col > * { opacity: 0; transform: translateY(8px); }
.case-stamp { transition: opacity .12s ease calc(var(--d, 0ms) + 100ms); }
.case-ledger div::before, .case-col::before { transition: transform .7s cubic-bezier(.2,.7,.2,1) calc(var(--d, 0ms) + var(--t, 0ms)); }
.case-ledger div > *, .case-col > * {
  transition: opacity .5s ease calc(var(--d, 0ms) + var(--t, 0ms) + 220ms), transform .5s ease calc(var(--d, 0ms) + var(--t, 0ms) + 220ms);
}
.case-ledger div:nth-child(2) { --t: 80ms; }
.case-ledger div:nth-child(3) { --t: 160ms; }
.case-ledger div:nth-child(4) { --t: 240ms; }
.case-col:nth-child(1) { --t: 300ms; }
.case-col:nth-child(2) { --t: 440ms; }
.case-col:nth-child(3) { --t: 580ms; }

/* ---------- 6. fit — the coda. Two plain columns either side of a centred hairline (the gap is
   padding on both sides of the rule, so both columns get the same measure). The heads are eyebrows,
   the same mono label the case panel uses above; the six lines are the actual self-selection, so
   they get the size and the ink. Less air than a section on both sides, so it reads as the quiet
   filter before the signature, not a fourth section. ---------- */
.fit { padding-top: 88px; display: grid; grid-template-columns: 1fr 1fr; gap: 0; }
.fit-col { display: flex; flex-direction: column; gap: 24px; }
.fit-col:first-child { padding-right: 56px; }
.fit-col + .fit-col { border-left: 1px solid var(--line); padding-left: 56px; }
.fit h2 {
  font-family: var(--mono); font-variation-settings: var(--fv-instrument);
  font-size: 12px; font-weight: 400; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted); line-height: 1;
}
.plain { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 18px; }
.plain li {
  position: relative; padding-left: 34px;
  font-size: 20px; line-height: 1.4; color: var(--ink);
  font-variation-settings: var(--fv-prose); letter-spacing: -0.005em; text-wrap: pretty;
}
/* the marks carry "" as alt text so screen readers skip them; the plain declaration first is the fallback where "/" is unsupported */
.plain li::before { position: absolute; left: 0; top: 3px; font-family: var(--mono); font-variation-settings: var(--fv-instrument); font-size: 18px; font-weight: 500; }
.plain-yes li::before { content: "+"; content: "+" / ""; color: var(--accent); }
.plain-no li { color: var(--ink-2); }
.plain-no li::before { content: "\2212"; content: "\2212" / ""; color: var(--ink-3); }

/* ---------- 7. sign-off — the last thing on the page. The label is stamped through the top
   rule, the same move .skill-name makes on the offer frame, so the block opens on a full-width
   line instead of an indent. The bottom bar is who said it on the left, what to do on the
   right — one row instead of a five-item stack. ---------- */
.signoff { padding-top: 72px; padding-bottom: var(--section-gap); }   /* closer to the filter above than a section is: one closing movement */
.signoff-inner { position: relative; border-top: 1px solid var(--ink); padding-top: 44px; }
.signoff-stamp {
  position: absolute; top: -7px; left: 0;
  background: var(--bg); padding-right: 18px;
  font-size: 12px; letter-spacing: 0.12em; color: var(--muted); line-height: 1;
}
.signoff-line {
  font-size: clamp(30px, 3.9vw, 54px); font-weight: 350;
  letter-spacing: -0.025em; line-height: 1.14;
  max-width: 24ch; text-wrap: balance;
}
.signoff-bar {
  border-top: 1px solid var(--line);
  padding-top: 26px; margin-top: 56px;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 28px; flex-wrap: wrap;
}
.signoff-sig { display: flex; flex-direction: column; gap: 4px; font-size: 16px; font-weight: 500; }
.signoff-role { font-family: var(--mono); font-variation-settings: var(--fv-instrument); font-size: 11px; letter-spacing: 0.1em; color: var(--muted); }
.signoff-bar .cta-row { gap: 20px; }
.signoff-bar .btn { padding: 17px 34px; font-size: 17px; transition: color .15s ease, filter .15s ease, transform .18s ease, box-shadow .18s ease; }
.signoff-bar .btn:hover { transform: translateY(-2px); box-shadow: 0 14px 28px -12px rgba(255,77,46,0.65); }
.signoff-bar .btn:active { transform: translateY(0); box-shadow: inset 0 2px 0 rgba(25,23,19,0.22); }   /* the lift drops, the press lands */
.signoff .link-ink { color: var(--ink-2); border-bottom-color: var(--line-btn); transition: color .15s ease, border-color .15s ease; }
.signoff .link-ink:hover { color: var(--accent); border-bottom-color: currentColor; }   /* the underline follows the text, like the hero link */

/* motion — the period lands. Once, when the block scrolls in: the rule draws out of the stamp, the
   line rises, the period lands last with a little overshoot, then the bar. The real border goes
   quiet under m-on and a pseudo on the same pixel draws it instead; without m-on none of this applies. */
html.m-on .signoff-inner { border-top-color: transparent; }
html.m-on .signoff-inner::before {
  content: ""; position: absolute; top: -1px; left: 0; right: 0; height: 1px;
  background: var(--ink); transform-origin: left center;
}
.signoff-line .acc { display: inline-block; transform-origin: 50% 85%; }
html.m-on .signoff-inner:not(.is-in)::before { transform: scaleX(0); }
html.m-on .signoff-inner:not(.is-in) .signoff-stamp { opacity: 0; }
html.m-on .signoff-inner:not(.is-in) .signoff-line,
html.m-on .signoff-inner:not(.is-in) .signoff-bar { opacity: 0; transform: translateY(14px); }
html.m-on .signoff-inner:not(.is-in) .signoff-line .acc { opacity: 0; transform: scale(.2); }
/* fill backwards, not both: every end frame is the resting style, and a finished animation that keeps
   filling leaves the text on its own layer, rasterised a shade differently from the no-motion page */
.signoff-inner.is-in::before            { animation: so-draw .8s cubic-bezier(.2,.7,.1,1) backwards; }
.signoff-inner.is-in .signoff-stamp     { animation: so-print .12s .1s backwards; }
.signoff-inner.is-in .signoff-line      { animation: so-rise .6s .12s cubic-bezier(.2,.7,.2,1) backwards; }
.signoff-inner.is-in .signoff-line .acc { animation: so-land .36s .66s cubic-bezier(.3,1.5,.5,1) backwards; }
.signoff-inner.is-in .signoff-bar       { animation: so-rise .55s .82s cubic-bezier(.2,.7,.2,1) backwards; }
@keyframes so-draw  { from { transform: scaleX(0); } to { transform: scaleX(1); } }
@keyframes so-print { from { opacity: 0; } to { opacity: 1; } }
@keyframes so-rise  { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }
@keyframes so-land  { from { opacity: 0; transform: scale(.2); } to { opacity: 1; transform: none; } }

/* ---------- underlined link, sits on dark bands ---------- */
.link-underline { color: var(--bg); font-size: 16px; font-weight: 500; border-bottom: 1px solid var(--dark-line); padding-bottom: 2px; }
.link-underline:hover { color: var(--accent); }

/* ---------- footer — the colophon: one left-aligned run, wordmark then the © line. The email is not
   repeated here; it sits 180px up, next to the person it belongs to. ---------- */
.footer { border-top: 1px solid var(--line); }
.footer-inner { padding-top: 26px; padding-bottom: 34px; display: flex; align-items: center; justify-content: flex-start; gap: 28px; flex-wrap: wrap; }
.footer .logo { color: var(--ink); }

/* ---------- responsive ---------- */
@media (max-width: 1100px) {
  /* three columns run under 35 characters a line here, so the story stacks early (measure capped) and the ledger goes 2×2 with it */
  .case-ledger { grid-template-columns: repeat(2, 1fr); }
  .case-cols { grid-template-columns: 1fr; gap: 0; }
  .case-col { padding: 22px 0; }
  .case-col:last-child { padding-bottom: 0; }
  .case-col p { max-width: 62ch; }
}

@media (max-width: 900px) {
  .offer-inner { grid-template-columns: 1fr; gap: 40px; padding-top: 72px; padding-bottom: 72px; }
  .statement-inner { grid-template-columns: 1fr; gap: 20px; padding-top: 72px; padding-bottom: 40px; }
  .statement .label { padding-top: 0; }
  .climb { padding-bottom: 0; }
  /* the line turns into a rail: dots down a left-hand line, the jump goes vertical, the arrow turns with it.
     --sx/--sy, stop 4's line and the --d beats tie with the section rules on specificity and win here by source order. */
  .stops { grid-template-columns: 1fr; gap: 0; padding-left: 26px; }
  .stop { padding: 14px 0 22px; }
  .stop::before { left: -26px; top: 18px; }
  .stop-line { --sx: 1; --sy: 0; top: 18px; left: -22px; width: 1px; height: 100%; transform-origin: 50% 0; }   /* from this dot down to the next */
  .stop:nth-child(4) .stop-line { width: 1px; height: calc(100% - 18px); }   /* ends at its own bottom, the jump takes over */
  .stop-next { margin-left: 0; margin-top: 26px; padding-top: 14px; }
  .stop-next .stop-line { width: 1px; height: calc(100% - 18px); }
  .stop:last-child { padding-bottom: 0; }   /* the rail ends on the last paragraph, not 22px below it */
  .stop-jump {
    --sx: 1; --sy: 0;
    right: auto; left: -22px; top: -26px; width: 1px; height: 44px;   /* 26 gap + 18 down to the accent dot */
    background: repeating-linear-gradient(180deg, var(--accent) 0 4px, transparent 4px 8px);
    transform-origin: 50% 0;
  }
  .more-arrow { transform: rotate(90deg); }
  .stop:nth-child(2) { --d: .3s; }
  .stop:nth-child(3) { --d: .6s; }
  .stop:nth-child(4) { --d: .9s; }
  .stop:nth-child(5) { --d: 1.58s; }
  .build-head { grid-template-columns: 1fr; gap: 20px; }
  .build-head-r { flex-direction: column; align-items: flex-start; gap: 20px; }
  .deck { --card: min(340px, 82vw); cursor: auto; }
  .card { min-height: 300px; padding: 40px 24px 26px; }
  .case { padding: 48px 40px 40px; }
  .fit { grid-template-columns: 1fr; gap: 32px; }   /* tighter than the section gap, so the two halves stay one block */
  .fit-col:first-child { padding-right: 0; }
  .fit-col + .fit-col { border-left: 0; padding-left: 0; border-top: 1px solid var(--line); padding-top: 32px; }
}

@media (max-width: 720px) {
  :root { --gutter: 20px; --section-gap: 72px; }
  .nav-links { gap: 16px; }
  .hero-inner { padding-top: 72px; padding-bottom: 64px; gap: 24px; }
  /* the phone ladder: every section head at one size; the fit heads stay eyebrows (.fit carries .section, so order decides) */
  .offer h2, .statement-text, .section h2, .case-head h2 { font-size: 30px; }
  .fit h2 { font-size: 12px; }
  .offer-inner { padding-top: 56px; padding-bottom: 56px; gap: 32px; }
  .offer p { font-size: 16px; }
  .offer-ask-line, .skill-point-text { font-size: 16px; }   /* one body size in the band, not two */
  .skill-frame { padding: 42px 20px 0; }
  .skill-points li { grid-template-columns: 36px 1fr; padding: 24px 20px; margin: 0 -20px; }
  .skill-points li:first-child { padding-bottom: 24px; }
  .skill-name { top: -10px; left: 16px; padding: 0 10px; font-size: 15px; letter-spacing: 0.1em; }
  .skill-partner { margin: 0 -20px; padding: 20px 20px; gap: 12px; font-size: 14px; }
  .bridge { font-size: 17px; }
  .case { padding: 36px 22px 28px; }
  .case-meta br { display: inline; }
  .case-meta span::before { content: none; }
  .case-ledger { gap: 28px 24px; }
  .case-ledger dt { font-size: 21px; }
  .fit { padding-top: 64px; }
  .plain li { font-size: 18px; padding-left: 30px; }
  .plain li::before { font-size: 16px; top: 2px; }
  .signoff { padding-top: 56px; }
  .signoff-line { font-size: 30px; max-width: none; }
  .signoff-bar { flex-direction: column; align-items: flex-start; gap: 24px; }
  .footer-inner { gap: 10px 28px; }
}
@media (max-width: 430px) {
  .footer .meta { text-wrap: balance; }   /* the line needs 380px; below this it wraps, so wrap it evenly */
}

@media (max-width: 560px) {
  .nav-links a:not(.btn) { display: none; }   /* the two text links go; the wordmark-to-links gap is still ~106px at 560 */
}

/* ---------- the skill form — the modal behind "Get the skill" (markup: end of index.html, logic: form.js) ---------- */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.modal-open { overflow: hidden; }
.scrim {
  position: fixed; inset: 0; z-index: 100;
  display: flex; align-items: flex-start; justify-content: center; padding: 24px;
  padding-top: max(24px, calc(50vh - 290px)); /* where a 580px sheet would sit centred — and it stays there whatever the step */
  background: rgba(25,23,19,0); transition: background-color .18s ease;
}
.scrim[hidden], .modal [hidden] { display: none !important; }
.scrim.is-open { background: rgba(25,23,19,0.55); }
.modal {
  width: 100%; max-width: 560px;
  background: var(--bg); color: var(--ink);
  border: 1px solid var(--line); border-radius: 16px;
  padding: 28px 32px 32px;
  max-height: calc(100vh - 48px); overflow: auto;
  box-shadow: 0 24px 64px rgba(25,23,19,0.18);
  transition: transform .24s cubic-bezier(.2,.7,.2,1), opacity .12s ease;
}
/* the fade lives on the scrim's background, not its opacity: a child can never be more opaque than its parent,
   so the sheet used to arrive see-through. The sheet fades on its own, faster, and rises 10px */
.scrim:not(.is-open) .modal { transform: translateY(10px); opacity: 0; }
/* between steps form.js writes an explicit height for ~300ms so the sheet tweens instead of jumping */
.modal.is-resizing { overflow: hidden; transition: height .24s cubic-bezier(.2,.7,.2,1), transform .24s cubic-bezier(.2,.7,.2,1), opacity .2s ease; }
/* step slide/fade. --dir is 1 going forward, -1 going back */
.is-leaving { opacity: 0; transform: translateX(calc(var(--dir, 1) * -10px)); transition: opacity .12s ease, transform .12s ease; }
.is-entering { opacity: 0; transform: translateX(calc(var(--dir, 1) * 14px)); }
.is-entering.go { opacity: 1; transform: none; transition: opacity .2s ease .05s, transform .24s cubic-bezier(.2,.7,.2,1) .05s; }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 14px; }
#elig-title { color: var(--ink); font-weight: 500; letter-spacing: 0.12em; margin-right: auto; }
.modal-close {
  width: 40px; height: 40px; margin: -8px -10px -8px 0;
  display: grid; place-content: center;
  border: 0; border-radius: 999px; background: transparent; color: var(--ink-3); cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.modal-close:hover { background: var(--white); color: var(--ink); }
.modal button { font-family: inherit; }
.modal button.btn { border: 0; cursor: pointer; font-variation-settings: var(--fv-display); }
.modal button.btn-ghost { border: 1px solid var(--line-btn); background: transparent; }

/* progress — the count sits in the head beside the ×; the hairline under the head IS the track, no step names */
.elig-count {
  flex: 0 0 auto; margin-right: 2px;
  font-family: var(--mono); font-variation-settings: var(--fv-instrument);
  font-size: 11px; letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-3);
}
.elig-rail { margin: 16px 0 0; padding: 0; border: 0; display: block; }
.elig-bar { display: block; height: 2px; border-radius: 0; background: var(--line); overflow: hidden; }
.elig-fill { display: block; width: 33.333%; height: 100%; border-radius: 0; background: var(--accent); transition: width .24s ease; }

/* fields */
.elig-form { margin-top: 26px; }
.step { border: 0; margin: 0; padding: 0; min-width: 0; display: flex; flex-direction: column; gap: 18px; }
.field { display: flex; flex-direction: column; gap: 8px; }
.field label { font-size: 14px; font-weight: 500; color: var(--ink); font-variation-settings: var(--fv-display); }
.field input {
  width: 100%; margin: 0;
  font: inherit; font-size: 16px; font-variation-settings: var(--fv-prose); color: var(--ink);
  background: var(--white); border: 1px solid var(--muted); border-radius: 12px; padding: 12px 14px; /* --muted: the boundary passes 4.5:1 on white */
  outline: none; transition: border-color .15s ease, box-shadow .15s ease;
}
.field input::placeholder { color: var(--muted); }
.field input:hover { border-color: var(--ink-3); }
.field input:focus-visible { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(25,23,19,0.08); }
.field [aria-invalid="true"] { border-color: var(--accent); }
.hint { font-size: 13px; line-height: 1.5; color: var(--ink-3); text-wrap: pretty; }
.hint:empty { display: none; }  /* most fields carry no hint at rest — the slot only fills on an error */
.hint-error { color: var(--accent-text); }  /* the input border stays --accent */

/* phone: country code beside the number */
.field-phone { display: flex; gap: 8px; }
.field-phone input { flex: 1 1 auto; min-width: 0; }
.elig-dial {
  flex: 0 1 200px; min-width: 0; margin: 0;
  font: inherit; font-size: 16px; font-variation-settings: var(--fv-prose); color: var(--ink);
  background-color: var(--white); border: 1px solid var(--muted); border-radius: 12px;
  padding: 12px 32px 12px 14px;
  appearance: none; -webkit-appearance: none; cursor: pointer;
  text-overflow: ellipsis; outline: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23776F62' stroke-width='1.5'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 12px center;
  transition: border-color .15s ease, box-shadow .15s ease;
}
.elig-dial:hover { border-color: var(--ink-3); }
.elig-dial:focus-visible { border-color: var(--ink); box-shadow: 0 0 0 3px rgba(25,23,19,0.08); }

/* foot */
.modal-foot { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 28px; }
.modal-foot .elig-continue { margin-left: auto; }

/* the bot trap: never seen, never tabbed to, never announced */
.elig-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* the last screen */
.elig-screen { margin-top: 30px; display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.elig-screen h3 { font-size: 32px; font-weight: 500; letter-spacing: -0.025em; line-height: 1.2; outline: none; text-wrap: balance; }
.elig-screen p { font-size: 16px; line-height: 1.55; color: var(--ink-2); text-wrap: pretty; max-width: 440px; }
.elig-yes .dot { display: none; }                 /* the completed track above is the mark */
.modal.is-sent .elig-count { visibility: hidden; }

@media (max-width: 820px) {
  .scrim { align-items: flex-end; padding: 0; }
  .scrim:not(.is-open) .modal { transform: translateY(48px); }  /* a sheet: rises from the bottom edge */
  .modal { max-width: none; border-radius: 16px 16px 0 0; border-bottom: 0; max-height: 92dvh; padding: 22px 20px calc(28px + env(safe-area-inset-bottom)); transition-duration: .28s, .14s; }
}
@media (max-width: 420px) {
  .elig-count { font-size: 10px; letter-spacing: 0.08em; }
  .elig-dial { flex-basis: 158px; padding: 12px 28px 12px 12px; background-position: right 10px center; }
  .elig-screen h3 { font-size: 26px; }
}
/* ---------- reduced motion — the scroll-in pre-states never apply here (they hang off html.m-on), so this
   only quiets what moves on hover, on load or inside the modal. ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  /* the spray keeps its resting scatter, it just never flies */
  .sp { animation: none; opacity: 1; transform: none; }
  .hero .link-ink .arr, .deck-btn { transition: none; }
  .signoff-bar .btn { transition: color .15s ease, filter .15s ease; }
  .signoff-bar .btn:hover { transform: none; box-shadow: none; }
  .signoff-bar .btn:active { box-shadow: inset 0 2px 0 rgba(25,23,19,0.22); }   /* the lift is motion, the press is not */
  /* the sheet appears in place; form.js swaps steps instantly when motion is off */
  .scrim, .elig-fill { transition: none; }
  .modal, .step, .elig-form, .elig-screen, .is-leaving, .is-entering, .is-entering.go { transition: none; transform: none; }
  .scrim:not(.is-open) .modal { opacity: 1; transform: none; }  /* same specificity as the rising rule, so it wins by order */
}
