@font-face {
  font-family: 'Archivo';
  src: url('fonts/archivo-var.woff2') format('woff2-variations');
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}

/* ═══ Tokens ══════════════════════════════════════════════════════════
   One accent, used where something must be acted on or read first.
   Measured contrast against --bg #0a0a07:
     ink 17.9:1 · muted 9.2:1 · signal 13.6:1 · line-strong 3.2:1
   On the signal band (#ddde00): on-signal 13.4:1 · on-signal-mute 8.7:1
   ══════════════════════════════════════════════════════════════════ */

:root {
  --bg:          oklch(0.145 0.008 110);
  --bg-raised:   oklch(0.205 0.011 110);
  --line:        oklch(0.360 0.016 110);   /* hairlines, decorative      */
  --line-soft:   oklch(0.300 0.014 110);   /* quietest rules             */
  --line-strong: oklch(0.500 0.021 110);   /* control boundaries, 3.2:1  */

  --ink:   oklch(0.966 0.006 110);
  --muted: oklch(0.760 0.015 110);

  --signal:         oklch(0.870 0.190 110);
  --signal-dim:     oklch(0.560 0.115 110);
  --on-signal:      oklch(0.160 0.030 110);
  --on-signal-mute: oklch(0.320 0.060 110);

  --measure: 68ch;
  --gutter: clamp(1.25rem, 5vw, 5rem);

  --step--1: clamp(0.82rem, 0.79rem + 0.14vw, 0.9rem);
  --step-0:  clamp(1rem, 0.96rem + 0.2vw, 1.125rem);
  --step-1:  clamp(1.3rem, 1.21rem + 0.45vw, 1.6rem);
  --step-2:  clamp(1.72rem, 1.5rem + 1.05vw, 2.5rem);
  --step-3:  clamp(2.3rem, 1.86rem + 2.15vw, 3.8rem);
  --step-4:  clamp(3rem, 2.1rem + 4.4vw, 5.5rem);

  /* Display width axis: Archivo Expanded is the signage voice, but it has
     to give ground on narrow viewports or long names overflow. */
  --wdth-display: 102;

  --ease-out-expo:  cubic-bezier(0.16, 1, 0.3, 1);
  --ease-out-quart: cubic-bezier(0.25, 1, 0.5, 1);
  --ease-out-quint: cubic-bezier(0.22, 1, 0.36, 1);

  --z-field: 0;
  --z-content: 1;
  --z-rail: 120;
  --z-overlay: 200;
}

@media (min-width: 26rem) { :root { --wdth-display: 108; } }
@media (min-width: 34rem) { :root { --wdth-display: 114; } }
@media (min-width: 48rem) { :root { --wdth-display: 118; } }

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

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: 'Archivo', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  font-size: var(--step-0);
  font-variation-settings: 'wdth' 100, 'wght' 400;
  /* Light type on dark reads lighter than it measures; give it room. */
  line-height: 1.68;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

h1, h2, h3 { text-wrap: balance; margin: 0; }
p { text-wrap: pretty; margin: 0; }

a {
  color: inherit;
  text-decoration-color: var(--signal-dim);
  text-underline-offset: 0.22em;
  text-decoration-thickness: 1px;
  transition: color 0.22s var(--ease-out-quart), text-decoration-color 0.22s var(--ease-out-quart);
}
a:hover { color: var(--signal); text-decoration-color: var(--signal); }

:focus-visible {
  outline: 2px solid var(--signal);
  outline-offset: 3px;
  border-radius: 2px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--signal);
  color: var(--on-signal);
  padding: 0.6rem 1rem;
  font-variation-settings: 'wdth' 100, 'wght' 650;
  z-index: var(--z-overlay);
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

/* ═══ Living background ═══════════════════════════════════════════════
   Fixed transport field behind everything. Decorative, aria-hidden, and
   never a scroll-overflow source: the oversized inner box is clipped by
   the fixed wrapper, so parallax has room to move without widening the
   document. Content bands sit above it on --z-content.
   ══════════════════════════════════════════════════════════════════ */

.field {
  position: fixed;
  inset: 0;
  z-index: var(--z-field);
  overflow: hidden;
  pointer-events: none;
  contain: layout paint style;
}
.field__inner {
  position: absolute;
  left: -80px;
  top: -80px;
  width: calc(100% + 160px);
  height: calc(100% + 160px);
  will-change: transform;
}
.field__c { position: absolute; inset: 0; width: 100%; height: 100%; }
/* Knock the field back across the reading column and let it breathe at the
   margins, so a passing packet never competes with a line of body copy. */
