/* The two sheets this one used to @import are now <link>ed in the document head.
   An @import is discovered only AFTER main.css has downloaded and parsed, so it
   serialises: main.css -> fonts.css -> the font files. Three round trips before
   text can paint in the right face. As parallel <link>s the browser starts all
   of them in the first burst. Cascade order is preserved by link order. */

/* ==========================================================================
   Kevin Eze — Dark Signal
   Implements Web Design/Design Guides/KE/KevinEze_Design_System.md v1.0.
   Section numbers in comments refer to that document.
   One figure, one light source, one colour.
   ========================================================================== */

:root {
  /* ---- 1. Colour · primary [IMG] ---- */
  --color-field:       #050506;
  --color-ember:       #a0161a;
  --color-ember-deep:  #7d1518;
  --color-white:       #ffffff;
  --color-mist:        #c9c9c9;

  /* ---- 1. Colour · extended ---- */
  --color-signal:      #e52126;
  --color-ember-line:  #da1e23;
  --color-bloom-core:  #4a0d10;
  --color-bloom-mid:   #2a080a;
  --color-mist-bright: #e8e8e8;
  --color-mist-dim:    #8a8a8a;
  --color-steel:       #6e6e6e;
  --color-plate:       #1a1a1e;
  --color-plate-2:     #121215;
  --color-grid:        rgba(229, 33, 38, .06);
  --hairline:          rgba(255, 255, 255, .10);

  /* Venture hover fills. Each traces to that brand's own system, not invented.
     AFN gold is the dark-ground value from the AFN design system; its ink is
     AFN's own --text-on-gold. */
  --afn-gold:      #d4a020;   /* ink #1a1208 -> 7.86:1 */
  --afn-gold-ink:  #1a1208;
  --afdf-green:    #2e7d32;   /* white -> 5.13:1 */
  --beta-red:      var(--color-ember-deep);  /* white -> 10.54:1 */

  /* ---- 1. Semantic aliases ---- */
  --surface-page:  var(--color-field);
  --surface-plate: var(--color-plate);
  --text-primary:  var(--color-white);       /* 20.37:1 */
  --text-strong:   var(--color-mist-bright); /* 16.63:1 */
  --text-body:     var(--color-mist);        /* 12.30:1 */
  --text-meta:     var(--color-mist-dim);    /*  5.90:1 */
  --action-fill:   var(--color-ember);
  --action-ink:    var(--ink-on-accent);
  --action-line:   var(--color-ember-line);  /*  4.07:1 */
  --ghost-line:    var(--color-steel);       /*  4.00:1 */
  --focus-ring:    var(--color-signal);      /*  4.44:1 */
  --logo-accent:   #ff2d2d;                  /* the mark's own red */
  /* The ember fill is red in both themes, so the ink on it never flips.
     Tying this to --color-white put near-black on red in the light theme. */
  --ink-on-accent: #ffffff;                  /* 8.00:1 on ember */

  /* ---- 2. Typography ---- */
  --font-display: 'JetBrains Mono', 'SF Mono', Menlo, monospace;
  --font-body:    'DM Sans', 'Helvetica Neue', sans-serif;
  --font-meta:    'DM Mono', 'Courier New', monospace;

  --type-hero:    clamp(44px, 5.2vw, 80px);
  --type-role:    clamp(17px, 1.5vw, 19px);
  --type-lead:    clamp(16px, 1.1vw, 18px);
  --type-body:    17px;
  --type-label:   16px;
  --type-stat:    clamp(64px, 9vw, 120px);
  --type-caption: 13px;
  --type-h2:      clamp(30px, 3.4vw, 46px);
  --type-h3:      clamp(20px, 1.8vw, 25px);

  /* ---- 3. Spacing · 8px unit ---- */
  --space-xs: 4px;   --space-sm: 8px;   --space-md: 16px;  --space-lg: 24px;
  --space-xl: 40px;  --space-2xl: 64px; --space-3xl: 96px;

  --shell:  1280px;
  --gutter: clamp(24px, 5vw, 64px);

  /* ---- 5. Motion ---- */
  --ease-out-expo:  cubic-bezier(.16, 1, .3, 1);
  --ease-in-expo:   cubic-bezier(.7, 0, .84, 0);
  /* Expo is the right curve for a 300ms interface response: it snaps away from
     the start. Stretched past a second it spends most of its life almost
     stationary, which reads as a stall rather than a glide. Entrances get their
     own gentler curve so the longer durations below actually feel like travel. */
  --ease-glide:     cubic-bezier(.22, .68, .24, 1);

  /* Interface feedback. Hover, focus, a pill changing state. These stay quick;
     slowing them makes the site feel laggy, not cinematic. */
  --duration-fast:      150ms;
  --duration-base:      300ms;
  --duration-slow:      600ms;
  /* Entrances. Nothing that glides in is under a second. */
  --duration-reveal:      1150ms;
  --duration-reveal-long: 1450ms;
  --duration-cinematic:   1400ms;

  --grid-size: 96px;
}

/* --------------------------------------------------------------------------
   Light theme. A divergence from DS section 1 ("the field is the only
   background this system has"), requested by Kevin. The hero and every page
   header keep the dark field in both themes, so the signature composition,
   the bloom and the subject plate, never changes.
   -------------------------------------------------------------------------- */
:root.light {
  --color-field:       #f2f1ee;
  --color-plate:       #e6e4e0;
  --color-plate-2:     #eceae6;
  --color-white:       #0f1113;   /* "white" becomes the ink on a light field */
  --color-mist:        #3d4148;
  --color-mist-bright: #23262b;
  --color-mist-dim:    #63686f;   /* 4.94:1 on the light field */
  --color-steel:       #9aa0a8;
  --hairline:          rgba(15, 17, 19, .14);
  --color-grid:        rgba(160, 22, 26, .07);
}
:root.light .pill--ghost { color: var(--text-primary); }
:root.light .hdr.is-stuck { background: rgba(242, 241, 238, .90); }
:root.light .totop { color: var(--text-primary); }

