/* =============================================================
   woodle.cloud — front door stylesheet
   One file. Light is the default surface; dark follows the OS.
   Signal teal is the only accent. Brand dot is emerald.
   All text pairs verified WCAG 2.1 AA in both surfaces.
   ============================================================= */

/* ---------- self-hosted type ----------
   Inter and JetBrains Mono are served from this origin, so a visitor makes no
   third-party request for them. Both are variable fonts clamped to the weights
   the page actually uses (400–600), latin subset, ~38 KB each.
   Built from the SIL OFL originals — see build/fonts/README.md.

   Space Grotesk is the display face and is SELF-HOSTED when present.
   It was briefly dropped on 30 Aug 2026 because the only available copy was
   Google's, and that was the site's last third-party request. The reasoning was
   sound; the premise was not — the font is SIL OFL and can simply be shipped
   from this origin. Restored 31 Aug.
   build/fonts/make-fonts.py cuts the .woff from a licensed TTF, and build.py
   emits its @font-face only when that file exists. Until then this chain falls
   through to Inter: no request, no 404, no third party, nothing broken.
   Tracking is back to -.03em, the value originally tuned for this face. It was
   briefly -.034em to compensate for Inter running wider; with Grotesk actually
   present that over-tightens.  */
@font-face{
  font-family:'Inter';
  src:url('../fonts/inter-latin.woff') format('woff');
  font-weight:400 600; font-style:normal; font-display:swap;
}
@font-face{
  font-family:'JetBrains Mono';
  src:url('../fonts/jetbrains-mono-latin.woff') format('woff');
  font-weight:400 500; font-style:normal; font-display:swap;
}

/* ---------- tokens ---------- */
:root{
  --sans:'Inter',system-ui,-apple-system,'Segoe UI',Roboto,sans-serif;
  --mono:'JetBrains Mono',ui-monospace,'SF Mono',Menlo,monospace;
  --grotesk:'Space Grotesk','Inter',system-ui,sans-serif;  /* see the note above */

  --r-sm:6px; --r:9px; --r-lg:14px; --r-pill:999px;
  --s1:4px; --s2:8px; --s3:12px; --s4:16px; --s5:20px; --s6:24px; --s8:32px; --s10:40px;
  --dur:220ms; --slow:700ms; --ease:cubic-bezier(.2,.7,.2,1);

  --dot:#12B39A;          /* brand mark — emerald, never the accent */
  --assist:#7C5CD6;       /* the assistant, and only the assistant */
  --measure:44rem;        /* reading width */

  /* type scale — eleven steps, nothing between them */
  --f0:11px;   --f1:12px;  --f2:13.5px; --f3:15px;  --f4:16px;  --f5:18px;
  --f6:22px;   --f7:27px;  --f8:34px;   --f9:46px;  --f10:58px;

  /* spacing ramp */
  --s12:48px; --s14:56px; --s16:64px; --s20:80px; --s22:88px; --s28:112px;
}
:root,[data-theme="light"]{
  /* Paper, not screen. 31 Aug (DESIGN-REVIEW-2 R1): the product is a lab's
     record, and a blue-grey ground read as instrument rather than notebook.
     #F4F1E9 is the WARMEST value where every text pair still clears AA —
     t3 lands at 4.57:1 and one step further (#F2EFE6) drops it to 4.49 and
     fails. Do not warm past this without re-checking t3.

     One caveat, checked rather than assumed: --t3 on --sunken computes to
     4.33:1, under AA. It is not a real failure — every sunken surface in this
     file explicitly sets --t2 or --t1 (card-ft, form .ff, tier .tag.q, the
     hovers), so that pairing does not occur. If you ever put --t3 on a sunken
     background, darken the ink; do not lighten the surface. */
  --page:#F4F1E9; --panel:#FFFFFF; --panel-2:#FBF9F4; --sunken:#EFEBE1;
  --t1:#181B22; --t2:#5A616E; --t3:#666E79;
  --line:#E6E1D5; --line-2:#D8D2C4;
  --acc:#0F7A6B; --acc-txt:#0B5F53; --acc-wash:#E8F6F3; --acc-ink:#FFFFFF;
  --band:#EDE7DA;   /* the closing field — deeper paper, never the accent wash */
  --assist-txt:#5B3FB0; --assist-wash:#F1EDFB;
  --warn:#9A6113; --warn-wash:#FBF1DF;
  --danger:#B23B33; --danger-wash:#FBEDEB; --danger-txt:#8E2E27;
  --sh:0 1px 2px rgba(16,24,40,.04),0 6px 16px -10px rgba(16,24,40,.12);
  --sh-lg:0 2px 4px rgba(16,24,40,.05),0 16px 32px -20px rgba(16,24,40,.18);
  --glow:none;
}
[data-theme="dark"]{
  --page:#0A1512; --panel:#0F1F1B; --panel-2:#132825; --sunken:#0C1A17;
  --t1:#F3F6F5; --t2:#B4C6C1; --t3:#8DA49E;
  --line:#1E322C; --line-2:#26403A;
  --acc:#12A594; --acc-txt:#5EE3CD; --acc-wash:rgba(18,165,148,.13); --acc-ink:#04181D;
  --band:#0D1F1B;
  --assist-txt:#C3AEF2; --assist-wash:rgba(124,92,214,.18);
  --warn:#E5B168; --warn-wash:rgba(154,97,19,.22);
  --danger:#F0938B; --danger-wash:rgba(178,59,51,.20); --danger-txt:#FBC9C4;
  --sh:0 1px 2px rgba(0,0,0,.3),0 6px 16px -10px rgba(0,0,0,.5);
  --sh-lg:0 2px 4px rgba(0,0,0,.35),0 16px 32px -20px rgba(0,0,0,.55);
  --glow:0 0 12px rgba(18,179,154,.7);
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --page:#0A1512; --panel:#0F1F1B; --panel-2:#132825; --sunken:#0C1A17;
    --t1:#F3F6F5; --t2:#B4C6C1; --t3:#8DA49E;
    --line:#1E322C; --line-2:#26403A;
    --acc:#12A594; --acc-txt:#5EE3CD; --acc-wash:rgba(18,165,148,.13); --acc-ink:#04181D;
    --band:#0D1F1B;
    --assist-txt:#C3AEF2; --assist-wash:rgba(124,92,214,.18);
    --warn:#E5B168; --warn-wash:rgba(154,97,19,.22);
    --danger:#F0938B; --danger-wash:rgba(178,59,51,.20); --danger-txt:#FBC9C4;
    --sh:0 1px 2px rgba(0,0,0,.3),0 6px 16px -10px rgba(0,0,0,.5);
    --sh-lg:0 2px 4px rgba(0,0,0,.35),0 16px 32px -20px rgba(0,0,0,.55);
    --glow:0 0 12px rgba(18,179,154,.7);
  }
}

/* ---------- base ---------- */
*{box-sizing:border-box}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{margin:0;background:var(--page);color:var(--t1);font-family:var(--sans);
  font-size:16px;line-height:1.6;-webkit-font-smoothing:antialiased}
img{max-width:100%;height:auto;display:block}
a{color:var(--acc-txt)}
:focus-visible{outline:2px solid var(--acc);outline-offset:2px;border-radius:2px}
.in{max-width:1140px;margin:0 auto;padding:0 32px}
/* .in-narrow shares .in's outer box so the LEFT EDGE never shifts between a
   wide pagehead and a narrow body. Reading width is applied to the content
   inside, not to the container — centring a narrower container inside a wider
   one moves the left margin by ~218px and reads as a broken jump. */
.in-narrow{max-width:1140px;margin:0 auto;padding:0 32px}
.in-narrow > *{max-width:var(--measure)}
.mono{font-family:var(--mono)}
.skip{position:absolute;left:-9999px;top:0;background:var(--acc);color:var(--acc-ink);
  padding:12px 18px;border-radius:0 0 var(--r) 0;z-index:200;text-decoration:none}
.skip:focus{left:0}
/* The reveal is deliberately almost nothing. 58 elements used to travel 14px
   over 700ms, which is motion everywhere — and motion everywhere reads as
   motion nowhere, while making the page feel longer than it is. Now they only
   resolve in opacity. The one element on the site that actually MOVES is the
   home-page tether drawing itself (section K), and it earns the attention
   precisely because nothing else competes for it. */
.rv{opacity:0;transition:opacity 340ms var(--ease)}
.rv.in{opacity:1}

/* ---------- brand ---------- */
.wm{font-family:var(--grotesk);font-size:18px;letter-spacing:-.02em;font-weight:500;
  display:inline-flex;align-items:center;color:var(--t1);text-decoration:none}
