/* ══ ONBENCH — implemented from Kevin's Claude Design canvas ══════════════
   Source of truth: .design-import/Onbench Website.dc.html (144,560 bytes)
   Specs derived from it: .design-import/SPEC-VISUAL.md, SPEC-COPY.md

   This file REPLACES the previous design system wholesale. That system was a
   reconstruction of the old onbench.com; this is a finished design, which is a
   stronger input. Concretely it reverses three things we had settled:
     - typeface   Tungsten + Geist + Geist Mono  ->  Archivo, one family
     - display    600 sentence case, tracking 0  ->  800 UPPERCASE, -0.035em
     - shape      50px pills                     ->  ZERO radius, zero shadow
   Git history holds the old system if any of it is ever wanted back.

   WHERE THIS DELIBERATELY DIVERGES FROM THE DESIGN — each one is a defect in
   the source, not a preference, and each is marked DIVERGENCE at its site:
     1. Two button instances hover to #00043B with no text-colour swap, which
        renders them invisible against the navy page. Normalised.
     2. Form inputs define `outline:none` with no focus style at all. A visible
        focus ring is added; shipping without one is a WCAG 2.4.7 failure.
     3. The two forms disagree with each other on label colour and input
        underline colour. Normalised to one value.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── Archivo, self-hosted ────────────────────────────────────────────────
   The design hotlinks Google Fonts. Self-hosted here for the same reasons the
   previous build was: hotlinking leaks visitor IP + UA to a third party with no
   consent, cannot be SRI-hashed, and pins an extra origin into the CSP.

   BOTH AXES ARE REQUIRED. The design sets `font-stretch: 110-112%` on display
   type, which drives the `wdth` axis — that is what gives the headlines their
   slightly expanded, poster-like cut. A static-weight subset silently loses it
   and the type will look subtly wrong everywhere. The file below carries
   wght 300..800 and wdth 75..125. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url('/assets/fonts/archivo-var-latin.woff2?v=510b8100') 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: 'Archivo';
  font-style: normal;
  font-weight: 300 800;
  font-stretch: 75% 125%;
  font-display: swap;
  src: url('/assets/fonts/archivo-var-latin-ext.woff2?v=a791cc00') 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;
}

/* Metric-matched fallback — the CLS fix, re-derived for Archivo.
   Method unchanged (Capsize, as next/font uses):
     size-adjust = xWidthAvg(webfont) / xWidthAvg(fallback)
     *-override  = hhea metric / (unitsPerEm x size-adjust)
   Measured off the shipped woff2 and macOS Arial.ttf:
     Arial    upem 2048  asc 1854  desc -434  gap 67  xWidthAvg 0.44111
     Archivo  upem 1000  asc  878  desc -210  gap  0  xWidthAvg 0.44918
   Archivo runs within 2% of Arial's width, so the swap is nearly free — a much
   better match than Tungsten's 62% ever was.
   NOTE: derived at wdth 100%. Display type sets font-stretch 112%, which the
   fallback cannot follow; headings will shift slightly more on swap than body
   copy does. Accepted — the alternative is a second fallback face per width. */
@font-face {
  font-family: 'Archivo Fallback';
  src: local('Arial');
  size-adjust: 101.83%;
  ascent-override: 86.22%;
  descent-override: 20.62%;
  line-gap-override: 0%;
}

:root {
  /* ── palette, exactly as the design uses it ──────────────────────────
     This EXTENDS the canonical nine rather than contradicting it: #1523EA,
     #7F85DB, #2E348A, #0A0F56 and #00043B are all brand values. The design
     adds intermediate navy steps and a periwinkle family. */
  --navy-950: #00043B;   /* base page bg, hero, footer, CTA banner */
  --navy-900: #0A0F56;
  --navy-900b:#0B1152;
  --navy-850: #0E1462;
  --navy-800: #141B6E;   /* card / tile surface */
  --navy-hover:#1B2382;  /* dark card hover — Kevin uses this on 7 of his 8 hover states */
  --navy-hover-row:#1A227E; /* roles-list row hover. Kevin's file uses this ONE value here and
                               #1B2382 everywhere else; his design is the source of truth, so
                               the one-off is preserved rather than normalised away. */

  --brand-blue: #1523EA; /* primary: buttons, active states, underlines, ::selection */

  --line:        #2E348A; /* hairline borders, grid gaps, dividers */
  --line-alt:    #3A4090; /* contact form panel border */
  --line-strong: #494D88; /* outline-button borders, input underlines */
  --line-input:  #565CA8;

  --periwinkle: #7F85DB;  /* eyebrows, links, icons, highlighted text */
  --muted-1:    #9DA2DC;
  --muted-2:    #A7ACDD;
  --muted-3:    #B9BDE8;
  --muted-4:    #C7CAEE;  /* hero lede copy */
  --white:      #ffffff;
  --error:      #FF9AA2;

  --font: 'Archivo', 'Archivo Fallback', system-ui, sans-serif;

  --maxw: 1280px;        /* standard content width */
  --maxw-narrow: 900px;  /* role detail, apply, article — reading width */
  --gut: 40px;
  --sect: 112px;         /* the design's dominant section padding */
  /* 79 = Kevin's 78px inner row + the header's own 1px bottom border. He sets the height on
     the inner div and lets the border add on top; we set it on the border-box header, so the
     token has to carry both or every page sits 1px high. Same reason --header-h is 65 (not
     64) at <=900. It also drives .nav.open's `top`, which must clear the border. */
  --header-h: 79px;
}

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

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