/* The frames that stay dark no matter the theme. Tokens are redeclared locally
   so everything inside them inherits the dark values without any extra rules. */
.frame-dark {
  --color-field:       #050506;
  --color-plate:       #1a1a1e;
  --color-plate-2:     #121215;
  --color-white:       #ffffff;
  --color-mist:        #c9c9c9;
  --color-mist-bright: #e8e8e8;
  --color-mist-dim:    #8a8a8a;
  --color-steel:       #6e6e6e;
  --hairline:          rgba(255, 255, 255, .10);
  --color-grid:        rgba(229, 33, 38, .06);

  /* The semantic aliases have to be restated here too. A property declared as
     var(...) on :root resolves there and inherits down as a literal value, so
     overriding only the primitives would leave --text-primary still holding the
     light theme's ink and put near-black text on this near-black field. */
  --surface-page:  var(--color-field);
  --surface-plate: var(--color-plate);
  --text-primary:  var(--color-white);
  --text-strong:   var(--color-mist-bright);
  --text-body:     var(--color-mist);
  --text-meta:     var(--color-mist-dim);
  --ghost-line:    var(--color-steel);

  background: var(--color-field);
  color: var(--text-body);
}

/* ========================================================================== */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: var(--space-3xl); }

body {
  background: var(--surface-page);
  color: var(--text-body);
  font-family: var(--font-body);
  font-size: var(--type-body);
  line-height: 1.65;
  overflow-x: clip;
  min-height: 100vh;
}

img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
button, input, textarea, select { font: inherit; color: inherit; }
button { background: none; border: 0; cursor: pointer; }
ul, ol { list-style: none; padding: 0; }

/* §4.4 focus, never removed */
:focus-visible { outline: 2px solid var(--focus-ring); outline-offset: 3px; }
::selection { background: var(--color-ember); color: var(--ink-on-accent); }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 200;
  background: var(--color-ember); color: var(--ink-on-accent);
  padding: var(--space-md) var(--space-lg);
  font-family: var(--font-display); font-size: var(--type-label);
}
.skip:focus { left: var(--space-md); top: var(--space-md); }

.shell { width: min(100% - (var(--gutter) * 2), var(--shell)); margin-inline: auto; }
.band  { padding-block: var(--space-3xl); }
.band--sm { padding-block: var(--space-2xl); }

/* ==========================================================================
   2. Type
   ========================================================================== */
.t-hero {
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--type-hero); line-height: .95; letter-spacing: -.02em;
  color: var(--text-primary);
}
.t-h2 {
  font-family: var(--font-display); font-weight: 800;
  font-size: var(--type-h2); line-height: 1.02; letter-spacing: -.02em;
  color: var(--text-primary);
}
.t-h3 {
  font-family: var(--font-display); font-weight: 500;
  font-size: var(--type-h3); line-height: 1.2; letter-spacing: -.01em;
  color: var(--text-primary);
}
/* §2 the role line: one line always, pipes in --text-meta */
.t-role {
  font-family: var(--font-display); font-weight: 500;
  font-size: var(--type-role); line-height: 1.25; letter-spacing: .01em;
  color: var(--text-strong);
  white-space: nowrap;
}
.t-role i { font-style: normal; color: var(--text-meta); padding-inline: .1em; }
.t-lead {
  font-size: var(--type-lead); line-height: 1.6;
  color: var(--text-body); max-width: 62ch;
}
.t-body { color: var(--text-body); max-width: 68ch; }
.t-body + .t-body { margin-top: var(--space-lg); }
.t-body strong { color: var(--text-strong); font-weight: 400; }
/* §4.6 metadata / caption face */
.t-meta {
  font-family: var(--font-meta); font-size: var(--type-caption);
  line-height: 1.4; letter-spacing: .18em; color: var(--text-meta);
  text-transform: uppercase;
}

/* ==========================================================================
   4.4 Pill Action
   ========================================================================== */
.pill {
  display: inline-flex; align-items: center; justify-content: center;
  gap: var(--space-sm);
  min-height: 48px;                       /* §10 F-02 */
  padding: 0 var(--space-xl);
  border-radius: 999px;
  border: 1px solid var(--action-line);
  background: var(--action-fill);
  color: var(--action-ink);
  font-family: var(--font-display); font-weight: 500;
  font-size: var(--type-label); letter-spacing: .04em;
  transition: background-color var(--duration-fast) var(--ease-out-expo),
              border-color var(--duration-fast) var(--ease-out-expo);
  white-space: nowrap;
}
.pill:hover { background: var(--color-signal); }         /* §4.4 no transform */
.pill--deep { background: var(--color-ember-deep); }
.pill--deep:hover { background: var(--color-ember); }
.pill--ghost {
  background: var(--color-plate);
  border-color: var(--ghost-line);
  color: var(--text-primary);
}
.pill--ghost:hover { background: var(--color-plate-2); border-color: rgba(255,255,255,.34); }
.pill[disabled] { opacity: .5; pointer-events: none; }

.pill-row { display: flex; flex-wrap: wrap; gap: var(--space-lg); }

/* Arrow link, §7 typographic only */
.alink {
  display: inline-flex; align-items: center; gap: var(--space-sm);
  min-height: 44px;
  font-family: var(--font-display); font-weight: 500; font-size: var(--type-label);
  letter-spacing: .04em; color: var(--text-primary);
  transition: color var(--duration-fast) var(--ease-out-expo);
}
.alink span { transition: transform var(--duration-fast) var(--ease-out-expo); }
.alink:hover { color: var(--text-primary); opacity: .62; }
.alink:hover span { transform: translateX(6px); }