.wm span{font-weight:400;color:var(--t2)}
.wm i{width:.25em;height:.25em;border-radius:50%;margin-left:.25em;display:inline-block;
  background:var(--dot);font-style:normal;transform:translateY(-.28em);box-shadow:var(--glow)}
.ed{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t2)}
.eyebrow{font-family:var(--mono);font-size:11px;letter-spacing:.18em;text-transform:uppercase;color:var(--acc-txt)}

/* ---------- nav ---------- */
.site-nav{border-bottom:1px solid var(--line);background:var(--page)}
.site-nav .in{display:flex;align-items:center;gap:22px;padding-top:24px;padding-bottom:24px;flex-wrap:wrap}
.site-nav .links{margin-left:auto;display:flex;gap:26px;align-items:center;font-size:13.5px}
.site-nav .links a{text-decoration:none;color:var(--t2);transition:color var(--dur) var(--ease)}
.site-nav .links a:hover{color:var(--t1)}
.site-nav .links a[aria-current="page"]{color:var(--t1);font-weight:500}
.navtoggle{display:none;margin-left:auto;background:none;border:1px solid var(--line-2);
  border-radius:var(--r);width:44px;height:44px;cursor:pointer;color:var(--t1);font-size:18px}

/* ---------- buttons ---------- */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:9px;border-radius:var(--r);
  padding:14px 24px;font-size:15px;font-weight:500;text-decoration:none;border:1px solid transparent;
  cursor:pointer;transition:all var(--dur) var(--ease);min-height:50px;font-family:var(--sans)}
.bp{background:var(--acc);color:var(--acc-ink)} .bp:hover{filter:brightness(1.08)}
.bq{border-color:var(--line-2);color:var(--t1);background:var(--panel)} .bq:hover{background:var(--sunken)}
.bt{color:var(--t2);padding-left:4px;padding-right:4px} .bt:hover{color:var(--t1)}
/* The system had exactly ONE button size: 50px tall, 15px type. So a routing
   choice — "which mail app do you want" — rendered at the same weight as "Get
   free access", the site's primary conversion. Four of them in a row shouted.
   .sm is the compact tier for choices that are plumbing rather than a call to
   action.

   The height STAYS at 44px. The first attempt at this used 38px and the QA
   suite caught it — 44px is the touch-target minimum and a thing looking
   quieter is not a reason to make it harder to hit. The de-emphasis comes from
   type size and horizontal padding, which cost nothing in accessibility. */
.btn.sm{padding:10px 16px;font-size:13.5px;min-height:44px;gap:7px}

/* ---------- page furniture ---------- */
.band{padding:84px 0;border-top:1px solid var(--line)}
.band.alt{background:var(--panel)}
.band.first{border-top:0}
.bk{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;color:var(--t2);margin-bottom:14px}
h1,h2,h3,h4{letter-spacing:-.028em;font-weight:600;line-height:1.1}
/* D — the display voice. Space Grotesk was loading for one wordmark; it now earns its request. */
.hero h1,.pagehead h1,.band h2,.endcta h2,.oops h1,.centred-head h2{
  font-family:var(--grotesk);font-weight:500;letter-spacing:-.03em;text-wrap:balance}
.band h2{margin:0 0 16px;font-size:34px;max-width:20ch}
.band .lede{margin:0 0 40px;font-size:18px;color:var(--t2);max-width:60ch}
/* VERTICAL PADDING ONLY. .pagehead is carried on the SAME element as .in
   (`<div class="in pagehead">`), and a `padding` shorthand here would reset
   .in's `0 32px` to `0` — putting the page title 32px left of the header and
   of every band beneath it, on 19 pages. Same specificity, later rule wins.
   See the guard in build/qa.py. */
/* ---------- page head ------------------------------------------------------
   Measured 31 Aug 2026: the head reached 713px of a 1140px block, leaving 427px
   — 37% of the width — empty on the right of EVERY interior page, then the band
   below snapped to full width. Emptiness is not the problem; restraint is the
   brand. The problem was the transition: a half-width opening followed by a
   full-width band reads as unfinished rather than spacious, because nothing
   explains why the right side was left alone.

   Two changes. The head now carries an optional right-hand column holding one
   TRUE FACT about the page — the same register as the rest of the writing, not
   decoration — and the vertical is tightened so content starts higher. Pages
   without a fact keep the old single-column shape and simply sit tighter. */
.pagehead{padding-top:38px;padding-bottom:32px}
.pagehead .ph-grid{display:grid;grid-template-columns:minmax(0,1.35fr) minmax(210px,.65fr);
  gap:56px;align-items:end}
.pagehead .ph-fact{border-top:2px solid var(--acc);padding-top:14px;align-self:end}
.pagehead .ph-fact dl{margin:0;display:grid;gap:11px}
.pagehead .ph-fact dt{font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--t3);margin:0}
.pagehead .ph-fact dd{margin:2px 0 0;font-size:15px;color:var(--t1);line-height:1.4}
@media (max-width:860px){
  .pagehead .ph-grid{grid-template-columns:1fr;gap:26px;align-items:start}
  .pagehead .ph-fact{border-top-width:1px}
}
.pagehead h1{margin:14px 0 16px;font-size:46px;line-height:1.05;max-width:17ch}
.pagehead .lede{margin:0;font-size:18px;color:var(--t2);max-width:60ch;line-height:1.55}
.crumb{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t3)}
.crumb a{color:var(--acc-txt);text-decoration:none}

/* ---------- hero ---------- */
.hero{padding:44px 0 90px}
.hero .grid{display:grid;grid-template-columns:1.02fr .98fr;gap:64px;align-items:center}
.hero h1{font-size:58px;line-height:1.02;letter-spacing:-.037em;margin:20px 0 24px;max-width:14ch}
.hero h1 em{font-style:normal;color:var(--acc-txt)}
.hero .lede{font-size:18px;line-height:1.55;color:var(--t2);max-width:44ch;margin:0 0 34px}
.hero .cta{display:flex;gap:8px;flex-wrap:wrap;align-items:center}
.qual{width:100%;margin-top:18px;font-size:13.5px;color:var(--t2);display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.qual .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--acc-txt);border:1px solid var(--line-2);border-radius:var(--r-pill);padding:3px 10px;white-space:nowrap}

/* photo with product card overlapping — environment behind, message in front */
.stack{position:relative;padding-bottom:70px}
.stack .ph{border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh-lg)}
.stack .ph img{width:100%;aspect-ratio:4/3;object-fit:cover}
.stack .card{position:absolute;left:-6%;bottom:0;width:78%}

/* ---------- the claim card ---------- */
.card{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);
  box-shadow:var(--sh-lg);overflow:hidden}
.card-hd{padding:12px 18px;border-bottom:1px solid var(--line);font-size:12px;color:var(--t2);
  display:flex;align-items:center;gap:9px}
.card-hd .dm{width:6px;height:6px;border-radius:50%;background:var(--dot);box-shadow:var(--glow);flex:none}
.card-bd{padding:20px 18px}
.card-bd .stmt{font-size:18px;line-height:1.45;margin:0 0 18px}
.card-bd dl{display:grid;grid-template-columns:auto 1fr;gap:9px 16px;margin:0;font-size:13.5px;
  padding-top:16px;border-top:1px solid var(--line)}
.card-bd dt{color:var(--t3);white-space:nowrap}
.card-bd dd{margin:0;color:var(--t1)}
.card-ft{padding:13px 18px;border-top:1px solid var(--line);background:var(--sunken);
  font-size:13.5px;color:var(--t2)}
.card-ft b{color:var(--t1);font-weight:500}
/* Was an inline style="display:flex" on the element, which beat every class
   rule — including .card-ft[hidden] — so hiding this footer from script did
   nothing at all. Layout belongs here, where a guard can reach it. */
.card-ft.row{display:flex;gap:10px;align-items:center;flex-wrap:wrap}
.card.lg .card-bd{padding:24px 22px}
.card.lg .card-bd .stmt{font-size:18px}
.card.lg .card-bd dl{font-size:15px;gap:11px 18px}

/* ---------- photo grids ---------- */
.four{display:grid;grid-template-columns:repeat(4,1fr);gap:18px}
.four figure{margin:0}
.four .im{border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--sh);margin-bottom:14px}
.four img{width:100%;aspect-ratio:4/3;object-fit:cover;transition:transform 900ms var(--ease)}
.four figure:hover img{transform:scale(1.04)}
.four figcaption{font-size:15px;color:var(--t1);line-height:1.45}
.four figcaption em{display:block;font-style:normal;font-size:13.5px;color:var(--t2);margin-top:5px}