.field::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to right,
      oklch(0.145 0.008 110 / 0) 0%,
      oklch(0.145 0.008 110 / 0.82) 21%,
      oklch(0.145 0.008 110 / 0.82) 79%,
      oklch(0.145 0.008 110 / 0) 100%),
    radial-gradient(120% 55% at 50% 0%, oklch(0.145 0.008 110 / 0.5) 0%, oklch(0.145 0.008 110 / 0) 72%);
}

/* Scroll progress. Decorative; absent unless scroll timelines exist. */
.rail {
  position: fixed;
  inset: 0 0 auto 0;
  height: 2px;
  z-index: var(--z-rail);
  pointer-events: none;
}
.rail__fill {
  display: block;
  height: 100%;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: 0 50%;
}

/* ═══ Bands ══════════════════════════════════════════════════════════ */

.band { position: relative; z-index: var(--z-content); }
.shell {
  width: 100%;
  max-width: 78rem;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* A section's opening rule: signal for the first stretch, then hairline.
   Structure marker instead of a tracked-out eyebrow. */
.rule {
  height: 2px;
  margin: 0 0 clamp(2rem, 4vw, 3rem);
  background: linear-gradient(90deg, var(--signal) 0 clamp(3.5rem, 8vw, 6rem), var(--line-soft) clamp(3.5rem, 8vw, 6rem));
  transform: scaleX(1);
  transform-origin: 0 50%;
}

/* ═══ Hero ══════════════════════════════════════════════════════════ */

.band--hero { padding-block: clamp(1.5rem, 4vh, 2.5rem) clamp(3.5rem, 9vh, 6.5rem); }

.mark {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.15rem 0.45rem;
  font-size: var(--step--1);
  color: var(--muted);
  font-variation-settings: 'wdth' 100, 'wght' 500;
  letter-spacing: 0.02em;
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: clamp(2.75rem, 8vh, 5rem);
}
.mark b {
  color: var(--signal);
  font-variation-settings: 'wdth' 108, 'wght' 700;
  font-weight: inherit;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.hero {
  display: grid;
  gap: clamp(2rem, 5vw, 3rem);
  grid-template-columns: 1fr;
  grid-template-areas: 'name' 'text' 'figure';
  align-items: start;
}
.hero__name { grid-area: name; }
.hero__text { grid-area: text; }
.hero__figure { grid-area: figure; margin: 0; }

.hero__name {
  font-size: var(--step-4);
  font-variation-settings: 'wdth' var(--wdth-display), 'wght' 880;
  letter-spacing: -0.038em;
  line-height: 0.88;
  max-width: 100%;
}
.hero__name span { display: block; }

/* Wide enough for the nameplate to run as a single line across the whole
   measure — the signage read — with the pitch and the diagram beneath it. */
@media (min-width: 72rem) {
  .hero {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
    grid-template-areas: 'name name' 'text figure';
    column-gap: clamp(2.5rem, 5vw, 4rem);
    align-items: center;
  }
  .hero__name span { display: inline-block; }
}

.hero__role {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 1.1rem;
  font-size: var(--step-1);
  font-variation-settings: 'wdth' 106, 'wght' 620;
  letter-spacing: -0.015em;
  line-height: 1.25;
  margin-bottom: 1.6rem;
}
.hero__years {
  color: var(--signal);
  font-variation-settings: 'wdth' 112, 'wght' 750;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.hero__pitch {
  max-width: 44ch;
  color: var(--muted);
  font-size: var(--step-1);
  line-height: 1.45;
  margin-bottom: clamp(1.9rem, 4vw, 2.6rem);
}
.hero__pitch strong {
  color: var(--ink);
  font-variation-settings: 'wdth' 100, 'wght' 650;
  font-weight: inherit;
}
.hero__pitch:last-child { margin-bottom: 0; }

/* ═══ Controls ══════════════════════════════════════════════════════ */

.actions { display: flex; flex-wrap: wrap; gap: 0.85rem; }
/* On a phone the actions read better as one decisive stack than as a ragged
   two-row wrap. */
@media (max-width: 27rem) {
  .actions { display: grid; grid-template-columns: 1fr; gap: 0.7rem; }
  .actions .btn { justify-content: center; }
}

.btn {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.9rem 1.6rem;
  font-size: var(--step-0);
  font-variation-settings: 'wdth' 102, 'wght' 650;
  letter-spacing: -0.005em;
  text-decoration: none;
  border: 1px solid var(--line-strong);
  color: var(--ink);
  background: transparent;
  transition: color 0.28s var(--ease-out-quart), border-color 0.28s var(--ease-out-quart),
              transform 0.3s var(--ease-out-expo), box-shadow 0.3s var(--ease-out-expo);
}
/* Secondary buttons fill from the left on hover — a route lighting up. */
.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.36s var(--ease-out-expo);
}
.btn:hover { color: var(--on-signal); border-color: var(--signal); }
.btn:hover::before { transform: scaleX(1); }
.btn:active { transform: translateY(1px) scale(0.99); }
.btn svg { flex: none; }

.btn--signal {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--on-signal);
}
.btn--signal::before { background: oklch(0.930 0.180 110); }
.btn--signal:hover {
  color: var(--on-signal);
  border-color: oklch(0.930 0.180 110);
  transform: translateY(-2px);
  box-shadow: 0 12px 34px -14px oklch(0.870 0.190 110 / 0.85);
}
.btn--signal:active { transform: translateY(0) scale(0.99); }

.tag {
  font-size: var(--step--1);
  font-variation-settings: 'wdth' 98, 'wght' 520;
  color: var(--muted);
  border: 1px solid var(--line-soft);
  padding: 0.3rem 0.72rem;
  white-space: nowrap;
  transition: color 0.22s var(--ease-out-quart), border-color 0.22s var(--ease-out-quart);
}
.tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; }

