/* ==========================================================================
   AdminLess — mnc.adminless.ai, the landing page

   One page, eight sections. Promoted out of _sandbox/mnc-design-mockup/
   mnc.css on 2026-09-14: the preset picker is gone and the `defaults` from
   its Remote.init are baked in — colour `boardroom`, type `fraunces`, copy
   `assured`. Colour and type are still read from custom properties, so a
   re-skin is one block in §1, but nothing at runtime writes them.

   Tokens, gutters, section rhythm, buttons, credentials and reveal motion
   come from tokens.css (imported before this file). This page may not
   redefine them. Its one declared exception (website/LANDING_PAGES.md): the
   h1 is 76px, not the family's 72, because the timeline sits under it and a
   larger h1 pushes the strip off a 900px viewport. Below 880 it steps to the
   shared mobile --h1 (44px).

   ⚠ NO INLINE STYLE ANYWHERE IN index.html. The nginx.conf beside this file
   serves `style-src 'self'` with no 'unsafe-inline', which blocks a style=""
   attribute exactly as hard as a <style> block. The mockup's per-element
   animation delays (--wd / --gd / --dd) were style attributes; they are
   classes here (§7). Anything new follows them into this file.

   House rules honoured in CSS, not just in copy:
     · the timeline is drawn once, in the hero, and has no second appearance;
     · every section below it carries a different kind of evidence, so the
       only section motion below the hero is the shared 12px reveal;
     · no opacity on a meaningful graphic — the run bar is told apart by its
       dash pattern, never by a washed-out colour that would drop under 3:1.
   ========================================================================== */

/* --------------------------------------------------------------------------
   0. Type, self-hosted. No Google Fonts request: `font-src 'self'` forbids
      it, and a third-party font origin hands that third party the IP address
      of every visitor to a page that sets no cookie and shows no banner.
      Fraunces is variable, so one file per subset covers 400 and 500; the
      italic is a separate file and carries the h1's second beat and every
      accented phrase in an h2.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: Fraunces;
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/fraunces-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Fraunces;
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/fraunces-var-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: Fraunces;
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/fraunces-var-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: Fraunces;
  font-style: italic;
  font-weight: 400 500;
  font-display: swap;
  src: url("fonts/fraunces-var-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/plex-sans-var-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Sans";
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("fonts/plex-sans-var-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/plex-mono-400-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/plex-mono-400-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/plex-mono-500-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url("fonts/plex-mono-500-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   1. The baked preset: colour `boardroom`, type `fraunces`. These were the
      mockup remote's defaults; the remote is gone, so this block is now the
      only place the palette and the pairing are written. Every rule below
      still reads them through the custom properties, so a re-skin is an edit
      here and nowhere else.
   -------------------------------------------------------------------------- */

:root {
  --paper:   #FFFFFF;
  --paper-2: #F7F8FA;   /* raised surface */
  --paper-3: #ECEFF4;   /* recessed surface */
  --ink:     #101C2E;
  --accent:  #27506F;   /* steel blue */
  --accent-deep: #17384F;
  --accent2: #27506F;
  --accent2-ink: #27506F;
  --muted:   #9AA3AE;   /* hairlines and decoration, never text */
  --muted-ink: #54606E; /* muted at text sizes */
  --rule:    #DBE0E7;
  --on-accent: #FFFFFF;
  --logo-blend: multiply;
  --logo-filter: none;

  /* The one colour the preset never supplied: an invalid form field has to
     be told apart from a valid one by something other than the accent, and
     the accent is the only non-neutral in this palette. 7.4:1 on the paper,
     so it is AA at any size. It is a red, not a green — "never a green on
     this page" (LANDING_PAGES.md) is about the brand accent and stands. */
  --error:   #A3231D;

  --font-display: Fraunces, "Iowan Old Style", Georgia, serif;
  --font-body: "IBM Plex Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --font-label: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
  --display-weight: 400;
  --display-weight-strong: 500;
  --display-style: normal;
}

/* --------------------------------------------------------------------------
   2. Reset and page shell. The page IS the frame this round: no dark stage,
      paper runs to the edge of the window.
   -------------------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--body);
  line-height: 1.55;
}

img { max-width: 100%; display: block; }

/* one global focus treatment for every interactive element on the page */
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 20;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--font-label);
  font-size: 13px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 12px 18px;
  text-decoration: none;
}
.skip:focus { left: 0; }