/* ==========================================================================
   Header — hamburger left, margin, mark left. CTA right. No inline nav.
   ========================================================================== */
.hdr {
  position: fixed; inset: 0 0 auto; z-index: 90;
  padding-block: var(--space-md);
  transition: background-color var(--duration-base) var(--ease-out-expo),
              border-color var(--duration-base) var(--ease-out-expo);
  border-bottom: 1px solid transparent;
}
.hdr.is-stuck {
  background: rgba(5, 5, 6, .88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: var(--hairline);
}
.hdr__in { display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg); }
.hdr__lead { display: flex; align-items: center; gap: var(--space-xl); flex: none; }

.mark { display: inline-flex; align-items: center; min-height: 48px; flex: none; }
.mark svg { width: 38px; height: auto; flex: none; color: var(--color-white); }

/* The hamburger, terminal style: a bracketed frame with three uneven rules.
   Corner ticks are drawn on the frame, so it reads as a console control rather
   than a generic three-line icon. */
.burger {
  position: relative;
  width: 56px; height: 56px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  transition: border-color var(--duration-fast) var(--ease-out-expo),
              background-color var(--duration-fast) var(--ease-out-expo);
}
.burger::before, .burger::after {
  content: ""; position: absolute; width: 7px; height: 7px;
  border: 1px solid currentColor; opacity: .5;
  transition: opacity var(--duration-fast), transform var(--duration-base) var(--ease-out-expo);
}
.burger::before { top: 4px; left: 4px; border-right: 0; border-bottom: 0; }
.burger::after { bottom: 4px; right: 4px; border-left: 0; border-top: 0; }
.burger:hover { background: rgba(255,255,255,.05); border-color: var(--ghost-line); }
.burger:hover::before { transform: translate(-1px, -1px); opacity: 1; }
.burger:hover::after { transform: translate(1px, 1px); opacity: 1; }

/* Three rules of different lengths. The middle one is short, which is the
   retro tell, and it retracts to nothing on open. */
.burger i { position: relative; display: block; width: 22px; height: 2px; background: currentColor; transition: background-color var(--duration-fast); }
.burger i::before, .burger i::after {
  content: ""; position: absolute; left: 0; height: 2px; background: currentColor;
  transition: transform var(--duration-base) var(--ease-out-expo),
              width var(--duration-base) var(--ease-out-expo), top var(--duration-base) var(--ease-out-expo);
}
.burger i::before { top: -7px; width: 22px; }
.burger i::after  { top: 7px;  width: 14px; }
.burger:hover i::after { width: 22px; }
.burger[aria-expanded="true"] i { background: transparent; }
.burger[aria-expanded="true"] i::before { top: 0; width: 22px; transform: rotate(45deg); }
.burger[aria-expanded="true"] i::after  { top: 0; width: 22px; transform: rotate(-45deg); }
.burger[aria-expanded="true"]::before { transform: translate(-2px, -2px); opacity: 1; }
.burger[aria-expanded="true"]::after  { transform: translate(2px, 2px); opacity: 1; }

/* Theme toggle, beside the CTA */
.hdr__end { display: flex; align-items: center; gap: var(--space-md); }
.tbtn {
  width: 48px; height: 48px; flex: none;
  display: grid; place-items: center;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  color: var(--text-primary);
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}
.tbtn:hover { border-color: var(--ghost-line); }
.tbtn svg { width: 19px; height: 19px; }
.tbtn .i-moon { display: none; }
:root.light .tbtn .i-sun { display: none; }
:root.light .tbtn .i-moon { display: block; }
/* The header sits over the dark hero, so its own chrome stays light-on-dark
   until the page scrolls and the bar picks up the page surface. */