/* ---------- E2 · the four places ------------------------------------------
   Three rebuilds of this band were rejected, and each time I changed the
   pictures or the typography. The actual fault was that the LAYOUT ARGUED WITH
   THE COPY: four equal photographs in a tidy even row reads as "organised", and
   the heading directly above it says the record is scattered across four places
   that "never meet". Design and words were fighting, so the band felt wrong
   however good the parts were.

   So the row now enacts the sentence instead of contradicting it. Left to right
   the evidence disperses — each plate a little smaller, a little lower, a little
   further from its neighbour, a little less saturated — and the rule above each
   caption fades from signal teal to nothing.

   The fourth place has NO PHOTOGRAPH. "A drawer, a phone, a shared drive, a
   person" cannot be photographed; that is the whole point of the line. An empty
   plate says it better than a fourth grey control panel, and it fixes the real
   complaint about this band — that four near-identical machines read as one
   thing repeated. Three photographs, one absence.  30 Aug 2026. */
/* Widths carry only a little of the dispersal. The first pass shrank column 3
   to 220px, which wrapped "In settings someone remembers" onto two lines while
   its neighbours stayed on one — a ragged caption baseline reads as a mistake,
   not as drift. The work is done by the vertical step and the desaturation
   instead; the widths just lean. */
.four.scatter{grid-template-columns:1.12fr 1.04fr 1fr .96fr;gap:20px;align-items:start}
.four.scatter .p2{margin-top:14px}
.four.scatter .p3{margin-top:28px}
.four.scatter .p4{margin-top:36px}
/* The dispersal, in four steps. Kept shallow on purpose: enough to feel the
   drift, never enough to look like a rendering fault. */
.four.scatter .p2 img{filter:saturate(.86)}
.four.scatter .p3 img{filter:saturate(.7) opacity(.9)}
/* The rule above each caption — the connection weakening across the row. */
.four.scatter figcaption{position:relative;padding-top:15px}
.four.scatter figcaption::before{content:"";position:absolute;top:0;left:0;
  width:30px;height:2px;border-radius:1px;background:var(--acc)}
.four.scatter .p2 figcaption::before{background:var(--acc);opacity:.55}
.four.scatter .p3 figcaption::before{background:var(--line-2);width:22px}
.four.scatter .p4 figcaption::before{background:var(--line);width:14px}
/* The absence. Same plate, same corner radius, nothing inside it. */
.four.scatter .im.none{display:flex;align-items:center;justify-content:center;
  aspect-ratio:4/3;border:1.5px dashed var(--line-2);background:var(--panel-2);
  box-shadow:none;border-radius:var(--r-lg)}
.four.scatter .im.none span{font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--t3)}
@media (max-width:820px){
  /* Stacked, the drift has nothing to drift across — drop it and let the
     photographs run full width, where they read better than they do at 258px. */
  .four.scatter{grid-template-columns:1fr;gap:var(--s6)}
  .four.scatter .p2,.four.scatter .p3,.four.scatter .p4{margin-top:0}
  .four.scatter .p2 img,.four.scatter .p3 img{filter:none}
}

.split{display:grid;grid-template-columns:1fr 1.05fr;gap:60px;align-items:center}
.split h2{max-width:16ch}
.split p{font-size:18px;color:var(--t2);max-width:42ch;margin:0 0 26px}
.split img{width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:var(--r-lg);box-shadow:var(--sh-lg)}

/* ---------- steps / spine ---------- */
.steps{display:grid;grid-template-columns:repeat(5,1fr);gap:14px}
.step{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);padding:22px}
.step .n{font-family:var(--mono);font-size:11px;letter-spacing:.12em;color:var(--acc-txt);margin-bottom:12px}
.step.assist .n{color:var(--assist-txt)}
.step h3{margin:0 0 8px;font-size:16px}
.step p{margin:0;font-size:13.5px;color:var(--t2)}

/* ---------- doors ---------- */
.grid4{display:grid;grid-template-columns:repeat(4,1fr);gap:16px}
.door{display:block;text-decoration:none;background:var(--panel);border:1px solid var(--line-2);
  border-radius:var(--r-lg);padding:24px 22px;transition:border-color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.door:hover{border-color:var(--acc);transform:translateY(-3px)}
.door .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t3);margin-bottom:12px}
.door h3{margin:0 0 8px;font-size:18px;color:var(--t1)}
.door p{margin:0 0 14px;font-size:13.5px;color:var(--t2)}
.door .go{font-size:13.5px;color:var(--acc-txt);font-weight:500}

/* ---------- pricing ---------- */
.tiers{display:grid;grid-template-columns:repeat(4,1fr);gap:16px;align-items:stretch}
.tier{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);padding:24px;
  display:flex;flex-direction:column}
.tier.feature{border-color:var(--acc);box-shadow:0 0 0 3px var(--acc-wash),var(--sh)}
.tier .tag{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  color:var(--acc-txt);background:var(--acc-wash);padding:3px 9px;border-radius:var(--r-pill);align-self:flex-start;margin-bottom:12px}
.tier .tag.q{background:var(--sunken);color:var(--t2)}
.tier h3{margin:0 0 4px;font-size:18px}
.tier .for{font-size:12px;color:var(--t2);margin-bottom:18px;min-height:54px}
.price{display:flex;align-items:baseline;gap:5px;flex-wrap:wrap;margin-bottom:3px}
.price .amt{font-size:34px;font-weight:600;letter-spacing:-.035em;font-variant-numeric:tabular-nums;line-height:1}
.price .amt.free{color:var(--acc-txt)}
.price .per{font-size:13.5px;color:var(--t2)}
.sub-price{font-size:12px;color:var(--t2);min-height:34px;margin-bottom:18px}
.tier .cta .btn{width:100%;padding:12px;font-size:13.5px;min-height:46px}
.feat-h{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--t2);margin-bottom:10px}
ul.fl{list-style:none;margin:0;padding:0;font-size:13.5px}
ul.fl li{display:grid;grid-template-columns:14px 1fr;gap:8px;margin-bottom:9px;color:var(--t2);align-items:start}
ul.fl li .ck{color:var(--acc);font-size:11px;line-height:1.5}
ul.fl li b{color:var(--t1);font-weight:500}
ul.fl li.core{color:var(--t1)}





.fx{font-size:12px;color:var(--t2);margin:0}
.founding .tag{font-family:var(--mono);font-size:11px;letter-spacing:.13em;text-transform:uppercase;
  background:var(--acc);color:var(--acc-ink);padding:3px 9px;border-radius:var(--r-pill)}
.slots .cnt{font-family:var(--mono);font-size:11px;color:var(--acc-txt);margin-left:8px}

/* ---------- rows / tables ---------- */
.rows{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);overflow:hidden}
.rows .r{display:grid;grid-template-columns:1fr 1.2fr;gap:24px;padding:17px 22px;border-bottom:1px solid var(--line);align-items:baseline}
.rows .r:last-child{border-bottom:0}
.rows .strike{font-size:15px;color:var(--t2);text-decoration:line-through;
  text-decoration-color:var(--danger);text-decoration-thickness:1.5px}
.rows .why{font-size:13.5px;color:var(--t2)}
.rows .why b{color:var(--t1);font-weight:500}

/* ---------- FAQ ---------- */
.faq{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);overflow:hidden}
.faq details{border-bottom:1px solid var(--line)}
.faq details:last-child{border-bottom:0}
.faq summary{padding:16px 22px;cursor:pointer;font-size:15px;font-weight:500;list-style:none;
  display:flex;align-items:center;gap:12px;min-height:54px;transition:background var(--dur) var(--ease)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{background:var(--sunken)}
.faq summary::after{content:"+";margin-left:auto;font-family:var(--mono);color:var(--t2);font-size:18px}
.faq details[open] summary::after{content:"–"}
.faq .a{padding:0 22px 18px;font-size:15px;color:var(--t2);max-width:80ch}
.faq .a p{margin:0 0 10px} .faq .a p:last-child{margin:0}
.faq .a b{color:var(--t1);font-weight:500}

/* ---------- article ---------- */
.wrap{display:grid;grid-template-columns:minmax(0,var(--measure)) 1fr;gap:56px;align-items:start;padding-bottom:76px}
article{min-width:0;font-size:18px;line-height:1.7}
article h2{font-size:27px;margin:48px 0 14px;line-height:1.2;scroll-margin-top:24px}
article h3{font-size:18px;letter-spacing:-.014em;margin:32px 0 10px}
article p{margin:0 0 20px;color:var(--t2)}
article strong{color:var(--t1);font-weight:500}
article ul,article ol{margin:0 0 22px;padding-left:22px;color:var(--t2)}
article li{margin-bottom:10px}
article a{text-decoration:none;border-bottom:1px solid var(--acc-wash)}
article a:hover{border-bottom-color:var(--acc)}
article .lead{font-size:18px;color:var(--t1)}
.pull{border-left:3px solid var(--acc);padding:6px 0 6px 22px;margin:32px 0;font-size:22px;line-height:1.5;color:var(--t1)}
.note{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);padding:20px 22px;margin:32px 0}
.note .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t3);margin-bottom:10px}
.note p:last-child{margin:0}
.inline-cta{background:var(--panel);border:1px solid var(--line-2);border-left:3px solid var(--acc);
  border-radius:0 var(--r-lg) var(--r-lg) 0;padding:20px 22px;margin:36px 0}