/* ═══ Routing diagram ═══════════════════════════════════════════════ */

.wire { width: 100%; height: auto; display: block; overflow: visible; }
/* Strokes are drawn at device weight, not viewBox weight, so the schematic
   keeps the same line quality whether it is 335px or 460px wide. */
.wire__path, .wire__trail, .wire__node, .wire__hub, .wire__halo { vector-effect: non-scaling-stroke; }
.wire__path { fill: none; stroke: var(--line-strong); stroke-width: 1.5; stroke-dasharray: 100; }
.wire__trail {
  fill: none;
  stroke: var(--signal);
  stroke-width: 2;
  stroke-linecap: round;
  opacity: 0;
}
.wire__node { fill: var(--bg-raised); stroke: var(--line-strong); stroke-width: 1.5; }
.wire__hub {
  fill: var(--bg);
  stroke: var(--signal);
  stroke-width: 2;
  transform: rotate(45deg);
  transform-box: fill-box;
  transform-origin: center;
}
.wire__halo {
  fill: none;
  stroke: var(--signal);
  stroke-width: 1.5;
  opacity: 0;
  transform: rotate(45deg);
  transform-box: fill-box;
  transform-origin: center;
}
/* Label size is in viewBox units, so it shrinks with the diagram. The ladder
   below keeps every port label between roughly 10 and 16 rendered px at every
   width the figure actually takes. */
.wire { --wire-label: 22px; }
@media (min-width: 26rem) { .wire { --wire-label: 17px; } }
@media (min-width: 36rem) { .wire { --wire-label: 13px; } }
@media (min-width: 48rem) { .wire { --wire-label: 10.5px; } }
@media (min-width: 72rem) { .wire { --wire-label: 14px; } }

.wire__label {
  fill: var(--muted);
  font-size: var(--wire-label);
  font-variation-settings: 'wdth' 100, 'wght' 600;
  letter-spacing: 0.1em;
}
.wire__hublabel {
  fill: var(--signal);
  font-size: var(--wire-label);
  font-variation-settings: 'wdth' 104, 'wght' 700;
  letter-spacing: 0.14em;
}
.wire__packet { fill: var(--signal); offset-rotate: auto; opacity: 0; }

/* ═══ Sections ══════════════════════════════════════════════════════ */

.section { padding-block: clamp(3.25rem, 8vw, 5.5rem); }

.section__head {
  display: grid;
  gap: 0.9rem;
  margin-bottom: clamp(2.25rem, 5vw, 3.5rem);
  max-width: var(--measure);
}
.section__title {
  font-size: var(--step-3);
  font-variation-settings: 'wdth' var(--wdth-display), 'wght' 800;
  letter-spacing: -0.032em;
  line-height: 1;
}
.section__lede {
  color: var(--muted);
  max-width: 54ch;
  font-size: clamp(1.05rem, 1rem + 0.28vw, 1.24rem);
  line-height: 1.5;
}