.page {
  position: relative;
  width: 100%;
  max-width: 1440px;
  margin: 0 auto;
  background: var(--paper);
}

/* The hero's registration crosses sit 7px proud of the wrap, so on a 375px
   screen they can poke past the document edge. Clip horizontally at the
   page edges — never a scroll — while vertical motion stays untouched.
   (clip, not hidden: a clip box never becomes a scroll container, so the
   sticky nav and the reveal transforms keep behaving.) */
html, body { overflow-x: clip; }

/* Fine paper grain — inline feTurbulence, ~3.5%. Decorative, never a photo. */
.page::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='g'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='4' stitchTiles='stitch'/></filter><rect width='200' height='200' filter='url(%23g)'/></svg>");
}

/* Content width from the shared tokens: 1152px measure, side padding from
   --gutter (136.5px at 1440, 28px below 880). */
.wrap {
  position: relative;
  width: 100%;
  max-width: calc(var(--measure) + 2 * var(--gutter));
  padding: 0 var(--gutter);
  margin: 0 auto;
}

/* registration-mark crosshairs, on the hero grid only */
.regs { position: absolute; inset: 0; pointer-events: none; z-index: 2; }
.regs i { position: absolute; width: 13px; height: 13px; }
.regs i::before,
.regs i::after { content: ""; position: absolute; background: var(--rule); }
.regs i::before { left: 6px; top: 0; width: 1px; height: 13px; }
.regs i::after  { top: 6px; left: 0; height: 1px; width: 13px; }
.regs i:nth-child(1) { left: -7px;  top: -7px; }
.regs i:nth-child(2) { right: -7px; top: -7px; }
.regs i:nth-child(3) { left: -7px;  bottom: -7px; }
.regs i:nth-child(4) { right: -7px; bottom: -7px; }

/* --------------------------------------------------------------------------
   3. Type primitives — sizes from the shared tokens, never redefined here
   -------------------------------------------------------------------------- */

.eyebrow {
  font-family: var(--font-label);
  font-size: var(--label);
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-ink);
  margin: 0 0 22px;
}
.eyebrow--accent { color: var(--accent); }

/* Declared exception (LANDING_PAGES.md): the token is 72px; this page clamps
   to 76px — the timeline sits under the h1, and 72 would push it off a 900px
   viewport. Below 880px it steps to the shared mobile --h1 (44px). */
.h1 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: var(--display-weight);
  font-style: var(--display-style);
  font-size: 76px;
  line-height: 0.98;
  letter-spacing: -0.022em;
  margin: 0;
  color: var(--ink);
}
/* Two beats, one per line — the headline never wraps mid-phrase. */
.h1 span { display: block; }
.h1 em { font-style: italic; color: var(--accent2); font-weight: var(--display-weight); }

.h2 {
  font-family: var(--font-display);
  font-optical-sizing: auto;
  font-weight: var(--display-weight);
  font-style: var(--display-style);
  font-size: var(--h2);
  line-height: 1.1;
  letter-spacing: -0.014em;
  margin: 0;
  color: var(--ink);
  max-width: 22ch;
}
.h2 em { font-style: italic; color: var(--accent2-ink); }

.h3 {
  font-family: var(--font-display);
  font-weight: var(--display-weight-strong);
  font-style: var(--display-style);
  font-size: var(--h3);
  line-height: 1.22;
  letter-spacing: -0.008em;
  margin: 0;
  color: var(--ink);
}

.lede { font-size: var(--body); line-height: 1.6; margin: 22px 0 0; color: var(--ink); max-width: 50ch; }
.body { font-size: var(--body); line-height: 1.62; color: var(--ink); margin: 0; }
.small { font-size: var(--label); line-height: 1.55; color: var(--muted-ink); margin: 0; }

.mono {
  font-family: var(--font-label);
  font-size: var(--label);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted-ink);
}

/* --------------------------------------------------------------------------
   4. Nav and buttons — mono uppercase dialect (frozen); hit boxes ≥ 44px
   -------------------------------------------------------------------------- */

.navbar {
  position: sticky;
  top: 0;
  z-index: 8;
  background: var(--paper);
  border-bottom: 1px solid var(--rule);
}

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  row-gap: 10px;
  min-height: 64px;
  padding: 8px 0;
}

