/* ---- tokens.css ---- */
/* Generated from design/tokens.json — edit that file, not this one.
   Colour family names are ENG002 Brand Guidelines v2.0 verbatim.

   Every brand hex has exactly one definition here. Dark mode below reassigns roles
   and never introduces a colour, which is what stops a second Structural Blue from
   appearing the first time someone themes a component. */
:root {
  /* Blue family — primary */
  --color-blue-l1: #508791;   /* Structural Blue */
  --color-blue-l2: #DCF0F0;
  --color-blue-l3: #2D3237;
  --color-blue-deep: #3E6D75; /* the blue you may set text in — 4.87:1 on the worst light surface */
  --color-blue-lift: #8FBFC8; /* the same job on the dark ramp */
  /* Green family — secondary */
  --color-green-l1: #969632;  /* Electric Green */
  --color-green-l2: #F0F5E6;
  --color-green-l3: #32371E;
  --color-green-mark: #82822C; /* green as a mark on light — clears 3:1, never a word */
  --color-green-lift: #C2C25A; /* the same, on the dark ramp */
  /* Grey family — tertiary */
  --color-grey-primary: #323232;  /* Engineering Grey */
  --color-grey-medium: #646464;
  --color-grey-light: #C8C8C8;
  --color-white: #FFFFFF;
  /* Gold + Red — supplement only, never primary identity.
     In figures they carry one meaning each: Gold is the approved budget, Red is overrun. */
  --color-gold-l1: #BE8C00; --color-gold-l2: #FAF0C8; --color-gold-l3: #463200;
  --color-red-l1: #963228;  --color-red-l2: #E6C8B4;  --color-red-l3: #3C1414;

  /* Light ramp — neutral scaffolding, not a brand family. The only thing that
     changes between the two colour schemes. */
  --color-slate-bg: #F5F7F5;
  --color-slate-surface: #FFFFFF;
  --color-slate-surface-2: #E9F1F0;
  --color-slate-text: #2F3434;
  --color-slate-text-2: #5E6664;
  --color-slate-text-3: #646B68;  /* quiet, and still 4.62:1 on the worst light surface */
  --color-slate-rule: #D8DEDC;

  /* Dark ramp */
  --color-night-bg: #1B1F22;
  --color-night-surface: #232729;
  --color-night-surface-2: #263239;
  --color-night-tint: #2A3C40;
  --color-night-text: #E6E9E6;
  --color-night-text-2: #AEB5B2;
  --color-night-text-3: #9DA5A2;
  --color-night-rule: #343A3E;

  /* Ink band — the one dark block that appears in both colour schemes:
     nav, hero, footer, feature cells.
     --color-ink-base is --color-blue-l3, so the band is brand-correct by construction. */
  --color-ink-base: #2D3237;
  --color-ink-deep: #232729;
  --color-ink-text: #F2F5F3;
  --color-ink-text-2: #B7BFBC;
  --color-ink-rule: rgba(255, 255, 255, .14);

  /* Roles */
  --surface-default: var(--color-slate-surface);
  --surface-page: var(--color-slate-bg);
  --surface-raised: var(--color-slate-surface-2);
  --surface-tinted: var(--color-blue-l2);
  --surface-muted: var(--color-green-l2);
  --surface-dark: var(--color-ink-base);
  --text-body: var(--color-slate-text);
  --text-muted: var(--color-slate-text-2);
  --text-quiet: var(--color-slate-text-3);
  --text-inverse: var(--color-ink-text);
  --text-inverse-muted: var(--color-ink-text-2);
  --interactive: var(--color-blue-l1);
  --interactive-text: var(--color-blue-deep);
  --interactive-fill: var(--color-blue-deep);
  --interactive-fill-text: var(--color-white);
  --sequence: var(--color-green-mark);
  --border: var(--color-slate-rule);
  --shadow-panel: 0 1px 0 rgba(47, 52, 52, .05), 0 14px 34px -20px rgba(47, 52, 52, .35);

  /* Type */
  --font-heading: 'Catamaran', Arial, Helvetica, sans-serif;
  --font-body: 'Lato', Georgia, serif;
  --step--1: clamp(.82rem, .8rem + .1vw, .88rem);
  --step-0:  clamp(1rem, .97rem + .15vw, 1.08rem);
  --step-1:  clamp(1.25rem, 1.18rem + .35vw, 1.42rem);
  --step-2:  clamp(1.56rem, 1.42rem + .7vw, 1.9rem);
  --step-3:  clamp(1.95rem, 1.68rem + 1.35vw, 2.53rem);
  --step-4:  clamp(2.44rem, 1.97rem + 2.35vw, 3.38rem);
  --step-5:  clamp(2.8rem, 2.1rem + 3.5vw, 4.5rem);
  --measure: 68ch;

  /* Space — a 1.5 ratio off 1rem */
  --space-3xs: .25rem; --space-2xs: .5rem; --space-xs: .75rem;
  --space-s: 1rem; --space-m: 1.5rem; --space-l: 2.25rem;
  --space-xl: 3.5rem; --space-2xl: 5rem; --space-3xl: 7rem;

  --gutter: clamp(1.25rem, 5vw, 4rem);
  --max-width: 1180px;

  /* Two radii and no others: anything clickable takes 3px, anything containing takes 6px. */
  --radius-interactive: 3px;
  --radius: 6px;

  /* Pattern — capped so it can never exceed the brand's 50% ceiling */
  --pattern-opacity: clamp(0, .14, .5);
  --pattern-tile: 104px;
  --pattern-color: var(--color-grey-primary);

  /* Photo treatment: solid brand fill under the image at 70% */
  --photo-image-opacity: .7;
}