.inline-cta .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--acc-txt);margin-bottom:9px}
.inline-cta p{margin:0 0 14px;font-size:15px}
aside{position:sticky;top:24px;font-size:13.5px}
aside .box{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);padding:18px 20px;margin-bottom:16px}
/* E3 · the table of contents is navigation, not a record artefact, and August's
   item C reserves the boxed treatment for record artefacts. Ruled instead. */
aside .ruled{padding:0 0 18px;margin-bottom:18px;border-bottom:1px solid var(--line)}

/* R4 · the photograph credit. This is the most trust-bearing sentence on the
   page — real benches, in a real lab — and it was set as a caption. The dot ties
   it to the brand mark; the second clause carries the claim it is making. */
.bleed .c .cd{display:inline-block;width:5px;height:5px;border-radius:50%;
  background:var(--dot);margin-right:9px;vertical-align:middle}
.bleed .c em{font-style:normal;color:var(--t3)}
aside .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t3);margin-bottom:12px}
aside .toc a{display:block;color:var(--t2);text-decoration:none;padding:6px 0 6px 12px;
  border-left:2px solid var(--line-2);transition:all var(--dur) var(--ease)}
aside .toc a:hover{color:var(--t1);border-left-color:var(--acc)}
aside .rel a{display:block;color:var(--t2);text-decoration:none;padding:9px 0;border-bottom:1px solid var(--line)}
aside .rel a:last-child{border-bottom:0}
aside .rel .t{color:var(--t1);display:block;margin-bottom:2px}

/* checklist */
.check{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);overflow:hidden;margin:32px 0}
.check-hd{padding:16px 22px;border-bottom:1px solid var(--line);display:flex;align-items:center;gap:10px;font-size:13.5px;font-weight:500}
.check-hd .dm{width:6px;height:6px;border-radius:50%;background:var(--dot);box-shadow:var(--glow)}
.check-hd .n{margin-left:auto;font-family:var(--mono);font-size:11px;color:var(--t3)}
.ci{display:grid;grid-template-columns:26px 1fr;gap:12px;padding:15px 22px;border-bottom:1px solid var(--line);
  font-size:15px;cursor:pointer;transition:background var(--dur) var(--ease)}
.ci:last-child{border-bottom:0}
.ci:hover{background:var(--panel-2)}
.ci .bx{width:19px;height:19px;border-radius:var(--r-sm);border:1.5px solid var(--line-2);margin-top:4px;
  display:flex;align-items:center;justify-content:center;font-size:11px;color:transparent;transition:all var(--dur) var(--ease)}
.ci.done .bx{background:var(--acc);border-color:var(--acc);color:var(--acc-ink)}
.ci.done .tx{color:var(--t3);text-decoration:line-through}
.ci .tx{color:var(--t1)}
.ci .tx em{display:block;font-style:normal;font-size:13.5px;color:var(--t2);margin-top:4px}

/* guide index cards */
.cards{display:grid;grid-template-columns:repeat(3,1fr);gap:20px}
.gcard{display:block;text-decoration:none;background:var(--panel);border:1px solid var(--line-2);
  border-radius:var(--r-lg);overflow:hidden;transition:border-color var(--dur) var(--ease),transform var(--dur) var(--ease)}
.gcard:hover{border-color:var(--acc);transform:translateY(-3px)}
.gcard img{width:100%;aspect-ratio:16/9;object-fit:cover}
.gcard .b{padding:20px 22px}
.gcard .k{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;color:var(--t3);margin-bottom:10px}
.gcard h3{margin:0 0 8px;font-size:18px;color:var(--t1)}
.gcard p{margin:0;font-size:13.5px;color:var(--t2)}
.gcard.soon{opacity:.62}
.gcard.soon:hover{transform:none;border-color:var(--line-2)}

/* ---------- proof + closing ---------- */
.proofline{padding:56px 0 0;display:flex;gap:24px;align-items:center;flex-wrap:wrap;border-top:1px solid var(--line);margin-top:64px}
.proofline .q{font-size:18px;line-height:1.5;color:var(--t1);max-width:50ch;flex:1 1 360px;margin:0}
.proofline .q .qm{color:var(--t3)}
.proofline .who{font-size:13.5px;color:var(--t2)}
.proofline .who b{display:block;color:var(--t1);font-weight:500;font-size:15px}
.company{padding:52px 0 0;font-size:15px;color:var(--t2)}
.company b{color:var(--t1);font-weight:500}
/* The closing band was --acc-wash (#E8F6F3, hue 167°) sitting on paper at hue
   44° — a 123° swing between the two largest colour fields on the page, and a
   cool mint slab in a site whose own tokens say "paper, not screen". The tint
   works at small scale, behind a notice or a badge, where it reads as an accent;
   full-bleed it reads as a different site.

   --band is a deeper paper in the same hue family (41°), one step below
   --sunken so the closing field is distinct from a panel. Verified AA: heading
   14.0:1, body 5.1:1, and the teal button still clears 4.2:1 on it.
   The teal stays where it belongs — the button and the tether mark. */
/* An informational notice, not a warning and not an accent field. It used to
   be --acc-wash across ~960px — the same cool-slab-on-warm-paper mistake as the
   closing band, twice more, and inline so no stylesheet check could see it.
   Ground stays paper; the teal does signal work as a rule at accent scale,
   which is the pattern the pull quote and the inline CTA already use. */
/* 15px, not the 14px the inline style used. That 14px was never on the type
   scale — it survived because inline styles are invisible to the scale check.
   Moving the rule into the stylesheet is what exposed it. */
.notice-line{max-width:960px;margin:0 auto 26px;padding:15px 20px;font-size:15px;
  color:var(--t1);background:var(--panel-2);border:1px solid var(--line);
  border-left:3px solid var(--acc);border-radius:0 var(--r) var(--r) 0;line-height:1.55}
.notice-line b{color:var(--t1)}

.endcta{text-align:center}
.endcta h2{margin:0 auto 16px;font-size:34px;max-width:22ch;line-height:1.12}
.endcta p{margin:0 auto 26px;font-size:16px;color:var(--t2);max-width:54ch}
.endcta .qual{justify-content:center;margin-top:18px}

/* ---------- footer ---------- */
.site-foot{border-top:1px solid var(--line);background:var(--panel);padding:44px 0 60px;margin-top:0}
.foot-grid{display:grid;grid-template-columns:1.4fr 1fr 1fr 1fr;gap:32px}
.foot-grid h4{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--t3);margin:0 0 14px;font-weight:500}
.foot-grid a{display:block;color:var(--t2);text-decoration:none;font-size:13.5px;padding:5px 0}
.foot-grid a:hover{color:var(--t1)}
.foot-grid p{margin:12px 0 0;font-size:13.5px;color:var(--t2);max-width:32ch}
.foot-base{margin-top:36px;padding-top:22px;border-top:1px solid var(--line);display:flex;gap:16px;
  align-items:center;flex-wrap:wrap;font-family:var(--mono);font-size:11px;color:var(--t3)}
.foot-base .rt{margin-left:auto}

/* ---------- 404 ---------- */
.oops{padding:120px 0;text-align:center}
.oops .code{font-family:var(--mono);font-size:12px;letter-spacing:.2em;color:var(--acc-txt);margin-bottom:20px}
.oops h1{font-size:46px;margin:0 auto 16px;max-width:20ch}
.oops p{font-size:18px;color:var(--t2);max-width:48ch;margin:0 auto 30px}