body {
  margin: 0;
  background: var(--navy-950);
  color: var(--white);
  font-family: var(--font);
  font-size: 17px;
  /* `normal`, NOT 1.6 — this matches the design's root, which sets no line-height at all.
     Ours inherited 1.6 into everything, so every element without an explicit value rendered
     ~60% taller than his: an 11px label 18px tall against his 12px, and an adopted section
     868px against his 644. It was patched one selector at a time seven times (see the
     micro-label block below) before the cause was addressed here.

     The earlier note said inverting this "would strip 1.6 from every prose block that relies
     on inheriting it, which is a much larger and riskier change." True — and it was the right
     call to defer WHILE THERE WAS NO INSTRUMENT. There is one now: the parity run measures
     every text element against his, so an over-strip shows up as `ref 1.6 -> impl normal` and
     is found rather than shipped. Prose gets 1.6 explicitly, exactly as his does. */
  line-height: normal;
  -webkit-font-smoothing: antialiased;
}

/* Body copy carries its own line-height, as it does in the design (his prose is written
   `line-height:1.6` inline, 31 times). These are the containers that were relying on
   inheritance before the inversion above. */
p, li, dd, blockquote, figcaption, td, th { line-height: 1.6; }

::selection { background: var(--brand-blue); color: var(--white); }

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

/* ZERO RADIUS, ZERO SHADOW — the design's shape language is hard-edged and
   flat. The only border-radius in the entire source is 50% on two decorative
   glow orbs. Browsers round buttons and inputs by default, so this is reset
   explicitly rather than left to chance. */
button, input, textarea, select { border-radius: 0; font: inherit; }

/* ── type ───────────────────────────────────────────────────────────────
   Display is UPPERCASE, weight 800, font-stretch 112%, with tight NEGATIVE
   tracking and sub-1.0 line-height. The negative tracking is what keeps caps
   at this weight from reading as a shout — it is doing real work, not
   decoration, and must not be dropped. */
h1, h2, h3 { margin: 0; font-weight: 800; }

.h-display {
  text-transform: uppercase;
  font-stretch: 112%;
  letter-spacing: -0.035em;
  /* NO line-height here, deliberately. Every display heading in the design
     carries its own — 0.86, 0.87, 0.88, 0.9, 0.94, 0.95, 1.02 — so there is no
     sensible shared default, and asserting one from a class outranks the
     per-page overrides that set the real values. */
  /* Optical correction: the leading glyph's negative tracking pulls the left
     edge in, so headings are nudged back out to sit flush with the grid. */
  margin-left: -0.026em;
}
/* .h-display is a CLASS and h1 is a TYPE selector, so .h-display's line-height
   was silently winning on every heading that did not carry a per-page override —
   the homepage hero rendered at 0.88 instead of the design's 0.86, and the CTA
   h2 at 0.88 instead of 0.9. Setting it on h1 itself (same specificity as the
   font-size beside it) is not enough; the class has to stop asserting a value
   the elements disagree about. */
/* REGRESSION UNDONE. A previous pass "fixed" .h-display beating h1 by adding
   `h1.h-display { line-height: 0.86 }` — specificity (0,1,1), which then beat
   every page-scoped override (.rl-h1, .ap-h1, .rd-h1, .article-h1, all at
   (0,1,0)) and forced 0.86 onto TEN headings that the design gives 0.88-0.95.
   Escalating specificity to win a cascade fight is what caused the problem in
   the first place; the fix is for .h-display to stop asserting the value. */
h1 { font-size: clamp(60px, 9vw, 148px); line-height: 0.86; }
h2 { font-size: 56px; line-height: 0.96; letter-spacing: -0.03em; font-stretch: 110%; text-transform: uppercase; }
h3 { font-size: 19px; line-height: 1.2; font-weight: 700; letter-spacing: -0.01em; }