/* Dark mode reassigns roles only. Every brand hex above keeps exactly one definition,
   which is what stops a redesign from quietly introducing a second Structural Blue. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --surface-default: var(--color-night-surface);
    --surface-page: var(--color-night-bg);
    --surface-raised: var(--color-night-surface-2);
    --surface-tinted: var(--color-night-tint);
    --surface-muted: var(--color-night-surface-2);
    --surface-dark: var(--color-ink-deep);
    --text-body: var(--color-night-text);
    --text-muted: var(--color-night-text-2);
    --text-quiet: var(--color-night-text-3);
    --interactive: var(--color-blue-lift);
    --interactive-text: var(--color-blue-lift);
    --interactive-fill: var(--color-blue-lift);
    --interactive-fill-text: var(--color-night-bg);
    --sequence: var(--color-green-lift);
    --border: var(--color-night-rule);
    --shadow-panel: 0 1px 0 rgba(0, 0, 0, .3), 0 14px 34px -20px rgba(0, 0, 0, .7);
    --pattern-color: var(--color-white);
    color-scheme: dark;
  }
}
:root[data-theme="dark"] {
  --surface-default: var(--color-night-surface);
  --surface-page: var(--color-night-bg);
  --surface-raised: var(--color-night-surface-2);
  --surface-tinted: var(--color-night-tint);
  --surface-muted: var(--color-night-surface-2);
  --surface-dark: var(--color-ink-deep);
  --text-body: var(--color-night-text);
  --text-muted: var(--color-night-text-2);
  --text-quiet: var(--color-night-text-3);
  --interactive: var(--color-blue-lift);
  --interactive-text: var(--color-blue-lift);
  --interactive-fill: var(--color-blue-lift);
  --interactive-fill-text: var(--color-night-bg);
  --sequence: var(--color-green-lift);
  --border: var(--color-night-rule);
  --shadow-panel: 0 1px 0 rgba(0, 0, 0, .3), 0 14px 34px -20px rgba(0, 0, 0, .7);
  --pattern-color: var(--color-white);
  color-scheme: dark;
}

/* ---- base.css ---- */
/* ---- reset ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation-duration: .01ms !important; animation-iteration-count: 1 !important; transition-duration: .01ms !important; }
}
body {
  font-family: var(--font-body);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--text-body);
  /* The page ground is the off-white, not pure white. White is a surface you put on
     top of it — that is what lets a panel read as a panel without a shadow. */
  background: var(--surface-page);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
img, svg, video { display: block; max-width: 100%; height: auto; }
/* A page that scrolls sideways on a phone reads as broken. Tables, figures and code
   get their own overflow container; the document body never does. */
html, body { overflow-x: clip; }
.wrap > * { min-width: 0; }
input, button, select, textarea { font: inherit; color: inherit; }
[hidden] { display: none !important; }

/* Keyboard focus must stay obvious — this site is read by people who tab. */
:focus-visible { outline: 3px solid var(--interactive); outline-offset: 2px; }
:focus:not(:focus-visible) { outline: none; }

.skip-link {
  position: absolute; left: var(--space-s); top: -4rem; z-index: 100;
  background: var(--surface-dark); color: var(--text-inverse);
  padding: var(--space-2xs) var(--space-s); border-radius: var(--radius-interactive);
  transition: top .15s ease;
}
.skip-link:focus { top: var(--space-s); }

/* The header is sticky, so anything scrolled to by a fragment link lands underneath
   it. That includes #main, which is where the skip link sends a keyboard reader —
   the one route that must not drop someone behind the navigation. */
:root { --header-height: 4.5rem; }
:target, #main, .section { scroll-margin-top: var(--header-height); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ---- reveal ----------------------------------------------------------
   Opt-in, and only once JS has said so. Without the .js class every revealed
   element is simply visible, so a reader with scripts off sees a complete page
   rather than an empty one — the failure mode of every scroll-animation library. */
@media (prefers-reduced-motion: no-preference) {
  .js .reveal { opacity: 0; transform: translateY(14px); }
  .js .reveal.is-in {
    opacity: 1; transform: none;
    transition: opacity .6s cubic-bezier(.2,.7,.2,1), transform .6s cubic-bezier(.2,.7,.2,1);
  }
}

/* ---- typography.css ---- */
/* Catamaran for headings, Lato for body — ENG002 Brand Guidelines v2.0.
   Self-hosted rather than the Google CDN: faster, and no third-party request on a
   site that procurement will scrutinise. Fallbacks are the brand's own (Arial/Georgia).

   Note there is no italic face. Catamaran ships none, and a synthesised oblique on the
   largest type on the site looks like a mistake — so emphasis is carried by weight,
   colour and a struck rule instead of a slant. See .hero__mark. */
@font-face {
  font-family: 'Catamaran'; font-style: normal; font-weight: 400 800; font-display: swap;
  src: url('/assets/fonts/catamaran-variable.woff2') format('woff2-variations');
}
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/lato-regular.woff2') format('woff2');
}
@font-face {
  font-family: 'Lato'; font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/lato-bold.woff2') format('woff2');
}

h1, h2, h3, h4 {
  font-family: var(--font-heading);
  color: var(--text-body);
  line-height: 1.1;
  letter-spacing: -0.02em;
  text-wrap: balance;
}
h1 { font-size: var(--step-4); font-weight: 800; letter-spacing: -0.032em; line-height: 1.04; }
h2 { font-size: var(--step-3); font-weight: 800; letter-spacing: -0.028em; }
h3 { font-size: var(--step-1); font-weight: 700; letter-spacing: -0.012em; }
h4 { font-size: var(--step-0); font-weight: 700; letter-spacing: 0; }

p, li { text-wrap: pretty; }
p + p { margin-top: var(--space-s); }

a { color: inherit; text-decoration-color: var(--interactive); text-underline-offset: .18em; text-decoration-thickness: 1px; }
a:hover { text-decoration-thickness: 2px; }

strong, b { font-weight: 700; }

.lede { font-size: var(--step-1); line-height: 1.5; color: var(--text-body); max-width: 56ch; }
.muted { color: var(--text-muted); }
.quiet { color: var(--text-quiet); font-size: var(--step--1); }

/* The eyebrow is a label, so it cannot be Structural Blue — 3.74:1 on the page ground.
   blue.deep exists for exactly this: the same hue, dark enough to be a word. */
.eyebrow {
  font-family: var(--font-heading); font-weight: 800; font-size: var(--step--1);
  letter-spacing: .06em; text-transform: uppercase; color: var(--interactive-text);
}

/* A standing statement, not a heading — set in the display face at body-copy weight so
   it reads as the writer's voice rather than as another level of structure. */
.statement {
  font-family: var(--font-heading); font-weight: 600;
  font-size: clamp(1.3rem, 1.9vw, 1.6rem); line-height: 1.3; letter-spacing: -0.015em;
  text-wrap: balance; max-width: 34ch;
}

/* The only monospace on the site, and it is not decoration: these are the identifiers
   an engineer actually reads — drawing refs, project tags, verification dates. */
.ref {
  font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;
  font-size: var(--step--1);
  font-variant-numeric: tabular-nums;
  color: var(--text-muted);
  letter-spacing: -0.01em;
  /* Source strings are long and have few break opportunities. Without this they set
     the page's minimum width and everything overflows on a phone. */
  overflow-wrap: anywhere;
  min-width: 0;
}

