/* =========================================================================
   MYCELIUM SYSTEMS — site.css
   Tokens lifted directly from the Q3 2026 investor deck.
   Edit tokens here; never hard-code hex or px in markup.
   ========================================================================= */

/* ---------- 1. Tokens --------------------------------------------------- */

:root {
  /* Ground — dark (cover / engine / closing bands) */
  --ink-900: #100d09;
  --ink-850: #17130d;
  --ink-800: #1c1710;
  --ink-700: #231d15;
  --ink-600: #2e2618;

  /* Ground — bone (reading sections) */
  --paper:        #f4eee2;
  --paper-raised: #fbf6ec;
  --paper-sunk:   #ede5d5;

  /* Rules */
  --rule:      #dcd2c1;
  --rule-soft: #e6ddcd;
  --rule-dark: rgba(244, 238, 226, 0.13);
  --rule-dark-soft: rgba(244, 238, 226, 0.07);

  /* Text on bone */
  --text:   #16130e;
  --text-2: #3f3a32;
  --text-3: #6a6156;
  --text-4: #8e857a;

  /* Text on ink */
  --on-ink:   #f4eee2;
  --on-ink-2: #b3a999;
  --on-ink-3: #7d7466;
  --on-ink-4: #5a5348;

  /* Accent — the single orange. Two values, one hue. */
  --orange:      #ed7d31;   /* on ink */
  --rust:        #a3551f;   /* on bone — carries AA at body sizes */
  --orange-wash: rgba(237, 125, 49, 0.14);
  --rust-wash:   rgba(163, 85, 31, 0.10);

  /* Type */
  --serif: "Spectral", "Iowan Old Style", Georgia, serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono:  "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;

  /* Fluid scale — 1.22 ratio, clamped */
  --t-mono:  0.6875rem;                                 /* 11px labels      */
  --t-mono-l:0.75rem;                                   /* 12px labels      */
  --t-xs:    0.8125rem;
  --t-sm:    0.875rem;
  --t-base:  clamp(0.9375rem, 0.9rem + 0.18vw, 1.0625rem);
  --t-lead:  clamp(1.0625rem, 1rem + 0.3vw, 1.25rem);
  --t-h4:    clamp(1.125rem, 1.05rem + 0.4vw, 1.4375rem);
  --t-h3:    clamp(1.375rem, 1.2rem + 0.8vw, 2rem);
  --t-h2:    clamp(1.875rem, 1.4rem + 2.2vw, 3.25rem);
  --t-h1:    clamp(2.375rem, 1.5rem + 3.9vw, 5.25rem);
  --t-stat:  clamp(3rem, 1.6rem + 6vw, 7rem);

  /* Space — 8px base */
  --u:  8px;
  --u2: 16px;
  --u3: 24px;
  --u4: 32px;
  --u6: 48px;
  --u8: 64px;
  --u12: 96px;
  --u16: 128px;
  --u20: 160px;

  --gutter: clamp(20px, 4.5vw, 72px);
  --measure: 62ch;
  --maxw: 1440px;

  --radius: 2px;
  --radius-pill: 999px;

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 480ms;
}

/* ---------- 2. Reset ---------------------------------------------------- */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--t-base);
  line-height: 1.6;
  font-feature-settings: "kern" 1, "liga" 1, "cv05" 1;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--serif);
  font-weight: 400;
  letter-spacing: -0.012em;
  /* Spectral's content box is ~1.4em tall; leading below that makes adjacent
     selection highlights collide, so this is the floor. */
  line-height: 1.18;
  text-wrap: balance;
}

/* figure carries a default `margin: 1em 40px` in every browser — easy to miss,
   and it silently throws off any layout that measures around one. */
p, figure, figcaption { margin: 0; }
ul, ol, dl, dd { margin: 0; padding: 0; }
li { list-style: none; }
img, svg, video, canvas { display: block; max-width: 100%; }
/* Must come after the rule above. Author styles outrank the UA's
   `[hidden] { display: none }` whatever the specificity, so setting `display` on
   those elements silently breaks the hidden attribute — which is how the media
   boxes ended up painting video, image and canvas all at once. */
[hidden] { display: none; }

a {
  color: inherit;
  text-decoration: none;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

:focus-visible {
  outline: 2px solid var(--rust);
  outline-offset: 3px;
}
.on-ink :focus-visible { outline-color: var(--orange); }

::selection { background: var(--orange); color: var(--ink-900); }

/* ---------- 3. Primitives ----------------------------------------------- */

.wrap {
  width: 100%;
  max-width: var(--maxw);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Mono label — the deck's connective tissue */
.label {
  font-family: var(--mono);
  font-size: var(--t-mono);
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-4);
}
.label--accent { color: var(--rust); }
.on-ink .label { color: var(--on-ink-3); }
.on-ink .label--accent { color: var(--orange); }

.num {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.1em;
  color: var(--rust);
}
.on-ink .num { color: var(--orange); }

.serif  { font-family: var(--serif); }
.lead {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--text-2);
  max-width: var(--measure);
}
.body-2 { color: var(--text-3); max-width: var(--measure); }
.on-ink .lead { color: var(--on-ink-2); }
.on-ink .body-2 { color: var(--on-ink-3); }

.rule { height: 1px; background: var(--rule); border: 0; margin: 0; }
.on-ink .rule { background: var(--rule-dark); }
.rule--heavy { height: 1px; background: var(--text); }
.on-ink .rule--heavy { background: var(--on-ink); }

/* Section frames */
.band { padding-block: clamp(64px, 9vw, 152px); }
.band--tight { padding-block: clamp(48px, 6vw, 96px); }
.band--bone   { background: var(--paper); }
.band--sunk   { background: var(--paper-sunk); }
.band--ink {
  background: var(--ink-850);
  color: var(--on-ink);
}
.band--ink-grad {
  background: linear-gradient(160deg, var(--ink-700) 0%, var(--ink-850) 55%, var(--ink-900) 100%);
  color: var(--on-ink);
}

.on-ink { color: var(--on-ink); }
.on-ink h1, .on-ink h2, .on-ink h3, .on-ink h4 { color: var(--on-ink); }

/* Section header: deck-style eyebrow + rule + title */
.sec-head { margin-bottom: clamp(32px, 4.5vw, 64px); }
.sec-head__top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--u3);
  padding-bottom: var(--u2);
  border-bottom: 1px solid var(--text);
  margin-bottom: clamp(24px, 3.5vw, 48px);
}
.on-ink .sec-head__top { border-bottom-color: var(--on-ink); }
.sec-head__title { font-size: var(--t-h2); }
.sec-head__grid {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: clamp(24px, 5vw, 88px);
  align-items: start;
}

/* Links */
.link {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--rust);
  padding-bottom: 4px;
  border-bottom: 1px solid currentColor;
  transition: gap 260ms var(--ease), opacity 260ms var(--ease);
}
.link:hover { gap: 1.1em; }
.on-ink .link { color: var(--orange); }
.link__arrow { transition: transform 320ms var(--ease-out); }
.link:hover .link__arrow { transform: translateX(2px); }