.nav__mark {
  font-family: var(--font-label);
  font-size: 14px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.nav__mark span { color: var(--accent); }

.nav__links { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 20px; }

/* every anchor carries a 44px-tall hit box, whether it is a text link or
   the filled CTA — the family floor, not a per-element decision */
.nav__links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.nav__links a:not(.btn) {
  font-family: var(--font-label);
  font-size: var(--label);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted-ink);
  text-decoration: none;
  padding: 0 2px;
  border-bottom: 1px solid transparent;
  white-space: nowrap;
}
.nav__links a:not(.btn):hover { color: var(--ink); border-bottom-color: var(--accent); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: var(--btn-h);
  padding: 12px 22px;
  border-radius: 2px;
  border: 1px solid transparent;
  font-family: var(--font-body);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}
/* a label swap must not change the primary button's shape */
.btn--primary { min-width: var(--btn-min); }

.btn--primary { background: var(--accent); color: var(--on-accent); }
.btn--primary:hover { background: var(--accent-deep); }

.btn--ghost { border-color: var(--rule); color: var(--ink); background: transparent; }
.btn--ghost:hover { border-color: var(--accent); color: var(--accent); }

.btn--sm { font-size: var(--label); padding: 10px 16px; }

.cta-row { display: flex; align-items: center; gap: 18px; margin-top: 34px; flex-wrap: wrap; }

/* --------------------------------------------------------------------------
   5. Section scaffolding + the shared reveal
   -------------------------------------------------------------------------- */

.sec { position: relative; border-top: 1px solid var(--rule); }
.sec__inner { padding: var(--section-pad) 0; }
.sec--tint { background: var(--paper-2); }

.sec__head {
  display: grid;
  grid-template-columns: 1fr 420px;
  gap: 72px;
  align-items: end;
  padding-bottom: 46px;
}
.sec__head p { margin: 0; }

/* The shared motion system (shared/motion.js) watches every [data-reveal]
   and flips it to .is-in once, on first reach; under reduced motion it
   jumps straight to the final state, so nothing below is ever undone.
   Gated on html.js: a JS-off reader gets every band in its finished state. */
html.js [data-reveal] {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--reveal-dur) ease, transform var(--reveal-dur) ease;
}
html.js [data-reveal].is-in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal] { opacity: 1; transform: none; transition: none; }
}

/* --------------------------------------------------------------------------
   6. Hero — trimmed to fit a 900px viewport: eyebrow, two-line h1, lede,
      CTA row, then the timeline. The credential band no longer lives here;
      the full seven-mark row appears once, in #work.
   -------------------------------------------------------------------------- */

.hero { padding: 44px 0 28px; }
.hero__copy { max-width: 900px; }
.hero .lede { max-width: 54ch; font-size: calc(var(--body) + 2px); }

.hero__fig {
  position: relative;
  margin: 30px 0 0;
  padding: 0 0 8px;
  container: fig / inline-size;
}
.hero__fig svg { width: 100%; height: auto; display: block; }

.replay {
  position: absolute;
  right: 0;
  top: -34px;
  appearance: none;
  background: none;
  border: 1px solid var(--rule);
  border-radius: 2px;
  padding: 6px 10px;
  font-family: var(--font-label);
  font-size: 10.5px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-ink);
  cursor: pointer;
}
.replay:hover { color: var(--accent); border-color: var(--accent); }

/* --------------------------------------------------------------------------
   7. The signature visual — the project timeline, drawn once
      Bars are thick stroked paths normalised to pathLength="1", so one
      dash-offset animation wipes each band left to right.
   -------------------------------------------------------------------------- */

.tl-cap {
  font-family: var(--font-label);
  font-size: 10.5px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  fill: var(--muted-ink);
}
.tl-axis { stroke: var(--rule); stroke-width: 1; fill: none; }
.tl-grid { stroke: var(--rule); stroke-width: 1; }
.tl-week {
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  fill: var(--ink);
}
.tl-name {
  font-family: var(--font-label);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  fill: var(--accent);
}
.tl-sub {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  fill: var(--muted-ink);
}
.tl-bar {
  fill: none;
  stroke: var(--accent);
  stroke-width: 22;
  stroke-linecap: butt;
}
/* User units, not pathLength fractions: this band is excluded from the
   dash-offset draw (it is wiped open instead), so its dashes must be real
   lengths — 12 on, 6 off — or they blur into a washed-out tone. */
