/* midbench.com — site layer (site.v11.css)
   v11 (2026-08-23, owner call): the CHAT-FIRST two-up. From 80rem the ask
   card is the wide column (1fr / 1.4fr, was 1.55fr / 1fr hub-first) and
   the connect column runs the portrait SPOTLIGHT build the phones ship
   (the loader in index.html flips it on this same 80rem query, progress
   carried); the card's width follows the viewport height (84.4vh/11.9rem
   cap = the measured page chrome folded through the card's 560x600
   aspect), so every height fits one viewport and the old anim-only
   root-size corridors are REMOVED — with the height-capped card the
   two-up floors now hold at EVERY regime (1280x700 included, the old
   recorded exception). Chat body measures 15.1-22.7px across the fits
   (was 13.4-16.9); spotlight labels 15.7-19.6px.
   v10 (2026-08-23, owner call on Claude's mobile-only recommendation): the
   MOBILE CAPTURE BAND. Below 56rem the email form leaves the hero for a
   quiet full-bleed strip at the very top of the page (input + button on
   one line; <= 21.25rem stacks) so the two animated facts reach the first
   phone screen. Same DOM, same one form, zero-JS :target error path
   intact; >= 56rem is untouched — the h1 + form hero unit stays (the
   desktop demos are width-locked, a band there would only demote the CTA).
   The old 34rem form-stacking rule retired with it. Everything else is v9
   unchanged.
   v9 (2026-08-23, owner call): ONE wordmark on the page. While the
   animations play (html.anim) the header hides — its wordmark would be
   the second "midbench" on the page — and the connect comp's hub wordmark,
   now set in the brand green (the favicon's colour; animation data
   .v4.js -> .v5.js, connect only changed, ask rewrapped byte-identical),
   is the page's one brand mark. The static page (no JS / reduced motion:
   the hub never mounts) keeps its header wordmark, so there is always
   exactly one; every other page keeps its header (the wordmark is their
   way home). The ≥80rem block no longer tunes the hidden header's shell.
   Everything else is v8 unchanged.
   v8 (2026-08-23): the stacked page's vertical rhythm (owner ask: the two
   fact labels must carry the same air above them, and sit the same way on
   their content). Below 56rem one unit, --fact-gap (3.5rem), sets the air
   between the hero form and "1 Connect.", between fact 1's last ink and
   "2 Ask.", and under the last fact before the footer (before: 88px over
   "1 Connect." against 41px over "2 Ask." on a phone); under .anim the
   connect canvas's transparent authored margins leave the flow (negative
   stage margins) so the label sits 1rem over the wordmark's ink the way
   "2 Ask." sits 0.75rem over its card edge (before: 50px vs 6px). The
   56–80rem stacked band mirrors its hero-to-facts air between the facts
   and pulls the landscape canvas's margins the same way. The ≥80rem two-up
   page and the static side-by-side page are untouched (the hub there sits
   centred on the card's height; one-viewport law holds). Everything else
   is v7 unchanged.
   v7 (2026-08-19): the portrait connect comp tucks its mini provider strip
   close under the spotlight (owner ask: on phones the air above the strip
   must read smaller than the page's gap to the "2 Ask." label), so the
   canvas cropped 360x430 -> 360x368 and the stage aspect follows; the
   animation data scripts are the .v4.js set (same-day cents + blank-fix
   passes ride the same deploy). Everything else is v6 unchanged.
   v6 (2026-08-19): the animations reach phones —
   the loader now serves a portrait build of each animation below 56rem
   (assets/{connect,ask}-{landscape,portrait}-{light,dark}.v2.js), so the
   stages carry per-breakpoint aspect ratios (portrait below 56rem,
   landscape above) and the 2026-08-18 phone stopgap (static page below
   56rem) is gone. Between the phones and the breakpoint the portrait
   stages cap near their authored size: growth past a 430-class phone goes
   to air, not scale. Everything else is v5 unchanged.
   v5 (2026-08-18): version bump for deploy — same layer, now carrying the
   2026-08-16 one-viewport pass and the 2026-08-18 animation-mode rules
   (the deployed v4 object is immutable-cached, so changes ride a new name).
   Layers on kit/tokens.v1.css (palette "Ledger", Plex subsets, focus ring) —
   link the kit first, then this file. Zero JS, zero third-party requests.
   v4 (2026-08-14): minimalist revision — one narrow column, wordmark-only
   header (no nav, no ≡ mark), hero → two facts (Connect + connector chips /
   Ask = the transcript, nested in the li) → closer. Email form keeps the
   zero-JS :target error path.
   Same-day polish (owner ask): connector chips carry vendored brand marks
   (kit/connectors/, inlined as symbols in index.html), accent period on the
   h1, soft shadow on the transcript card, input hover; the two facts sit
   side by side from 56rem up (.shell-wide widens that section to --page).
   2026-08-16 (owner ask): the closer form is gone — one form, in the hero —
   and desktop aims for a single viewport: vh-scaled hero/section padding +
   a tighter transcript from 56rem up, sticky footer (body flex column).
   2026-08-18: the two facts animate — the vendored Lotties (tools/lottie/)
   become the visible content of Connect and Ask whenever html carries
   .anim (scripting on + motion OK; head script in index.html). The static
   chips and transcript stay in the markup as the no-JS / reduced-motion
   page. Animated layout: phones give the stages the full shell width, mid
   widths stack them centered, and from 80rem the facts sit side by side
   under a wider (86rem) cap. Same day, later (owner asks): header shell
   full width (wordmark top-left), and under .anim the fact labels center
   over their animations (number bubble inline, gutter gone).
   Same day, later still (the desktop floor pass): both landscape
   compositions are authored larger (connect tiles 75 / labels 17.5, ask
   body 20.3), so the .anim rules stop granting the transcript its roomy
   desktop padding, the stacked caps widen a notch, and the animated two-up
   page tightens its vertical chrome so the raised comps still hold one
   viewport; the static page keeps the 2026-08-16 tuning untouched. */