/* Pills (roadmap status) */
.pill {
  display: inline-block;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  padding: 6px 14px 5px;
  border-radius: var(--radius-pill);
}
.pill--done    { background: var(--rust-wash); color: var(--rust); }
.pill--now     { background: var(--orange-wash); color: var(--rust); box-shadow: inset 0 0 0 1px var(--rust); }
.pill--planned { background: rgba(110, 100, 86, 0.12); color: var(--text-4); }

/* ---------- 4. Header / nav --------------------------------------------- */

.nav {
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(16, 13, 9, 0.9);
  background: color-mix(in srgb, var(--ink-900) 88%, transparent);
  backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--rule-dark);
  color: var(--on-ink);
}
.nav__inner {
  display: flex;
  align-items: center;
  gap: var(--u4);
  height: 66px;
}
.nav__brand {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-right: auto;
  line-height: 1;
}
.nav__mark {
  width: auto;
  height: 28px;
  flex: none;
  display: block;   /* asset is cropped flush to the ink, so no nudge needed */
}
.nav__word {
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  font-weight: 500;
  /* Trailing space compensates the tracking on the final letter, which would
     otherwise push the lockup visually left of centre. */
  letter-spacing: 0.24em;
  padding-right: 0.24em;
  color: var(--on-ink);
  white-space: nowrap;
  display: block;
  /* Caps have no descender, so the glyphs sit high in their line box —
     nudge down to optically centre against the mark. */
  line-height: 1;
  transform: translateY(1px);
}
.nav__tabs {
  display: flex;
  align-items: center;
  gap: clamp(14px, 2vw, 30px);
}
.nav__tab {
  position: relative;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--on-ink-3);
  padding-block: 6px;
  transition: color 220ms var(--ease);
}
.nav__tab::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: -1px;
  height: 1px;
  background: var(--orange);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 380ms var(--ease-out);
}
.nav__tab:hover { color: var(--on-ink); }
.nav__tab:hover::after,
.nav__tab[aria-current="page"]::after { transform: scaleX(1); }
.nav__tab[aria-current="page"] { color: var(--orange); }

.nav__cta {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--ink-900);
  background: var(--orange);
  padding: 9px 16px 8px;
  border-radius: var(--radius);
  transition: filter 220ms var(--ease);
}
.nav__cta:hover { filter: brightness(1.1); }

.nav__toggle { display: none; }

/* Scroll progress hairline */
.progress {
  position: fixed;
  top: 0; left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left;
  background: var(--orange);
  z-index: 80;
  will-change: transform;
}

@media (max-width: 900px) {
  .nav__tabs {
    position: fixed;
    inset: 66px 0 auto 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--ink-850);
    border-bottom: 1px solid var(--rule-dark);
    padding: var(--u2) var(--gutter) var(--u3);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity 240ms var(--ease), transform 240ms var(--ease);
  }
  .nav.is-open .nav__tabs { opacity: 1; transform: none; pointer-events: auto; }
  .nav__tab { padding-block: 14px; border-bottom: 1px solid var(--rule-dark-soft); }
  .nav__tab::after { display: none; }
  .nav__cta { display: none; }
  .nav__toggle {
    display: block;
    font-family: var(--mono);
    font-size: var(--t-mono);
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--on-ink-2);
  }
}

/* ---------- 5. Hero ------------------------------------------------------ */

.hero {
  position: relative;
  min-height: min(100vh, 860px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  background: linear-gradient(155deg, var(--ink-700) 0%, var(--ink-850) 52%, var(--ink-900) 100%);
  color: var(--on-ink);
  overflow: hidden;
  padding-block: clamp(72px, 12vh, 140px);
}
.hero__mesh {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
}
.hero__inner { position: relative; z-index: 1; }
.hero__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--u3);
  padding-bottom: var(--u2);
  border-bottom: 1px solid var(--rule-dark);
  margin-bottom: clamp(40px, 8vh, 110px);
}
.hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: clamp(32px, 6vw, 80px);
  align-items: center;
}
.hero__title {
  font-size: var(--t-h1);
  line-height: 1.16;
  max-width: 15ch;
}
.hero__kicker {
  width: 92px;
  height: 1px;
  background: var(--orange);
  margin: clamp(24px, 3vw, 40px) 0 clamp(20px, 2.5vw, 30px);
  transform-origin: left;
}
.hero__sub {
  font-size: var(--t-lead);
  color: var(--on-ink-2);
  max-width: 44ch;
  line-height: 1.5;
}
.hero__mark {
  width: clamp(140px, 20vw, 290px);
  height: auto;
}
.hero__mark { object-fit: contain; }
.hero__foot {
  position: relative;
  z-index: 1;
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--u3);
  margin-top: clamp(48px, 9vh, 120px);
  padding-top: var(--u2);
  border-top: 1px solid var(--rule-dark);
}
.hero__readout {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.1em;
  color: var(--on-ink-4);
  font-variant-numeric: tabular-nums;
}
.hero__cue {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-3);
}
.hero__cue i {
  display: block;
  width: 1px;
  height: 26px;
  background: linear-gradient(var(--orange), transparent);
  animation: cue 2.4s var(--ease) infinite;
}
@keyframes cue {
  0%   { transform: scaleY(0.2); transform-origin: top; opacity: 0; }
  40%  { transform: scaleY(1);   transform-origin: top; opacity: 1; }
  100% { transform: scaleY(1);   transform-origin: bottom; opacity: 0; }
}

@media (max-width: 860px) {
  .hero__grid { grid-template-columns: 1fr; }
  .hero__mark { width: 108px; }
  .hero__title { max-width: none; }
}

/* ---------- 6. Page header (interior pages) ------------------------------ */

.phead {
  background: linear-gradient(165deg, var(--ink-700) 0%, var(--ink-850) 70%, var(--ink-900) 100%);
  color: var(--on-ink);
  padding-block: clamp(56px, 9vw, 128px) clamp(40px, 6vw, 88px);
  position: relative;
  overflow: hidden;
}
.phead__mesh { position: absolute; inset: 0; opacity: 0.55; }

.phead__inner { position: relative; z-index: 1; }
.phead__top {
  display: flex;
  justify-content: space-between;
  gap: var(--u3);
  padding-bottom: var(--u2);
  border-bottom: 1px solid var(--rule-dark);
  margin-bottom: clamp(32px, 6vw, 72px);
}
.phead__title { font-size: var(--t-h1); max-width: 18ch; }
.phead__sub {
  margin-top: var(--u3);
  font-size: var(--t-lead);
  color: var(--on-ink-2);
  max-width: 56ch;
}

/* ---------- 7. Stats ----------------------------------------------------- */

.stat { display: block; }
.stat__fig {
  font-family: var(--serif);
  font-size: var(--t-stat);
  line-height: 0.92;
  color: var(--rust);
  letter-spacing: -0.02em;
  font-variant-numeric: lining-nums tabular-nums;
}
.on-ink .stat__fig { color: var(--orange); }
.stat__unit {
  margin-top: var(--u2);
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text);
}
.on-ink .stat__unit { color: var(--on-ink); }
.stat__note { margin-top: 6px; color: var(--text-3); font-size: var(--t-sm); }
.on-ink .stat__note { color: var(--on-ink-3); }
.stat--rule { border-top: 1px solid var(--text); padding-top: var(--u3); }
.on-ink .stat--rule { border-top-color: var(--on-ink); }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: clamp(24px, 4vw, 56px);
}

/* ---------- 8. Column set (deck's 3-up) ---------------------------------- */