.tl-bar--run { stroke-dasharray: 12 6; }
.tl-tail { fill: none; stroke: var(--accent); stroke-width: 2; }
.tl-head { fill: var(--accent); }
.tl-demo { fill: var(--paper); }
.tl-note {
  font-family: var(--font-label);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  fill: var(--muted-ink);
}

/* The per-element animation delays. In the mockup these were style=""
   attributes on the elements themselves (--wd on a week label, --gd on a
   hairline, --dd on a demo dot). A style attribute is blocked by
   `style-src 'self'` exactly as an inline <style> is, so the stagger lives
   here instead, one class per element, values unchanged. Only the media
   query below consumes them; with motion blocked they are inert. */
.tl-week--1 { --wd: 0.34s; }
.tl-week--2 { --wd: 0.42s; }
.tl-week--3 { --wd: 0.50s; }
.tl-week--4 { --wd: 0.58s; }

.tl-grid--1 { --gd: 0.30s; }
.tl-grid--2 { --gd: 0.34s; }
.tl-grid--3 { --gd: 0.38s; }
.tl-grid--4 { --gd: 0.42s; }
.tl-grid--5 { --gd: 0.46s; }
.tl-grid--6 { --gd: 0.50s; }
.tl-grid--7 { --gd: 0.54s; }
.tl-grid--8 { --gd: 0.58s; }
.tl-grid--9 { --gd: 0.62s; }

/* one dot per weekly demo, arriving a week apart */
.tl-demo--1 { --dd: 1.22s; }
.tl-demo--2 { --dd: 1.38s; }
.tl-demo--3 { --dd: 1.54s; }
.tl-demo--4 { --dd: 1.70s; }
.tl-demo--5 { --dd: 1.86s; }

/* The RUN band is the one bar that cannot be revealed with a dash-offset,
   because it keeps a real dash pattern: its group is wiped open from the
   band's own left edge instead. The origin is that edge in view-box units
   (x=1000, the centre line of row 4 at y=284) — see the <svg> in index.html. */
.tl .tl-runwipe {
  transform-box: view-box;
  transform-origin: 1000px 284px;
}

@keyframes tl-draw { to { stroke-dashoffset: 0; } }
@keyframes tl-fade { to { opacity: 1; } }
@keyframes tl-pop  { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: translateY(0); } }
@keyframes tl-wipe { to { transform: scaleX(1); } }

/* The finished strip is the DEFAULT, so "reduced motion" needs nothing undone
   and no rule has to out-specify another. Only when motion is welcome is the
   strip taken apart, to be put back a band at a time. */
@media (prefers-reduced-motion: no-preference) {
  .tl .tl-axis,
  .tl .tl-grid,
  .tl .tl-bar:not(.tl-bar--run),
  .tl .tl-tail { stroke-dasharray: 1; stroke-dashoffset: 1; }
  .tl .tl-week,
  .tl .tl-name,
  .tl .tl-sub,
  .tl .tl-demo,
  .tl .tl-head,
  .tl .tl-note { opacity: 0; }
  .tl .tl-runwipe { transform: scaleX(0); }
}