p { margin: 0 0 1em; text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

/* Kevin's section eyebrow, measured: 11px / 700 / 0.18em / 22px, line-height normal.
   Ours was 12px / 700 / 0.16em / 18px and inherited body's 1.6 line-height — wrong on FOUR
   properties at once, on a label that appears on nearly every section. That is most of why
   our sections ran taller than his even where the headings matched.
   His uppercase labels are not one spec: a census of his file finds 8+ variants
   (11/0.18em/22px x10, 11/0.16em/10px x10, 12/0.14em x9, 13/0.12em x6...). This class is the
   SECTION eyebrow only; the others are context labels and should not be folded in here. */
.eyebrow {
  font-size: 11px; font-weight: 700; letter-spacing: 0.18em; line-height: normal;
  text-transform: uppercase; color: var(--periwinkle); margin: 0 0 22px;
}
/* CONTRAST FIX — a real defect in the design's own pairing, not a preference.
   Periwinkle on the page ground (#00043B) is 5.81:1 and fine. On the card
   surface (#141B6E) the same colour measures 4.45:1 and misses AA for 12px
   text by 0.05. Stepping to --muted-1 on card surfaces gives 6.12:1 and keeps
   the label reading as a quiet kicker rather than promoting it. */
.hairline .eyebrow { color: var(--muted-1); }
.lede { font-size: 19px; line-height: 1.6; color: var(--muted-4); }
.body-lg { font-size: 19px; line-height: 1.6; color: var(--muted-3); }
.muted { color: var(--muted-2); }

/* ── layout ─────────────────────────────────────────────────────────── */
.wrap { max-width: var(--maxw); margin: 0 auto; padding: 0 var(--gut); }
.wrap-narrow { max-width: var(--maxw-narrow); margin: 0 auto; padding: 0 var(--gut); }

/* Content sits ABOVE the decorative layer, everywhere — not just where someone
   remembered. Every section's shard and bird SVGs are position:absolute with
   z-index:auto, and a positioned element paints above a STATIC in-flow sibling
   regardless of DOM order. So on the pages whose wrap was left static, the shard
   composited over the copy: /roles rendered "WORK WITH GREAT PEOPLE & CLIENTS."
   with a translucent band washing out the middle of both lines and the lede
   under it. Some pages carried an inline position:relative to counter this and
   some did not, which is exactly the kind of thing that should not be per-page.
   position:relative alone (no z-index) is enough — the wrap follows the SVGs in
   DOM order, so it paints last — and it creates no stacking context, so the
   sticky-hero cover on the homepage is unaffected.
   Lighthouse cannot catch this: it derives contrast from CSS colours, not from
   what is composited on top. */
:is(section, article, header, footer, main, div) > :is(.wrap, .wrap-narrow) { position: relative; }
section { padding: var(--sect) 0; position: relative; }
.sect-hero { padding: 110px 0 92px; }

.grid-2 { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 40px; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0,1fr)); gap: 40px; }
.grid-4 { display: grid; grid-template-columns: repeat(4, minmax(0,1fr)); gap: 40px; }

/* ── hairline grid — the design's dominant card idiom ───────────────────
   A container painted --line, with a 1px grid gap, holding solid-filled
   cells. The gap shows the container through as a seamless hairline between
   cards. No per-cell borders, so no doubled lines at the joins. */
.hairline {
  display: grid; gap: 1px;
  background: var(--line); border: 1px solid var(--line);
}
/* Kevin's card padding, measured: 40px 30px 48px. Ours was 38px 38px 46px — and the 8px of
   extra SIDE padding was the part that mattered: it narrows the text column by 16px, so the
   copy wraps an extra line and the card ends up TALLER despite having less vertical padding.
   That was the whole of the +20px on the pillars row. */
.hairline > * { background: var(--navy-800); padding: 40px 30px 48px; }
.hairline-dark > * { background: var(--navy-950); }
.hairline-2 { grid-template-columns: repeat(2, minmax(0,1fr)); }
.hairline-3 { grid-template-columns: repeat(3, minmax(0,1fr)); }
.hairline-4 { grid-template-columns: repeat(4, minmax(0,1fr)); }

/* ── buttons ────────────────────────────────────────────────────────────
   Uppercase, 0.12em tracking, weight 700, square. */
.btn {
  /* An explicit colour, so a .btn dropped inside coloured copy can never
     inherit it. Without this, a bare .btn inside a periwinkle status paragraph
     rendered #7f85db on #1523EA = 2.55:1 — caught by the contrast gate on
     three pages. */
  color: var(--white);
  display: inline-block; border: 0; cursor: pointer;
  font-family: var(--font); font-size: 13px; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase;
  /* The design's root wrapper sets no line-height, so controls inherit
     `normal`. Ours inherit body's 1.6, which inflated every button by 13%
     (54px -> 61px measured) and every nav link's line box by 46% (13px -> 19px)
     while the padding stayed pixel-identical. */
  line-height: normal;
  padding: 19px 32px;
}
.btn-primary { background: var(--brand-blue); color: var(--white); }
/* DIVERGENCE 1. The design's CTA-banner and article-footer buttons hover to
   background:#00043B with no text-colour change — on a navy page that makes
   the control vanish under the cursor. Read as an authoring slip, not intent.
   All primary buttons use the standard swap. */