/* ---------- responsive ---------- */
@media (max-width:1000px){
  .tiers,.four,.grid4,.cards{grid-template-columns:repeat(2,1fr)}
  .steps{grid-template-columns:repeat(3,1fr)}
  .wrap{grid-template-columns:1fr;gap:0}
  aside{position:static;margin-top:40px}
}
@media (max-width:1000px){
  .hero .grid,.split{grid-template-columns:1fr;gap:44px}
}
@media (max-width:900px){
  .hero h1{font-size:34px;max-width:none}
  .band h2,.split h2{font-size:27px;max-width:none}
  .pagehead h1{font-size:34px} .endcta h2{font-size:22px}
  .stack{padding-bottom:0} .stack .card{position:static;width:100%;margin-top:16px}
  .foot-grid{grid-template-columns:1fr 1fr}
  /* The mobile bar must wrap — the dropdown is a second row — so the desktop
     nowrap is reversed here. And an absolutely-positioned CTA cannot clear the
     menu toggle at 375px, so on a phone it returns to the flow and the edition
     label yields to it. One of the two, never both. */
  .site-nav .links{display:none;order:3;width:100%;flex-direction:column;align-items:flex-start;gap:0}
  .site-nav .links.open{display:flex}
  .site-nav .links a{padding:12px 0;width:100%;border-bottom:1px solid var(--line)}
  .navtoggle{display:block}
  .rows .r{grid-template-columns:1fr;gap:8px}
}
@media (max-width:600px){
  .in-narrow>*{max-width:none}
  .tiers,.four,.grid4,.steps,.cards,.foot-grid{grid-template-columns:1fr}
  .in,.in-narrow{padding:0 22px}
  .hero h1{font-size:27px} .band{padding:56px 0}
}
@media (prefers-reduced-motion:reduce){
  *{transition:none!important;animation:none!important}
  .rv{opacity:1;transform:none}
  html{scroll-behavior:auto}
}
@media print{
  .site-nav,.site-foot,.endcta,aside{display:none}
  body{background:#fff;color:#000}
}

/* ---------- access form ---------- */
.opt{display:flex;align-items:center;gap:12px;padding:14px 16px;border:1px solid var(--line-2);
  border-radius:var(--r);margin-bottom:9px;cursor:pointer;font-size:15px;
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);min-height:52px}
.opt:hover{background:var(--sunken)}
.opt:has(input:checked){border-color:var(--acc);background:var(--acc-wash)}
.opt input{accent-color:var(--acc);width:18px;height:18px;flex:none}
.opt:focus-within{outline:2px solid var(--acc);outline-offset:2px}

/* ---------- visually-present section headings that carry structure ---------- */
.vh-visual{font-family:var(--mono);font-size:11px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--t2);margin:0 0 22px;font-weight:500}
.fh{font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--t3);margin:0 0 14px;font-weight:500}

/* ---------- :has() fallback for the access options ---------- */
@supports not selector(:has(*)){
  .opt input:checked{outline:2px solid var(--acc);outline-offset:3px}
}

/* =============================================================
   v2 — discovery funnel. Rhythm, full-bleed imagery, lead forms.
   ============================================================= */

/* ---------- band rhythm: not everything is 84px ---------- */
.band.tight{padding:52px 0}
.band.tall{padding:116px 0}
.band.flush{padding-top:0}

/* ---------- full-bleed photograph ---------- */
.bleed{position:relative;width:100%;overflow:hidden;background:var(--panel-2)}
.bleed img{width:100%;height:auto;aspect-ratio:2.4/1;max-height:520px;object-fit:cover;object-position:center}
.bleed .over{position:absolute;inset:auto 0 0 0;padding:64px 0 30px;
  background:linear-gradient(180deg,transparent,rgba(8,12,11,.82))}
.bleed .over .in{color:#EAF2EF}
.bleed .over p{margin:0;font-size:clamp(18px,2.4vw,27px);line-height:1.35;letter-spacing:-.02em;
  max-width:30ch;font-weight:500;color:#fff}
.bleed .over .c{margin-top:10px;font-size:12px;color:#B9CBC5}

/* ---------- the claim card as a recurring signature ---------- */
.card.sig{max-width:520px}
.card.sig .card-hd{background:var(--panel-2)}
.centre{display:flex;justify-content:center}

/* ---------- simple pricing ---------- */
.tiers.simple{grid-template-columns:repeat(3,1fr);gap:18px;max-width:960px;margin:0 auto}
.tiers.simple .tier{padding:28px 26px}
.tiers.simple .for{min-height:44px;font-size:13.5px}
.tiers.simple .price .amt{font-size:34px}
.tiers.simple ul.fl{font-size:13.5px}
.tiers.simple ul.fl li{margin-bottom:11px}
.inst-line{max-width:960px;margin:22px auto 0;padding:20px 26px;background:var(--panel);
  border:1px solid var(--line-2);border-radius:var(--r-lg);display:flex;gap:18px;
  align-items:center;flex-wrap:wrap;font-size:15px;color:var(--t2)}
.inst-line b{color:var(--t1);font-weight:500}
.inst-line a{margin-left:auto;white-space:nowrap}

/* ---------- lead forms ---------- */
.form-card{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);
  box-shadow:var(--sh);overflow:hidden;max-width:var(--measure)}
.form-card .fb{padding:26px 24px}
.fld{margin-bottom:18px}
.fld label{display:block;font-size:13.5px;color:var(--t2);margin-bottom:7px}
.fld label .opt-tag{color:var(--t3)}
.fld input,.fld select,.fld textarea{width:100%;padding:13px 15px;border:1px solid var(--line-2);
  border-radius:var(--r);background:var(--panel-2);color:var(--t1);font-size:16px;
  font-family:var(--sans);min-height:50px}
.fld textarea{min-height:104px;resize:vertical;line-height:1.5}
.fld input:focus,.fld select:focus,.fld textarea:focus{outline:2px solid var(--acc);outline-offset:1px;border-color:var(--acc)}
.form-card .ff{padding:16px 24px;border-top:1px solid var(--line);background:var(--sunken);
  display:flex;gap:12px;align-items:center;flex-wrap:wrap;font-size:12px;color:var(--t2)}
.form-card .ff .rt{margin-left:auto}
.two-up{display:grid;grid-template-columns:1fr 1fr;gap:0 18px}

/* ---------- security panel ---------- */
.sec-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:18px}
.sec-item{background:var(--panel);border:1px solid var(--line-2);border-radius:var(--r-lg);padding:24px}
.sec-item h3{margin:0 0 9px;font-size:16px}
.sec-item p{margin:0;font-size:13.5px;color:var(--t2)}

@media (max-width:1000px){ .tiers.simple,.sec-grid{grid-template-columns:1fr} }
@media (max-width:600px){ .two-up{grid-template-columns:1fr} .bleed img{height:clamp(220px,38vh,320px)} }

/* centred display heading.
   The measure MUST sit on the heading, not the wrapper: `ch` resolves against the
   element's own computed font-size, so a bare div resolves it at inherited 16px. */
.centred-head{text-align:center;margin:0 auto 40px}
.centred-head h2{max-width:26ch;margin-left:auto;margin-right:auto;text-wrap:balance}
@media (max-width:640px){.centred-head h2{max-width:none}}

/* ---------- coverage pages: instrument lookup, storage grid ---------- */
.lookup{max-width:var(--measure);margin:0 0 26px}
.lookup label{display:block;font-size:13.5px;font-weight:500;color:var(--t2);margin-bottom:7px}
.lookup input{width:100%;padding:14px 16px;border:1px solid var(--line-2);border-radius:var(--r);
  background:var(--panel);color:var(--t1);font-size:16px;font-family:var(--sans);min-height:52px}
.lookup input:focus{outline:2px solid var(--acc);outline-offset:1px;border-color:var(--acc)}
.lookup .cnt{margin-top:9px;font-size:13.5px;color:var(--t2)}

.igroup{margin-top:30px}
.igroup > h3{font-size:12px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;
  color:var(--t2);margin:0 0 10px;padding-bottom:8px;border-bottom:1px solid var(--line)}
.irow{display:grid;grid-template-columns:1.15fr 1fr auto;gap:14px;align-items:baseline;
  padding:11px 2px;border-bottom:1px solid var(--line)}
.irow .nm{font-size:15px;color:var(--t1)}
.irow .wr{font-size:13.5px;color:var(--t2);font-family:var(--mono)}
.pill{font-size:11px;font-weight:600;letter-spacing:.04em;text-transform:uppercase;
  padding:4px 9px;border-radius:var(--r-pill);white-space:nowrap;justify-self:end}
.pill.read{background:var(--acc-wash);color:var(--acc-txt)}
.pill.watch{background:var(--panel-2);color:var(--t2);border:1px solid var(--line-2)}
.igroup[hidden],.irow[hidden]{display:none}
.noresult{padding:22px 2px;color:var(--t2);font-size:15px}

.legend{display:flex;gap:20px;flex-wrap:wrap;margin:18px 0 4px;font-size:13.5px;color:var(--t2)}
.legend span{display:flex;gap:8px;align-items:center}

@media (max-width:700px){
  .irow{grid-template-columns:1fr auto;gap:6px 12px}
  .irow .wr{grid-column:1/2}
  .pill{grid-row:1/3;align-self:center}
}

/* ---------- legal documents ---------- */
.legal{font-size:16px;line-height:1.72}
.legal h2{font-size:18px;margin:38px 0 12px;padding-top:20px;border-top:1px solid var(--line)}
.legal h2:first-of-type{border-top:0;padding-top:0;margin-top:0}
.legal p{margin:0 0 14px;color:var(--t1)}
.legal ul{margin:0 0 16px;padding-left:22px}
.legal li{margin-bottom:8px;color:var(--t1)}
.legal a{color:var(--acc-txt)}
.legal hr{border:0;border-top:1px solid var(--line-2);margin:44px 0}
.legal-meta{font-size:13.5px;color:var(--t2);font-family:var(--mono)}
.legal-table{width:100%;border-collapse:collapse;margin:0 0 20px;font-size:15px}
.legal-table th{text-align:left;font-weight:500;color:var(--t2);font-size:12px;
  letter-spacing:.06em;text-transform:uppercase;padding:0 12px 9px 0;border-bottom:1px solid var(--line-2)}
.legal-table td{padding:11px 12px 11px 0;border-bottom:1px solid var(--line);vertical-align:top;color:var(--t1)}
.legal-table tr td:first-child{width:34%}
@media (max-width:600px){
  .legal-table,.legal-table tbody,.legal-table tr,.legal-table td{display:block;width:auto}
  .legal-table thead{display:none}
  .legal-table tr{padding:12px 0;border-bottom:1px solid var(--line-2)}
  .legal-table td{border:0;padding:2px 0}
  .legal-table tr td:first-child{width:auto;font-weight:500}
}
.foot-legal{display:flex;flex-wrap:wrap;gap:20px;margin-top:34px;padding-top:20px;
  border-top:1px solid var(--line-2)}
.foot-legal a{font-size:13.5px;color:var(--t2);text-decoration:none}
.foot-legal a:hover{color:var(--t1);text-decoration:underline}

/* ---------- form feedback ---------- */
.fld-err{display:block;margin-top:6px;font-size:13.5px;color:var(--danger)}
/* ---------- the completion panel ------------------------------------------
   One block, built inside the card body so it inherits the card's own gutter.
   Before this it was appended to the form root: the card's content sat 23px in
   from the edge and this sat at 1px, so the whole thing was 22px out of
   alignment — and it stacked two bordered, differently-coloured boxes inside an
   already-bordered card. Three nested containers where one panel was wanted.

   The summary now uses the dt/dd language the claim card and the page-head
   facts already use, so it reads as part of the site rather than as output. */
.sent{padding-top:20px;margin-top:22px;border-top:1px solid var(--line)}
.sent-pad{padding-left:22px;padding-right:22px;padding-bottom:22px}
.sent-lead{margin:0 0 18px;font-size:15px;line-height:1.55;color:var(--t2);max-width:56ch}

.sent-sum{margin:0 0 20px;display:grid;grid-template-columns:auto 1fr;
  gap:9px 20px;align-items:baseline}
.sent-sum dt{margin:0;font-family:var(--mono);font-size:11px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--t3);white-space:nowrap}
.sent-sum dd{margin:0;font-size:15px;color:var(--t1);line-height:1.45}