@media (prefers-reduced-motion: no-preference) {
  .tl.is-playing .tl-axis  { animation: tl-draw 0.62s cubic-bezier(0.4, 0, 0.2, 1) forwards; }
  .tl.is-playing .a-2      { animation-delay: 0.10s; }
  .tl.is-playing .tl-grid  { animation: tl-draw 0.3s ease forwards; animation-delay: var(--gd); }
  .tl.is-playing .tl-cap   { animation: tl-fade 0.4s ease forwards; }

  .tl.is-playing .tl-week  { animation: tl-fade 0.34s ease forwards; animation-delay: var(--wd); }

  /* one row at a time: the name and the caption arrive with their band */
  .tl.is-playing .r-1 .tl-bar  { animation: tl-draw 0.40s cubic-bezier(0.4, 0, 0.2, 1) 0.62s forwards; }
  .tl.is-playing .r-1 .tl-name { animation: tl-pop 0.34s ease 0.62s forwards; }
  .tl.is-playing .r-1 .tl-sub  { animation: tl-fade 0.34s ease 0.74s forwards; }

  .tl.is-playing .r-2 .tl-bar  { animation: tl-draw 0.86s cubic-bezier(0.4, 0, 0.2, 1) 1.04s forwards; }
  .tl.is-playing .r-2 .tl-name { animation: tl-pop 0.34s ease 1.04s forwards; }
  .tl.is-playing .r-2 .tl-sub  { animation: tl-fade 0.34s ease 1.16s forwards; }
  .tl.is-playing .tl-demo      { animation: tl-fade 0.22s ease forwards; animation-delay: var(--dd); }

  .tl.is-playing .r-3 .tl-bar  { animation: tl-draw 0.40s cubic-bezier(0.4, 0, 0.2, 1) 1.98s forwards; }
  .tl.is-playing .r-3 .tl-name { animation: tl-pop 0.34s ease 1.98s forwards; }
  .tl.is-playing .r-3 .tl-sub  { animation: tl-fade 0.34s ease 2.10s forwards; }

  .tl.is-playing .r-4 .tl-runwipe { animation: tl-wipe 0.46s cubic-bezier(0.4, 0, 0.2, 1) 2.40s forwards; }
  .tl.is-playing .r-4 .tl-name    { animation: tl-pop 0.34s ease 2.40s forwards; }
  .tl.is-playing .r-4 .tl-sub     { animation: tl-fade 0.34s ease 2.52s forwards; }
  .tl.is-playing .tl-tail         { animation: tl-draw 0.34s ease 2.80s forwards; }
  .tl.is-playing .tl-head         { animation: tl-fade 0.26s ease 2.96s forwards; }
  .tl.is-playing .tl-note         { animation: tl-fade 0.4s ease 3.08s forwards; }
}

/* reduced motion: nothing to undo — the strip is already finished. */
@media (prefers-reduced-motion: reduce) {
  .replay { display: none; }
}

/* the strip is a vector: it scales with the column, and the in-SVG type
   steps down with the column, not the viewport, so the wrap at 880 and 375
   stays legible at every width. */
@container fig (max-width: 720px) {
  .tl-cap  { font-size: 9px; }
  .tl-week { font-size: 9px; letter-spacing: 0.08em; }
  .tl-name { font-size: 10.5px; letter-spacing: 0.08em; }
  .tl-sub  { font-size: 8px; letter-spacing: 0.03em; }
  .tl-note { font-size: 8px; letter-spacing: 0.1em; }
}
@container fig (max-width: 420px) {
  .tl-cap  { font-size: 8px; letter-spacing: 0.1em; }
  .tl-week { font-size: 8px; letter-spacing: 0.05em; }
  .tl-name { font-size: 9px; letter-spacing: 0.05em; }
  .tl-sub  { font-size: 7px; letter-spacing: 0.02em; }
  .tl-note { font-size: 7px; letter-spacing: 0.06em; }
}

/* --------------------------------------------------------------------------
   8. take-on — four ruled columns (a column set, not a drawing)
   -------------------------------------------------------------------------- */

.types { display: grid; grid-template-columns: repeat(4, 1fr); }
.types > div {
  display: flex;
  flex-direction: column;
  padding: 0 26px 0 24px;
  border-left: 1px solid var(--rule);
}
.types > div:first-child { border-left: 0; padding-left: 0; }
.types__no {
  display: block;
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--accent);
  margin-bottom: 14px;
}
.types .h3 { min-height: 84px; }
.types p { margin: 12px 0 0; font-size: calc(var(--body) - 2px); line-height: 1.55; }
.types__eg {
  /* pinned to the bottom of the column, so all four hairlines line up */
  margin-top: auto;
  padding-top: 14px;
  border-top: 1px solid var(--rule);
  font-family: var(--font-label);
  font-size: 11.5px;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--muted-ink);
}