/* ---- base ---- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 var(--fs-1)/1.6 var(--font);
  /* sticky footer: main grows, so short pages still put the footer at the
     bottom and the one-viewport desktop layout has no gap above it */
  min-height: 100vh; min-height: 100svh;
  display: flex; flex-direction: column;
}
main { flex: 1; display: flex; flex-direction: column; justify-content: center; }
h1, h2, p, ol, ul, figure, figcaption { margin: 0; }
img, svg { max-width: 100%; }
a { color: var(--accent); text-underline-offset: 0.15em; }
strong { font-weight: 600; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; }
}

/* the whole site is one narrow column */
.shell { max-width: 44rem; margin: 0 auto; padding-inline: clamp(1.25rem, 5vw, 2rem); }
/* ...except the facts section, which widens so the two facts can sit side by
   side on desktop (the wider cap is invisible while they stack: .facts keeps
   its own 36rem cap below the two-column breakpoint) */
.shell-wide { max-width: var(--page); }

/* ---- header: the wordmark, nothing else ----
   The header shell spans the full page (owner ask 2026-08-18): the narrow
   shell used to put the wordmark center-left on desktop; it reads top-left
   now, on every page. */
.site-header .shell { max-width: none; padding-block: 1.6rem; }
.brand { color: var(--text); display: inline-flex; }
a.brand:hover { color: var(--accent); }
.brand .wordmark { height: 1rem; width: auto; display: block; }

/* ---- buttons ---- */
.btn {
  display: inline-block;
  background: var(--accent); color: var(--on-accent);
  font: 600 0.95rem/1.6 var(--font); text-decoration: none;
  padding: 0.55rem 1.05rem; border: 0; border-radius: var(--r);
  cursor: pointer;
  transition: filter 120ms ease;
}
.btn:hover { filter: brightness(1.12); }
.btn:active { filter: brightness(0.95); }