.btn-primary:hover { background: var(--white); color: var(--navy-950); }
.btn-secondary { background: none; color: var(--white); border: 1px solid var(--line-strong); }
.btn-secondary:hover { border-color: var(--white); }
.btn-lg { padding: 24px 40px; font-size: 14px; }
.btn-sm { padding: 15px 26px; font-size: 12px; }

/* Focus ring. The design defines none anywhere; shipping without one fails
   WCAG 2.4.7. White reads on every surface in this palette. */
:focus-visible { outline: 2px solid var(--white); outline-offset: 3px; }

/* ── forms ──────────────────────────────────────────────────────────────
   Underline-only inputs on a transparent field.
   DIVERGENCE 3: the design's two forms disagree — labels #7F85DB vs #9DA2DC,
   underlines #494D88 vs #565CA8. Normalised to the periwinkle label and the
   lighter underline.

   CORRECTION: an earlier version of this comment called that "the more legible
   pair of the two". That is false for the label, and the claim was mine, not a
   measurement. On the page ground #00043B the label we KEPT (#7F85DB) is
   5.81:1; the one we REJECTED (#9DA2DC) is 7.99:1 — the rejected one is more
   legible. Both clear AA for 11px text, so nothing here is broken, but the real
   reason for the choice is consistency: periwinkle is the label colour used by
   .eyebrow everywhere else on the site. That is a design argument, not a
   legibility one, and it should not have been dressed up as the latter.
   (The underline half of the claim does hold: #565CA8 is 3.23:1 against
   #494D88's 2.50:1.) */
.field { display: block; margin-bottom: 30px; }
.field label {
  display: block; font-size: 11px; font-weight: 700; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--periwinkle); margin-bottom: 10px;
}
.field input, .field textarea, .field select {
  width: 100%; background: transparent; color: var(--white);
  border: 0; border-bottom: 1px solid var(--line-input);
  padding: 12px 0; font-size: 18px;
  /* Kevin's controls render 45px; ours were 54px on identical padding and font-size, because
     they inherited body's 1.6 while his are `normal`. Six fields x 9px is most of why our
     contact form column ran 146px taller than his. Same inheritance that has now shown up on
     eyebrows, section labels and form controls — it is the single most repeated cause in this
     whole parity pass. */
  line-height: normal;
}
.field textarea { min-height: 130px; resize: vertical; }
/* DIVERGENCE 2: focus state added (design sets outline:none and stops). */
.field input:focus-visible, .field textarea:focus-visible, .field select:focus-visible {
  outline: none; border-bottom-color: var(--white); box-shadow: 0 1px 0 0 var(--white);
}
.field .err { color: var(--error); font-size: 13px; margin-top: 8px; }

/* Pill selectors — sentence case, unlike every other button in the system.
   The design's `accentColor` canvas variant drove ONLY this selected state and
   nothing else; a static site cannot offer a per-viewer switcher, so the
   default #1523EA is hardcoded and the swatch concept is dropped. */
.pill {
  background: transparent; color: var(--white);
  border: 1px solid var(--line-strong);
  padding: 11px 16px; font-size: 13px; font-weight: 600; cursor: pointer;
}
.pill[aria-pressed="true"] { background: var(--brand-blue); border-color: var(--white); }