.closing {
  margin-top: 48px;
  padding-top: 22px;
  border-top: 1px solid var(--rule);
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-style: var(--display-style);
  font-size: 21px;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   9. how — a numbered list on hairlines (no second timeline)
   -------------------------------------------------------------------------- */

.steps { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--rule); }
.steps li {
  display: grid;
  /* 128px so the assured set's longer "Step 01 of 4" label still sits on one line */
  grid-template-columns: 128px 1fr 1.25fr;
  gap: 40px;
  align-items: baseline;
  padding: 28px 0;
  border-bottom: 1px solid var(--rule);
}
.steps__no {
  font-family: var(--font-label);
  font-size: var(--label);
  font-weight: 500;
  letter-spacing: 0.16em;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
}
.steps .h3 { font-size: var(--h3); }
.steps p { margin: 0; font-size: var(--body); line-height: 1.6; color: var(--ink); }

.quote {
  margin: 44px 0 0;
  padding: 26px 30px;
  background: var(--paper-3);
  border-left: 3px solid var(--accent);
  font-family: var(--font-label);
  font-size: var(--label);
  line-height: 1.65;
  letter-spacing: 0.01em;
  color: var(--ink);
}

/* --------------------------------------------------------------------------
   10. private-ai — a definition table (a third kind of evidence)
   -------------------------------------------------------------------------- */

.ai { display: grid; grid-template-columns: 1fr 1fr; gap: 72px; align-items: start; }
.ai__facts { margin: 0; border-top: 1px solid var(--rule); }
.ai__facts > div {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 24px;
  padding: 22px 0;
  border-bottom: 1px solid var(--rule);
}
.ai__facts dt {
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-ink);
}
.ai__facts dd { margin: 0; font-size: var(--body); line-height: 1.5; color: var(--ink); }
.ai__note { margin-top: 26px; }
/* was a style="margin-top:20px" attribute in the mockup */
.ai__body { margin-top: 20px; }

/* --------------------------------------------------------------------------
   11. work — the trust line, two client cards, then the full credentials
      row. The seven marks live HERE, exactly once on the page: one row,
      one label, one opacity, the family order — and a per-mark height.
   -------------------------------------------------------------------------- */

.clients { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
.client {
  padding: 34px 34px 30px;
  /* a card on a tinted section needs the plain paper to read as raised */
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
}
.client__top { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin-bottom: 18px; }
.client__name {
  font-family: var(--font-label);
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink);
}
.client p { margin: 0 0 10px; font-size: var(--body); line-height: 1.6; }
.client p:last-child { margin: 0; color: var(--muted-ink); font-size: var(--label); }

.creds { margin-top: 54px; padding-top: 34px; border-top: 1px solid var(--rule); }
.creds__trust {
  margin: 0 0 30px;
  font-size: var(--body);
  line-height: 1.6;
  color: var(--muted-ink);
  max-width: 62ch;
}
.creds__label {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-ink);
  margin: 0 0 22px;
}
.logos {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 46px;
  row-gap: 26px;
  opacity: var(--creds-opacity);
}
.logos img {
  height: var(--mark-h, var(--creds-logo-h));
  width: auto;
  object-fit: contain;
  filter: var(--logo-filter);
  mix-blend-mode: var(--logo-blend);
}
/* Real programme lockups from public/programmes/ — see SOURCES.md.
   Microsoft publishes no lockup: the flag stands alone (Jake, 2026-09-13).

   Normalised OPTICALLY, not mechanically. One flat height is what made this
   row read wrong: for the two single-line wordmarks (Google for Startups,
   Microsoft) the box height IS the cap height, so they shouted, while the
   stacked lockups (SUTD, Create4Good, raiSE, Inception) spend that same box
   across two or three lines and went quiet — SUTD nearly illegible.
   (Jake, 2026-09-14: "the logos and the sizing of the other organisations
   are quite glaring".) These seven values are the family scale, ported
   verbatim from ../claims-design-mockup/claims.css; ../legal-design-mockup/
   legal.css independently arrived at the same weights. --creds-logo-h stays
   the fallback and the common line the row centres on. */
.logos__mark--sutd      { --mark-h: 28px; }
.logos__mark--c4g       { --mark-h: 29px; }
.logos__mark--raise     { --mark-h: 30px; }
.logos__mark--esg       { --mark-h: 25px; }
.logos__mark--gfs       { --mark-h: 19px; }
.logos__mark--microsoft { --mark-h: 20px; }
.logos__mark--inception { --mark-h: 31px; }

/* --------------------------------------------------------------------------
   12. engagement — a two-row price table, and the one number on the page
   -------------------------------------------------------------------------- */