/* ---- email capture form (zero-JS :target error path) ---- */
.access-form { display: flex; gap: 0.6rem; max-width: 28rem; margin: 2rem auto 0; }
.access-form input[type="email"] {
  flex: 1; min-width: 0;
  font: 400 var(--fs-1)/1.4 var(--font);
  color: var(--text); background: var(--bg);
  padding: 0.55rem 0.85rem;
  border: 1px solid var(--border); border-radius: var(--r);
  transition: border-color 120ms ease;
}
.access-form input[type="email"]:hover { border-color: var(--muted); }
.access-form input[type="email"]::placeholder { color: var(--muted); opacity: 1; }
.access-form .btn { white-space: nowrap; }
.hp { position: absolute; left: -9999px; }   /* honeypot — off-screen, not display:none */
.form-error { display: none; }
:target > .form-error {
  display: block; margin-top: 0.8rem; font-size: 0.95rem; font-weight: 600;
  text-align: left;
  background: var(--surface); border-left: 3px solid var(--accent);
  border-radius: 0 var(--r) var(--r) 0;
  padding: 0.5rem 0.8rem;
}

/* ---- hero ---- */
.hero { text-align: center; padding-block: clamp(4.5rem, 13vw, 8.5rem) 2rem; }
.hero h1 {
  font-size: var(--fs-4); font-weight: 600; line-height: 1.1;
  letter-spacing: -0.02em; text-wrap: balance;
}
.hero h1 .dot { color: var(--accent); }

/* ---- the mobile capture band (owner ask 2026-08-23, on Claude's
   mobile-only recommendation): below 56rem the email form leaves the hero
   and becomes a quiet announcement-style strip at the very top — input and
   button on ONE line — so the two animated facts reach the first phone
   screen (hub wordmark y=341 -> y=223 at 390x844, measured). Same DOM, one
   form: the hero's shell turns flex and #try-again takes order -1, pulled
   full-bleed with the centred-container margin trick, so the zero-JS
   :target error path keeps working (the error renders as a second row in
   the strip, on page bg for contrast against the strip's surface). On the
   static page the strip sits under the wordmark header like a normal
   announcement bar. Desktop (>=56rem) keeps the h1 + form hero unit: the
   demos there are width-locked (measured hub top 270 -> 269 in the band
   mock), so a band would only demote the page's one CTA. Only the tiniest
   phones (<= 21.25rem: the 320 class clips the placeholder at ~111px input)
   stack the strip's form to two rows. */
@media (max-width: 55.99rem) {
  .hero { padding-top: 0; }
  .hero .shell { display: flex; flex-direction: column; }
  .hero h1 { margin-top: clamp(3.5rem, 9vw, 6rem); }
  #try-again {
    order: -1;
    margin-inline: calc(50% - 50vw);   /* full-bleed out of the centred shell */
    background: var(--surface);
    border-bottom: 1px solid var(--border);
    padding: 0.55rem clamp(1rem, 4vw, 1.5rem);
  }
  .access-form { margin: 0 auto; max-width: 30rem; }
  .access-form input[type="email"] { padding: 0.4rem 0.7rem; }
  .access-form .btn { padding: 0.45rem 0.9rem; font-size: 0.85rem; }
  :target > .form-error { background: var(--bg); margin: 0.6rem auto 0.2rem; max-width: 30rem; }
}
@media (max-width: 21.25rem) {
  .access-form { flex-direction: column; align-items: stretch; }
}

/* ---- sections ---- */
/* The stacked page (below 56rem: phones and portrait tablets) runs on ONE
   vertical unit, --fact-gap: the air between the hero form and "1 Connect.",
   the air between fact 1's last ink and "2 Ask.", and the air under the last
   fact before the footer are all the same 3.5rem (owner ask 2026-08-23: the
   two fact labels carry equal air above them — before, a phone showed 88px
   over "1 Connect." against 41px over "2 Ask."). The hero keeps a fixed 2rem
   under its form; the section's top padding supplies the rest. From 56rem
   up the one-viewport block below overrides all of this. */
.section { --fact-gap: 3.5rem; padding-block: calc(var(--fact-gap) - 2rem) var(--fact-gap); }