.hdr:not(.is-stuck) .tbtn, .hdr:not(.is-stuck) .burger { color: #fff; border-color: rgba(255,255,255,.16); }
.hdr:not(.is-stuck) .burger i, .hdr:not(.is-stuck) .burger i::before, .hdr:not(.is-stuck) .burger i::after { background: #fff; }
.hdr:not(.is-stuck) .mark svg { color: #fff; }

/* ==========================================================================
   Menu overlay — the only place navigation exists
   ========================================================================== */
.menu {
  position: fixed; inset: 0; z-index: 80;
  background: var(--color-field);
  /* Top padding clears the fixed header, which sits above this overlay so the
     close control stays reachable. Content starts at the top and scrolls,
     because centring six rows pushes them up under the header. */
  padding: 104px var(--gutter) var(--space-2xl);
  display: flex; flex-direction: column; justify-content: flex-start;
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--duration-slow) var(--ease-out-expo), visibility var(--duration-slow);
  visibility: hidden;
  overflow-y: auto;
}
.menu.is-open { clip-path: inset(0 0 0 0); visibility: visible; }
.menu__list { max-width: var(--shell); margin-inline: auto; width: 100%; }
/* §4.8 Index List, used as the menu */
.menu__list a {
  display: flex; align-items: baseline; justify-content: space-between; gap: var(--space-lg);
  padding: var(--space-md) var(--space-md);
  border-bottom: 1px solid var(--hairline);
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(26px, 3.6vw, 44px); line-height: 1.1; letter-spacing: -.02em;
  color: var(--text-primary);
  transition: background-color var(--duration-fast) var(--ease-out-expo),
              padding-left var(--duration-base) var(--ease-out-expo);
  opacity: 0; transform: translateY(20px);
}
.menu.is-open .menu__list a { animation: rise var(--duration-slow) var(--ease-out-expo) forwards; }
.menu__list a:hover { background: var(--color-ember); padding-left: var(--space-xl); }
.menu__list a b { font-family: var(--font-meta); font-weight: 400; font-size: var(--type-caption); letter-spacing: .18em; color: var(--text-meta); }
.menu__list a:hover b { color: var(--color-white); }
.menu__foot {
  max-width: var(--shell); margin: var(--space-xl) auto 0; width: 100%;
  display: flex; flex-wrap: wrap; gap: var(--space-md) var(--space-xl);
  padding-inline: var(--space-md);
}
.menu__foot a { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; font-family: var(--font-display); font-size: var(--type-label); color: var(--text-meta); transition: opacity var(--duration-fast); }
.menu__foot a:hover { color: var(--text-primary); }

/* ==========================================================================
   4.1 Hero Frame · 4.2 Bloom · 4.3 Grid
   Stacking order is fixed: field -> bloom -> grid -> subject -> copy.
   ========================================================================== */
.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;
  display: flex; align-items: center;
  padding-block: calc(var(--space-3xl) + 48px) var(--space-3xl);
  overflow-x: clip;
}
/* §4.2 the bloom. One per frame, off-centre. */
.bloom {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(ellipse 70% 85% at 52% 42%,
    var(--color-bloom-core) 0%, var(--color-bloom-mid) 34%, rgba(42,8,10,0) 68%);
}

/* Grain, at the weight the reference uses. Generated by the browser from an
   inline SVG turbulence, so it costs ~300 bytes instead of an 83KB tile. */
.ethereal__grain {
  position: absolute; inset: 0;
  opacity: .14; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='200' height='200' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
  background-size: 200px;
}
/* §4.3 the grid, masked by the bloom, never reaching an edge */
.grid-field {
  position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background-image:
    repeating-linear-gradient(to right,  var(--color-grid) 0 1px, transparent 1px var(--grid-size)),
    repeating-linear-gradient(to bottom, var(--color-grid) 0 1px, transparent 1px var(--grid-size));
  mask-image: radial-gradient(ellipse 62% 74% at 52% 42%, #000 0%, transparent 72%);
  -webkit-mask-image: radial-gradient(ellipse 62% 74% at 52% 42%, #000 0%, transparent 72%);
}
.hero__in {
  position: relative; z-index: 3;
  display: grid; grid-template-columns: minmax(0, 6fr) minmax(0, 6fr); align-items: center;
  gap: var(--space-2xl);
}
.hero__copy { max-width: 560px; }                 /* §3 copy column */
.hero__name { margin-bottom: var(--space-lg); }
.hero__role { margin-bottom: var(--space-xl); }
.hero__lead { margin-bottom: var(--space-2xl); }

/* §4.5 Subject Plate — bleeds right and bottom, never framed */
.hero__subject {
  position: absolute; z-index: 2;
  bottom: 0;
  /* The box is the right-hand half of the frame: page centre to the right edge.
     The plate is centred inside it, which is where Kevin asked for it. Running
     to right:0 rather than to the shell edge hands the gutter back to the plate,
     which is the difference between a 640px and a 720px box at 1440 and is the
     only free size left once the whole body has to fit. §4.5's bleed is kept on
     the bottom edge only; the right bleed is what was clipping his arm. */
  /* Past centre rather than exactly on it. Two reasons, both Kevin's: it is the
     "tilt to the left a little", and a wider box is a taller plate, which buys
     back part of what fitting the whole body inside the frame costs.
     The offset has to earn its room though. It is worth 60px at 1440 and winds
     back to nothing by 1150, where the copy column has closed the gap and any
     further nudge would put Kevin's shoulder behind his own lead paragraph. */
  left: calc(50% - clamp(0px, (100vw - 1150px) * 0.21, 60px)); right: 0;
  height: 88%;
  /* Centred in that half, sitting on the floor of the frame. */
  display: flex; align-items: flex-end; justify-content: center;
  pointer-events: none;
}
/* max-height AND max-width, with both intrinsic dimensions left to resolve
   themselves, means whichever axis runs out first is the one that binds. The
   plate is scaled down to fit rather than bled off the edge, so the full body
   is inside the frame. This replaces the old right:-222px, which hung 222px of
   Kevin's arm off the right of the viewport. */
.hero__subject img {
  max-height: 100%; max-width: 100%;
  height: auto; width: auto;
  filter: grayscale(1);
}

/* §4.6 Metadata Bar — one per frame */
.metabar {
  position: absolute; z-index: 3; left: 0; right: 0; bottom: var(--space-xl);
  display: flex; justify-content: space-between; gap: var(--space-lg);
  pointer-events: none;
}

/* ==========================================================================
   4.7 Stat Block
   ========================================================================== */
.stats { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-xl) var(--space-lg); }
.stat__n {
  font-family: var(--font-display); font-weight: 800;
  font-size: clamp(40px, 5.4vw, 72px); line-height: .85; letter-spacing: -.03em;
  color: var(--text-primary);                      /* §4.7 figures never take red */
}
.stat__l { margin-top: var(--space-md); color: var(--text-body); font-size: var(--type-label); }

/* ==========================================================================
   Press strip — "As Featured In"

   WDOS M-05b, condition 4, says eight logos or fewer belong in a static grid.
   There are seven. The motion is an explicit client instruction, logged as an
   override in DECISIONS.md. The other three conditions of M-05b are honoured
   below in full: real logos, pauses on hover AND focus, still under
   prefers-reduced-motion.

   Note this is M-05b, the logo rule. M-05, the ban on horizontally scrolling
   TEXT that Kevin set on day one, is untouched: no words move on this site.
   ========================================================================== */
.press__h {
  color: var(--text-meta);
  text-transform: uppercase; letter-spacing: .22em;
  margin-bottom: var(--space-xl);
}
.press__rail {
  position: relative;
  overflow: hidden;
  /* Feathered ends, so marks arrive and leave instead of being guillotined at
     the edge. Same mask both sides; the gradient is a mask, not a fill, so DS
     section 1's "only the bloom may be a gradient" is not in play. */
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
.press__track {
  display: flex; width: max-content;
  animation: pressRun 64s linear infinite;
}
.press__set {
  display: flex; align-items: center;
  gap: clamp(48px, 6vw, 96px);
  padding-right: clamp(48px, 6vw, 96px);
}
/* Half, because the track holds the set twice. At the halfway point the second
   set is sitting exactly where the first started, so the reset is invisible. */
@keyframes pressRun { to { transform: translateX(-50%); } }

/* M-05b condition 2: hover AND focus. focus-within is what catches the keyboard
   user tabbing through, who would otherwise be chasing a moving target. */
.press__rail:hover .press__track,
.press__rail:focus-within .press__track { animation-play-state: paused; }

.press__item {
  display: flex; align-items: center;
  min-height: 44px;                                 /* 10 F-02 tap target */
  opacity: .78;
  transition: opacity var(--duration-base) var(--ease-out-expo);
}
.press__item:hover, .press__item:focus-visible { opacity: 1; }
.press__item img {
  display: block;
  height: 34px; width: auto;                        /* one height for all seven */
}
/* The marks ship in the light field's own near-white, so on the dark field they
   are used untouched. On the light field one inversion turns that near-white
   into #0d0e11, near-black, which is the pairing Kevin asked for. Inverting
   costs nothing here because the source is already a single flat tone: there is
   no hue to corrupt, only a value to flip. */
:root.light .press__item img { filter: invert(1); }

@media (max-width: 720px) { .press__item img { height: 26px; } }

@media (prefers-reduced-motion: reduce) {
  /* M-05b condition 3. Static, and the clone is dropped so the row does not
     read as fourteen outlets. */
  .press__track { animation: none; flex-wrap: wrap; width: auto; }
  .press__set[aria-hidden="true"] { display: none; }
  .press__set { flex-wrap: wrap; gap: var(--space-xl); }
  .press__rail { -webkit-mask-image: none; mask-image: none; }
}

/* ==========================================================================
   4.8 Index List — ventures, insights, anything enumerable
   ========================================================================== */
.index { border-top: 1px solid var(--hairline); }
.index__row {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 6fr) auto;
  gap: var(--space-lg) var(--space-2xl); align-items: baseline;
  padding: var(--space-xl) var(--space-md);
  border-bottom: 1px solid var(--hairline);
  transition: background-color var(--duration-fast) var(--ease-out-expo),
              padding-left var(--duration-base) var(--ease-out-expo);
}
a.index__row:hover { background: var(--color-ember); padding-left: var(--space-xl); }
/* Each venture hovers into its own brand colour rather than one house red. */
a.index__row[data-brand="afn"]:hover  { background: var(--afn-gold); }
a.index__row[data-brand="afdf"]:hover { background: var(--afdf-green); }
a.index__row[data-brand="beta"]:hover { background: var(--beta-red); }
a.index__row[data-brand="afn"]:hover .index__t,
a.index__row[data-brand="afn"]:hover .index__d,
a.index__row[data-brand="afn"]:hover .index__code,
a.index__row[data-brand="afn"]:hover .index__tags span { color: var(--afn-gold-ink); }
a.index__row[data-brand="afn"]:hover .index__tags span { border-color: rgba(26,18,8,.4); }
a.index__row:hover .index__d, a.index__row:hover .index__code, a.index__row:hover .index__tags span { color: var(--color-white); }
a.index__row:hover .index__tags span { border-color: rgba(255,255,255,.4); }
.index__t { font-family: var(--font-display); font-weight: 800; font-size: var(--type-h3); letter-spacing: -.01em; color: var(--text-primary); }
.index__d { color: var(--text-body); font-size: var(--type-label); transition: color var(--duration-fast); }
.index__code { font-family: var(--font-meta); font-size: var(--type-caption); letter-spacing: .18em; color: var(--text-meta); white-space: nowrap; transition: color var(--duration-fast); }
.index__tags { display: flex; flex-wrap: wrap; gap: var(--space-sm); margin-top: var(--space-md); }
.index__tags span {
  font-family: var(--font-meta); font-size: 12px; letter-spacing: .12em; text-transform: uppercase;
  color: var(--text-meta); border: 1px solid var(--hairline); border-radius: 999px;
  padding: 4px 12px; transition: color var(--duration-fast), border-color var(--duration-fast);
}

/* Two-column content splits. These live in the stylesheet rather than inline
   so the responsive rules can actually reach them. */
.split2 { display: grid; gap: var(--space-3xl); align-items: start; }
.split2--about   { grid-template-columns: 6fr 5fr; }
.split2--contact { grid-template-columns: 5fr 7fr; }

/* ==========================================================================
   Insights — the blog
   ========================================================================== */
.feature {
  display: grid; grid-template-columns: 7fr 5fr; gap: var(--space-2xl);
  align-items: center;
  padding-bottom: var(--space-3xl); border-bottom: 1px solid var(--hairline);
}
.feature__media { position: relative; }
/* The card is far smaller than a hero frame, so the bloom is re-centred on the
   subject's face. Peak is unchanged: the DS caps it at 1.32:1 and this is the
   same two stops. (DS 4.2) */
.feature__media .bloom {
  background: radial-gradient(ellipse 78% 62% at 54% 34%,
    var(--color-bloom-core) 0%, var(--color-bloom-mid) 38%, rgba(42,8,10,0) 72%);
}
.feature__media img {
  position: relative; z-index: 2; width: 100%;
  aspect-ratio: 3 / 2; object-fit: cover; border-radius: 2px;
}
.feature__t { margin: var(--space-md) 0 var(--space-lg); }

.posts { display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr)); gap: 1px; background: var(--hairline); margin-top: var(--space-3xl); }
.posts--4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 1180px) { .posts--4 { grid-template-columns: repeat(2, 1fr); } }