/* ── header ─────────────────────────────────────────────────────────── */
.site-head {
  position: sticky; top: 0; z-index: 80; height: var(--header-h);
  background: rgba(0, 4, 59, 0.94);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.site-head .wrap { display: flex; align-items: center; gap: 28px; height: 100%; }
.site-head .logo img { height: 31px; width: auto; }
.nav { display: flex; gap: 26px; margin-left: auto; align-items: center; }
.nav a {
  font-size: 12px; font-weight: 600; letter-spacing: 0.14em; line-height: normal;
  text-transform: uppercase; opacity: .72; transition: opacity 150ms;
}
.nav a:hover, .nav a.on { opacity: 1; }
.nav-cta { background: var(--brand-blue); padding: 12px 20px; opacity: 1 !important; transition: background 150ms; }
.nav-cta:hover { background: var(--white); color: var(--navy-950); }
.burger { display: none; margin-left: auto; background: none; border: 0; color: var(--white); font-size: 22px; cursor: pointer; padding: 6px 8px; }

/* ── footer ─────────────────────────────────────────────────────────── */
/* Padding lives on the INNER wrapper, as it does in the design: his <footer> computes
   0/0/0/0 and his grid wrapper carries 64/40/40/40. Ours had it on the footer element, which
   measured as paddingTop 0 -> 64 on the root at every viewport. Net spacing is unchanged; the
   structure now matches, so his next edit to it lands somewhere we can follow.
   font-size 16px is his footer root value — ours inherited body's 17px. */
.site-foot { background: var(--navy-950); border-top: 1px solid var(--line); padding: 0; font-size: 16px; position: relative; overflow: hidden; }
.site-foot .wrap { position: relative; padding-top: 64px; padding-bottom: 40px; }
.foot-bird { position: absolute; bottom: -90px; right: -60px; width: 520px; height: auto; color: var(--periwinkle); opacity: .23; pointer-events: none; will-change: transform; }
.foot-top img { height: 24px; width: auto; }
.foot-blurb { font-size: 16px; line-height: 1.6; color: var(--muted-1); margin: 24px 0 0; max-width: 38ch; }
.foot-top { display: grid; grid-template-columns: 1.4fr 1fr 1fr; gap: 56px; }
/* line-height: normal because this is an <h2> and so inherits the global
   `h2 { line-height: 0.96 }`, which rendered an 11px label 10.55px tall against his 12px.
   His is a <div> and has no such rule to inherit. The semantic heading is right for the
   labelled nav; the display line-height is not. */
.foot-col h2 { font-size: 11px; font-weight: 700; letter-spacing: 0.18em; line-height: normal; text-transform: uppercase; color: var(--periwinkle); margin: 0 0 20px; font-stretch: normal; }
/* The design sets EVERY footer link to #FFFFFF, and gives only the Site column a
   hover (to periwinkle). This shipped inverted on both axes — a dim --muted-2
   default with a white hover — which left the footer nav visibly greyer than the
   white logo beside it. Only caught by rendering the design side by side; it is
   invisible to source diffing because both rules are well-formed.

   The "Get in touch" column intentionally has NO hover, matching the design.
   Hover affordance is not a WCAG requirement and :focus-visible still covers
   keyboard users, so this is fidelity rather than a regression. */
/* The trailing margin was counted too: his column is a flex stack with gap:12, so 4 links
   give 3 gaps. Ours gave 4 margins and the column measured 147 against his 136. */
.foot-col a { display: block; color: var(--white); font-size: 16px; margin-bottom: 12px; }
.foot-col a:last-of-type { margin-bottom: 0; }
.foot-col-site a { transition: color 150ms; }
.foot-col-site a:hover { color: var(--periwinkle); }
.foot-bottom { display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap; margin-top: 40px; color: var(--muted-1); font-size: 13px; }

/* ── motion ─────────────────────────────────────────────────────────────
   Glow-orb pulse. Absolutely positioned, centred on its own coordinate. */
@keyframes ob-glow {
  0%, 100% { opacity: .55; transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: .9;  transform: translate(-50%, -50%) scale(1.12); }
}
/* The pulse is OPT-IN. The design animates exactly one orb — the Home hero
   (line 116 of the canvas). The About and Careers orbs are declared with no
   `animation` property at all and are static. A shared animated .glow class
   made two pages quietly breathe when the reference does not. */
.glow {
  position: absolute; border-radius: 50%; pointer-events: none;
}
.glow-pulse { animation: ob-glow 9s ease-in-out infinite; }

/* Rotating word in the hero eyebrow. The cycling itself needs JS; this is the
   per-word curve, applied on each swap. */
@keyframes ob-word {
  0%   { opacity: 0; transform: translateY(0.4em); }
  10%  { opacity: 1; transform: translateY(0); }
  90%  { opacity: 1; transform: translateY(0); }
  100% { opacity: 0; transform: translateY(-0.4em); }
}
/* `both` matters: the JS interval and the CSS animation run on independent
   clocks, so without a retained end state the word snaps back to full opacity
   for a frame before the node is swapped. Stops the flicker. Percentages are
   the design's 0/10/90/100, not the 0/12/88/100 first shipped. */
.word-cycle { display: inline-block; animation: ob-word 4400ms cubic-bezier(0.33, 0, 0.15, 1) both; }

@media (prefers-reduced-motion: reduce) {
  .glow { animation: none; }
  .word-cycle { animation: none; }
  [data-parallax] { transform: none !important; }
}

/* ── micro-label line-height ─────────────────────────────────────────────
   Kevin sets no body line-height, so every small uppercase label in his design
   renders at `normal`. Ours inherits body's 1.6, which makes an 11px label 18px
   tall against his 12px. Patched one selector at a time seven times during this
   parity pass (hero eyebrow, section eyebrow, logo-band label, step number, stat
   label, form controls, blog tag) before it was worth stating once.

   Scoped to SMALL UPPERCASE text specifically, not to body: dropping body to
   `normal` would strip 1.6 from every prose block that relies on inheriting it,
   which is a much larger and riskier change. This targets the class of element
   that is actually wrong, and each page was re-measured after applying it. */
.eyebrow, .blog-card-tag, .blog-card-meta, .blog-featured-label, .blog-featured-meta,
.blog-featured-cta, .blog-recent-label, .rl-back, .rl-count, .rl-row-loc, .rl-row-view,
.rd-back, .ap-back, .ap-summary-label, .ap-field-label, .ap-file-label,
.field label, .home-logos-label, .home-acc-stat-label, .home-step-num {
  line-height: normal;
}

/* ── adopted sections ────────────────────────────────────────────────────
   Sections marked [data-kev] are Kevin's own markup, transplanted verbatim from
   Onbench Website.dc.html rather than reimplemented. See tools/adopt-section.mjs.

   His markup carries every visual decision inline, but it assumes HIS helmet
   baseline — and the one that matters is line-height. He sets none, so his text
   renders at `normal`; dropped into our page it inherits body's 1.6 and every
   block without an inline line-height grows ~60%. The adopted accountable
   section measured 868px against his 644 until this block existed.

   His mobile rules are attribute-matched (`[style*="grid-template-columns"]`)
   because his prototype styles everything inline. Everywhere else we ported his
   DECISIONS onto our classes; here we need his SELECTORS too, because adopted
   markup has no classes of ours to hook. Scoped to [data-kev] so they cannot
   reach the sections we still author. */
[data-kev] {
  /* A REAL inheritance boundary, not a patch. `line-height: normal` here fixed the one
     inherited property that had been caught; there are ~30 inherited properties and the other
     29 were still leaking, having simply not produced a visible defect yet.

     `all: initial` is the only primitive that stops inheritance: @scope and shadow DOM do not
     (inherited properties cross both), and `all: revert` reverts inherited properties absent
     from the UA sheet — colour among them — back to `inherit`, so the host still leaks through.
     Applied to the WRAPPER it resets the boundary only: descendants keep their UA defaults, so
     his <h1> stays bold and block and his <p> keeps its margins. Custom properties are excluded
     from `all`, so our --tokens still reach through if ever needed. */
  all: initial;
  display: block;
  /* Re-declared because `all: initial` clears them, and his root assumes both. Taken from his
     root wrapper (`font-family:Archivo,…`), not guessed. */
  font-family: var(--font);
  color: var(--white);
  /* `section { padding: var(--sect) 0 }` is ours and it double-pads his markup: his own inner
     wrapper already carries `padding: 112px 40px`, so the adopted section rendered 868px
     against his 644 — the extra 224 being exactly our 112 top + 112 bottom laid on top of his.
     His sections own their padding; ours must not add any. */
  padding: 0;
}
[data-kev] a { color: var(--muted-1); text-decoration: none; }
[data-kev] a:hover { color: var(--white); text-decoration: underline; }

/* A DELIBERATE DEVIATION FROM HIS DESIGN, because his fails WCAG AA here.
   His numbered step markers (01-06 in the benefits section) are #494D88 on #141B6E —
   1.91:1 against a 4.5:1 requirement. Adopting his markup verbatim imported the defect and
   failed our color-contrast gate, which is an ERROR gate on this project, not a warning.
   #9DA2DC is the nearest token in his own hue family that passes, at 6.12:1. Measured, not
   eyeballed: --periwinkle is 4.45:1 and would still fail.
   This is the same class as the 3.75:1 table headers on the admin board — his design has
   contrast problems that only surface once his markup is actually rendered and audited. It
   should be fixed in his file; until then we override rather than ship a failing page. */
[data-kev] span[style*="color: rgb(73, 77, 136)"] { color: #9DA2DC !important; }

@media (max-width: 900px) {
  [data-kev] > div { padding-left: 20px !important; padding-right: 20px !important; }
  [data-kev] [style*="grid-template-columns"] { grid-template-columns: minmax(0,1fr) !important; }
  [data-kev] [style*="grid-template-columns"] > * { grid-column: auto !important; }
  /* He also drops every large gap to 40 here — enumerated because his selector can only
     match the literal inline value. Collapsing the columns without the gap left a stacked
     80px gutter and a constant +40px on the section. */
  [data-kev] [style*="grid-template-columns"][style*="gap: 88px"],
  [data-kev] [style*="grid-template-columns"][style*="gap: 80px"],
  [data-kev] [style*="grid-template-columns"][style*="gap: 64px"],
  [data-kev] [style*="grid-template-columns"][style*="gap: 56px"],
  [data-kev] [style*="grid-template-columns"][style*="gap: 48px"] { gap: 40px !important; }

  /* HIS data-m EXCEPTIONS, and they must come after the blanket collapse above so they win.
     Without them the generic "every grid becomes one column" rule also flattened his photo
     rows: the join-our-team photo strip went to a single column of full-width images and the
     section measured 7881px at 900 — and grew as the viewport widened, which is the tell that
     a grid collapsed that should not have. */
  [data-kev] [data-m="photorow"] { grid-template-columns: repeat(4, minmax(0,1fr)) !important; }
  [data-kev] [data-m="photorow"] > div { margin-top: 0 !important; }
  [data-kev] [data-m="logos"] { grid-template-columns: repeat(3, minmax(0,1fr)) !important; gap: 28px 24px !important; }
  [data-kev] [data-m="collage"] { margin-top: 40px !important; margin-left: 0 !important;
    width: 100% !important; justify-content: flex-start; }
  [data-kev] [data-m="tile"] { width: 52px !important; height: 52px !important; }
  [data-kev] [style*="height: 420px"] { height: 280px !important; }
  [data-kev] button, [data-kev] a[style] { min-height: 44px; }
}
@media (max-width: 640px) {
  [data-kev] h1, [data-kev] h2, [data-kev] h3,
  [data-kev] p, [data-kev] span { overflow-wrap: break-word; }
  [data-kev] h2 { font-size: clamp(26px, 8.2vw, 42px) !important; }
  [data-kev] h3 { font-size: clamp(19px, 5.4vw, 26px) !important; }
  [data-kev] > div { padding-left: 18px !important; padding-right: 18px !important; }
  /* His 640 card-padding rules, enumerated exactly as he wrote them — an attribute selector
     can only match the literal inline value, so each padding he uses needs its own entry.
     Missing these left the playbook step cards at full padding and the section +84px at 640,
     +108px at 390. */
  [data-kev] [style*="padding: 52px 48px"],
  [data-kev] [style*="padding: 36px 40px 38px"] { padding: 26px 22px !important; }
  [data-kev] [style*="padding: 40px 36px 48px"],
  [data-kev] [style*="padding: 40px 34px"],
  [data-kev] [style*="padding: 36px 30px 42px"],
  [data-kev] [style*="padding: 34px 30px 40px"] { padding: 28px 22px 32px !important; }
  /* he drops the decorative collage entirely below 640 rather than shrinking it */
  [data-kev] [data-m="collage"] { display: none !important; }
}

/* ── responsive ─────────────────────────────────────────────────────────
   THE DESIGN CONTAINS NO MEDIA QUERIES AT ALL. Responsiveness there is
   clamp() + minmax() + flex-wrap, plus two container queries. That leaves
   every multi-column grid — the 4-col pillars, 7-col logo strip, 8-col career
   photo strip — with no defined mobile behaviour: they would simply squeeze.

   THAT IS NO LONGER TRUE. Kevin's reference went responsive on 2026-09-03: it
   now carries two breakpoints, 900 and 640, and 26 rules. So this block stops
   being authored guesswork and goes back to being a transcription — and the
   breakpoints below are HIS, not the 1024/860/560 invented here while there
   was nothing to follow.

   His selectors are attribute matches — main [style*="grid-template-columns"],
   [style*="padding: 52px 48px"] — because his prototype styles everything
   inline and that is the only hook he has. We have real classes, so what is
   ported below is his DECISIONS, not his selectors. Copying [style*=…] matching
   into a class-based stylesheet would be fragile and slower for no gain.

   Two of his mobile rules are deliberately NOT ported, because they are floors
   we already clear and copying them would only add noise:
     input font-size:16px   — ours is 18px (the floor exists to stop iOS
                              zooming on focus below 16px)
     button min-height:44px — our .btn is padding:19px 32px at 13px ≈ 54px */
@media (max-width: 900px) {
  /* Kevin collapses the header to 64px on mobile; ours stayed at the desktop 78px at every
     width, so the whole page sat 13px lower than his and the sticky bar ate more of a short
     viewport than it should. --header-h also drives .nav.open's `top`, so it has to move
     here rather than being patched on .site-head alone. */
  /* --sect stays 112px. Kevin's mobile rules only ever touch padding-LEFT/RIGHT
     (`main section > div { padding-left:20px; padding-right:20px }`); his vertical section
     rhythm is identical at every width. Ours dropped to 76px, which is 2 x 36px = the exact
     -72px every section ran short of his at 900, 640 and 390. */
  :root { --gut: 20px; --header-h: 65px; }

  /* every multi-column grid collapses — his single broadest rule */
  .grid-2, .grid-3, .grid-4,
  .hairline-2, .hairline-3, .hairline-4 { grid-template-columns: minmax(0,1fr); }
  .foot-top { grid-template-columns: 1fr; }
  .foot-bottom { flex-direction: column; }
  /* His `button { min-height: 44px }` at 900, which styles.css previously declined to port on
     the grounds that "our .btn is padding:19px 32px at 13px = 54px". True of .btn, and false
     of every other tappable thing: his footer links measure 44px tall at 900/640/390 and ours
     measured 17. The floor was cleared where it was checked and missed where it was not.
     min-height ALONE — no flex. Reaching the 44px with `display:flex; align-items:center`
     centres the label but changes the box type, and the parity run immediately reported 7
     `display: block -> flex` and 7 `alignItems` findings against his markup: 17 new signatures
     for 12 resolved. The height is the accessibility requirement; the flexbox was decoration. */
  .foot-col a, .nav a { min-height: 44px; }
  /* Card padding does NOT shrink at 900. Kevin keeps the full 40px 30px 48px here and only
     reduces at 640, to 28px 22px 32px. Ours dropped to 28px 24px 32px a breakpoint early,
     which made the stacked card columns ~184px shorter than his at both 900 and 640. */

  /* he caps the logo band at 3-up rather than collapsing it */
  .home-logo-grid { grid-template-columns: repeat(3, minmax(0,1fr)); gap: 28px 24px; }

  /* tall fixed blocks: his 420px -> 280px */
  /* Kevin caps every 420px-tall block at 280 here. His selector is [style*="height: 420px"]
     because his prototype sets that inline; ours sets it in a CLASS, so the ported attribute
     selector matched NOTHING and .home-acc-photo stayed 420px — 140px of the 158px that
     section ran tall at 900. Match on our real class names instead of his markup hook. */
  .home-id-figure, .home-acc-photo, [style*="height: 420px"] { height: 280px; }

  .burger { display: block; }
  .nav { display: none; }
  .nav.open { display: flex; flex-direction: column; align-items: flex-start; gap: 0;
    position: absolute; top: var(--header-h); left: 0; right: 0;
    background: var(--navy-950); border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line); padding: 8px var(--gut) 18px; }
  /* his nav items are full-width 52px rows, not inline links */
  .nav.open a { min-height: 52px; width: 100%; display: flex; align-items: center; font-size: 14px; }
}

@media (max-width: 640px) {
  :root { --gut: 18px; }

  /* his 640 card padding, applied to the same cards his attribute selectors target */
  .hairline > * { padding: 28px 22px 32px; }

  /* THE BIG ONE. Ours sat on the clamp floor of clamp(60px,9vw,148px), so the
     homepage h1 rendered 60px at 390px against his 37.4px — 1.6x oversized.
     These three are his exact mobile scale. */
  h1, .h-display { font-size: clamp(28px, 9.6vw, 54px); }
  h2 { font-size: clamp(26px, 8.2vw, 42px); }
  h3 { font-size: clamp(19px, 5.4vw, 26px); }

  /* long words — emails, URLs, unbroken product names — must not push the
     layout sideways. We had no equivalent at any width. */
  h1, h2, h3, p, span, li, a { overflow-wrap: break-word; }

  /* he drops the decorative collage entirely rather than shrinking it */
  .home-collage, [data-m="collage"] { display: none; }
}

/* ── draft banner ───────────────────────────────────────────────────────
   Layer 2 of the draft gate is the noindex meta; this is the human-visible
   layer. Carried over from the previous build — it was dropped when this file
   was replaced, leaving the banner rendering as unstyled body text. It comes
   off at cutover together with the Access policy and the robots headers, never
   separately. */
/* ── utilities ──────────────────────────────────────────────────────── */
.vh { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }
.skip { position: absolute; left: -9999px; }
.skip:focus { left: 12px; top: 12px; z-index: 200; background: var(--white); color: var(--navy-950); padding: 10px 16px; }

/* ── article (single blog post) ─────────────────────────────────────── */
/* Was copied verbatim into all 7 post files — 38 identical lines each, 266 in
   total, with nothing keeping them in sync. Already scoped to .article-*, so
   lifting it here is a pure move. A new post now inherits it for free, which is
   the precondition for a post being authorable content rather than a file only
   an engineer can safely create. */
/* Article (single post) — scoped to .article-*, shared verbatim across all 7 posts. */
/* overflow:hidden is not decoration. The decorative bird SVGs are absolutely positioned and
   deliberately bleed past the edges; every one of Kevin's sections carries overflow:hidden to
   clip them. Ours did not, so all seven article pages had 169px of horizontal overflow and a
   sideways scrollbar — at EVERY width, 1440 down to 390. A real bug, not a parity nit. */
.article-head { position: relative; overflow: hidden; padding: 80px 0 76px; }
.article-back {
  display: inline-block; margin-bottom: 44px;
  color: var(--periwinkle); font-size: 12px; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase;
}
.article-back:hover { color: var(--white); }
.article-tag { margin-bottom: 24px; }
.article-h1 {
  font-size: clamp(38px, 5vw, 68px);
  font-stretch: 110%;
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin: 0 0 28px;
}
.article-dek {
  font-size: 20px; line-height: 1.55; color: var(--muted-4);
  margin: 0 0 36px; max-width: 56ch; text-wrap: pretty;
}
.article-meta {
  display: flex; gap: 24px; flex-wrap: wrap;
  font-size: 12px; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--periwinkle);
  border-top: 1px solid var(--line); padding-top: 24px;
}
.article-body-sect { background: var(--navy-900); position: relative; overflow: hidden;
  padding: 80px 0 96px; }
.article-body { display: flex; flex-direction: column; gap: 28px; }
.article-body p { font-size: 19px; line-height: 1.7; color: var(--muted-4); margin: 0; text-wrap: pretty; }
.article-cta {
  margin-top: 56px; padding-top: 36px; border-top: 1px solid var(--line);
  display: flex; align-items: center; justify-content: space-between;
  gap: 24px; flex-wrap: wrap;
}
.article-cta p { font-size: 17px; color: var(--muted-3); max-width: 44ch; margin: 0; }
.article-cta .btn { padding: 17px 28px; font-size: 12px; }