.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: clamp(24px, 3.5vw, 56px);
}
.col { border-top: 1px solid var(--text); padding-top: var(--u3); }
.on-ink .col { border-top-color: var(--on-ink); }
.col__n { display: block; margin-bottom: var(--u2); }
.col__t { font-size: var(--t-h3); margin-bottom: var(--u2); }
/* Number + title only, as on the slide — no trailing gap under the last line. */
.cols--titles .col__t { margin-bottom: 0; }
.col__b { color: var(--text-3); font-size: var(--t-sm); line-height: 1.65; }
.on-ink .col__b { color: var(--on-ink-3); }

/* ---------- 9. Sticky step scrollytelling -------------------------------- */

.steps {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(32px, 6vw, 104px);
  align-items: start;
}
.steps__rail { position: sticky; top: 120px; }
.steps__index { display: grid; gap: 2px; }
.steps__item {
  display: grid;
  grid-template-columns: 3.2em 1fr;
  gap: var(--u2);
  align-items: baseline;
  padding: 14px 0;
  border-top: 1px solid var(--rule);
  color: var(--text-4);
  text-align: left;
  width: 100%;
  transition: color 300ms var(--ease);
}
.steps__item:last-child { border-bottom: 1px solid var(--rule); }
.steps__item .n { font-family: var(--mono); font-size: var(--t-mono); letter-spacing: 0.1em; }
.steps__item .t { font-family: var(--serif); font-size: var(--t-h4); }
.steps__item.is-active { color: var(--text); }
.steps__item.is-active .n { color: var(--rust); }
.steps__bar {
  height: 1px;
  background: var(--rule);
  margin-top: var(--u3);
  position: relative;
  overflow: hidden;
}
.steps__bar i {
  position: absolute;
  inset: 0;
  background: var(--rust);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 460ms var(--ease-out);
}

.steps__flow { display: grid; gap: clamp(40px, 8vh, 96px); }
.step {
  border-top: 1px solid var(--rule);
  padding-top: var(--u3);
  min-height: 34vh;
}
.step__n { display: block; margin-bottom: var(--u2); }
.step__t { font-size: var(--t-h2); margin-bottom: var(--u3); }
.step__b { color: var(--text-2); max-width: 46ch; font-size: var(--t-lead); line-height: 1.55; }

@media (max-width: 900px) {
  .steps { grid-template-columns: 1fr; }
  .steps__rail { position: static; }
}

/* ---------- 10. Explorer (cursor field + click-to-video) ------------------ */

.ex {
  position: relative;
  background: var(--ink-900);
  border-top: 1px solid var(--rule-dark);
  border-bottom: 1px solid var(--rule-dark);
  color: var(--on-ink);
}
.ex__frame {
  position: relative;
  /* Full screen below the sticky nav. */
  height: calc(100vh - 66px);
  min-height: 560px;
}

/* Section label floats over the field rather than stacking above it, so the
   frame keeps the full viewport. */
.ex__head {
  position: absolute;
  top: 0; left: 0; right: 0;
  z-index: 3;
  pointer-events: none;
  padding-top: var(--u3);
  transition: opacity 520ms var(--ease), filter 520ms var(--ease);
}
/* Recede with the sphere when a node opens. Dropping the z-index matters as
   much as the dimming: at z-index 3 it paints over the panel, so a dimmed
   header would still lay a blurred rule across the "01 · Model" eyebrow. */
.ex.is-open .ex__head {
  z-index: 0;
  opacity: 0.14;
  filter: blur(2px);
}
.ex__headInner {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--u3);
  padding-bottom: var(--u2);
  border-bottom: 1px solid var(--rule-dark);
}

/* -- default state: the field -- */
.ex__stage {
  position: absolute;
  inset: 0;
  transition: opacity 520ms var(--ease), filter 520ms var(--ease);
}
.ex.is-open .ex__stage {
  opacity: 0.14;
  filter: blur(2px);
  cursor: zoom-out;            /* the dimmed field is also a way out */
}
.ex.is-open .hot { pointer-events: none; }
/* A node on the far side of the globe is scenery, not a target */
.hot.is-back { pointer-events: none; }
.hot.is-back .hot__label { opacity: 0; }

/* Grabbable globe */
.ex__stage { cursor: grab; }
.ex__stage.is-grabbing { cursor: grabbing; }
.ex.is-open .ex__stage { cursor: zoom-out; }
.ex__canvas { position: absolute; inset: 0; width: 100%; height: 100%; }

.ex__hint {
  position: absolute;
  left: var(--gutter);
  bottom: var(--u3);
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--on-ink-4);
}
.ex__hint b { color: var(--orange); font-weight: 500; }
.ex__hint span { padding-inline: 0.5em; opacity: 0.5; }

/* Hotspots — JS drives `transform` from each node's lat/lon on the globe */
.hot {
  position: absolute;
  left: 0;
  top: 0;
  transform: translate3d(50%, 50%, 0) translate(-50%, -50%);
  transition: opacity 160ms linear;
  will-change: transform, opacity;
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  color: var(--on-ink-2);
}
.hot__dot {
  width: 9px;
  height: 9px;
  background: var(--orange);
  border-radius: 50%;
  transition: transform 380ms var(--ease-out);
}
.hot__ring {
  position: absolute;
  width: 34px;
  height: 34px;
  border: 1px solid rgba(237, 125, 49, 0.45);
  border-radius: 50%;
  transform: scale(0.72);
  opacity: 0;
  transition: transform 460ms var(--ease-out), opacity 340ms var(--ease);
}
.hot__ring--2 { width: 62px; height: 62px; border-color: rgba(237, 125, 49, 0.2); }
.hot__label {
  position: absolute;
  top: calc(50% + 26px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-3);
  transition: color 300ms var(--ease), transform 380ms var(--ease-out);
}
.hot:hover .hot__dot,
.hot:focus-visible .hot__dot { transform: scale(1.5); }
.hot:hover .hot__ring,
.hot:focus-visible .hot__ring { transform: scale(1); opacity: 1; }
.hot:hover .hot__label,
.hot:focus-visible .hot__label { color: var(--on-ink); transform: translateX(-50%) translateY(3px); }

/* -- open state: media + readout -- */
.ex__view {
  position: absolute;
  inset: 0;
  display: grid;
  grid-template-columns: 52px minmax(0, 1.55fr) minmax(0, 1fr);
  opacity: 0;
  pointer-events: none;
  transition: opacity 460ms var(--ease);
}
/* Panel itself is click-through; only its real surfaces catch the pointer,
   so the gaps around the video fall through to the backdrop and close. */
.ex.is-open .ex__view { opacity: 1; pointer-events: none; }
.ex.is-open .ex__rail,
.ex.is-open .ex__mediaBox,
.ex.is-open .ex__read { pointer-events: auto; }

/* The obvious way out */
.ex__x {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 5;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule-dark);
  border-radius: 50%;
  background: rgba(16, 13, 9, 0.72);
  color: var(--on-ink-2);
  font-family: var(--mono);
  font-size: 19px;
  line-height: 1;
  opacity: 0;
  pointer-events: none;
  transform: scale(0.85);
  transition: opacity 300ms var(--ease), transform 300ms var(--ease-out),
              color 200ms var(--ease), border-color 200ms var(--ease);
}
.ex.is-open .ex__x { opacity: 1; pointer-events: auto; transform: none; }
.ex__x:hover { color: var(--orange); border-color: rgba(237, 125, 49, 0.55); }
.ex__x::after {
  content: "Close";
  position: absolute;
  top: 50%;
  right: calc(100% + 12px);
  transform: translateY(-50%);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--on-ink-4);
  opacity: 0;
  transition: opacity 240ms var(--ease);
}
.ex__x:hover::after { opacity: 1; }