.send-choices{display:flex;flex-wrap:wrap;gap:10px;align-items:center}
.send-choices .btn{margin-top:0}

/* Kept only so the copy button has something to select. It used to be the
   biggest element on the screen — a monospace dump where the content goes. */
.form-copy{position:absolute;left:-9999px;width:1px;height:1px;opacity:0}

/* Start again, demoted. It was the primary teal button on the completion
   screen — the loudest thing on the page at the moment somebody had finished. */
.restart{display:inline-block;margin-top:18px;padding:0;border:0;background:none;
  font-family:var(--sans);font-size:13.5px;color:var(--t2);cursor:pointer;
  text-decoration:underline;text-underline-offset:3px}
.restart:hover{color:var(--t1)}
@media (max-width:520px){
  /* Four full-width buttons stacked is a 200px wall of teal and outline on a
     phone. Two columns keeps every target at 44px, keeps Gmail first and
     obvious, and halves the height. The label column in the summary goes above
     its value rather than beside it, because "People who would use it" beside a
     value at 375px leaves nothing for the value. */
  .send-choices{display:grid;grid-template-columns:1fr 1fr;gap:8px}
  .send-choices .btn{width:100%;justify-content:center;padding-left:8px;padding-right:8px}
  .sent-sum{grid-template-columns:1fr;gap:2px}
  .sent-sum dt{margin-top:12px}
  .sent-sum dd{font-size:16px}
  .sent-sum dt:first-child{margin-top:0}
}
@media (max-width:520px){
  .send-choices{flex-direction:column;align-items:stretch}
  .send-choices .btn{width:100%;text-align:center;justify-content:center}
}
.fld input[aria-invalid],.fld select[aria-invalid],.fld textarea[aria-invalid]{
  border-color:var(--danger);outline:1px solid var(--danger);outline-offset:-2px}
.form-msg{margin:16px 0 0;padding:12px 15px;border-radius:var(--r);font-size:15px;line-height:1.55}
.form-msg.ok{background:var(--acc-wash);color:var(--acc-txt);border:1px solid var(--acc)}
.form-msg.err{background:var(--danger-wash);color:var(--danger-txt);border:1px solid var(--danger)}
.form-msg.warn,.form-msg.busy{background:var(--panel-2);color:var(--t2);border:1px solid var(--line-2)}

/* =============================================================
   v4 — craft pass. Tether, ruled surface, accent moment,
   photo roles, staggered motion, spacing ramp.
   ============================================================= */

/* ---------- A · THE TETHER ------------------------------------
   The product's whole thesis is that a result stays attached to
   the evidence underneath it. Nothing in the visual language said
   so. This does: an accent rule carries the statement down into
   its provenance and terminates in the brand mark.
   It self-selects — it appears only where there IS provenance. */
.card-bd:has(dl){position:relative;padding-left:36px}
.card-bd:has(dl)::before{content:"";position:absolute;left:15px;top:7px;bottom:25px;width:2px;
  background:var(--acc);opacity:.42;border-radius:1px}
.card-bd:has(dl)::after{content:"";position:absolute;left:11.5px;bottom:16px;width:9px;height:9px;
  border-radius:50%;background:var(--dot);box-shadow:0 0 0 3px var(--acc-wash)}
@supports not selector(:has(*)){
  .card-bd{border-left:2px solid var(--acc-wash)}
}
/* the tether at page scale — the closing mark, on every page */
.tether-mark{display:block;width:2px;height:34px;margin:0 auto 22px;background:var(--acc);
  opacity:.42;border-radius:1px;position:relative}
.tether-mark::after{content:"";position:absolute;left:-4px;bottom:-12px;width:10px;height:10px;
  border-radius:50%;background:var(--dot);box-shadow:0 0 0 3px var(--acc-wash)}

/* ---------- C · THE RULED SURFACE -----------------------------
   Two treatments, not one. Ruled carries explanation. Boxed is
   reserved for record artefacts — so a claim card no longer looks
   like an FAQ. */
.faq,.rows{background:none;border:0;border-radius:0;border-top:1px solid var(--line-2)}
.faq details{border-bottom:1px solid var(--line)}
.faq summary{padding-left:0;padding-right:4px}
.faq .a{padding-left:0;padding-right:0}
.faq summary:hover{background:none;color:var(--acc-txt)}
.rows .r{padding-left:0;padding-right:0}
.rows{border-bottom:1px solid var(--line-2)}
.note{background:none;border:0;border-left:2px solid var(--acc);border-radius:0;
  padding:2px 0 2px 22px;box-shadow:none}
.sec-item{background:none;border:0;border-radius:0;border-top:1px solid var(--line-2);
  padding:18px 0 0;box-shadow:none}
.step{background:none;border:0;border-radius:0;border-top:2px solid var(--line-2);
  padding:18px 0 0;box-shadow:none}