.prose > * + * { margin-top: var(--space-s); }
.prose h2 { margin-top: var(--space-l); }
.prose h3 { margin-top: var(--space-m); }
.prose ul, .prose ol { padding-left: 1.25em; }
.prose li + li { margin-top: var(--space-3xs); }
.prose a { text-decoration: underline; text-decoration-color: var(--interactive-text); }

/* ---- layout.css ---- */
.wrap { width: 100%; max-width: var(--max-width); margin-inline: auto; padding-inline: var(--gutter); }
.measure { max-width: var(--measure); }

/* ---- section rhythm -------------------------------------------------
   Sections are separated by a datum rule with a section tick at the left —
   the mark an engineer reads on a drawing, not a decorative divider. */
.section { padding-block: var(--space-2xl); position: relative; background: var(--surface-page); }
@media (max-width: 47rem) { .section { padding-block: var(--space-xl); } }
.section + .section { border-top: 1px solid var(--border); }
.section > .wrap > .section-head { position: relative; margin-bottom: var(--space-l); }
.section-head::before {
  content: ""; position: absolute; left: calc(var(--space-s) * -1); top: .35em;
  width: 3px; height: 1.1em; background: var(--interactive);
}
.section-head h2 { max-width: 24ch; }
.section-head .intro { margin-top: var(--space-xs); max-width: 62ch; color: var(--text-muted); }
.section-head .eyebrow { display: block; margin-bottom: var(--space-2xs); }

/* Surfaces. A section that changes ground does not also need a rule against its
   neighbour — the change of ground is the division. */
.section--surface { background: var(--surface-default); }
.section--raised  { background: var(--surface-raised); }
.section--tinted  { background: var(--surface-tinted); }
.section--muted   { background: var(--surface-muted); }
.section--dark    { background: var(--surface-dark); color: var(--text-inverse); }
.section--surface, .section--raised, .section--tinted, .section--muted, .section--dark,
.section--surface + .section, .section--raised + .section,
.section--tinted + .section, .section--muted + .section, .section--dark + .section {
  border-top: 1px solid transparent;
}

/* The ink band is the same in both colour schemes, so it states its own colours
   rather than inheriting roles that flip underneath it. */
.section--dark h1, .section--dark h2, .section--dark h3, .section--dark h4 { color: var(--text-inverse); }
.section--dark p, .section--dark .lede, .section--dark li { color: var(--text-inverse); }
.section--dark .muted, .section--dark .ref, .section--dark .quiet { color: var(--text-inverse-muted); }
.section--dark .eyebrow { color: var(--color-blue-lift); }
.section--dark a { text-decoration-color: var(--color-blue-lift); }
.section--dark .section-head::before { background: var(--color-blue-lift); }

/* The sequence accent: Electric Green, and only ever as a rule or a tick.
   #969632 is 3.1:1 on white — it cannot be a word, so it is never set as one. */
.section--sequence .section-head::before { background: var(--sequence); }

/* ---- hexagon pattern ------------------------------------------------
   Brand rules: single colour, 50% opacity maximum, and fades apply to the whole
   pattern never to fragments. Both are structural here — the mask sits on the
   pseudo-element, so content is never faded, and the opacity is clamped. */
.pattern { position: relative; isolation: isolate; }
.pattern::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  /* The pattern is a mask, not a background image, so its colour comes from CSS.
     That is what keeps it to the single permitted colour per the brand guide. */
  background-color: var(--pattern-color);
  opacity: var(--pattern-opacity);
  -webkit-mask: url('/assets/brand/hex-pattern.svg') repeat 0 0 / var(--pattern-tile) auto;
  mask: url('/assets/brand/hex-pattern.svg') repeat 0 0 / var(--pattern-tile) auto;
}
/* Fades compose a gradient with the pattern mask, so the fade always applies to the
   whole pattern and never to a fragment of it — and never to the content above it. */