.ex__rail {
  border-right: 1px solid var(--rule-dark);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  padding-block: var(--u3);
}
.ex__railBtn {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.08em;
  color: var(--on-ink-4);
  padding: 10px 0;
  transition: color 240ms var(--ease), background 240ms var(--ease);
}
.ex__railBtn:hover { color: var(--on-ink-2); }
.ex__railBtn.is-active { color: var(--orange); background: rgba(237, 125, 49, 0.07); }

.ex__media {
  position: relative;
  border-right: 1px solid var(--rule-dark);
  display: grid;
  place-items: center;
  padding: clamp(20px, 3vw, 44px);
  min-width: 0;
}
.ex__mediaBox {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: #0b0906;
  border: 1px solid var(--rule-dark);
  overflow: hidden;
}
.ex__mediaBox video,
.ex__mediaBox img,
.ex__mediaBox canvas,
.ex__mediaBox iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  object-fit: contain;   /* engine captures are 4:3-ish; never crop the run */
}
.ex__mediaBox video[hidden] { display: none; }
.ex__fig {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  display: flex;
  justify-content: space-between;
  gap: var(--u2);
  padding: 10px 14px;
  background: linear-gradient(transparent, rgba(8, 6, 4, 0.82));
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-ink-3);
}
.ex__fig b { color: var(--orange); font-weight: 500; }

.ex__read {
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 3vw, 48px) clamp(20px, 2.6vw, 40px);
  overflow-y: auto;
  min-width: 0;
}
.ex__read h3 {
  font-size: var(--t-h2);
  margin-block: var(--u2) var(--u3);
}
.ex__read p {
  color: var(--on-ink-2);
  font-size: var(--t-base);
  line-height: 1.62;
}
.ex__read dl {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 0;
  margin-top: auto;
  padding-top: var(--u4);
}
.ex__read dt, .ex__read dd {
  padding: 11px 0;
  border-top: 1px solid var(--rule-dark);
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.ex__read dt { color: var(--on-ink-4); padding-right: var(--u3); }
.ex__read dd { color: var(--on-ink); text-align: right; }

.ex__nav {
  display: flex;
  align-items: center;
  gap: var(--u2);
  margin-top: var(--u4);
  padding-top: var(--u3);
  border-top: 1px solid var(--rule-dark);
}
.ex__navBtn {
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-ink-3);
  padding: 8px 12px;
  border: 1px solid var(--rule-dark);
  border-radius: var(--radius);
  transition: color 220ms var(--ease), border-color 220ms var(--ease);
}
.ex__navBtn:hover { color: var(--orange); border-color: rgba(237, 125, 49, 0.4); }
.ex__close { margin-left: auto; }

/* Source articles are data only */
.ex__data { display: none; }

@media (max-width: 1000px) {
  .ex__frame { height: auto; }
  .ex__stage { position: relative; height: 58vh; min-height: 380px; }
  .ex.is-open .ex__stage { display: none; }
  .ex__view {
    position: relative;
    inset: auto;
    grid-template-columns: 1fr;
    display: none;
  }
  .ex.is-open .ex__view { display: grid; }
  .ex__rail {
    flex-direction: row;
    justify-content: flex-start;
    overflow-x: auto;
    border-right: 0;
    border-bottom: 1px solid var(--rule-dark);
    padding: 0 var(--gutter);
  }
  .ex__railBtn { padding: 14px 12px; }
  .ex__media { border-right: 0; border-bottom: 1px solid var(--rule-dark); }
}

/* ---------- 11. Figure switcher (physics page) --------------------------- */

.fig {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(28px, 4.5vw, 72px);
  align-items: start;
}
/* No rule above the first mechanic — each row carries its own bottom border,
   and a heavy top line here read as a stray mark. */
.figList { border-top: 0; }
.figList__btn {
  display: block;
  width: 100%;
  text-align: left;
  padding: clamp(16px, 2vw, 24px) 0;
  border-bottom: 1px solid var(--rule);
  position: relative;
  transition: padding-left 380ms var(--ease-out);
}
.on-ink .figList__btn { border-bottom-color: var(--rule-dark); }
.figList__btn::before {
  content: "";
  position: absolute;
  left: 0; top: 50%;
  width: 0; height: 1px;
  background: var(--rust);
  transform: translateY(-50%);
  transition: width 380ms var(--ease-out);
}
.figList__btn:hover { padding-left: 14px; }
.figList__btn.is-active { padding-left: 26px; }
.figList__btn.is-active::before { width: 16px; }
.figList__t {
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--text);
  transition: color 260ms var(--ease);
}
.figList__btn.is-active .figList__t { color: var(--rust); }
.figList__d {
  margin-top: 8px;
  color: var(--text-3);
  font-size: var(--t-sm);
  max-width: 52ch;
}
.figStage { position: sticky; top: 108px; }
.figStage__box {
  position: relative;
  aspect-ratio: 16 / 10;
  background: var(--ink-900);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.figStage__box video,
.figStage__box canvas {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.figStage__cap {
  display: flex;
  justify-content: space-between;
  gap: var(--u2);
  padding-top: 14px;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-4);
}
.figStage__cap b { color: var(--rust); font-weight: 500; }

@media (max-width: 880px) {
  .fig { grid-template-columns: 1fr; }
  .figStage { position: static; order: -1; }
}

/* ---------- 12. Interactive list rows (use cases, positioning) ----------- */

.rows { border-top: 1px solid var(--text); }
.on-ink .rows { border-top-color: var(--on-ink); }
.row {
  border-bottom: 1px solid var(--rule);
  width: 100%;
  text-align: left;
  display: block;
}
.on-ink .row { border-bottom-color: var(--rule-dark); }
.row__head {
  display: grid;
  grid-template-columns: 4.5em 1fr auto;
  gap: var(--u3);
  align-items: baseline;
  padding: clamp(18px, 2.4vw, 30px) 0;
  transition: padding-left 400ms var(--ease-out);
}
.row:hover .row__head, .row.is-open .row__head { padding-left: clamp(8px, 1.5vw, 20px); }
.row__t {
  font-family: var(--serif);
  font-size: var(--t-h3);
  color: var(--text);
  transition: color 260ms var(--ease);
}
.on-ink .row__t { color: var(--on-ink); }
.row.is-open .row__t { color: var(--rust); }
.on-ink .row.is-open .row__t { color: var(--orange); }
.row__sign {
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  color: var(--text-4);
  transition: transform 400ms var(--ease-out);
}
.row.is-open .row__sign { transform: rotate(45deg); }
.row__body {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 460ms var(--ease-out);
}
.row.is-open .row__body { grid-template-rows: 1fr; }
.row__bodyInner { overflow: hidden; }
.row__bodyPad {
  padding: 0 0 clamp(20px, 2.6vw, 34px) 4.5em;
  color: var(--text-3);
  max-width: 68ch;
}
.on-ink .row__bodyPad { color: var(--on-ink-3); }

@media (max-width: 640px) {
  .row__head { grid-template-columns: 2.8em 1fr auto; gap: var(--u2); }
  .row__bodyPad { padding-left: 2.8em; }
}

/* ---------- 13. Comparison (positioning) --------------------------------- */

.vs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  gap: 0;
  align-items: stretch;
}
/* Each column is a flex stack with the description flexing, which pushes every
   MYCELIUM block to the same baseline no matter how the copy above it runs. */