/* Pagination */
.pager {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-lg);
  margin-top: var(--space-3xl); padding-top: var(--space-lg);
  border-top: 1px solid var(--hairline);
}
.pager__nums { display: flex; gap: var(--space-xs); }
.pager__n, .pager__step {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; min-width: 44px; padding: 0 var(--space-sm);
  font-family: var(--font-display); font-size: var(--type-label); font-weight: 500;
  letter-spacing: .04em; color: var(--text-meta);
  border-radius: 2px;
  transition: color var(--duration-fast) var(--ease-out-expo),
              background-color var(--duration-fast) var(--ease-out-expo);
}
.pager__step { gap: var(--space-sm); padding: 0 var(--space-md); }
.pager__n:hover, .pager__step:hover { color: var(--text-primary); background: var(--color-plate); }
.pager__n.is-here { color: var(--action-ink); background: var(--color-ember); }

.post {
  display: flex; flex-direction: column;
  background: var(--color-field);
  transition: background-color var(--duration-base) var(--ease-out-expo);
}
.post:hover { background: var(--color-plate-2); }
.post__img { display: block; overflow: hidden; }
.post__img img {
  width: 100%; aspect-ratio: 3 / 2; object-fit: cover;
  transition: opacity var(--duration-base) var(--ease-out-expo);
}
.post:hover .post__img img { opacity: .82; }
.post__body { display: flex; flex-direction: column; flex: 1; padding: var(--space-xl) var(--space-lg); }
.post__meta { display: flex; gap: var(--space-md); margin-bottom: var(--space-lg); }
.post__t { display: block; margin-bottom: var(--space-md); }
.post__d { display: block; color: var(--text-body); font-size: var(--type-label); flex: 1; }
.post__foot { display: block; margin-top: var(--space-xl); }
.post:hover .alink { color: var(--text-primary); opacity: .62; }