.step:hover{border-top-color:var(--acc)}
/* boxed survives only for record artefacts and interactive objects */
.card,.tier,.gcard,.door,.form-card,.check,.founding{box-shadow:var(--sh)}
.card{box-shadow:var(--sh-lg)}

/* ---------- E · ONE ACCENT MOMENT PER PAGE --------------------
   The closing band. One per page, never two. */
.endcta{background:var(--band);border-top:1px solid var(--line-2);padding:var(--s20) 0}
.endcta h2{color:var(--t1)}
.endcta p{color:var(--t2)}

/* ---------- G · PHOTOGRAPHS BY ROLE ---------------------------
   Establishing = full bleed. Evidence = 4:3 in a grid, ruled not
   floated. Texture = small, square, inline. */
.four .im{box-shadow:none;border:1px solid var(--line);border-radius:var(--r)}
.split img{box-shadow:none;border:1px solid var(--line);border-radius:var(--r)}
.stack .ph{box-shadow:var(--sh)}
.gcard img{border-bottom:1px solid var(--line)}

/* ---------- I · CHOREOGRAPHED MOTION --------------------------
   A group arrives as a group, not as one block. The travel is gone (see .rv):
   the sequence now reads in opacity alone, and the delays are halved so a row
   of four resolves in under a third of a second rather than announcing itself. */
.rv.stagger>*{opacity:0;transition:opacity 320ms var(--ease)}
.rv.stagger.in>*{opacity:1}
.rv.stagger.in>*:nth-child(1){transition-delay:0ms}
.rv.stagger.in>*:nth-child(2){transition-delay:28ms}
.rv.stagger.in>*:nth-child(3){transition-delay:56ms}
.rv.stagger.in>*:nth-child(4){transition-delay:84ms}
.rv.stagger.in>*:nth-child(5){transition-delay:112ms}
.rv.stagger.in>*:nth-child(n+6){transition-delay:140ms}
@media (prefers-reduced-motion:reduce){
  .rv.stagger>*{opacity:1;transform:none;transition:none}
}

/* ---------- F · the spacing ramp, applied ---------------------- */
.band{padding:var(--s20) 0}
.band.tight{padding:var(--s12) 0}
.band.tall{padding:var(--s28) 0}
.band.flush{padding-top:0}
.hero{padding:var(--s10) 0 var(--s22)}
.pagehead{padding-top:var(--s14);padding-bottom:var(--s10)}   /* vertical only — see above */
.four,.grid4,.cards,.tiers{gap:var(--s4)}
.steps{gap:var(--s6)}
.site-foot{padding:var(--s10) 0 var(--s16)}
@media (max-width:600px){ .band{padding:var(--s14) 0} }
.ci .bx{border-radius:var(--r-sm)}

/* row label — a definition row, not a struck-through refusal */
.rows .r .lbl{font-size:var(--f3);color:var(--t1)}
.rows .r .lbl b{font-weight:500}
/* FAQ answers written as bare paragraphs, not wrapped in .a */
.faq details>p{margin:0 0 16px;padding:0;font-size:var(--f3);color:var(--t2);max-width:80ch}

/* ---------- specificity repair --------------------------------
   `.vh-visual` is a quiet structural section label, not a display
   heading. It is an <h2> inside a .band, so `.band h2` outranked
   it on font-size (and, once Space Grotesk was promoted, on
   font-family too) — a single class can never beat a descendant
   selector. Matched here at equal specificity, placed last. */
h2.vh-visual{
  font-family:var(--mono);
  font-size:var(--f0);
  font-weight:500;
  letter-spacing:.16em;
  text-transform:uppercase;
  color:var(--t2);
  line-height:1.4;
  max-width:none;
  margin:0 0 22px;
}

/* ---------- scientific advisors ------------------------------
   PARKED 30 Aug 2026 — rules live in build/parked/advisors.css until the
   advisors page returns. See CHASE-LIST.md item 2.
   ------------------------------------------------------------- */

/* ---------- instrument groups, collapsed ---------------------
   Six headings fit one screen. Search opens what matches. */
.igroup{border-bottom:1px solid var(--line)}
.igroup:first-of-type{border-top:1px solid var(--line-2)}
.igroup>summary{display:flex;align-items:center;gap:14px;padding:16px 2px;cursor:pointer;
  list-style:none;min-height:56px;transition:background var(--dur) var(--ease)}
.igroup>summary::-webkit-details-marker{display:none}
.igroup>summary:hover{background:var(--panel-2)}
.igroup>summary::after{content:"+";margin-left:auto;font-family:var(--mono);
  font-size:var(--f5);color:var(--t3);line-height:1;padding-right:4px}
.igroup[open]>summary::after{content:"\2013"}
.igroup[open]>summary{background:var(--panel-2)}
.igroup .gt{font-family:var(--mono);font-size:var(--f0);letter-spacing:.08em;
  text-transform:uppercase;color:var(--t1);font-weight:500}
.igroup .gc{font-family:var(--mono);font-size:var(--f1);color:var(--t3);
  background:var(--sunken);border-radius:var(--r-pill);padding:2px 9px}
.grows{padding:2px 0 14px}

/* ============================================================================
   J · THE HEADER THAT PAYS RENT
   ----------------------------------------------------------------------------
   Sticky, but it earns the pixels rather than simply claiming them.

   At rest it is the full 73px introduction: wordmark, edition, five links.
   Past the first screen it condenses to 60px and changes job — the edition
   chip retires (you only need introducing once) and the section label takes
   its exact slot, so the header narrates position instead of identity. One
   slot, two states, no extra width.

   The call to action arrives only once the hero's own button has left the
   viewport, so it is never redundant with what is already on screen. That
   restraint is the whole idea: the header offers what the page can't.
   ========================================================================== */
/* The header has ONE size and ONE appearance, at every scroll position.
   FINAL, 31 Aug 2026 — defect QA-001, third and last iteration.

   It used to shrink its padding from 24px to 8px on scroll. That is a height
   change on a sticky element, animated, and it is the last thing that was still
   visibly moving after the label and CTA swaps were removed. Three attempts at
   an animated header produced three different visible defects. There is no
   fourth attempt: the state is gone, not tuned.

   What holds it together without any state:
   · background is var(--page), fully opaque — text passing under is never
     legible through it, which is what the blur was compensating for
   · border-bottom (set in the base rule) separates it from the content
   · no transition, no class, no JS, nothing to get out of sync

   Height is therefore constant: 24 + content + 24 + 1px border. */
.site-nav{position:sticky;top:0;z-index:90}
/* ---------------------------------------------------------------------------
   The header does not change on scroll.  DECIDED 31 Aug 2026 — defect QA-001.

   It used to swap three things as you scrolled: the edition label out, a
   section label in, a CTA in. Two attempts to animate that failed in two
   different ways — the first clipped the text mid-word, the second put an
   absolutely-positioned button on top of the nav links. Both shipped a visibly
   broken bar on the highest-traffic element of the site.

   So the swap is gone, not fixed. The header is one thing at every scroll
   position: wordmark, edition label, links. It stays sticky, because these
   pages are long and losing the nav on the way down is a real cost — but
   nothing inside it moves, resizes or fades.

   What went with it, and why it is affordable:
   · the section label — wayfinding, but every band already carries a heading
   · the sticky CTA — every page ends in a CTA band, and the hero has one
   --------------------------------------------------------------------------- */
.site-nav .ed{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;flex-shrink:1;min-width:0}
.site-nav .wm,.navtoggle{flex-shrink:0}

/* ============================================================================
   K · THE TETHER AT VIEWPORT SCALE
   ----------------------------------------------------------------------------
   The site already owns one device: a rule that runs from a claim down to the
   evidence beneath it, ending in a dot. It marks provenance on cards, and it
   closes every page.

   Here it becomes the scroll indicator. The rule fills as you read and the dot
   travels at its leading edge, so the page is tethered to itself in exactly the
   way the product tethers a conclusion to its evidence. It costs no layout
   space and repeats the one idea the site is built on — which is what makes a
   thing memorable, rather than adding a fourth flourish.
   ========================================================================== */
.tether-rail{position:fixed;left:0;top:0;bottom:0;width:2px;z-index:95;
  pointer-events:none;background:var(--line)}
.tether-rail i{position:absolute;left:0;top:0;width:2px;height:0;display:block;
  background:var(--acc);opacity:.5}
.tether-rail i::after{content:"";position:absolute;left:-3.5px;bottom:-4px;
  width:9px;height:9px;border-radius:50%;background:var(--dot);
  box-shadow:0 0 0 3px var(--acc-wash)}