.vs__col {
  padding: 0 clamp(16px, 2.4vw, 34px);
  border-left: 1px solid var(--rule);
  display: flex;
  flex-direction: column;
}
.vs__col:first-child { padding-left: 0; border-left: 0; }
.vs__label { display: block; margin-bottom: var(--u3); }

/* Logo / screenshot slot above each competitor name */
.vs__shot {
  position: relative;
  /* Fixed height, not an aspect ratio: the first column carries no left padding,
     so its content box is wider and a ratio-sized slot came out taller — which
     pushed that column's name and copy out of line with the other two.
     Tuned so the slot sits near the ~1.8:1 of all three screenshots, which lets
     them fill the frame instead of floating in letterboxing. */
  height: clamp(150px, 15.5vw, 230px);
  margin-bottom: var(--u3);
  background: var(--paper-raised);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.vs__shot::before {
  content: attr(data-label);
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-4);
  text-align: center;
  padding: var(--u2);
}
.vs__shot img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  /* cover, not contain: slot and source are both about 1.8:1, so this fills the
     frame edge to edge while trimming only a few pixels */
  object-fit: cover;
  object-position: center;
  background: var(--paper-raised);
}

.vs__name { font-family: var(--serif); font-size: var(--t-h4); margin-bottom: var(--u2); }
.vs__desc {
  color: var(--text-3);
  font-size: var(--t-sm);
  line-height: 1.65;
  padding-bottom: var(--u3);
  flex: 1;                 /* eats the slack so .vs__ours aligns across columns */
}
.vs__ours { border-top: 1px solid var(--text); padding-top: var(--u3); }
.vs__oursLabel { color: var(--rust); }
.vs__oursText { margin-top: 10px; color: var(--text); font-size: var(--t-sm); }

/* ---------- 14. Pipeline compression (economics) ------------------------- */

.pipe {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(28px, 4vw, 64px);
}
.pipe__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--u2);
  padding-bottom: 12px;
  border-bottom: 1px solid var(--text);
}
.pipe--ours .pipe__head { border-bottom-color: var(--rust); }
.pipe__title { font-family: var(--mono); font-size: var(--t-mono-l); letter-spacing: 0.13em; text-transform: uppercase; }
.pipe--ours .pipe__title { color: var(--rust); }
.pipe__row {
  display: grid;
  grid-template-columns: 3em minmax(0, 1fr) minmax(0, 1.15fr);
  column-gap: var(--u3);
  align-items: start;
  padding: 14px 0;
  border-bottom: 1px solid var(--rule-soft);
  /* Equal row heights keep the two pipelines in step: without this, a
     description that wraps to two lines pushes one column out of register
     with the other for every row below it. */
  min-height: 5em;
}
.pipe__row .n { font-family: var(--mono); font-size: var(--t-mono); color: var(--text-4); }
.pipe--ours .pipe__row .n { color: var(--rust); }
.pipe__row .t { font-weight: 500; font-size: var(--t-sm); }
.pipe__row .d { color: var(--text-3); font-size: var(--t-sm); }

.compress {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: clamp(20px, 3vw, 48px);
  border-top: 1px solid var(--text);
  padding-top: var(--u3);
  margin-top: clamp(32px, 4vw, 56px);
}
.compress__cell + .compress__cell { border-left: 1px solid var(--rule); padding-left: clamp(16px, 2.4vw, 40px); }

/* Bars and numerals are wildly different heights; sitting them on a shared
   baseline box is what lines the three captions up with each other. */
.compress__cell { display: flex; flex-direction: column; }
.compress__val {
  display: flex;
  align-items: flex-end;
  min-height: clamp(46px, 5.2vw, 76px);
}
.compress__val .stat__fig { line-height: 0.86; }

.bars { display: flex; align-items: flex-end; gap: 4px; height: 26px; }
.bars i {
  display: block;
  width: 11px;
  height: 100%;
  background: var(--text-4);
  transform: scaleY(0.25);
  transform-origin: bottom;
  transition: transform 620ms var(--ease-out), background 620ms var(--ease);
}
.bars--ours i { background: var(--rust); }
.is-in .bars i { transform: scaleY(1); }
.bars__arrow { align-self: center; color: var(--text-4); font-family: var(--mono); padding-inline: 10px; }
.compress__cap { margin-top: 14px; }

@media (max-width: 700px) {
  .compress__cell + .compress__cell { border-left: 0; padding-left: 0; }
}

/* ---------- 15. Roadmap (scroll-linked horizontal) ----------------------- */

.road { background: var(--paper); --card: clamp(240px, 24vw, 320px); --cardGap: clamp(20px, 2.6vw, 40px); }
.road__pin { height: 340vh; position: relative; }
.road__sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  /* No flex gap — the media and hint carry their own matched margins, which is
     what keeps the timeline optically centred between them. */
  gap: 0;
  overflow: hidden;
  padding-block: clamp(40px, 6vh, 72px) clamp(24px, 4vh, 48px);
}

/* Media frame for the milestone currently under the centre line */
.road__media {
  width: min(760px, calc(100vw - var(--gutter) * 2));
  margin-inline: auto;
  flex: 0 1 auto;
  min-height: 0;
}
.road__mediaBox {
  position: relative;
  aspect-ratio: 16 / 9;
  max-height: 42vh;
  margin-inline: auto;
  background: var(--ink-900);
  border: 1px solid var(--rule);
  overflow: hidden;
}
.road__mediaBox video,
.road__mediaBox img,
.road__mediaBox canvas,
.road__mediaBox iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  object-fit: contain;
}
/* Stands in for a milestone with nothing to show yet.
   The [hidden] rule is required: setting `display` in a class beats the browser's
   `[hidden] { display: none }`, which would leave this painted over every stage. */
.mediaWip[hidden] { display: none; }
.mediaWip {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-family: var(--mono);
  font-size: var(--t-mono-l);
  font-weight: 500;
  letter-spacing: 0.34em;
  text-indent: 0.34em;
  text-transform: uppercase;
  color: var(--on-ink-4);
}

.road__cap {
  display: flex;
  justify-content: space-between;
  gap: var(--u2);
  padding-top: 12px;
  font-family: var(--mono);
  font-size: var(--t-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-4);
}
.road__cap b { color: var(--rust); font-weight: 500; }

/* Centre marker: two short ticks sitting clear of the cards. A full-height
   line ran straight through whichever milestone was centred — worse the
   taller the viewport, which is why it read as broken at 1080p. */
.road__viewport {
  position: relative;
  /* Matches .road__hint's margin-top so the timeline sits centred between the
     graphic above and the scroll cue below, and the tick clears the caption. */
  margin-top: clamp(28px, 4vw, 56px);
}
.road__viewport::before,
.road__viewport::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 1px;
  height: 12px;
  background: var(--rust);
  opacity: 0.45;
  z-index: 2;
}
.road__viewport::before { top: -20px; }
.road__viewport::after  { bottom: -20px; }