/* Article cover, under the post headline */
.article__cover { margin-top: var(--space-2xl); }
/* In-body photograph. Full measure, breaking the 68ch column deliberately so
   it reads as a plate rather than an inline thumbnail. */
.article__fig {
  margin: var(--space-2xl) 0;
  width: min(100%, 900px);
}
.article__fig img { width: 100%; aspect-ratio: 5 / 3; object-fit: cover; border-radius: 2px; }
.article__cover img {
  width: 100%; max-width: 900px;
  aspect-ratio: 3 / 2; object-fit: cover;
  border-radius: 2px;
}

/* Article body */
.article { max-width: 68ch; }
.article h2 { font-family: var(--font-display); font-weight: 800; font-size: var(--type-h3); color: var(--text-primary); margin: var(--space-2xl) 0 var(--space-md); letter-spacing: -.01em; }
.article h3 { font-family: var(--font-display); font-weight: 500; font-size: 19px; color: var(--text-strong); margin: var(--space-xl) 0 var(--space-sm); }
.article p { color: var(--text-body); margin-bottom: var(--space-lg); }
.article ul { display: grid; gap: var(--space-sm); margin-bottom: var(--space-lg); }
.article li { position: relative; padding-left: var(--space-lg); color: var(--text-body); }
.article li::before { content: ""; position: absolute; left: 0; top: .72em; width: 8px; height: 1px; background: var(--color-ember-line); }
.article a { color: var(--text-primary); border-bottom: 1px solid var(--color-ember-line); }
.article a:hover { opacity: .62; }
.article strong { color: var(--text-strong); font-weight: 400; }
.article blockquote {
  border-left: 1px solid var(--color-ember-line);
  padding-left: var(--space-lg); margin: var(--space-2xl) 0;
  font-family: var(--font-display); font-weight: 500; font-size: var(--type-role);
  line-height: 1.4; color: var(--text-strong); max-width: 46ch;
}

/* ==========================================================================
   Page head (interior)
   ========================================================================== */
.phead { position: relative; padding-block: calc(var(--space-3xl) + 72px) var(--space-2xl); overflow-x: clip; }
.phead .bloom { opacity: .7; }
.phead > .shell { position: relative; z-index: 3; }
.crumb { display: flex; align-items: center; gap: var(--space-sm); margin-bottom: var(--space-lg); }
.crumb a, .crumb span { font-family: var(--font-meta); font-size: var(--type-caption); letter-spacing: .18em; text-transform: uppercase; color: var(--text-meta); }
.crumb a { display: inline-flex; align-items: center; min-height: 44px; }
.crumb a:hover { color: var(--text-primary); }
.phead .t-hero { max-width: 18ch; }
.phead .t-lead { margin-top: var(--space-lg); }

/* ==========================================================================
   Forms
   ========================================================================== */
.form { display: grid; gap: var(--space-lg); max-width: 34rem; }
.field { display: grid; gap: var(--space-sm); }
.field label { font-family: var(--font-display); font-weight: 500; font-size: var(--type-label); color: var(--text-strong); letter-spacing: .02em; }
.field .req { color: var(--text-meta); }
.field input, .field textarea, .field select {
  width: 100%; min-height: 48px; padding: var(--space-md);
  background: var(--color-plate-2);
  border: 1px solid var(--hairline);
  border-radius: 2px;
  color: var(--text-primary); font-size: var(--type-label);
  transition: border-color var(--duration-fast) var(--ease-out-expo);
}
.field textarea { min-height: 152px; resize: vertical; line-height: 1.6; }
.field input::placeholder, .field textarea::placeholder { color: var(--text-meta); }
.field input:focus, .field textarea:focus, .field select:focus { border-color: var(--ghost-line); }
.field input[aria-invalid="true"], .field textarea[aria-invalid="true"] { border-color: var(--color-ember-line); border-width: 2px; }
.err { font-size: 15px; color: var(--text-primary); font-weight: 500; display: none; }
.err.is-on { display: block; }
.form__note { font-size: 15px; color: var(--text-meta); }
.form__status { font-size: var(--type-label); color: var(--text-strong); }
.form__status.is-ok { color: var(--text-primary); }
.form__status.is-err { color: var(--text-strong); }
/* Honeypot. Off-screen rather than display:none, because some bots skip
   hidden fields but fill positioned ones. */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.deflist { display: grid; gap: var(--space-xl); }