/* ---- transcript — the chat box that IS fact 2 ("Ask") ---- */
.transcript {
  margin: 0.9rem 0 0; text-align: left;
  background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r-lg);
  padding: clamp(1.1rem, 3vw, 1.6rem);
  display: flex; flex-direction: column; gap: 1.1rem;
  box-shadow: 0 1px 2px rgb(28 27 25 / 4%), 0 16px 40px -20px rgb(28 27 25 / 18%);
}
@media (prefers-color-scheme: dark) {
  .transcript { box-shadow: 0 1px 2px rgb(0 0 0 / 35%); }
}
.turn { max-width: 88%; }
.turn.you {
  align-self: flex-end; text-align: left;
  background: var(--bg); border: 1px solid var(--border); border-radius: 10px;
  padding: 0.55rem 0.9rem;
}
.turn.books { align-self: flex-start; }
.turn.books p { font-size: 0.98rem; }
.amt { font-family: var(--mono); font-variant-numeric: tabular-nums; font-size: 0.94em; }
.tx-wrap { overflow-x: auto; margin-top: 0.6rem; }
.tx { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.tx td { padding: 0.4rem 0; border-top: 1px solid var(--border); vertical-align: baseline; }
.tx td:first-child { color: var(--muted); white-space: nowrap; padding-right: 1rem; }
.tx td:last-child {
  text-align: right; font-family: var(--mono); font-variant-numeric: tabular-nums;
  white-space: nowrap; padding-left: 1rem;
}
.tx tr.total td { font-weight: 600; color: var(--text); }

/* one continuous session: the conversations flow top to bottom inside a
   scrollable window, so the card itself never grows and the one-viewport
   desktop layout holds. The window height shows the whole verbatim capture
   plus the top of the next question, which keeps the scroll affordance
   visible; keyboard users reach it via tabindex on .convos. */
.convos {
  display: flex; flex-direction: column; gap: 1.1rem;
  max-height: 40rem;
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
  scrollbar-color: var(--border) transparent;
}
.convos::-webkit-scrollbar { width: 8px; }
.convos::-webkit-scrollbar-track { background: transparent; }
.convos::-webkit-scrollbar-thumb { background: var(--border); border-radius: 4px; }
.convo { display: flex; flex-direction: column; gap: 1.1rem; }

/* the PDF the financials answer hands over — a bare row, deliberately
   unboxed: on this page boxes mean questions (the right-aligned bubbles),
   so answer-side content never gets one. The icon is the one spot of
   non-palette color: the classic red-and-white PDF mark. */
.file {
  display: inline-flex; align-items: center; gap: 0.55rem;
  margin-top: 0.5rem;
}
.file-ic { width: 1.75rem; height: 1.75rem; fill: #E2231A; flex: none; }
.file-text { display: grid; line-height: 1.35; }
.file-name { font-weight: 600; font-size: 0.92rem; }
.file-meta { font-size: 0.8rem; color: var(--muted); }

/* the composer bar at the foot of the chat — decorative (the site ships no JS) */
.ask-bar {
  display: flex; align-items: center; gap: 0.6rem;
  background: var(--bg);
  border: 1px solid var(--border); border-radius: 10px;
  padding: 0.45rem 0.45rem 0.45rem 0.9rem;
}
.ask-q {
  flex: 1; min-width: 0;
  font-size: 0.95rem; line-height: 1.5;
  color: var(--muted);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.ask-go {
  flex: none; width: 1.7rem; height: 1.7rem; padding: 0.4rem;
  background: var(--accent); fill: var(--on-accent); border-radius: 50%;
}

/* ---- the two facts (Connect / Ask) ---- */
.facts {
  list-style: none; counter-reset: fact; padding: 0;
  margin: 0 auto; max-width: 36rem;
  display: grid; gap: var(--fact-gap, 1.6rem); text-align: left;
}
/* side by side on desktop, stacked below — the Ask column gets the wider
   share so the transcript wraps less and the whole page stays one screen */
@media (min-width: 56rem) {
  .facts {
    max-width: none;
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
    gap: 2rem 3rem;
    align-items: start;
  }
}
.facts > li { counter-increment: fact; position: relative; padding-left: 2.4rem; color: var(--muted); }
.facts > li::before {
  content: counter(fact);
  position: absolute; left: 0; top: 0.1em;
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.55rem; height: 1.55rem; border-radius: 50%;
  border: 1.5px solid var(--accent); color: var(--accent);
  font-size: 0.8rem; font-weight: 600; font-variant-numeric: tabular-nums;
}
.facts strong { color: var(--text); }

/* connector chips under "Connect" — each mark + name. Marks are vendored
   official artwork (kit/connectors/ — sources in its README), inlined as
   <symbol>s in index.html so the site stays self-contained: no hand-drawn
   brand marks, nothing hotlinked. Deel is a lettermark tile in the site's
   own type until official art exists. */
.sprite { display: none; }
.connectors {
  list-style: none; padding: 0; margin: 0.9rem 0 0;
  display: flex; flex-wrap: wrap; gap: 0.45rem;
  font-size: 0.82rem; line-height: 1.4;
}
.connectors li {
  display: inline-flex; align-items: center; gap: 0.42em;
  padding: 0.26rem 0.7rem 0.26rem 0.55rem; border-radius: 999px; white-space: nowrap;
  color: var(--accent);
  border: 1px solid var(--border);
  background: var(--surface);
}
.connectors .ci { width: 1.08em; height: 1.08em; fill: currentColor; flex: none; }
@supports (background: color-mix(in srgb, red 5%, white)) {
  .connectors li {
    background: color-mix(in srgb, var(--accent) 6%, var(--bg));
    border-color: color-mix(in srgb, var(--accent) 30%, var(--border));
  }
}

/* ---- the fact animations (html.anim: scripting on, motion OK) ----
   Vendored Lotties become the facts' visible content under html.anim,
   one build per breakpoint side (the loader in index.html picks it on
   this same 56rem query): Connect floats bare on the page background
   (assets/connect-landscape-*.v5.js, 900x560, from 56rem;
   connect-portrait-*.v5.js, 360x368, below), Ask plays inside the same
   transcript card (assets/ask-landscape-*.v5.js, 560x600, transparent;
   ask-portrait-*.v5.js, 360x560). The static chips and transcript stay in
   the markup underneath — they are the no-JS / reduced-motion page, and
   the tools/lottie generators parse them at build time, so never remove
   them. Stages carry the mounted build's aspect ratio up front, per
   breakpoint: booting and breakpoint swaps never shift layout. */
.stage { display: none; }
.anim .stage { display: block; width: 100%; }
.anim .stage svg { display: block; }
.stage-connect { aspect-ratio: 360 / 368; margin-top: 0.9rem; }
.stage-ask { aspect-ratio: 360 / 560; }
@media (min-width: 56rem) {
  .stage-connect { aspect-ratio: 900 / 560; }
  .stage-ask { aspect-ratio: 560 / 600; }
}
.anim .connectors, .anim .convos, .anim .ask-bar { display: none; }

/* one wordmark on the page (owner call 2026-08-23): while the hub plays,
   the header — the wordmark alone since the v4 revision — hides, and the
   connect comp's green hub wordmark is the brand mark. The header markup
   stays: it IS the static page's brand (no JS / reduced motion never
   mount the hub), and the generators parse its wordmark path. Only the
   homepage ever carries html.anim, so every other page keeps its header. */
.anim .site-header { display: none; }

/* the fact labels sit centered over their animations (owner ask
   2026-08-18): the number bubble leaves its absolute gutter and rides
   inline with the word, so the stages span the full column */
.anim .facts > li { padding-left: 0; text-align: center; }
.anim .facts > li::before {
  position: static;
  display: inline-flex;
  vertical-align: middle;
  margin-right: 0.55rem;
}

/* every width: the card slims its padding so the demo renders as large as
   the screen allows (>=56rem this overrides the one-viewport 1rem/1.25rem
   card padding — the animation carries its own internal air), and the
   centered fact label sits closer to the card */
.anim .transcript { padding: 0.8rem; margin-top: 0.4rem; }

/* below the breakpoint the portrait builds serve. Both are authored 360
   wide for the phone stages (280–387px, scales 0.78–1.08), so between the
   430-class phones and 56rem the stages stop growing near authored size
   and center instead — a 744 tablet at full shell width would render the
   type half again larger than the static page's and the composition
   cartoonish. Caps: connect 24rem (384px stage, scale 1.07); the ask
   stage sits inside the card's 0.8rem padding + 1px borders, so the CARD
   caps at 24.25rem to land the stage at ~360px (scale 1.0) — capping the
   stage alone would strand the animation in a wide empty card. */
@media (max-width: 55.99rem) {
  .anim .stage-connect {
    max-width: 24rem; margin-inline: auto;
    /* the portrait canvas's own transparent margins leave the flow: 36
       authored px above the wordmark (10% of its 360 width) and 15.5 under
       the mini strip (4.3%), each capped at its 24rem-stage size. So the
       label sits 1rem over the wordmark's ink while "2 Ask." sits 0.75rem
       over its card edge (bold text over bold text wants the extra notch;
       the two read as the same attachment), and --fact-gap runs ink to ink
       (owner ask 2026-08-23; before, "1 Connect." floated 50px over the
       wordmark while "2 Ask." sat 6px over the card). Nothing in the comp
       ever paints in those margins (the wordmark only pulses in place, the
       dot rides the wire below it), so the overlap with the label line is
       invisible. */
    margin-top: calc(1rem - min(10%, 2.4rem));
    margin-bottom: calc(0rem - min(4.3%, 1.03rem));
  }
  .anim .transcript { max-width: 24.25rem; margin-inline: auto; margin-top: 0.75rem; }
}

/* mid widths: side by side would starve both animations, so the animated
   facts stack, each at its own comfortable width (the static page keeps
   its 56rem two-up — this only retunes the animated one). Caps widened a
   notch by the authored raise: the stacked band scrolls anyway, and the
   extra width keeps the squat 14.5px tier above the legibility floors.
   The band runs to 80rem (not the pre-raise 76rem): between 76 and 80rem
   the two-up columns fall under the 86rem cap's width, and the raised
   comps' floors only clear at cap-width columns — 80rem is also where the
   one-viewport law's desktop rectangle (1280px) begins. */
@media (min-width: 56rem) and (max-width: 79.99rem) {
  .anim .facts {
    max-width: 49rem; grid-template-columns: none;
    /* stacked here too, so the fact-to-fact air mirrors the hero-to-facts
       air (the one-viewport block's hero bottom + section top, vh-scaled) */
    gap: calc(clamp(1rem, 2.2vh, 1.75rem) + clamp(1.25rem, 2.8vh, 2.5rem));
  }
  .anim .stage-connect {
    /* the landscape canvas's transparent margins leave the flow the same
       way: 47 authored px over the top tiles (5.2% of its 900 width), 33
       under the bottom labels (3.65%) */
    margin-top: calc(1rem - 5.2%);
    margin-bottom: -3.65%;
  }
  .anim .transcript { max-width: 36rem; margin-inline: auto; margin-top: 0.75rem; }
  /* no header above it here (v9), and this band scrolls: give the headline
     the phone's kind of top air instead of the one-viewport block's */
  .anim .hero { padding-top: 4rem; }
}

/* from 80rem the two facts sit side by side under a wider cap — and since
   2026-08-23 (owner call) the CHAT is the wide column: the ask card is the
   product, the connect fact is the means. The old 1.55:1 hub-first share
   existed only because the landscape hub goes sub-legible under ~700px and
   the width-locked card outgrew short screens; both dissolve here — the
   connect column runs the portrait SPOTLIGHT build the phones ship (the
   loader flips it at this same 80rem query; 26rem cap, floors clear with
   room), and the card takes exactly the width the viewport HEIGHT allows
   (its 560x600 aspect makes width a function of height under the
   one-viewport law): the 84.4vh/11.9rem line is the measured page chrome
   above and below the card (vh-scaled paddings + rem-sized h1/form/label/
   footer) folded through that aspect, so the card always lands a few px
   inside the fold and the old root-size corridors (12.75/14.5 forcing
   bands) are gone — no height needs them now. The spotlight's canvas air
   leaves the flow like everywhere else (36/360 over the wordmark, capped
   at the 26rem stage's 2.6rem). */
@media (min-width: 80rem) {
  .anim .shell-wide { max-width: 86rem; }
  .anim .facts { grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr); gap: 2rem 3.5rem; }
  .stage-connect { aspect-ratio: 360 / 368; }
  .anim .stage-connect {
    max-width: 26rem; margin-inline: auto;
    margin-top: calc(1rem - min(10%, 2.6rem));
  }
  .anim .transcript {
    margin-inline: auto;
    max-width: min(100%, max(20rem, 84.4vh - 11.9rem));
    max-width: min(100%, max(20rem, 84.4svh - 11.9rem));
  }
}

/* the raised comps are taller in the column, so the animated two-up page
   tightens its vertical chrome to keep holding one viewport (the static
   page keeps the 2026-08-16 tuning: everything here is .anim-scoped) */
@media (min-width: 80rem) {
  .anim .hero { padding-block: clamp(1.1rem, 3.8vh, 3.5rem) clamp(0.75rem, 1.8vh, 1.75rem); }
  .anim .section { padding-block: clamp(0.9rem, 2vh, 2.5rem); }
  .anim .site-footer .shell { padding-block: 0.75rem; }
}
/* ---- footer ---- */
.site-footer { border-top: 1px solid var(--border); }
.site-footer .shell {
  padding-block: 1.8rem; font-size: 0.85rem; color: var(--muted);
  text-align: center; display: grid; gap: 0.5rem;
}
.site-footer nav { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.4rem 1.2rem; }
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--accent); }