.road__track {
  display: flex;
  gap: var(--cardGap);
  padding-inline: calc(50vw - var(--card) / 2);
  will-change: transform;
}
.road__stop {
  flex: 0 0 var(--card);
  border-top: 1px solid var(--rule);
  padding-top: var(--u3);
  position: relative;
  cursor: pointer;
  opacity: 0.34;
  transition: opacity 420ms var(--ease), border-color 420ms var(--ease);
}
.road__stop.is-active {
  opacity: 1;
  border-top-color: var(--rust);
}
.road__stop::before {
  content: "";
  position: absolute;
  top: -5px; left: 0;
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--rust);
}
.road__stop--now::before {
  background: var(--paper);
  box-shadow: 0 0 0 1.5px var(--rust), inset 0 0 0 2.5px var(--rust);
  width: 11px; height: 11px;
  top: -6px;
}
.road__stop--future::before { background: var(--text-4); }
.road__date { display: block; margin-bottom: 10px; }
.road__stop--now .road__date { color: var(--rust); }
.road__name { font-size: var(--t-h3); margin-bottom: var(--u2); font-family: var(--sans); font-weight: 600; letter-spacing: -0.01em; }
.road__desc { color: var(--text-3); font-size: var(--t-sm); line-height: 1.65; margin-bottom: var(--u3); min-height: 5.2em; }
.road__hint {
  padding-inline: var(--gutter);
  margin-top: clamp(28px, 4vw, 56px);
  display: flex;
  justify-content: space-between;
  gap: var(--u3);
}
.road__scrub { height: 1px; background: var(--rule); position: relative; margin-top: 14px; }
.road__scrub i {
  position: absolute; inset: 0;
  background: var(--rust);
  transform: scaleX(0);
  transform-origin: left;
}

@media (max-width: 860px) {
  .road__pin { height: auto; }
  .road__sticky { position: static; height: auto; padding-block: var(--u6); overflow: visible; }
  .road__track {
    flex-direction: column;
    transform: none !important;
    padding-inline: var(--gutter);
    gap: var(--u4);
  }
  .road__stop { flex: 1 1 auto; opacity: 1; cursor: default; }
  .road__desc { min-height: 0; }
  .road__hint { display: none; }
  .road__media { width: auto; padding-inline: var(--gutter); }
  .road__mediaBox { max-height: none; }
  .road__viewport::before { display: none; }
}

/* ---------- 16. Team ----------------------------------------------------- */

.team { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 0; }
.team__m { padding: 0 clamp(16px, 2.6vw, 40px); border-left: 1px solid var(--rule); }
.team__m:first-child { padding-left: 0; border-left: 0; }
.team__ph {
  width: 108px; height: 108px;
  border-radius: 50%;
  background: var(--paper-sunk);
  object-fit: cover;
  margin-bottom: var(--u3);
  filter: grayscale(1) contrast(1.04);
  transition: filter 500ms var(--ease);
}
.team__m:hover .team__ph { filter: grayscale(0); }
.team__n { font-size: var(--t-h3); margin-bottom: 8px; }
.team__r { display: block; margin-bottom: var(--u3); }
.team__b { color: var(--text-3); font-size: var(--t-sm); line-height: 1.65; }

/* ---------- 17. Marquee -------------------------------------------------- */

.marquee {
  position: relative;
  overflow: hidden;
  padding-block: var(--u3);
  border-top: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
          mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.on-ink .marquee { border-color: var(--rule-dark); }
.marquee__track {
  display: flex;
  width: max-content;
  animation: slide 46s linear infinite;
}
/* Two identical sets, each carrying its own trailing gap, so the -50%
   wrap lands exactly on the seam. */
.marquee__set {
  display: flex;
  gap: clamp(28px, 4vw, 64px);
  padding-right: clamp(28px, 4vw, 64px);
}
.marquee:hover .marquee__track { animation-play-state: paused; }
.marquee__item {
  font-family: var(--serif);
  font-size: var(--t-h4);
  color: var(--text-3);
  white-space: nowrap;
}
.on-ink .marquee__item { color: var(--on-ink-3); }
@keyframes slide { to { transform: translateX(-50%); } }

/* ---------- 18. Footer --------------------------------------------------- */

.foot {
  background: var(--ink-900);
  color: var(--on-ink);
  /* Sized for a grid-only footer — the closing line lives on the last tab. */
  padding-block: clamp(40px, 5vw, 72px) var(--u6);
}
.foot__grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: clamp(24px, 3vw, 48px);
  padding-top: var(--u4);
  border-top: 1px solid var(--rule-dark);
}
.foot__h { display: block; margin-bottom: var(--u2); }
.foot__l { display: block; padding: 5px 0; color: var(--on-ink-2); font-size: var(--t-sm); transition: color 220ms var(--ease); }
.foot__l:hover { color: var(--orange); }
.foot__bar {
  display: flex;
  justify-content: space-between;
  gap: var(--u3);
  flex-wrap: wrap;
  margin-top: clamp(40px, 5vw, 72px);
  padding-top: var(--u3);
  border-top: 1px solid var(--rule-dark);
}
.foot__contact a {
  color: var(--on-ink-2);
  transition: color 200ms var(--ease);
}
.foot__contact a:hover { color: var(--orange); }

/* ---------- 19. Next-page pager ------------------------------------------ */

.pager {
  display: block;
  border-top: 1px solid var(--rule-dark);
  padding-block: clamp(36px, 5vw, 72px);
  background: var(--ink-850);
  color: var(--on-ink);
}
.pager__inner { display: flex; justify-content: space-between; align-items: flex-end; gap: var(--u3); }
.pager__t { font-size: var(--t-h2); transition: color 300ms var(--ease); }
.pager:hover .pager__t { color: var(--orange); }
.pager__arrow { font-family: var(--mono); font-size: var(--t-h3); color: var(--orange); transition: transform 420ms var(--ease-out); }
.pager:hover .pager__arrow { transform: translateX(10px); }

/* ---------- 20. Reveal on scroll ----------------------------------------- */

.reveal {
  opacity: 0;
  transform: translateY(18px);
  transition:
    opacity 760ms var(--ease-out) calc(var(--i, 0) * 70ms),
    transform 760ms var(--ease-out) calc(var(--i, 0) * 70ms);
}
.reveal.is-in { opacity: 1; transform: none; }

/* ---------- 21. Motion / reduced ---------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .reveal { opacity: 1; transform: none; }
  .road__pin { height: auto; }
  .road__sticky { position: static; height: auto; padding-block: var(--u6); }
  .road__track { flex-direction: column; transform: none !important; }
}

/* ---------- 22. Component odds and ends ---------------------------------- */