/* THE ONE DELIBERATE MOMENT.
   The home-page hero card is the site's argument in miniature: a statement,
   and the record underneath it. Its tether draws itself, once, on load — the
   rule descending, then the dot arriving at the foot. It is the only element
   on the site that moves, and it says the thing the copy is trying to say. */
.hero .card-bd:has(dl)::before{animation:tether-draw 900ms var(--ease) 260ms both}
.hero .card-bd:has(dl)::after{animation:tether-land 380ms var(--ease) 1060ms both}
@keyframes tether-draw{from{transform:scaleY(0)}to{transform:scaleY(1)}}
@keyframes tether-land{from{opacity:0;transform:scale(.4)}to{opacity:1;transform:scale(1)}}
.hero .card-bd:has(dl)::before{transform-origin:top}

/* ============================================================================
   E1 · THE WALK
   ----------------------------------------------------------------------------
   POSITIONING.md 1.1: "the emotional payload of this product is not the list —
   it's the walk: click a published statement, drop to the run, drop to the raw
   file." The card used to show the destination. Now a stranger can perform it.

   Three states: the claim, the run beneath it, the file beneath that. The
   tether needs no extra code to follow — it spans the card body, so every step
   revealed makes it grow down to the evidence. That is the whole gesture: the
   rule reaching further as the claim is traced to its source.

   Without JavaScript every step is already open and the button never appears,
   so the card degrades to exactly what it was before.
   ------------------------------------------------------------------------- */
.wstep[hidden]{display:none}
.wstep + .wstep{margin-top:14px}
.walk .wstep.just{animation:wstep-in 240ms var(--ease) both}
@keyframes wstep-in{from{opacity:0}to{opacity:1}}
.wmore{display:inline-flex;align-items:center;gap:8px;margin-top:16px;padding:4px 0;
  background:none;border:0;cursor:pointer;font-family:var(--mono);font-size:var(--f0);
  letter-spacing:.11em;text-transform:uppercase;color:var(--acc-txt);
  transition:color var(--dur) var(--ease)}
.wmore::after{content:"\2193";font-size:12px}
/* an author `display` beats the [hidden] attribute — without this the button
   stays on screen after the last step. Same trap as .wstep above. */
.wmore[hidden]{display:none}

/* THE SAME TRAP, THIRD TIME. An author `display` beats the [hidden] attribute,
   so `el.hidden = true` silently does nothing on any element this file gives a
   display to. .card-ft is display:flex, so hiding the completion-screen footer
   in JS had no effect and "Start again" stayed the loudest button on the page.
   Any element hidden from script needs a guard like this one. */
.card-ft[hidden]{display:none}
.wmore:hover{color:var(--acc)}
.walk .wdone{margin:16px 0 0;font-family:var(--mono);font-size:var(--f0);letter-spacing:.11em;
  text-transform:uppercase;color:var(--t3)}
@media (prefers-reduced-motion:reduce){.walk .wstep.just{animation:none}}

/* ============================================================================
   L · THE UNDERLINE GROWS FROM A POINT
   ----------------------------------------------------------------------------
   The highest-frequency interaction on the site, so it is where a house style
   is actually learned. A body link rests on a hairline; on hover an accent
   underline is drawn left to right from a small dot at its origin — the same
   gesture as the tether, at the scale of a single word.
   ========================================================================== */
main p a,main li a,main dd a,main .why a,main .lede a,main figcaption a{
  color:var(--acc-txt);text-decoration:none;padding-bottom:2px;
  -webkit-box-decoration-break:clone;box-decoration-break:clone;
  background-image:linear-gradient(var(--acc),var(--acc)),
                   linear-gradient(var(--line-2),var(--line-2));
  background-repeat:no-repeat,no-repeat;
  background-position:0 100%,0 100%;
  background-size:0 1.5px,100% 1px;
  transition:background-size var(--dur) var(--ease)}
main p a:hover,main li a:hover,main dd a:hover,main .why a:hover,
main .lede a:hover,main figcaption a:hover,
main p a:focus-visible,main li a:focus-visible,main dd a:focus-visible,
main .why a:focus-visible,main .lede a:focus-visible,main figcaption a:focus-visible{
  background-size:100% 1.5px,100% 1px}
/* the point the underline is drawn from */
main p a,main li a,main dd a,main .why a,main .lede a{position:relative}
main p a::before,main li a::before,main dd a::before,
main .why a::before,main .lede a::before{
  content:"";position:absolute;left:-6px;bottom:1px;width:3px;height:3px;
  border-radius:50%;background:var(--dot);opacity:0;
  transition:opacity var(--dur) var(--ease)}
main p a:hover::before,main li a:hover::before,main dd a:hover::before,
main .why a:hover::before,main .lede a:hover::before{opacity:.65}
/* buttons keep their own treatment */
main p a.btn,main li a.btn,main .lede a.btn{background-image:none;padding-bottom:14px}
main p a.btn::before,main li a.btn::before,main .lede a.btn::before{display:none}

/* The header row must not wrap. The container caps at 1140px, so above that the
   available width is a fixed 1076px no matter how wide the window is — and
   wordmark + label + five links + CTA can exceed it. Wrapping would push the
   links onto a second line and make the PINNED header taller than the resting
   one, which is the failure this whole section exists to avoid. So: no wrap,
   and the label is the element that yields, by ellipsis. It is the only piece
   here that is decorative rather than functional, so it is the right one to cut. */
@media (min-width:901px){
  .site-nav .in{flex-wrap:nowrap}
  .site-nav .links{flex:none}
}

/* Anchor targets must clear the pinned header, or a jump to #ilook lands the
   heading underneath it. */
:target,[id]{scroll-margin-top:84px}
aside{top:88px}
@media (max-width:900px){
  /* the mobile menu expands INSIDE the header, so it must not be pinned —
     an open menu taller than the viewport would otherwise be unscrollable. */
  .site-nav{position:static}
  .tether-rail{display:none}
}
@media (prefers-reduced-motion:reduce){
  .tether-rail i::after{transition:none}
  .hero .card-bd:has(dl)::before,.hero .card-bd:has(dl)::after{animation:none}
}
@media print{
  .tether-rail{display:none}
}

/* ============================================================================
   M · COLUMN COUNTS THAT COLLAPSE
   ----------------------------------------------------------------------------
   These replace four inline `style="grid-template-columns:…"` declarations.
   An inline style beats EVERY media query no matter how specific the selector,
   so those four grids never collapsed: import.html held three columns at 360px
   and overflowed the viewport by 74px, and the others stayed at three and four
   squeezed columns on a phone.

   The lesson is the same one .pagehead taught two hours ago — a more specific
   declaration silently defeating the layout system, valid the whole time. There
   is a guard in build/qa.py for both.
   ========================================================================== */
.cols-3{grid-template-columns:repeat(3,1fr)}
.cols-4{grid-template-columns:repeat(4,1fr)}
@media (max-width:900px){ .cols-3,.cols-4{grid-template-columns:repeat(2,1fr)} }
@media (max-width:600px){ .cols-3,.cols-4{grid-template-columns:1fr} }

/* ---------- N · THE HEADER ON A PHONE ------------------------------------
   At 360px the row was [wordmark][ACADEMIC EDITION][menu] = 372px of content in
   316px of space, so it wrapped and the header stood 144px tall — 19% of the
   screen before a word of content. Tighter padding, and the edition retires on
   the narrowest screens where the wordmark alone has to carry the brand. */
@media (max-width:900px){
  .site-nav .in{padding-top:14px;padding-bottom:14px}
}
@media (max-width:420px){
  /* Was display:none, which left the phone showing only "woodle.cloud" — no
     indication of WHICH woodle product, on the surface with least context.
     Restored 30 Aug 2026 in a shortened form. The header defect this file
     fought for three rounds came from animating the bar on scroll, not from
     this label; the bar is a fixed size now and the label cannot reflow it. */
  .site-nav .ed{font-size:9.5px;letter-spacing:.10em}
  .site-nav .ed .ed-long{display:none}
}

/* The headline is two statements, not one — the black half states the good news
   and the teal half turns it. On desktop the line breaks fall between them, so
   the colour change lands at the start of a line and the turn reads. Below
   ~520px "Just" was being pulled up onto the end of the black line, so the
   colour changed mid-sentence and the two halves stopped reading as two halves.
   Give the second statement its own line at those widths. 30 Aug 2026. */
@media (max-width:520px){
  .hero h1 em{display:block}
}