.terms { border-top: 1px solid var(--rule); }
.terms > div {
  display: grid;
  grid-template-columns: 1fr 1.4fr;
  gap: 60px;
  padding: 30px 0;
  border-bottom: 1px solid var(--rule);
  align-items: baseline;
}
.terms .h3 { font-size: var(--h3); }
.terms p { margin: 0; font-size: var(--body); line-height: 1.6; }

/* the price band: the one number this page makes, set large, beside the ask */
.band {
  margin: 0;
  font-family: var(--font-display);
  font-weight: var(--display-weight);
  font-style: var(--display-style);
  font-size: 40px;
  line-height: 1.1;
  letter-spacing: -0.012em;
  color: var(--accent);
}
.range {
  margin: 14px 0 0;
  font-size: var(--body);
  line-height: 1.5;
  color: var(--ink);
}
/* The band, the range line and the no-price note share the width, so the
   section does not trail off into an empty right half. */
.terms__foot {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 72px;
  margin-top: 46px;
  align-items: start;
}
.terms__foot .cta-row { margin-top: 26px; }
.terms__foot .small { margin-top: 8px; }

/* --------------------------------------------------------------------------
   13. faq — a question column, answers in the open
   -------------------------------------------------------------------------- */

.faq { display: grid; grid-template-columns: 1fr; gap: 0; }
.faq > div {
  padding: 26px 0;
  border-top: 1px solid var(--rule);
}
.faq dt { font-family: var(--font-body); font-size: var(--body); font-weight: 600; color: var(--ink); }
.faq dd { margin: 10px 0 0; font-size: var(--body); line-height: 1.6; color: var(--muted-ink); max-width: 72ch; }

/* --------------------------------------------------------------------------
   14. book — a dead booking placeholder and a dead form
   -------------------------------------------------------------------------- */

.book { display: grid; grid-template-columns: 1fr 1fr; gap: 60px; align-items: start; }
/* was a style="margin-top:12px" attribute on each column's intro line */
.book__intro { margin-top: 12px; }

.slot {
  border: 1px solid var(--rule);
  border-radius: 2px;
  background: var(--paper-2);
  padding: 26px;
  margin-top: 24px;
}
.slot__label {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-ink);
  margin: 0 0 20px;
}
.slot__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 14px; }
.slot__grid span {
  height: 38px;
  border: 1px dashed var(--rule);
  border-radius: 2px;
  display: block;
}
.slot__note {
  margin: 0 0 18px;
  font-size: var(--label);
  line-height: 1.5;
  color: var(--muted-ink);
}

.form { margin-top: 24px; }
.field { margin-bottom: 20px; }
.field label {
  display: block;
  font-family: var(--font-label);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-ink);
  margin-bottom: 8px;
}
.field input {
  width: 100%;
  min-height: 46px;
  padding: 11px 14px;
  background: var(--paper);
  border: 1px solid var(--rule);
  border-radius: 2px;
  font-family: var(--font-body);
  font-size: 16px;
  color: var(--ink);
}
.field input::placeholder { color: var(--muted); }

/* Invalid state. The value the visitor typed is never cleared — only marked,
   with the reason next to the field it belongs to. */
.field input[aria-invalid="true"] { border-color: var(--error); }
.field__err {
  display: none;
  margin: 8px 0 0;
  font-family: var(--font-label);
  font-size: 11.5px;
  line-height: 1.5;
  letter-spacing: 0.02em;
  color: var(--error);
}
.field__err.is-shown { display: block; }

/* Honeypot: present for a bot, gone for everyone else. Not display:none —
   some bots skip what is display:none, which is the whole point of the
   field. Off-screen, zero-size, out of the tab order (tabindex="-1" in the
   markup) and aria-hidden, so no assistive technology meets it either. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* The one aria-live region on the page: what happened to the submission. */
.form__status {
  margin: 14px 0 0;
  font-size: var(--label);
  line-height: 1.55;
  color: var(--muted-ink);
}
.form__status:empty { margin: 0; }
.form__status--ok { color: var(--accent); font-weight: 500; }
.form__status--bad { color: var(--error); }
.form__note { margin-top: 14px; }

/* --------------------------------------------------------------------------
   15. Footer
   -------------------------------------------------------------------------- */

.foot { border-top: 1px solid var(--rule); background: var(--paper-2); }
.foot__inner { padding: 54px 0 46px; }
/* No sites directory: this page stands on its own, so the footer is the
   company line and nothing else. */