/* Explorer readout needs a flex column so the spec list can sit at the base */
.ex__read > [data-slot] {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
.ex__count { margin-inline: var(--u2); }

/* Non-sticky variant of the figure stage, for side-by-side figures */
.figStage--static { position: static; }

.duo {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: clamp(20px, 3vw, 40px);
}

/* Linear motif for the two closing bands. Sits low and runs edge to edge;
   non-interactive so it never eats a text selection. */
.rail {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  width: 100%;
  height: clamp(150px, 30%, 280px);
  z-index: 0;
  pointer-events: none;
}

/* Hero-scale statement, for the argument each dark band lands on. */
.statement {
  font-size: var(--t-h1);
  line-height: 1.14;
  max-width: 17ch;
}
.statement__kicker {
  width: 92px;
  height: 1px;
  background: var(--orange);
  margin: clamp(22px, 3vw, 36px) 0 clamp(20px, 2.6vw, 32px);
}

/* The line a section resolves on. The emphasis carries the turn, so it needs
   no extra rule or box around it. */
.closer {
  font-family: var(--serif);
  font-size: var(--t-h2);
  line-height: 1.22;
  letter-spacing: -0.012em;
  max-width: 22ch;
  color: var(--on-ink);
  text-wrap: balance;
}
.closer em { font-style: normal; color: var(--orange); }


/* ---- Closing band: revealed mark + motes ---------------------------------
   The mark sits behind everything, almost fully greyed down. A second copy in
   full colour is masked to a soft circle at the cursor, so moving across the
   section wipes the orange back in. Two stacked images and a mask — no canvas,
   no per-frame work beyond one custom property. */

/* Motes drifting up from the base of the band, under the type. */
.motes {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}


/* Two body paragraphs as one even block — equal measures, unlike the weighted
   heading/body split of .sec-head__grid. */
.prose-2 {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: clamp(24px, 4vw, 64px);
  align-items: start;
}
.prose-2 > p { max-width: 52ch; }

.compress__viz { display: flex; align-items: flex-end; }

/* Bars stagger in as the block reveals */
.bars i:nth-child(1)  { transition-delay: 0ms; }
.bars i:nth-child(2)  { transition-delay: 40ms; }
.bars i:nth-child(3)  { transition-delay: 80ms; }
.bars i:nth-child(4)  { transition-delay: 120ms; }
.bars i:nth-child(5)  { transition-delay: 160ms; }
.bars i:nth-child(6)  { transition-delay: 200ms; }
.bars i:nth-child(7)  { transition-delay: 240ms; }
.bars i:nth-child(8)  { transition-delay: 280ms; }
.bars i:nth-child(9)  { transition-delay: 320ms; }
.bars i:nth-child(10) { transition-delay: 360ms; }
.bars i:nth-child(11) { transition-delay: 400ms; }
.bars i:nth-child(12) { transition-delay: 440ms; }
.bars--ours i:nth-child(1) { transition-delay: 520ms; }
.bars--ours i:nth-child(2) { transition-delay: 570ms; }
.bars--ours i:nth-child(3) { transition-delay: 620ms; }
.bars--ours i:nth-child(4) { transition-delay: 670ms; }

/* ---------- 23. Utilities ------------------------------------------------ */

.stack-2  > * + * { margin-top: var(--u2); }
.stack-3  > * + * { margin-top: var(--u3); }
.stack-4  > * + * { margin-top: var(--u4); }
.stack-6  > * + * { margin-top: var(--u6); }
.mt-6 { margin-top: var(--u6); }
.mt-8 { margin-top: var(--u8); }
.mt-12 { margin-top: clamp(48px, 7vw, 96px); }
.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;
}

/* ---------- 24. Phone layout --------------------------------------------- */

/* Everything below is additive and every declaration sits inside a media
   query, so the desktop cascade is byte-for-byte what it was. Placement is
   load-bearing: several of these rules tie on specificity with a base rule or
   with the 900 / 1000 / 860px blocks above and win only on source order, so
   this section has to stay last in the file. */