.deflist dt { font-family: var(--font-meta); font-size: var(--type-caption); letter-spacing: .18em; text-transform: uppercase; color: var(--text-meta); margin-bottom: var(--space-sm); }
.deflist dd { color: var(--text-body); font-size: var(--type-label); }
.deflist a { color: var(--text-primary); border-bottom: 1px solid var(--hairline); }
.deflist a:hover { border-color: var(--color-ember-line); }

/* ==========================================================================
   Footer
   ========================================================================== */
.ftr { border-top: 1px solid var(--hairline); padding-block: var(--space-2xl); }
.ftr__in { display: grid; grid-template-columns: 2fr 1fr 1fr; gap: var(--space-2xl); }
.ftr__bio { color: var(--text-meta); font-size: var(--type-label); max-width: 34ch; margin-top: var(--space-md); }
.ftr__h { font-family: var(--font-meta); font-size: var(--type-caption); letter-spacing: .18em; text-transform: uppercase; color: var(--text-meta); margin-bottom: var(--space-md); }
.ftr__list a, .ftr__list span { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; font-size: var(--type-label); color: var(--text-body); transition: color var(--duration-fast); }
.ftr__list a:hover { color: var(--text-primary); }
.ftr__bot {
  border-top: 1px solid var(--hairline); margin-top: var(--space-2xl); padding-top: var(--space-lg);
  display: flex; flex-wrap: wrap; justify-content: space-between; align-items: center; gap: var(--space-md) var(--space-xl);
}
.ftr__bot, .ftr__bot a { font-family: var(--font-meta); font-size: var(--type-caption); letter-spacing: .12em; color: var(--text-meta); text-transform: uppercase; }
.ftr__bot nav { display: flex; flex-wrap: wrap; gap: var(--space-lg); }
.ftr__bot a { display: inline-flex; align-items: center; min-height: 44px; }
.ftr__bot a:hover { color: var(--text-primary); }

.totop {
  position: fixed; right: var(--gutter); bottom: var(--space-lg); z-index: 70;
  width: 48px; height: 48px; display: grid; place-items: center;
  border-radius: 999px; border: 1px solid var(--ghost-line);
  background: var(--color-plate); color: var(--color-white);
  opacity: 0; visibility: hidden;
  transition: opacity var(--duration-base) var(--ease-out-expo),
              visibility 0s linear var(--duration-base),
              border-color var(--duration-fast);
}
.totop.is-on { opacity: 1; visibility: visible; transition: opacity var(--duration-base) var(--ease-out-expo), visibility 0s linear 0s, border-color var(--duration-fast); }
.totop:hover { border-color: var(--color-ember-line); }

/* ==========================================================================
   5. Motion — the hero entrance.
   The grid and the subject plate still never animate in place; the subject
   only slides in once and then holds. (DS §5, with the bloom exception logged.)
   ========================================================================== */
@keyframes rise { to { opacity: 1; transform: none; } }
@keyframes charRise { to { transform: none; } }
@keyframes slideInRight { to { opacity: 1; transform: none; } }
@keyframes caretBlink { 0%, 49% { opacity: 1 } 50%, 100% { opacity: 0 } }

.js .anim { opacity: 0; transform: translateY(24px); }
.js .is-lit .anim {
  animation: rise var(--duration-cinematic) var(--ease-glide) forwards;
  animation-delay: calc(var(--i, 0) * 130ms);
}

/* The subject glides in from the right, once, then holds. Slowest thing on the
   page on purpose: it is the largest object, and large objects that move fast
   read as cheap. */
.js .hero__subject { opacity: 0; transform: translateX(7%); }
.js .is-lit .hero__subject {
  animation: slideInRight 1.9s var(--ease-glide) forwards;
  animation-delay: 240ms;
}

/* Per-character mask rise on the name. Vertical only. */
.split { display: block; }
.split .ln { display: block; overflow: hidden; padding-bottom: .04em; }
.js .split .ch { display: inline-block; white-space: pre; transform: translateY(105%); }
.js .is-lit .split .ch {
  animation: charRise var(--duration-cinematic) var(--ease-glide) forwards;
  animation-delay: calc(var(--d, 0ms) + 140ms);
}

/* ---- Typewriter --------------------------------------------------------
   The visible text is revealed a character at a time while a full-width ghost
   holds the line's real width underneath, so nothing reflows as it types and
   the layout never shifts. */
.type { position: relative; display: inline-block; }
.type__ghost { visibility: hidden; }
.type__out {
  position: absolute; inset: 0;
  white-space: nowrap; overflow: hidden;
}
.type__caret {
  display: inline-block; width: .58em; height: 1.05em;
  margin-left: .08em; vertical-align: -.16em;
  background: var(--color-ember-line);
}
.js .is-typing .type__caret,
.js .is-typed  .type__caret { animation: caretBlink 1.05s step-end infinite; }
/* Without JS the ghost carries the text and the caret is dropped. */
.type__out, .type__caret { display: none; }
.js .type__out { display: block; }
.js .type__caret { display: inline-block; }
.js .type .type__ghost { visibility: hidden; }
.js .is-typed .type__ghost { visibility: visible; }
.js .is-typed .type__out { display: none; }

/* ==========================================================================
   Scroll reveals — four distinct treatments, not one fade on everything.
   Hidden state is scoped behind .js, so nothing disappears if the script fails.
   ========================================================================== */