/* ---- one-viewport desktop ----
   From the two-column breakpoint up, the whole page aims to fit one screen:
   hero/section padding scales with viewport height (floors keep it from
   collapsing), the transcript tightens a notch. Below 56rem nothing changes —
   the stacked mobile page scrolls as before. */
@media (min-width: 56rem) {
  .site-header .shell { padding-block: 1.1rem; line-height: 1; }
  .hero { padding-block: clamp(1.5rem, 4.6vh, 3.5rem) clamp(1rem, 2.2vh, 1.75rem); }
  .access-form { margin-top: 1rem; }
  .section { padding-block: clamp(1.25rem, 2.8vh, 2.5rem); }
  .transcript { padding: 1rem 1.25rem; gap: 0.55rem; line-height: 1.5; }
  .convo, .convos { gap: 0.55rem; }
  .convos { max-height: 22.5rem; }
  .turn { max-width: 94%; }
  .turn.you { padding: 0.45rem 0.8rem; }
  .tx { line-height: 1.4; }
  .tx td { padding-block: 0.2rem; }
  .site-footer .shell {
    max-width: var(--page);
    padding-block: 1.1rem;
    display: flex; flex-wrap: wrap; justify-content: space-between;
    align-items: baseline; gap: 0.4rem 1.5rem; text-align: left;
  }
}
/* squat windows (wide but short): scale the whole rem grid down a notch
   rather than cutting any one thing — media-query rems use the 16px initial
   size, so the breakpoints themselves don't move */
@media (min-width: 56rem) and (max-height: 51.25rem) {
  html { font-size: 14.5px; }
}
@media (min-width: 56rem) and (max-height: 43.75rem) {
  html { font-size: 12.75px; }
}
.prose { padding-block: 2.6rem 4rem; }
.prose h1 { font-size: 1.55rem; font-weight: 600; letter-spacing: -0.015em; }
.prose h2 { font-size: 1.1rem; font-weight: 600; margin-top: 2.2rem; margin-bottom: 0.5rem; }
.prose p, .prose ul { margin-top: 0.7rem; }
.prose li { margin-top: 0.45rem; }
.prose li::marker { color: var(--muted); }
.prose .meta { font-size: 0.85rem; color: var(--muted); }

/* ---- simple centered pages (404, thanks) ---- */
.simple { text-align: center; padding-block: clamp(4rem, 14vw, 8rem); }
.simple h1 { font-size: var(--fs-3); font-weight: 600; }
.simple p { color: var(--muted); margin-top: 0.7rem; max-width: 34rem; margin-inline: auto; }
.simple a { display: inline-block; margin-top: 1.4rem; }