@media (max-width: 768px) {

  /* -- Primitives -- */

  /* The 1.15fr / 1fr heading split has no breakpoint of its own. At 375px it
     resolves to 166px / 145px, which leaves a 31px serif h2 in a column
     narrower than the words it holds. One column below the tablet line. */
  .sec-head__grid { grid-template-columns: minmax(0, 1fr); }

  /* .link is a 12px mono line over 4px of padding — a 23px target, and on
     index.html it is the only CTA above the fold. More padding would drag the
     underline off the text, so the hit area is a pseudo instead: absolutely
     positioned, therefore out of the inline-flex flow, therefore free. */
  .link { position: relative; }
  .link::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 50%;
    height: 44px;
    transform: translateY(-50%);
  }

  /* The standalone disclaimers on market.html run 130+ characters of 11px
     mono at 0.14em — four lines of tracked-out uppercase on a phone. Scoped
     to direct children of .wrap so the short captions and eyebrows that also
     carry .label keep the deck's size. */
  .wrap > p.label {
    font-size: var(--t-mono-l);
    letter-spacing: 0.08em;
    line-height: 1.7;
  }

  /* -- Header / nav -- */

  /* Both nav targets are sized by their own line box: the brand lockup is 28px
     tall, the drawer toggle 32 x 18 — and below 900px the toggle is the only
     navigation affordance there is. .nav__inner is a fixed 66px flex row with
     align-items: center, so growing either one moves no glyph, it only grows
     the hit box; flex-end plus a left-side pad grows the toggle inward from
     the gutter and holds the glyphs still through the MENU / CLOSE swap.
     `display: flex` ties with `display: block` at :395 — source order is the
     only reason it wins, which is why this block has to come after it. */
  .nav__brand { min-height: 44px; }
  .nav__toggle {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    min-width: 44px;
    min-height: 44px;
    padding-left: 12px;
  }

  /* -- Hero -- */

  /* 100vh is the LARGE viewport on mobile Safari, so the hero reserves height
     the phone never shows and .hero__readout lands just under the fold on a
     375 x 667. svh is the box actually on screen; dvh would relayout the hero
     every time the URL bar collapses. The foot's own 9vh margin has to move
     with it or it re-opens most of the gap on its own. */
  .hero {
    min-height: min(100svh, 860px);
    padding-block: clamp(72px, 12svh, 140px);
  }
  .hero__foot { margin-top: clamp(40px, 9svh, 120px); }

  /* -- Page header (interior pages) -- */

  /* An absolutely positioned <canvas> with auto width and height takes its
     intrinsic size, not its insets, so inset: 0 alone leaves .phead__mesh at
     whatever ratio the JS last wrote — half the header's height on a phone,
     with the field's radius computed from that. .hero__mesh and .motes both
     declare the size; this one was missed. */
  .phead__mesh { width: 100%; height: 100%; }

  /* -- Explorer -- */

  /* The 1000px block drops the frame to height: auto but leaves min-height
     standing, so a closed frame holds 560px around a 387px stage — ~173px of
     dead ground under the globe. Nothing else inside is in flow (.ex__head
     and .ex__x are absolute, .ex__view is display: none until open), so the
     frame can size to the stage cleanly. */
  .ex__frame { min-height: 0; }

  /* touch-action appears nowhere else in the file, so the browser owns the
     gesture: it cancels the drag mid-stroke and the globe never spins. The
     pointermove listener is registered { passive: true } and structurally
     cannot preventDefault its way out, so declaring intent here is the only
     available fix. pan-y hands horizontal drags to the field and leaves
     vertical scroll — and pinch-zoom — with the browser. Pitch is lost on
     touch; yaw is the axis the nodes ride on. */
  .ex__stage,
  .ex__canvas { touch-action: pan-y pinch-zoom; }

  /* A long node label is ~236px of nowrap mono centred on a point the field
     can park anywhere on the sphere — 63% of a 375px viewport — and with no
     hover the label is the only name a node has before you tap it.
     max-content plus a cap wraps it instead of hanging it off screen. */
  /* Paired with fitNarrow in site.js: at 375px the sphere's half-extent is
     116px, so a label capped at 130px (65px either side of its node) lands at
     181px against a 187.5px half-frame. Raising either number puts the
     furthest node's label back over the edge. */
  .hot__label {
    white-space: normal;
    width: max-content;
    max-width: min(34vw, 130px);
    text-align: center;
    letter-spacing: 0.08em;
    line-height: 1.3;
  }

  /* Once the rail is horizontal it is five identical two-digit targets ~39px
     wide with 2px between them. The gap is the half that actually prevents
     mis-taps; 5 x 44 + 4 x 8 still clears 375px without scrolling the rail. */
  .ex__rail { gap: var(--u); }
  .ex__railBtn { min-width: 44px; }

  /* The longest term sets the `auto` track for every row and crushes the
     right-aligned value against it. Stacked, each pair reads as one block
     under one rule — which is why dd has to give up its own border and top
     padding, or every hairline doubles. */
  .ex__read dl { grid-template-columns: 1fr; }
  .ex__read dt { padding-right: 0; padding-bottom: 0; }
  .ex__read dd { text-align: left; border-top: 0; padding-top: 0; }

  /* The 1000px block sizes .ex__railBtn for touch and stops there — prev/next
     and Close were left on the desktop 8px/12px box at ~33 x 36. */
  .ex__navBtn { padding: 14px 12px; min-width: 44px; }

  /* -- Pipeline compression -- */

  /* Two 300px tracks still fit at 768px, so each pipeline gets ~334px and the
     header is as cramped there as at 375px. Wrap rather than stack: between
     ~450 and ~690px the header fits on one line and should keep its
     space-between. flex: 0 0 auto is required, or the items shrink instead of
     wrapping. */
  .pipe__head { flex-wrap: wrap; row-gap: 6px; }
  .pipe__head > * { flex: 0 0 auto; }

  /* 3em + 1fr + 1.15fr inside a 335px row leaves ~130px for the description.
     Title and description share the second track instead, stacked — .d
     already carries grid-column: 2, so auto-placement needs no help. */
  .pipe__row {
    grid-template-columns: 2.6em minmax(0, 1fr);
    column-gap: var(--u2);
    row-gap: 2px;
  }
  .pipe__row .d { grid-column: 2; }

  /* -- Roadmap -- */

  /* The 860px block sets .road__media to width: auto. Its parent is a column
     flex box, so the inline axis is the cross axis, and margin-inline: auto
     opts the item out of stretch — leaving the 16:9 frame to be sized by the
     caption string, which is rewritten per milestone, so the video box jitters
     as the roadmap advances. Kill the auto margin rather than outrun it.
     Ties with :1417, so it must stay after it. */
  .road__media {
    width: 100%;
    margin-inline: 0;
  }

  /* The 860px block hides the top centre tick once the track goes vertical and
     leaves its pair behind. Half a centre marker marks nothing. */
  .road__viewport::after { display: none; }

  /* -- Footer -- */

  /* .foot__grid is one column below ~190px of track, so the links stack flush
     at a 32px pitch — runs of three adjacent sub-44px targets with no
     separator. 22.4px line box + 22px = 44.4px. padding-block rather than the
     shorthand, so the inline padding stays at 0. */
  .foot__l { padding-block: 11px; }

  /* The only mailto on the site is a bare inline box ~18px tall, under the
     24px floor let alone 44. The negative margin cancels the growth against
     .foot__bar's line box, so the bar's height and wrapping are unchanged and
     the overhang is absorbed by its existing 24px of padding. */
  .foot__contact a {
    display: inline-block;
    padding-block: 14px;
    margin-block: -14px;
  }
}

/* Equal row heights only earn their keep while the two pipelines are side by
   side. Once .pipe is a single column there is nothing left to hold register
   with, and a 5em floor under a two-line row is just air. */
@media (max-width: 640px) {
  .pipe__row { min-height: 0; }
}

/* .team is auto-fit minmax(260px) with gap: 0, so it goes single column at
   ~571px — and below that the left border and inset that separate the columns
   are drawing down the side of a stacked card, indenting members 2 and 3
   against member 1 until a name reads as a subhead of the paragraph above it.
   The portraits that would otherwise separate them are removed by the img
   onerror, so this rule is all there is. Capped at 560 rather than 768
   deliberately: at 768 the grid is still 2-up and this would rule between
   side-by-side cards. */
@media (max-width: 560px) {
  .team { gap: var(--u4); }
  .team__m {
    padding-inline: 0;
    border-left: 0;
  }
  .team__m + .team__m {
    padding-top: var(--u4);
    border-top: 1px solid var(--rule);
  }
}

/* Same failure one track-width down: .vs is minmax(250px) with gap: 0, so it
   collapses at ~550px, where the column rules become hairlines dividing
   nothing and the three cards butt together with no separator at all. 540 is
   the first width guaranteed to be single-column. */
@media (max-width: 540px) {
  .vs__col {
    padding-inline: 0;
    border-left: 0;
  }
  .vs__col + .vs__col {
    margin-top: var(--u4);
    padding-top: var(--u4);
    border-top: 1px solid var(--rule);
  }
}

/* -- Touch affordances ---------------------------------------------------- */

/* Kept under the same 768px cap as everything else: a mouse never matches
   hover: none, and a touch tablet above the cap keeps today's behaviour. */
@media (hover: none) and (pointer: coarse) and (max-width: 768px) {

  /* .hot's rings and its label brightening only resolve through :hover, which
     never fires here — so a node is a 9px dot inside an 88px box with no
     boundary, and Android flashes a grey 88px rectangle around it on tap. The
     rest state gets the rings. JS writes inline styles to the .hot button
     only, never to these children, so no !important is needed. */
  .hot { -webkit-tap-highlight-color: transparent; }
  .hot__ring { transform: scale(1); opacity: 1; }
  .hot__ring--2 { opacity: 0.6; }
  .hot__label { color: var(--on-ink-2); }

  /* Both hints name a gesture the device cannot perform. Neither string is
     static — the readout has live X/Y prepended on every move and goes stale
     the instant the finger lifts — so the only CSS-side fix is to collapse the
     text node and let generated content carry the touch wording; textContent
     writes cannot clear a ::after. touch-action on .hero is what makes the
     replacement copy true: the field's pointer host is the hero itself.
     The middot is escaped so the copy survives regardless of the charset the
     host serves this file with. Caveat: the accessible name still says
     "hover" / "drag". Fixing that means editing the markup. */
  .hero { touch-action: pan-y pinch-zoom; }
  .hero__readout { font-size: 0; letter-spacing: 0; }
  .hero__readout::after {
    content: "Node lattice " "\0000B7" " drag to deform";
    font-size: var(--t-mono);
    letter-spacing: 0.1em;
  }
  .ex__hint { font-size: 0; letter-spacing: 0; }
  .ex__hint::after {
    content: "Swipe sideways to spin " "\0000B7" " Tap a node as it comes round";
    font-size: var(--t-mono);
    letter-spacing: 0.16em;
  }
}