.pattern--fade-top::before,
.pattern--fade-bottom::before,
.pattern--fade-centre::before {
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
  -webkit-mask-repeat: repeat, no-repeat;
  mask-repeat: repeat, no-repeat;
  -webkit-mask-size: var(--pattern-tile) auto, cover;
  mask-size: var(--pattern-tile) auto, cover;
}
.pattern--fade-top::before {
  -webkit-mask-image: url('/assets/brand/hex-pattern.svg'), linear-gradient(to bottom, #000, transparent 70%);
  mask-image: url('/assets/brand/hex-pattern.svg'), linear-gradient(to bottom, #000, transparent 70%);
}
.pattern--fade-bottom::before {
  -webkit-mask-image: url('/assets/brand/hex-pattern.svg'), linear-gradient(to top, #000, transparent 70%);
  mask-image: url('/assets/brand/hex-pattern.svg'), linear-gradient(to top, #000, transparent 70%);
}
.pattern--fade-centre::before {
  -webkit-mask-image: url('/assets/brand/hex-pattern.svg'), radial-gradient(circle at 50% 45%, #000 0%, transparent 72%);
  mask-image: url('/assets/brand/hex-pattern.svg'), radial-gradient(circle at 50% 45%, #000 0%, transparent 72%);
}
.pattern--none::before { content: none; }
.section--dark { --pattern-color: var(--color-white); }

/* ---- photo treatment ------------------------------------------------
   Solid brand fill at 100% underneath, photo at 70% on top. Headshots are exempt
   and must say so explicitly (filter: none in the page source). */
.photo { background: var(--photo-fill, var(--color-blue-l1)); overflow: hidden; }
.photo img { opacity: var(--photo-image-opacity); mix-blend-mode: normal; width: 100%; }
.photo--blue  { --photo-fill: var(--color-blue-l1); }
.photo--green { --photo-fill: var(--color-green-l1); }
.photo--none  { background: none; }
.photo--none img { opacity: 1; }

.grid { display: grid; gap: var(--space-m); }
@media (min-width: 46rem) {
  .grid--2 { grid-template-columns: repeat(2, 1fr); }
  .grid--3 { grid-template-columns: repeat(3, 1fr); }
  .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 64rem) {
  .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* A two-column split that stacks. Used by the hero, the thesis and the closing band. */
.split { display: grid; gap: var(--space-xl); align-items: start; }
@media (min-width: 61rem) {
  .split { grid-template-columns: minmax(0, 1.1fr) minmax(0, .9fr); gap: var(--space-2xl); align-items: center; }
  .split--even { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .split--wide-right { grid-template-columns: minmax(0, .9fr) minmax(0, 1.1fr); align-items: start; }
}

/* ---- components.css ---- */
/* ---- header ----------------------------------------------------------
   The nav is the ink band, on every page. It is the one piece of chrome that never
   changes with the colour scheme, which is what makes it read as the masthead rather
   than as part of whatever section happens to be underneath it. */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: color-mix(in srgb, var(--color-ink-base) 90%, transparent);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
  color: var(--color-ink-text);
  border-bottom: 1px solid var(--color-ink-rule);
}
@supports not (backdrop-filter: blur(10px)) { .site-header { background: var(--color-ink-base); } }
.site-header .wrap { display: flex; align-items: center; justify-content: space-between; gap: var(--space-m); padding-block: var(--space-2xs); }
.brand { display: inline-flex; align-items: center; text-decoration: none; }
/* The vendored logo files are JPEGs with a black background flattened in, so the logo
   is painted here instead: a derived alpha mask filled with a brand colour. One asset
   works on light and dark, and the colour can only ever be one from the palette. */
.brand__logo {
  display: block; width: calc(var(--logo-h) * 4.44); height: var(--logo-h);
  --logo-h: 30px;
  background-color: var(--color-ink-text);
  -webkit-mask: url('/assets/brand/logo-horizontal.png') no-repeat center / contain;
  mask: url('/assets/brand/logo-horizontal.png') no-repeat center / contain;
}
/* Brand rule: clear space equals the logo at 50% scale on all sides. */
.brand { padding: calc(var(--logo-h, 30px) * .5) 0; }
.brand__logo--inverse { background-color: var(--color-white); --logo-h: 30px; }

.nav { display: none; }
.nav ul { display: flex; gap: var(--space-m); list-style: none; padding: 0; margin: 0; }
.nav a {
  text-decoration: none; font-family: var(--font-heading); font-weight: 600;
  font-size: var(--step--1); white-space: nowrap;
  color: var(--color-ink-text); opacity: .8;
  padding-block: var(--space-2xs); border-bottom: 2px solid transparent;
  transition: opacity .15s ease, border-color .15s ease;
}
.nav a:hover, .nav a[aria-current="page"] { opacity: 1; border-bottom-color: var(--color-blue-lift); }
@media (min-width: 66rem) { .nav { display: block; } .nav-toggle { display: none; } }
/* .btn sets display: inline-flex later in this file at the same specificity, so this
   needs the extra class to win. On a phone the CTA lives inside the drawer instead. */
.site-header .site-header__cta { display: none; }
@media (min-width: 66rem) { .site-header .site-header__cta { display: inline-flex; } }
.nav-toggle {
  background: none; color: var(--color-ink-text);
  border: 1px solid var(--color-ink-rule); border-radius: var(--radius-interactive);
  padding: var(--space-2xs) var(--space-xs); cursor: pointer;
  font-family: var(--font-heading); font-weight: 700; font-size: var(--step--1);
}
.nav-drawer { border-top: 1px solid var(--color-ink-rule); background: var(--color-ink-base); color: var(--color-ink-text); }
.nav-drawer ul { list-style: none; margin: 0; padding: var(--space-2xs) 0 var(--space-s); }
.nav-drawer li + li { border-top: 1px solid var(--color-ink-rule); }
.nav-drawer a { display: block; padding: var(--space-xs) var(--gutter); text-decoration: none; font-family: var(--font-heading); font-weight: 600; }
.nav-drawer .btn { margin: var(--space-s) var(--gutter) 0; }
@media (min-width: 66rem) { .nav-drawer { display: none !important; } }

/* ---- hero ------------------------------------------------------------ */
.hero { padding-block: var(--space-2xl) var(--space-xl); }
.hero--home { padding-block: var(--space-2xl) var(--space-2xl); }
/* Structural Blue is 3.7:1 on the page ground — fine for a rule or a mark, below AA for
   small text. So the label takes the text-weight blue and the graphic blue stays a
   graphic, which is also the better division of labour: the accent does one job. */
.hero__eyebrow {
  font-size: var(--step--1); color: var(--text-muted);
  margin-bottom: var(--space-s); display: flex; align-items: center; gap: var(--space-2xs);
}
.hero__eyebrow::before { content: ""; width: 14px; height: 2px; background: var(--interactive); flex: none; }
.hero h1 { max-width: 20ch; }
.hero--home h1 { font-size: var(--step-5); max-width: 15ch; }
.hero__body { margin-top: var(--space-m); max-width: 58ch; font-size: var(--step-1); line-height: 1.5; }
.hero__body strong { font-weight: 700; }
.hero__sub { margin-top: var(--space-s); max-width: 54ch; color: var(--text-muted); }
/* The single piece of motion on the site that is not opt-in: one rule drawing itself,
   once, like a line being struck on a drawing. Suppressed by the reduced-motion reset. */
.hero__rule { height: 2px; background: var(--interactive); margin-top: var(--space-l); transform-origin: left; animation: strike .8s .15s cubic-bezier(.2,.7,.2,1) both; }
@keyframes strike { from { transform: scaleX(0); } to { transform: scaleX(1); } }
.hero__media { margin-top: var(--space-l); aspect-ratio: 16 / 7; }
.hero__media img { height: 100%; object-fit: cover; }

/* Emphasis in the headline. Catamaran has no italic, so the emphasis is carried by
   colour and by the rule struck underneath — which is the mark this firm's own
   drawings use anyway. Not a slant the font cannot actually produce. */
.hero__mark { font-style: normal; position: relative; display: inline-block; color: var(--color-blue-l2); }
.hero__mark::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: .04em; height: .07em;
  background: var(--color-green-lift); transform-origin: left;
  animation: strike 1s .45s cubic-bezier(.2,.8,.2,1) both;
}

/* The one dark block at the top of the page. */
.hero--ink { position: relative; overflow: hidden; isolation: isolate; padding-block: var(--space-2xl) var(--space-2xl); }
.hero--ink .hero__canvas { position: absolute; inset: 0; width: 100%; height: 100%; z-index: -2; }
.hero--ink::after {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background:
    linear-gradient(180deg, transparent 45%, var(--color-ink-base) 100%),
    radial-gradient(70% 60% at 18% 30%, rgba(80, 135, 145, .22), transparent 70%);
}
.hero--ink .hero__eyebrow { color: var(--color-ink-text-2); }
.hero--ink .hero__eyebrow::before { background: var(--color-blue-lift); }
.hero--ink .hero__body { color: var(--color-ink-text-2); }
.hero--ink .hero__body strong { color: var(--color-ink-text); }
.hero--ink .hero__sub { color: var(--color-ink-text-2); }
.hero--ink .hero__rule { background: var(--color-blue-lift); }

/* ---- the fact schedule ----------------------------------------------
   The one place this site spends its boldness. Figures are presented the way a
   drawing schedule presents them — ruled, tabular, and carrying provenance —
   because the hardest reader here is a lender's analyst who wants numbers with
   dates, not marketing. */
.schedule { border-top: 2px solid var(--text-body); }
.schedule__row { display: grid; gap: var(--space-2xs) var(--space-m); padding-block: var(--space-m); border-bottom: 1px solid var(--border); }
@media (min-width: 52rem) {
    /* minmax(0, …) on every track: without it a long source string refuses to shrink
     and pushes the whole page wider than the viewport. */
  .schedule__row { grid-template-columns: minmax(0, 15rem) minmax(0, 10rem) minmax(0, 1fr); align-items: baseline; }
  .schedule__value { text-wrap: nowrap; }
}
.schedule__value { font-family: var(--font-heading); font-weight: 800; font-size: var(--step-2); line-height: 1.05; letter-spacing: -0.03em; color: var(--text-body); font-variant-numeric: tabular-nums; text-wrap: balance; }
/* Keep the label column from wrapping a two-word label onto two lines. */
.schedule__label { font-size: var(--step-0); text-wrap: balance; }
.schedule__source { font-size: var(--step--1); }
.section--dark .schedule { border-top-color: var(--color-blue-lift); }
.section--dark .schedule__row { border-bottom-color: var(--color-ink-rule); }
.section--dark .schedule__value { color: var(--text-inverse); }

/* The band layout: the same rows, stood up side by side. It keeps the source line —
   the prototype dropped it, and provenance is the whole argument of this component. */
.schedule--band { border-top: 0; display: grid; gap: 0; }
.schedule--band .schedule__row {
  display: block; border-bottom: 0; border-left: 1px solid var(--border);
  padding: var(--space-m) var(--space-s) var(--space-m) var(--space-m);
}
.schedule--band .schedule__row:first-child { border-left: 0; padding-left: 0; }
.schedule--band .schedule__value { font-size: clamp(1.8rem, 3vw, 2.5rem); }
.schedule--band .schedule__label { margin-top: var(--space-2xs); font-size: var(--step--1); color: var(--text-muted); }
.schedule--band .schedule__source { margin-top: var(--space-3xs); color: var(--text-quiet); }
@media (min-width: 40rem) { .schedule--band { grid-template-columns: repeat(2, minmax(0, 1fr)); } .schedule--band .schedule__row:nth-child(odd) { border-left: 0; padding-left: 0; } }
@media (min-width: 64rem) {
  .schedule--band { grid-template-columns: repeat(var(--band-columns, 5), minmax(0, 1fr)); }
  .schedule--band .schedule__row:nth-child(odd) { border-left: 1px solid var(--border); padding-left: var(--space-m); }
  .schedule--band .schedule__row:first-child { border-left: 0; padding-left: 0; }
}
@media (max-width: 39.99rem) {
  .schedule--band .schedule__row { border-left: 0; padding-left: 0; border-bottom: 1px solid var(--border); }
}

/* ---- tiles (services) ------------------------------------------------
   Ruled cells, not shadowed cards. An engineering firm's own documents use
   schedules and tables; identical drop-shadowed cards belong to a different trade. */
.tiles { display: grid; gap: 0; border-top: 2px solid var(--text-body); border-left: 1px solid var(--border); }
@media (min-width: 46rem) { .tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 70rem) { .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.tile {
  position: relative; overflow: hidden; display: flex; flex-direction: column;
  padding: var(--space-m); min-height: 11rem;
  border-right: 1px solid var(--border); border-bottom: 1px solid var(--border);
  transition: background-color .2s ease;
}
/* The hover mark is the same left tick the section heads use — a rule being struck,
   not a card lifting. */
.tile::after {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 3px;
  background: var(--interactive); transform: scaleY(0); transform-origin: top;
  transition: transform .25s ease;
}
.tile:hover { background: var(--surface-default); }
.tile:hover::after { transform: scaleY(1); }
.tile h3 { font-size: var(--step-1); }
.tile h3 a { text-decoration: none; }
.tile h3 a::after { content: ""; position: absolute; inset: 0; }
.tile p { margin-top: var(--space-2xs); color: var(--text-muted); font-size: var(--step--1); flex: 1; }
.tile__tags { margin-top: var(--space-s); display: flex; flex-wrap: wrap; gap: var(--space-3xs); }
.tile__tags span {
  font-size: var(--step--1); padding: .2em .5em; border: 1px solid var(--border);
  border-radius: var(--radius-interactive); color: var(--text-muted); background: var(--surface-default);
}
.tile--tint { background: var(--surface-tinted); }
.tile--tint:hover { background: var(--surface-tinted); }
.tile--tint .tile__tags span { background: transparent; }
.tile--feature { background: var(--surface-dark); color: var(--text-inverse); justify-content: center; }
.tile--feature::after { display: none; }
.tile--feature:hover { background: var(--surface-dark); }
.tile--feature h3 { color: var(--text-inverse); font-size: var(--step-2); }
.tile--feature p { color: var(--text-inverse-muted); flex: 0; max-width: 46ch; }
.tile--feature .btn { align-self: flex-start; margin-top: var(--space-s); }
/* The feature cell is an ink surface inside a light section, so it does not inherit
   the .section--dark button rules and has to state them itself. */
.tile--feature .btn--ghost { color: var(--color-ink-text); border-color: var(--color-ink-rule); }
.tile--feature .btn--ghost:hover { background: rgba(255, 255, 255, .1); border-color: var(--color-blue-lift); }
@media (min-width: 46rem) { .tile--feature { grid-column: span 2; } }

/* ---- cards (projects, people, insights) ------------------------------ */
.cards { display: grid; gap: var(--space-l); }
@media (min-width: 46rem) { .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 70rem) { .cards--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.card { position: relative; border-top: 2px solid var(--text-body); padding-top: var(--space-s); }
.card__media { aspect-ratio: 3 / 2; margin-bottom: var(--space-s); }
.card__media img { height: 100%; object-fit: cover; }
.card h3 { font-size: var(--step-1); }
.card h3 a { text-decoration: none; }
.card h3 a::after { content: ""; position: absolute; inset: 0; }
.card p { margin-top: var(--space-2xs); color: var(--text-muted); }
.card__meta { margin-top: var(--space-s); display: grid; gap: var(--space-3xs); }
.card__meta div { font-size: var(--step--1); color: var(--text-muted); }

/* ---- callout ----------------------------------------------------------
   One habit, one claim, set apart. Tinted and left-ruled, the way a note is
   flagged in the margin of a drawing. */
.callout {
  margin-top: var(--space-l); max-width: 60ch;
  padding: var(--space-s) var(--space-m);
  background: var(--surface-tinted);
  border-left: 3px solid var(--interactive);
  border-radius: 0 var(--radius-interactive) var(--radius-interactive) 0;
}
.callout__label {
  display: block; font-family: var(--font-heading); font-weight: 800;
  font-size: var(--step--1); letter-spacing: .06em; text-transform: uppercase;
  color: var(--interactive-text); margin-bottom: var(--space-3xs);
}
.section--dark .callout { background: rgba(255, 255, 255, .06); border-left-color: var(--color-blue-lift); }
.section--dark .callout__label { color: var(--color-blue-lift); }

/* ---- steps (a real sequence, so numbering is information) ------------ */
.steps { counter-reset: step; display: grid; gap: var(--space-m); }
.step { counter-increment: step; display: grid; grid-template-columns: 2.5rem 1fr; gap: var(--space-s); align-items: start; }
.step::before { content: counter(step, decimal-leading-zero); font-family: var(--font-heading); font-weight: 700; color: var(--interactive-text); font-variant-numeric: tabular-nums; padding-top: .15em; }
.step h3 { font-size: var(--step-0); }
.step p { color: var(--text-muted); margin-top: var(--space-3xs); }
.step__output { margin-top: var(--space-2xs); font-size: var(--step--1); color: var(--text-quiet); }
.step__output b { color: var(--text-body); font-family: var(--font-heading); font-weight: 700; }

/* The ruled layout: the sequence laid out as a run of stations, each under its own
   datum rule with a tick in the green sequence accent. */
.steps--ruled { display: grid; gap: var(--space-m) var(--space-m); max-width: none; counter-reset: step; }
@media (min-width: 61rem) { .steps--ruled { grid-template-columns: repeat(var(--step-columns, 5), minmax(0, 1fr)); gap: 0 var(--space-m); } }
.steps--ruled .step { display: block; position: relative; padding-top: var(--space-s); border-top: 2px solid var(--border); }
.steps--ruled .step::before { content: ""; position: absolute; top: -2px; left: 0; width: 48px; height: 2px; background: var(--sequence); padding: 0; }
.steps--ruled .step h3 { font-size: var(--step-1); }

/* ---- faq -------------------------------------------------------------- */
.faq { border-top: 1px solid var(--border); max-width: 68ch; }
.faq details { border-bottom: 1px solid var(--border); }
.faq summary { cursor: pointer; padding-block: var(--space-s); font-family: var(--font-heading); font-weight: 700; font-size: var(--step-0); list-style: none; display: flex; justify-content: space-between; gap: var(--space-s); align-items: baseline; }
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after { content: "+"; color: var(--interactive-text); font-weight: 400; font-size: var(--step-1); line-height: 1; }
.faq details[open] summary::after { content: "\2212"; }
.faq details > div { padding-bottom: var(--space-s); color: var(--text-muted); }

/* ---- quote ----------------------------------------------------------- */
.quote { border-left: 3px solid var(--interactive); padding-left: var(--space-m); max-width: 52ch; }
.quote p { font-family: var(--font-heading); font-weight: 400; font-size: var(--step-2); line-height: 1.3; letter-spacing: -0.02em; }
.quote footer { margin-top: var(--space-s); font-size: var(--step--1); color: var(--text-muted); }

/* ---- logo wall (client names as text, not logos we may not be licensed for) */
.namelist { display: flex; flex-wrap: wrap; gap: var(--space-2xs) var(--space-m); list-style: none; padding: 0; margin: 0; }
.namelist li { font-family: var(--font-heading); font-weight: 600; font-size: var(--step-1); color: var(--text-body); }

/* The marquee is the same list, running. It is decoration over real text: the names
   are in the DOM once whether or not it moves, and it stops dead under reduced motion. */
.marquee { overflow: hidden; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
/* The track holds the list twice so the loop has somewhere to scroll to; translating
   it by half its width lands exactly on the start of the second copy. */
.marquee__track { display: flex; width: max-content; }
.marquee .namelist { flex-wrap: nowrap; width: max-content; gap: 0; }
.marquee .namelist li { white-space: nowrap; padding-inline: var(--space-m); border-left: 1px solid var(--border); color: var(--text-muted); }
@media (prefers-reduced-motion: no-preference) {
  .marquee__track { animation: marquee 52s linear infinite; }
  .marquee:hover .marquee__track, .marquee:focus-within .marquee__track { animation-play-state: paused; }
}
@keyframes marquee { to { transform: translateX(-50%); } }
/* Standing still, the duplicate list is noise. Hide it and let the row scroll by hand. */
@media (prefers-reduced-motion: reduce) {
  .marquee { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }
  .marquee .namelist[aria-hidden="true"] { display: none; }
}
.logo-wall { display: grid; gap: var(--space-m); }
@media (min-width: 52rem) { .logo-wall { grid-template-columns: auto minmax(0, 1fr); align-items: center; gap: var(--space-l); } }
.logo-wall__label { font-family: var(--font-heading); font-weight: 700; font-size: var(--step-0); color: var(--text-muted); white-space: nowrap; }

/* ---- buttons / cta band ---------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-m); border-radius: var(--radius-interactive);
  text-decoration: none; font-weight: 700; font-family: var(--font-heading);
  font-size: var(--step--1); line-height: 1; white-space: nowrap;
  border: 2px solid var(--interactive-fill); cursor: pointer;
  transition: background-color .15s ease, color .15s ease, border-color .15s ease, transform .15s ease;
}
.btn:hover { transform: translateY(-1px); }
.btn:active { transform: translateY(1px); }
/* White on Structural Blue is 4.03:1 — below AA for a 15px bold label. The fill is the
   text-weight blue instead, which measures 5.75:1. */
.btn--primary { background: var(--interactive-fill); color: var(--interactive-fill-text); }
.btn--primary:hover { background: var(--color-ink-base); border-color: var(--color-ink-base); color: var(--color-ink-text); }
.btn--ghost { color: var(--text-body); border-color: var(--border); background: transparent; }
.btn--ghost:hover { background: var(--surface-tinted); border-color: var(--interactive); }
.site-header .btn--primary, .nav-drawer .btn--primary { background: var(--color-blue-deep); border-color: var(--color-blue-deep); color: var(--color-white); }
.site-header .btn--primary:hover, .nav-drawer .btn--primary:hover { background: var(--color-blue-l1); border-color: var(--color-blue-l1); }
.section--dark .btn--primary { background: var(--color-blue-lift); border-color: var(--color-blue-lift); color: var(--color-ink-base); }
.section--dark .btn--primary:hover { background: var(--color-blue-l2); border-color: var(--color-blue-l2); }
.section--dark .btn--ghost { color: var(--text-inverse); border-color: var(--color-ink-rule); }
.section--dark .btn--ghost:hover { background: rgba(255, 255, 255, .1); border-color: var(--color-blue-lift); }
.btn-row { display: flex; flex-wrap: wrap; gap: var(--space-s); margin-top: var(--space-l); }
.btn__arrow { width: 1em; height: 1em; flex: none; transition: transform .15s ease; }
.btn:hover .btn__arrow { transform: translateX(3px); }

/* The closing band: a named person, not a mailbox. */
.responder { margin-top: var(--space-l); display: flex; gap: var(--space-s); align-items: center; }
.responder__mark {
  width: 44px; height: 44px; flex: none; border-radius: var(--radius);
  background: var(--color-blue-deep); color: var(--color-white);
  display: grid; place-items: center;
  font-family: var(--font-heading); font-weight: 800; font-size: var(--step-0);
}
.section--dark .responder__mark { background: var(--color-blue-lift); color: var(--color-ink-base); }
.responder__name { font-family: var(--font-heading); font-weight: 700; }
.responder__role { display: block; font-size: var(--step--1); color: var(--text-muted); }
.section--dark .responder__role { color: var(--text-inverse-muted); }

/* ---- breadcrumb ------------------------------------------------------ */
.breadcrumb { padding-block: var(--space-s); font-size: var(--step--1); }
.breadcrumb ol { list-style: none; display: flex; flex-wrap: wrap; gap: var(--space-2xs); padding: 0; margin: 0; }
.breadcrumb li + li::before { content: "/"; color: var(--text-quiet); margin-right: var(--space-2xs); }

/* ---- stub notice ----------------------------------------------------- */
.stub-notice { border: 1px solid var(--border); border-left: 3px solid var(--interactive); padding: var(--space-m); max-width: 60ch; background: var(--surface-tinted); }
.stub-notice p + p { margin-top: var(--space-2xs); }

/* ---- footer ---------------------------------------------------------- */
.site-footer { background: var(--color-ink-base); color: var(--color-ink-text-2); padding-block: var(--space-xl) var(--space-l); }
.site-footer h2 { font-size: var(--step--1); letter-spacing: .04em; text-transform: uppercase; color: var(--color-ink-text); margin-bottom: var(--space-s); }
.site-footer a { color: var(--color-blue-l2); }
.site-footer a:hover { color: var(--color-white); }
.site-footer ul { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-2xs); font-size: var(--step--1); }
.site-footer__cols { display: grid; gap: var(--space-l); }
@media (min-width: 46rem) { .site-footer__cols { grid-template-columns: 1.5fr 1fr 1fr; } }
@media (min-width: 72rem) { .site-footer__cols { grid-template-columns: 1.5fr 1fr 1fr 1.3fr; } }
.site-footer__brand address { margin-top: var(--space-m); font-size: var(--step--1); line-height: 1.75; }
.site-footer__standards li { color: var(--color-ink-text-2); }
.tagline { font-family: var(--font-heading); font-weight: 600; color: var(--color-ink-text); }
.site-footer__legal { margin-top: var(--space-xl); padding-top: var(--space-m); border-top: 1px solid var(--color-ink-rule); font-size: var(--step--1); color: var(--color-ink-text-2); display: flex; flex-wrap: wrap; gap: var(--space-s); justify-content: space-between; }
address { font-style: normal; }

/* ---- figures.css ---- */
/* ---- figures ---------------------------------------------------------
   The only place on the site permitted a shadow. Everything else is ruled, because
   this firm's own documents are ruled — but a figure reading out numbers is an
   instrument, and an instrument sits on the page rather than in it.
   design/tokens.json $rules.shadow-allowed-on is the list; keep them in step. */

.panel {
  background: var(--surface-default);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-m);
  box-shadow: var(--shadow-panel);
}
.section--dark .panel, .hero--ink .panel {
  background: rgba(255, 255, 255, .035);
  border-color: var(--color-ink-rule);
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .6);
}
.panel__title { font-family: var(--font-heading); font-weight: 700; font-size: var(--step-1); }
.panel__sub { margin-top: var(--space-3xs); font-size: var(--step--1); color: var(--text-muted); max-width: 40em; }
.section--dark .panel__sub, .hero--ink .panel__sub { color: var(--color-ink-text-2); }
/* The chart is decoration over the figures below it. It is aria-hidden and carries no
   number that is not also set as text — a retrieval engine cannot read an SVG path. */
.panel__chart { margin-top: var(--space-s); width: 100%; height: auto; }

.panel__figures {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(6rem, 1fr));
  gap: var(--space-s); margin: var(--space-s) 0 0;
  padding-top: var(--space-s); border-top: 1px solid var(--border);
}
.section--dark .panel__figures, .hero--ink .panel__figures { border-top-color: var(--color-ink-rule); }
.panel__figures dt { font-size: var(--step--1); color: var(--text-muted); }
.section--dark .panel__figures dt, .hero--ink .panel__figures dt { color: var(--color-ink-text-2); }
.panel__figures dd {
  margin: var(--space-3xs) 0 0; font-family: var(--font-heading); font-weight: 800;
  font-size: var(--step-1); letter-spacing: -0.015em; font-variant-numeric: tabular-nums;
  color: var(--text-body);
}
.section--dark .panel__figures dd, .hero--ink .panel__figures dd { color: var(--color-ink-text); }
/* Gold is the approved-budget threshold and nothing else. Never a surface, never a
   word on its own — here it marks the figure the threshold applies to. */
.panel__figures dd[data-mark="threshold"] { color: var(--color-gold-l1); }
.hero--ink .panel__figures dd[data-mark="threshold"], .section--dark .panel__figures dd[data-mark="threshold"] { color: #E3B94A; }

/* Every figure that makes up numbers says so, in words, on the page. The schema makes
   `basis` required so this line cannot be forgotten — the same trick Media.filter uses. */
.figure-basis { margin-top: var(--space-s); font-size: var(--step--1); color: var(--text-muted); line-height: 1.5; max-width: 62ch; }
.figure-basis b { color: var(--text-body); font-weight: 700; }
.section--dark .figure-basis, .hero--ink .figure-basis { color: var(--color-ink-text-2); }
.section--dark .figure-basis b, .hero--ink .figure-basis b { color: var(--color-ink-text); }

/* ---- comparison, bar mode -------------------------------------------
   Drawn in HTML and CSS with the numbers as real text. Never an image: a retrieval
   engine cannot read a figure out of a chart, and this is the site's key number. */
.comparison { display: grid; gap: var(--space-m); max-width: 44rem; }
.comparison__bar { display: grid; grid-template-columns: 1fr; gap: var(--space-3xs); }
.comparison__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-s); }
.comparison__label { font-size: var(--step-0); }
.comparison__figure { font-family: var(--font-heading); font-weight: 800; font-size: var(--step-2); letter-spacing: -0.03em; font-variant-numeric: tabular-nums; }
.comparison__track { height: 14px; background: var(--border); border-radius: 2px; }
.comparison__fill { height: 100%; background: var(--interactive); border-radius: 2px; }
.comparison__bar--contrast .comparison__fill { background: var(--text-muted); }
.comparison__footnote { margin-top: var(--space-m); font-size: var(--step--1); color: var(--text-muted); max-width: 56ch; }

/* ---- comparison, timeline mode ---------------------------------------
   When the overrun surfaces, not how big it is. The point of the figure is the
   position of the marker on the track, so the percentage is also written out. */
.timeline {
  border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-default); box-shadow: var(--shadow-panel); overflow: hidden;
}
.timeline__head, .timeline__foot { padding: var(--space-2xs) var(--space-m); font-size: var(--step--1); color: var(--text-muted); }
.timeline__head { border-bottom: 1px solid var(--border); }
.timeline__foot { border-top: 1px solid var(--border); background: var(--surface-page); }
.timeline__foot b { color: var(--text-body); }
.timeline__row { display: grid; gap: var(--space-2xs); padding: var(--space-s) var(--space-m) var(--space-m); }
.timeline__row + .timeline__row { border-top: 1px solid var(--border); }
@media (min-width: 46rem) {
  .timeline__row { grid-template-columns: minmax(0, 9rem) minmax(0, 1fr); gap: var(--space-m); align-items: center; }
}
.timeline__who { font-family: var(--font-heading); font-weight: 700; font-size: var(--step-0); line-height: 1.2; }
.timeline__who small { display: block; font-family: var(--font-body); font-weight: 400; font-size: var(--step--1); color: var(--text-muted); margin-top: var(--space-3xs); }
.timeline__track { position: relative; height: 2.2rem; min-width: 0; }
.timeline__spent { position: absolute; top: 50%; left: 0; height: 5px; transform: translateY(-50%); border-radius: 2px; background: var(--color-red-l1); opacity: .8; width: var(--at, 0%); }
.timeline__row--early .timeline__spent { background: var(--sequence); opacity: 1; }
.timeline__marker { position: absolute; top: 50%; left: var(--at, 0%); transform: translate(-50%, -50%); }
.timeline__marker::before { content: ""; display: block; width: 13px; height: 13px; border-radius: 50%; background: var(--color-red-l1); border: 3px solid var(--surface-default); box-shadow: 0 0 0 1.5px var(--color-red-l1); }
.timeline__row--early .timeline__marker::before { background: var(--sequence); box-shadow: 0 0 0 1.5px var(--sequence); }
.timeline__marker span {
  position: absolute; top: 100%; margin-top: var(--space-3xs);
  white-space: nowrap; font-size: var(--step--1); color: var(--text-muted);
  left: 50%; transform: translateX(var(--label-shift, -50%));
}
.timeline__options { display: flex; gap: var(--space-3xs); flex-wrap: wrap; font-size: var(--step--1); color: var(--text-muted); }
.timeline__options span { padding: .25em .6em; border: 1px solid var(--border); border-radius: var(--radius-interactive); }
.timeline__options .is-picked { border-color: var(--interactive); color: var(--interactive-text); font-weight: 700; }

/* ---- simulation ------------------------------------------------------
   The canvas is aria-hidden decoration. Everything it says is also in the table
   underneath, which is what a reader with JS off, and what a retrieval crawler, get. */
.simulation { background: var(--surface-default); border: 1px solid var(--border); border-radius: var(--radius); padding: var(--space-m); box-shadow: var(--shadow-panel); }
.simulation__head { display: flex; justify-content: space-between; align-items: baseline; gap: var(--space-s); flex-wrap: wrap; font-size: var(--step--1); color: var(--text-muted); }
.simulation__count { font-variant-numeric: tabular-nums; color: var(--text-body); font-weight: 700; }
/* Nothing draws here without JS, and an empty box reads as a broken image. The table
   below it carries the figures either way, so the canvas simply is not there. */
.simulation__canvas { display: none; width: 100%; height: auto; margin-top: var(--space-2xs); }
.js .simulation__canvas { display: block; }
.js .simulation__legend { display: flex; }
.simulation__legend { display: none; }
.simulation__legend { gap: var(--space-m); flex-wrap: wrap; margin-top: var(--space-2xs); font-size: var(--step--1); color: var(--text-muted); }
.simulation__legend span { display: flex; align-items: center; gap: var(--space-3xs); }
.simulation__legend i { width: 14px; height: 3px; border-radius: 2px; flex: none; }
.simulation__controls { display: flex; gap: var(--space-3xs); flex-wrap: wrap; margin-top: var(--space-s); }
.chip {
  font-family: var(--font-heading); font-weight: 700; font-size: var(--step--1);
  padding: var(--space-3xs) var(--space-2xs); border-radius: var(--radius-interactive);
  border: 1px solid var(--border); background: transparent; color: var(--text-body);
  cursor: pointer; transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}
.chip:hover { background: var(--surface-tinted); }
.chip[aria-pressed="true"] { background: var(--interactive-fill); border-color: var(--interactive-fill); color: var(--interactive-fill-text); }

/* The always-present readout. JS refines the numbers in place; it never creates them. */
.simulation__table { width: 100%; margin-top: var(--space-s); border-collapse: collapse; font-size: var(--step--1); }
.simulation__table caption { text-align: left; color: var(--text-muted); padding-bottom: var(--space-2xs); }
.simulation__table th, .simulation__table td { text-align: left; padding: var(--space-2xs) var(--space-s) var(--space-2xs) 0; border-bottom: 1px solid var(--border); }
.simulation__table th { font-family: var(--font-heading); font-weight: 700; color: var(--text-body); }
.simulation__table td { font-variant-numeric: tabular-nums; color: var(--text-muted); }
.simulation__table tbody th { font-weight: 400; color: var(--text-muted); }

/* Side notes beside a figure — ruled, never boxed. */
.notes { display: grid; border-top: 2px solid var(--text-body); }
.notes > div { padding-block: var(--space-s) var(--space-m); border-bottom: 1px solid var(--border); }
.notes h3 { font-size: var(--step-1); }
.notes p { margin-top: var(--space-3xs); color: var(--text-muted); font-size: var(--step--1); line-height: 1.55; max-width: 48ch; }