/* Capabilities — a ruled list, deliberately not a card grid. */
.caps { display: grid; gap: 0; }
.cap {
  display: grid;
  gap: 0.45rem 2.5rem;
  padding-block: clamp(1.4rem, 3vw, 2rem);
  border-top: 1px solid var(--line-soft);
  align-items: start;
}
.cap:first-child { border-top: 0; padding-top: 0; }
@media (min-width: 48rem) {
  .cap { grid-template-columns: minmax(0, 16rem) minmax(0, 1fr); }
}
.cap__name {
  font-size: var(--step-1);
  font-variation-settings: 'wdth' 106, 'wght' 660;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
.cap__body { color: var(--muted); max-width: 62ch; }

/* Work — the flagship reads loudest; the rest step down. */
.work { display: grid; gap: clamp(2.5rem, 5vw, 3.75rem); }
.work__item {
  display: grid;
  gap: 0.75rem;
  padding-top: clamp(1.6rem, 3vw, 2.25rem);
  border-top: 1px solid var(--line-soft);
}
.work__item:first-child { border-top: 0; padding-top: 0; }

.work__title {
  font-size: var(--step-2);
  font-variation-settings: 'wdth' 112, 'wght' 740;
  letter-spacing: -0.03em;
  line-height: 1.05;
}
.work__item:first-child .work__title { font-size: var(--step-3); }
.work__kicker {
  color: var(--signal);
  font-size: var(--step--1);
  font-variation-settings: 'wdth' 100, 'wght' 620;
  letter-spacing: 0.04em;
}
.work__body { color: var(--muted); max-width: var(--measure); margin-top: 0.15rem; }
.work__body b {
  color: var(--ink);
  font-variation-settings: 'wdth' 100, 'wght' 620;
  font-weight: inherit;
}

.stack { display: flex; flex-wrap: wrap; gap: 0.55rem; max-width: 62rem; }
.stack .tag {
  border-color: var(--line);
  color: var(--ink);
  font-variation-settings: 'wdth' 100, 'wght' 560;
  padding: 0.42rem 0.85rem;
}
.stack .tag:hover, .tags .tag:hover { border-color: var(--signal); color: var(--signal); }

/* ═══ Contact — the page flips polarity where the action is ═════════ */

.band--signal {
  background-color: var(--signal);
  /* the transport field continues under the panel, in reverse */
  background-image: repeating-linear-gradient(
    to bottom,
    oklch(0.160 0.030 110 / 0.09) 0 1px,
    transparent 1px 96px
  );
  color: var(--on-signal);
}
.contact { padding-block: clamp(4rem, 10vw, 7rem); }
.contact__title {
  font-size: var(--step-3);
  font-variation-settings: 'wdth' var(--wdth-display), 'wght' 830;
  letter-spacing: -0.034em;
  line-height: 0.98;
  margin-bottom: 1.1rem;
  max-width: 17ch;
}
.contact__lede {
  color: var(--on-signal-mute);
  max-width: 48ch;
  font-size: clamp(1.05rem, 1rem + 0.28vw, 1.24rem);
  line-height: 1.5;
  margin-bottom: clamp(2rem, 4vw, 2.6rem);
}
.band--signal a { text-decoration-color: oklch(0.160 0.030 110 / 0.45); }
.band--signal a:hover { color: var(--on-signal); text-decoration-color: var(--on-signal); }
.band--signal :focus-visible { outline-color: var(--on-signal); }

.band--signal .btn {
  border-color: oklch(0.160 0.030 110 / 0.55);
  color: var(--on-signal);
}
.band--signal .btn::before { background: var(--on-signal); }
.band--signal .btn:hover { color: var(--signal); border-color: var(--on-signal); }

.band--signal .btn--signal {
  background: var(--on-signal);
  border-color: var(--on-signal);
  color: var(--signal);
}
.band--signal .btn--signal::before { background: oklch(0.230 0.045 110); }
.band--signal .btn--signal:hover {
  color: var(--signal);
  border-color: var(--on-signal);
  box-shadow: 0 14px 34px -16px oklch(0.160 0.030 110 / 0.9);
}

/* ═══ Footer ════════════════════════════════════════════════════════ */

.foot {
  padding-block: 2.25rem 3rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.75rem;
  align-items: baseline;
  justify-content: space-between;
  color: var(--muted);
  font-size: var(--step--1);
}
.foot__links { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.foot__links a { text-decoration: none; position: relative; }
.foot__links a::after {
  content: '';
  position: absolute;
  left: 0; right: 0; bottom: -0.28em;
  height: 1px;
  background: var(--signal);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 0.32s var(--ease-out-expo);
}
.foot__links a:hover::after { transform: scaleX(1); }

/* ═══ Motion ════════════════════════════════════════════════════════
   Everything below is additive. The default state of every element is
   its final, readable state; motion only ever layers on top, and only
   inside this query. If the JS never runs, or animations never fire,
   the page is complete.
   ══════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: no-preference) {

  @keyframes rise    { from { opacity: 0; transform: translate3d(0, 1.15rem, 0); } to { opacity: 1; transform: none; } }
  @keyframes slot    { from { opacity: 0; clip-path: inset(-0.18em -0.12em 100% -0.12em); transform: translate3d(0, 0.22em, 0); }
                       to   { opacity: 1; clip-path: inset(-0.18em -0.12em -0.18em -0.12em); transform: none; } }
  @keyframes glide   { from { opacity: 0; transform: translate3d(-0.9rem, 0, 0); } to { opacity: 1; transform: none; } }
  @keyframes pop     { from { opacity: 0; transform: translate3d(0, 0.5rem, 0) scale(0.97); } to { opacity: 1; transform: none; } }
  @keyframes drawin  { from { stroke-dashoffset: 100; } to { stroke-dashoffset: 0; } }
  @keyframes fadein  { from { opacity: 0; } to { opacity: 1; } }
  @keyframes sweep   { from { stroke-dashoffset: 70; } to { stroke-dashoffset: -930; } }
  @keyframes run     { from { offset-distance: 0%; } to { offset-distance: 100%; } }
  @keyframes ping    { 0%   { opacity: 0.5; transform: rotate(45deg) scale(1); }
                       55%  { opacity: 0;   transform: rotate(45deg) scale(1.42); }
                       100% { opacity: 0;   transform: rotate(45deg) scale(1.42); } }
  @keyframes ruleout { from { transform: scaleX(0); } to { transform: scaleX(1); } }
  @keyframes railgrow{ from { transform: scaleX(0); } to { transform: scaleX(1); } }

  /* ── Page-load choreography. One rehearsed entrance, ~1.3s total. ── */

  .mark        { animation: fadein 0.7s var(--ease-out-quart) 0.05s both; }
  .hero__name span { animation: slot 1s var(--ease-out-expo) both; }
  .hero__name span:nth-child(1) { animation-delay: 0.12s; }
  .hero__name span:nth-child(2) { animation-delay: 0.22s; }
  .hero__role  { animation: rise 0.85s var(--ease-out-expo) 0.36s both; }
  .hero__pitch { animation: rise 0.85s var(--ease-out-expo) 0.44s both; }
  .hero .actions { animation: rise 0.85s var(--ease-out-expo) 0.52s both; }

  /* ── The diagram builds itself, then starts carrying traffic. ── */

  .wire__path  { animation: drawin 1.5s var(--ease-out-quart) 0.4s both; }
  .wire__path:nth-child(1) { animation-delay: 0.40s; }
  .wire__path:nth-child(2) { animation-delay: 0.48s; }
  .wire__path:nth-child(3) { animation-delay: 0.56s; }
  .wire__path:nth-child(4) { animation-delay: 0.72s; }
  .wire__path:nth-child(5) { animation-delay: 0.80s; }
  .wire__path:nth-child(6) { animation-delay: 0.88s; }

  .wire__node, .wire__label { animation: fadein 0.7s var(--ease-out-quart) 1.1s both; }
  .wire__hub, .wire__hublabel { animation: fadein 0.7s var(--ease-out-quart) 0.95s both; }

  /* The broker pings each time a message reaches it: first packet starts
     at 1.4s and crosses the hub at ~50% of a 4.8s traversal, so hits land
     at 3.8s and every 1.2s after. */
  .wire__halo { animation: ping 1.2s var(--ease-out-quart) 3.8s infinite both; }

  /* A light running the wire ahead of nothing — the packet's own wake,
     normalised with pathLength so all four routes stay in step. */
  .wire__trail {
    stroke-dasharray: 70 1000;
    animation: sweep 4.8s linear calc(var(--d, 0s) + 1.4s) infinite both;
    opacity: 0.5;
  }

  @supports (offset-path: path('M 0 0 L 1 1')) {
    .wire__packet {
      animation: run 4.8s linear calc(var(--d, 0s) + 1.4s) infinite both,
                 fadein 0.7s linear 1.4s both;
      opacity: 1;
    }
  }

  /* ── Scroll. Continuous, off-main-thread where supported. ── */

  @supports (animation-timeline: scroll()) {
    .rail__fill {
      animation: railgrow linear both;
      animation-timeline: scroll(root block);
    }
    /* The diagram recedes faster than the page scrolls: the depth cue is the
       difference in rate, not the movement itself. */
    .hero__figure {
      animation: heroDrift linear both;
      animation-timeline: scroll(root block);
      animation-range: 0 90vh;
    }
    @keyframes heroDrift {
      from { opacity: 1; transform: none; }
      to   { opacity: 0.22; transform: translate3d(0, -3.25rem, 0) scale(0.955); }
    }
  }

  /* ── Reveals. Scoped to .js-reveal, which only exists once the
        observer is wired up; each one fits what it reveals. ── */

  /* The section's opening rule draws itself out from the left. */
  .js-reveal .rule {
    animation: ruleout 0.85s var(--ease-out-expo) both;
    animation-play-state: paused;
  }
  .js-reveal .rule.is-in { animation-play-state: running; }

  .js-reveal [data-reveal] > * {
    animation: glide 0.7s var(--ease-out-quint) both;
    animation-play-state: paused;
  }
  .js-reveal [data-reveal].is-in > * { animation-play-state: running; }

  /* Headings rise into their slot; the lede glides in behind. */
  .js-reveal .section__head > .section__title {
    animation-name: slot;
    animation-duration: 0.9s;
    animation-timing-function: var(--ease-out-expo);
  }
  .js-reveal .section__head.is-in > *:nth-child(2) { animation-delay: 0.1s; }

  .js-reveal .caps.is-in > *:nth-child(2) { animation-delay: 0.07s; }
  .js-reveal .caps.is-in > *:nth-child(3) { animation-delay: 0.14s; }
  .js-reveal .caps.is-in > *:nth-child(4) { animation-delay: 0.21s; }

  /* A work entry arrives as a unit: rule, then kicker, title, body, tags. */
  .js-reveal .work__item > * { animation-name: rise; animation-duration: 0.75s; }
  .js-reveal .work__item.is-in > *:nth-child(2) { animation-delay: 0.06s; }
  .js-reveal .work__item.is-in > *:nth-child(3) { animation-delay: 0.12s; }
  .js-reveal .work__item.is-in > *:nth-child(4) { animation-delay: 0.18s; }

  /* Seventeen tags, 22ms apart — 374ms end to end. */
  .js-reveal .stack > * { animation-name: pop; animation-duration: 0.5s; }
  .js-reveal .stack.is-in > * { animation-delay: calc(var(--i, 0) * 22ms); }
  .js-reveal .stack.is-in > *:nth-child(1)  { --i: 0; }
  .js-reveal .stack.is-in > *:nth-child(2)  { --i: 1; }
  .js-reveal .stack.is-in > *:nth-child(3)  { --i: 2; }
  .js-reveal .stack.is-in > *:nth-child(4)  { --i: 3; }
  .js-reveal .stack.is-in > *:nth-child(5)  { --i: 4; }
  .js-reveal .stack.is-in > *:nth-child(6)  { --i: 5; }
  .js-reveal .stack.is-in > *:nth-child(7)  { --i: 6; }
  .js-reveal .stack.is-in > *:nth-child(8)  { --i: 7; }
  .js-reveal .stack.is-in > *:nth-child(9)  { --i: 8; }
  .js-reveal .stack.is-in > *:nth-child(10) { --i: 9; }
  .js-reveal .stack.is-in > *:nth-child(11) { --i: 10; }
  .js-reveal .stack.is-in > *:nth-child(12) { --i: 11; }
  .js-reveal .stack.is-in > *:nth-child(13) { --i: 12; }
  .js-reveal .stack.is-in > *:nth-child(14) { --i: 13; }
  .js-reveal .stack.is-in > *:nth-child(15) { --i: 14; }
  .js-reveal .stack.is-in > *:nth-child(16) { --i: 15; }
  .js-reveal .stack.is-in > *:nth-child(17) { --i: 16; }
}

/* ═══ Reduced motion ════════════════════════════════════════════════
   Nothing above applies. The diagram stays fully drawn, the packets sit
   at their entry ports, the background field is painted once and never
   animates. Only instant-feel feedback survives.
   ══════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .wire__packet { opacity: 1; }
  .wire__trail { opacity: 0; }
  /* Hover feedback survives as an instant state change, not a sweep. */
  .btn:hover::before { transform: scaleX(1); }
}