@keyframes rvUp    { from { opacity: 0; transform: translateY(28px); } to { opacity: 1; transform: none; } }
@keyframes rvNum   { from { opacity: 0; transform: translateY(40%); }  to { opacity: 1; transform: none; } }
@keyframes rvWipe  { from { opacity: 0; clip-path: inset(0 100% 0 0); transform: translateX(-14px); }
                     to   { opacity: 1; clip-path: inset(0 0 0 0);    transform: none; } }
@keyframes rvPlate { from { opacity: 0; transform: scale(1.035); filter: blur(9px); }
                     to   { opacity: 1; transform: none;          filter: none; } }

/* `is-in` declares the FINAL state itself and the animation only plays the way
   in. Driving the end state from animation-fill-mode instead means a tab that
   never runs animations, a throttled background tab for instance, leaves the
   page blank. The keyframes carry their own `from` so the motion still reads. */
.js [data-rv] { opacity: 0; }
.js [data-rv].is-in { opacity: 1; transform: none; filter: none; clip-path: none; }
/* Once the reveal has run, drop the animation entirely so the declared end
   state above is what actually paints. Without this, an animation that is
   registered but never ticks, which is what a throttled tab does, holds the
   element on its first keyframe forever. */
.js [data-rv].is-done { animation: none !important; }

.js [data-rv="up"]          { transform: translateY(34px); }
.js [data-rv="up"].is-in    { animation: rvUp var(--duration-reveal) var(--ease-glide) var(--rd, 0ms); }

.js [data-rv="wipe"]        { clip-path: inset(0 100% 0 0); transform: translateX(-14px); }
.js [data-rv="wipe"].is-in  { animation: rvWipe var(--duration-reveal-long) var(--ease-glide) var(--rd, 0ms); }

.js [data-rv="plate"]       { transform: scale(1.035); filter: blur(9px); }
.js [data-rv="plate"].is-in { animation: rvPlate var(--duration-reveal-long) var(--ease-glide) var(--rd, 0ms); }

.js [data-rv="num"]         { transform: translateY(40%); }
.js [data-rv="num"].is-in   { animation: rvNum var(--duration-reveal) var(--ease-glide) var(--rd, 0ms); }

@media (prefers-reduced-motion: reduce) {
  .js [data-rv] { opacity: 1 !important; transform: none !important; filter: none !important; clip-path: none !important; animation: none !important; }
}

/* ==========================================================================
   Responsive
   ========================================================================== */
/* Desktop only: the displacement filter is too costly on phones, and Kevin is
   happy with the mobile hero as it stands. */
@media (max-width: 1080px) {
  /* The subject is a sibling of the shell, so the hero has to become a column
     here or it stays a two-up with the figure beside the copy. */
  .hero {
    min-height: auto; display: flex; flex-direction: column; align-items: stretch;
    padding-block: calc(var(--space-3xl) + 48px) 0;
  }
  .hero__in { grid-template-columns: minmax(0, 1fr); }
  .hero__copy { max-width: none; }
  .hero__subject {
    order: 2;                       /* copy first, figure under it */
    /* EVERY desktop offset has to be unwound here, not just `right`. The desktop
       rule sets `left` to push the plate into the right-hand half, and on a
       relatively positioned element a leftover `left` shifts it sideways rather
       than being ignored, which threw the mobile figure off to the right.
       `margin-inline: auto` is what centres it, and it only works from a clean
       left/right. */
    position: relative; left: auto; right: auto; bottom: auto;
    display: block;
    height: auto; width: min(100%, 420px);
    margin: var(--space-2xl) auto 0;
  }
  .hero__subject img { height: auto; width: 100%; max-height: none; max-width: 100%; }
  .metabar { display: none; }
  .feature { grid-template-columns: 1fr; }
  .posts { grid-template-columns: 1fr !important; }
  .split2 { grid-template-columns: 1fr !important; gap: var(--space-2xl); }
  .ftr__in { grid-template-columns: 1fr 1fr; }
  .index__row { grid-template-columns: 1fr; gap: var(--space-md); }
  .index__code { grid-row: 1; }
}

@media (max-width: 720px) {
  /* DS section 2 says the role line is always one line. That is written for the
     21:9 hero frame and is not physically possible at 375px without dropping
     below the 13px floor, so it wraps here instead. Divergence logged in README. */
  .t-role { white-space: normal; }
  .stats { grid-template-columns: 1fr 1fr; }
  .ftr__in { grid-template-columns: 1fr; }
  .hdr__lead { gap: var(--space-md); }
  .pill-row .pill { width: 100%; }          /* body CTAs go full width */
  .hdr .pill {                              /* the header CTA never does */
    width: auto; min-height: 44px;
    padding: 0 var(--space-md);
    font-size: 14px; letter-spacing: .02em;
  }
  .pill-row { flex-direction: column; align-items: stretch; }
  .ftr__bot { flex-direction: column; align-items: flex-start; }
}

@media (max-width: 400px) {
  .hdr .pill { padding: 0 12px; font-size: 13px; }
  .burger { width: 48px; height: 48px; }
  .hdr__lead { gap: var(--space-sm); }
}

/* §5 mandatory */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { animation: none !important; transition-duration: .01ms !important; }
  .js .anim { opacity: 1 !important; transform: none !important; }
  .js .split .ch { transform: none !important; }
  .js .hero__subject { opacity: 1 !important; transform: none !important; }
  .stars { opacity: 1 !important; }
  .js .type .type__ghost { visibility: visible !important; }
  .js .type__out, .js .type__caret { display: none !important; }
}

@media print {
  .hdr, .menu, .totop, .bloom, .grid-field, .metabar { display: none !important; }
  body { background: #fff; color: #000; }
}