.foot__legal {
  margin: 0;
  font-family: var(--font-label);
  font-size: 11.5px;
  line-height: 1.8;
  letter-spacing: 0.03em;
  color: var(--muted-ink);
}
.foot__legal a { color: var(--muted-ink); text-decoration: none; border-bottom: 1px solid var(--rule); }
.foot__legal a:hover { color: var(--accent); }

/* --------------------------------------------------------------------------
   16. Breakpoints — the shared 880px step moves the token scale; here the
      grids wrap: four columns to two, two to one, the head full-width.
   -------------------------------------------------------------------------- */

@media (max-width: 880px) {
  .h1 { font-size: var(--h1); }
  .sec__head { grid-template-columns: 1fr; gap: 24px; align-items: start; }
  .types { grid-template-columns: 1fr 1fr; gap: 34px 32px; }
  .types > div:nth-child(odd) { border-left: 0; padding-left: 0; }
  .ai { grid-template-columns: 1fr; gap: 44px; }
  .ai__facts > div { grid-template-columns: 1fr; gap: 8px; }
  .clients { grid-template-columns: 1fr; gap: 28px; }
  .terms > div { grid-template-columns: 1fr; gap: 12px; }
  .terms__foot { grid-template-columns: 1fr; gap: 32px; }
  .book { grid-template-columns: 1fr; gap: 40px; }
  .steps li { grid-template-columns: 96px 1fr; gap: 16px 24px; }
  .band { font-size: 32px; }
}

@media (max-width: 560px) {
  .types { grid-template-columns: 1fr; gap: 30px; }
  .types > div { border-left: 0; padding-left: 0; }
  .steps li { grid-template-columns: 1fr; gap: 6px 0; }
  .cta-row { flex-direction: column; align-items: stretch; }
  .cta-row .btn { width: 100%; }
  .h1 { font-size: var(--h1); }
}

/* --------------------------------------------------------------------------
   16b. The hero timeline on phones — the stacked text list

   The drawing is a 1152-unit viewBox. In a 319px column that is a 3.6x
   downscale, which put its 7-9px labels at about 2-3 rendered pixels: measured
   at 375, not guessed. Since the four phases existed ONLY inside the SVG, the
   page did not degrade there, it lost the content. So below 560 the drawing is
   swapped for the same four phases as real, selectable, scalable text.
   (Jake, 2026-09-14.)

   The swap is a true either/or, and `display: none` is load-bearing on BOTH
   sides: it removes a subtree from the accessibility tree as well as from
   layout, so a screen reader is never handed the figure and the list together.
   -------------------------------------------------------------------------- */

/* above 560 the list does not exist at all */
.tl-list,
.tl-list__note { display: none; }

@media (max-width: 560px) {
  /* the drawing goes; the list arrives */
  .hero__fig .tl { display: none; }

  .tl-list {
    display: grid;
    gap: 22px;
    margin: 0;
    padding: 0;
    list-style: none;          /* the <ol> is for order, not for bullets */
  }
  .tl-list__row {
    display: grid;
    gap: 2px;
    padding-left: 16px;
    /* one hairline down the left, the flattened form of the timeline's rail */
    border-left: 2px solid var(--accent);
  }
  .tl-list__when {
    margin: 0;
    font-family: var(--font-label);
    font-size: var(--label);
    font-weight: 500;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: var(--accent);
  }
  .tl-list__name {
    margin: 0;
    font-family: var(--font-display);
    font-weight: var(--display-weight-strong);
    font-size: var(--h3);
    line-height: 1.2;
    color: var(--ink);
  }
  .tl-list__sub {
    margin: 0;
    font-size: var(--body);
    line-height: 1.5;
    color: var(--muted-ink);
  }
  .tl-list__note {
    display: block;
    margin: 22px 0 0;
    font-size: var(--label);
    line-height: 1.5;
    color: var(--muted-ink);
  }
  /* the replay control drives the drawing, so it has nothing to do here */
  .hero__fig .replay { display: none; }
}

/* --------------------------------------------------------------------------
   17. Anchors must clear the sticky nav
   -------------------------------------------------------------------------- */

#hero, .sec, #book, #foot { scroll-margin-top: 78px; }
