/* Nib — landing page.
   Same visual language as the product: warm near-black ground, brass ink,
   editorial serif over engineering sans. The site and the app should read as
   one thing, so the tokens below mirror prototype/assets/base.css. */

/* Fonts are linked from the document head — see index.html for why. */

:root {
  --stage: #0a0a0c; --stage-2: #0e0e11; --panel: #131317; --panel-2: #17171c; --raised: #1d1d23;
  --line: rgba(255,255,255,.075); --line-2: rgba(255,255,255,.13);
  /* Contrast on the #0a0a0c ground, measured rather than eyeballed:
     ink 16.3:1 · ink-2 7.8:1 · ink-3 4.6:1 · ink-4 3.3:1.
     ink-3 was #6e6b64 at 3.7:1 and carried most of the body copy, which is
     under the 4.5:1 floor for normal text. ink-4 was #48463f at 2.1:1, which
     fails at any size — it is now reserved for decoration that nobody has to
     read, and clears 3:1 anyway. */
  --ink: #ece9e3; --ink-2: #a5a29a; --ink-3: #7d7a72; --ink-4: #65625c;
  --brass: #e3a63c; --brass-dim: #8a6521; --brass-wash: rgba(227,166,60,.11);
  --ok: #62c08a; --ok-wash: rgba(98,192,138,.12);
  --risk: #e2685c; --risk-wash: rgba(226,104,92,.12);
  --calm: #7aa7d9;
  --add: rgba(98,192,138,.09); --del: rgba(226,104,92,.08);
  --r: 7px; --r-lg: 11px;
  --sans: 'IBM Plex Sans', ui-sans-serif, system-ui, sans-serif;
  --mono: 'IBM Plex Mono', ui-monospace, monospace;
  --serif: 'Instrument Serif', Georgia, serif;
  --ease: cubic-bezier(.2,.7,.3,1);

  /* diagram palette — house style semantics kept: cyan = data, amber = control */
  --dg-lane: #121218; --dg-lane-alt: #0f0f14; --dg-lane-line: #23232c;
  --dg-card: #1a1a21; --dg-card-line: #2c2c36;
  --dg-edge: #45454f; --dg-flow: #7aa7d9; --dg-ctrl: var(--brass);
  --dg-badge: #1d1d26; --dg-label-bg: var(--stage);
}

* { box-sizing: border-box; margin: 0; padding: 0 }
html { -webkit-font-smoothing: antialiased; scroll-behavior: smooth }
body { background: var(--stage); color: var(--ink); font: 400 16px/1.62 var(--sans); letter-spacing: -.005em }

.grain::before {
  content: ''; position: fixed; inset: 0; z-index: 9999; pointer-events: none;
  opacity: .17; mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.5'/%3E%3C/svg%3E");
}
.spot::after {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 720px; z-index: -1; pointer-events: none;
  background: radial-gradient(65% 100% at 50% -18%, rgba(227,166,60,.08), transparent 70%);
}

.wrap { max-width: 1180px; margin: 0 auto; padding: 0 26px }
.wrap.narrow { max-width: 780px }
.eyebrow { font: 500 11.5px/1.2 var(--sans); letter-spacing: .12em; text-transform: uppercase; color: var(--ink-3) }
.display { font-family: var(--serif); font-weight: 400; letter-spacing: -.02em }
.display em { font-style: italic; color: var(--brass) }
.dim { color: var(--ink-3) }
.mono, code { font-family: var(--mono); font-size: .9em }
code { background: rgba(255,255,255,.05); border: 1px solid var(--line); border-radius: 4px; padding: 1px 5px; color: #e8c98d }

.btn {
  display: inline-flex; align-items: center; gap: 7px; height: 34px; padding: 0 14px;
  border: 1px solid var(--line-2); border-radius: var(--r); background: var(--raised);
  color: var(--ink); font: 450 14.5px var(--sans); text-decoration: none; white-space: nowrap;
  transition: all .15s var(--ease);
}
.btn:hover { background: #26262d; border-color: rgba(255,255,255,.22) }
.btn.primary { background: var(--brass); border-color: var(--brass); color: #22180a; font-weight: 550 }
.btn.primary:hover { background: #f0b34a; border-color: #f0b34a }
.btn.lg { height: 46px; padding: 0 22px; font-size: 15.5px }
.btn.sm { height: 32px; padding: 0 12px; font-size: 13.5px }

.chip {
  display: inline-flex; align-items: center; gap: 5px; height: 20px; padding: 0 8px; border-radius: 100px;
  font: 500 11.5px/1 var(--sans); border: 1px solid var(--line-2); color: var(--ink-2);
  background: rgba(255,255,255,.02); white-space: nowrap;
}
.chip.ok { color: var(--ok); border-color: rgba(98,192,138,.3); background: var(--ok-wash) }
.chip.risk { color: var(--risk); border-color: rgba(226,104,92,.3); background: var(--risk-wash) }

/* ── nav ─────────────────────────────────────────────── */
.nav {
  position: sticky; top: 0; z-index: 60; display: flex; align-items: center; gap: 16px;
  max-width: 1180px; margin: 0 auto; padding: 16px 26px;
  background: rgba(10,10,12,.72); backdrop-filter: blur(10px);
}
.brand { display: flex; align-items: center; gap: 8px; text-decoration: none; color: inherit }
.brand .mark { width: 7px; height: 7px; border-radius: 50%; background: var(--brass); box-shadow: 0 0 14px 2px rgba(227,166,60,.55) }
.brand b { font: 400 19px var(--serif); letter-spacing: -.01em }
.nav-links { margin-left: auto; display: flex; align-items: center; gap: 20px }
.nav-links a { color: var(--ink-3); text-decoration: none; font-size: 14px; transition: color .15s }
.nav-links a:hover { color: var(--ink) }
.nav-links a.btn { color: var(--ink) }
/* Section anchors go; Sign in stays. Hiding it left a returning user with no
   way in but the sign-up button. */
@media (max-width: 720px) {
  .nav-links { gap: 14px }
  .nav-links a:not(.btn):not(.nav-keep) { display: none }
}

/* ── hero ────────────────────────────────────────────── */
.hero { max-width: 1180px; margin: 0 auto; padding: 76px 26px 60px }
.hero h1 { font: 400 clamp(40px, 6.6vw, 74px)/1.02 var(--serif); letter-spacing: -.025em; margin: 16px 0 0 }
.hero h1 em { font-style: italic; color: var(--brass) }
.lede { margin-top: 22px; max-width: 60ch; font-size: 18px; line-height: 1.62; color: var(--ink-2) }
.hl { color: var(--ink); border-bottom: 1px solid var(--brass-dim) }
.cta { display: flex; gap: 10px; margin-top: 30px; flex-wrap: wrap }
.proof { display: flex; gap: 26px; margin-top: 44px; padding-top: 22px; border-top: 1px solid var(--line); flex-wrap: wrap }
.proof span { font-size: 13.5px; color: var(--ink-3) }
.proof b { font: 400 23px var(--serif); color: var(--brass); margin-right: 7px }

/* ── bands ───────────────────────────────────────────── */
.band { padding: 74px 0; border-top: 1px solid var(--line) }
.band.alt { background: var(--stage-2) }
.band h2.display { font-size: clamp(27px, 3.6vw, 40px); margin: 12px 0 0; letter-spacing: -.02em }
.sub { margin-top: 14px; max-width: 68ch; color: var(--ink-2); font-size: 16px; line-height: 1.65 }
.sub.small { font-size: 14px; margin-top: 14px }

.g3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 26px; margin-top: 34px }
.g2 { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-top: 30px }
@media (max-width: 900px) { .g3, .g2 { grid-template-columns: 1fr } }

.problem h3 { font-size: 16.5px; font-weight: 500; margin-bottom: 8px }
.problem p { color: var(--ink-2); font-size: 15px; line-height: 1.68 }
.turn {
  margin-top: 40px; padding: 20px 24px; border-left: 2px solid var(--brass);
  background: linear-gradient(90deg, var(--brass-wash), transparent 70%);
  font-size: 17px; line-height: 1.7; color: var(--ink-2); max-width: 74ch;
}
.turn b { color: var(--ink) }

/* ── diagram ─────────────────────────────────────────── */
.diagram { width: 100%; height: auto; display: block; margin-top: 30px }
.caption { color: var(--ink-3); font: 400 12.5px var(--mono); margin-top: 12px }

.lane-band { fill: var(--dg-lane); stroke: var(--dg-lane-line); stroke-width: 1 }
.lane-band.alt { fill: var(--dg-lane-alt) }
.lane-band.you { fill: rgba(227,166,60,.05); stroke: rgba(227,166,60,.28) }
.lane-label { fill: var(--ink); font-family: var(--mono); font-size: 12px; font-weight: 600; letter-spacing: 1.5px }
.lane-label.you { fill: var(--brass) }
.lane-owner { fill: var(--ink-2); font-family: var(--mono); font-size: 10.5px }
.lane-tag { fill: var(--ink-4); font-family: var(--mono); font-size: 10px }
.lane-tag.ctrl { fill: var(--brass); opacity: .8 }

.edge { fill: none; stroke: var(--dg-edge); stroke-width: 1.6 }
.edge.flow { stroke: var(--dg-flow); stroke-width: 1.6; stroke-dasharray: 3 9; opacity: .9; animation: dgflow 1.1s linear infinite }
.edge.ctrl { stroke: var(--dg-ctrl); stroke-dasharray: 5 4; opacity: .7 }
.edge.ctrl.flow { stroke: var(--dg-ctrl); stroke-dasharray: 3 9; opacity: .9 }
@keyframes dgflow { to { stroke-dashoffset: -24 } }
.mk-a { fill: var(--dg-edge) } .mk-c { fill: var(--dg-ctrl) }
.divider { stroke: rgba(227,166,60,.3); stroke-width: 1; stroke-dasharray: 4 6 }
.divider-label { fill: var(--brass); font-family: var(--mono); font-size: 10px; opacity: .85 }

.bg { fill: var(--dg-label-bg); opacity: .93 }
.elabel { fill: var(--ink-2); font-family: var(--mono); font-size: 11px }
.badge circle { fill: var(--dg-badge); stroke: var(--dg-flow); stroke-width: 1.4 }
.badge.ctrl circle { stroke: var(--dg-ctrl) }
.badge text { fill: var(--ink); font-family: var(--mono); font-size: 10px; font-weight: 600; text-anchor: middle; dominant-baseline: central }

.node .card { fill: var(--dg-card); stroke: var(--dg-card-line); stroke-width: 1; transition: stroke .15s }
.node:hover .card { stroke: var(--dg-flow) }
.node .card.you { fill: rgba(227,166,60,.07); stroke: rgba(227,166,60,.4) }
.tick { fill: var(--dg-flow) } .tick.ctrl { fill: var(--dg-ctrl) }
.n-kind { fill: var(--ink-4); font-family: var(--mono); font-size: 9px; letter-spacing: 1.2px }
.n-title { fill: var(--ink); font-family: var(--sans); font-size: 14px; font-weight: 600 }
.n-sub { fill: var(--ink-2); font-family: var(--mono); font-size: 10.5px }
.token { fill: var(--dg-flow) } .token.trail { opacity: .45 } .token.trail2 { opacity: .2 }

@media (prefers-reduced-motion: reduce) { .edge.flow { animation: none; opacity: .5 } .token { display: none } }

/* ── review cards ────────────────────────────────────── */
.gh { border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel); overflow: hidden }
.gh.short { display: flex; flex-direction: column }
.gh.held { opacity: .82; border-style: dashed }
.gh-h { display: flex; align-items: center; gap: 9px; padding: 10px 13px; border-bottom: 1px solid var(--line); background: var(--panel-2); font-size: 12.5px }
.avatar { width: 21px; height: 21px; border-radius: 50%; background: var(--brass); color: #0a0a0c; display: grid; place-items: center; font: 600 9px var(--sans) }
.gh-file { padding: 8px 13px; font: 400 11.5px var(--mono); color: var(--ink-2); border-bottom: 1px solid var(--line) }
.gh-diff, .gh-sug .add { font: 400 12px/1.7 var(--mono) }
.gh-diff div, .gh-sug .add { padding: 1px 13px; white-space: pre-wrap }
.gh-diff .add, .gh-sug .add { background: var(--add); color: #b9e3cb }
.gh-diff .del { background: var(--del); color: #e6ada6 }
.gh-b { padding: 13px; font-size: 14px; line-height: 1.55 }
.gh-b.big { font-size: 17px; padding: 20px 16px }
.gh-sug { margin: 0 13px 13px; border: 1px solid var(--line); border-radius: 5px; overflow: hidden }
.gh-sug-h { display: flex; gap: 8px; align-items: center; font: 500 10.5px var(--sans); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-3); padding: 6px 10px; background: var(--stage-2); border-bottom: 1px solid var(--line) }
.gh-sug-h .ok { color: var(--ok); letter-spacing: .04em; text-transform: none; font-size: 11px }
.gh-held { margin: 0 13px 12px; font: 400 11.5px var(--mono); color: var(--ink-3); border-left: 2px solid var(--line-2); padding-left: 9px }
.gh-note { padding: 0 13px 15px; font-size: 13.5px; color: var(--ink-2); line-height: 1.62; margin-top: auto }

/* ── control ─────────────────────────────────────────── */
.control { gap: 22px }
.ctl { padding: 20px 22px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel) }
.ctl-n { font: 400 13px var(--mono); color: var(--brass); margin-bottom: 10px }
.ctl h3 { font-size: 16.5px; font-weight: 500; margin-bottom: 8px }
.ctl p { color: var(--ink-2); font-size: 15px; line-height: 1.68 }
.disclosure-note { display: flex; gap: 13px; margin-top: 26px; padding: 18px 22px; border: 1px solid rgba(227,166,60,.28); border-radius: var(--r-lg); background: var(--brass-wash) }
.disclosure-note span { color: var(--brass); font-size: 15px }
.disclosure-note p { font-size: 15px; line-height: 1.68; color: var(--ink-2) }
.disclosure-note b { color: var(--ink) }

/* ── cost ────────────────────────────────────────────── */
.cost-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; margin-top: 32px }
@media (max-width: 900px) { .cost-grid { grid-template-columns: 1fr } }
.stat { padding: 20px 22px; border: 1px solid var(--line); border-radius: var(--r-lg); background: var(--panel) }
.stat .n { font: 400 42px var(--serif); line-height: 1; letter-spacing: -.02em }
.stat .n small { font-size: 20px; color: var(--ink-3) }
.stat .l { margin-top: 9px; font-size: 14.5px; color: var(--ink-2) }
.stat .d { margin-top: 7px; font-size: 12.5px; color: var(--ink-3); line-height: 1.6 }

.table { margin-top: 26px; border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; background: var(--panel) }
table { border-collapse: collapse; width: 100% }
th { text-align: left; font: 500 11.5px var(--sans); letter-spacing: .11em; text-transform: uppercase; color: var(--ink-3); padding: 11px 16px; background: var(--panel-2); border-bottom: 1px solid var(--line) }
td { padding: 14px 16px; border-bottom: 1px solid var(--line); font-size: 14.5px; color: var(--ink-2) }
td b { color: var(--ink); font-weight: 500 }
tr:last-child td { border-bottom: 0 }
tr.free td b { color: var(--ok) }
.table-note { padding: 15px 16px; font-size: 14px; color: var(--ink-2); line-height: 1.68; border-top: 1px solid var(--line); background: var(--stage-2) }

/* ── learning ────────────────────────────────────────── */
.delta { margin-top: 26px; border: 1px solid var(--line); border-radius: var(--r-lg); overflow: hidden; font: 400 12.5px/1.75 var(--mono) }
.delta-h { padding: 9px 14px; background: var(--panel-2); border-bottom: 1px solid var(--line); color: var(--ink-2); font-size: 11.5px }
.delta div:not(.delta-h) { padding: 1px 14px }
.delta .p { background: var(--add); color: #b9e3cb }
.delta .m { background: var(--del); color: #e6ada6 }
.delta .c { color: var(--ink-3); background: var(--panel) }

/* ── footer ──────────────────────────────────────────── */
.foot { padding: 84px 0 60px; border-top: 1px solid var(--line); text-align: center }
.foot h2 { font-size: clamp(26px, 3.4vw, 38px) }
.foot .sub { margin: 16px auto 0 }
.foot .cta { justify-content: center; margin-top: 28px }
.foot-meta { margin-top: 54px; padding-top: 22px; border-top: 1px solid var(--line); display: flex; gap: 14px; justify-content: center; flex-wrap: wrap; font-size: 13.5px; color: var(--ink-3) }
.foot-meta a { color: var(--ink-3); text-decoration: none }
.foot-meta a:hover { color: var(--ink) }

/* colophon — quieter than the rest, it's an aside not a pitch */
.colophon h2.display { font-size: clamp(23px, 2.9vw, 32px) }
.colophon .sub { font-size: 14px; color: var(--ink-3) }
.colophon .sub em { color: var(--ink-2); font-style: italic }
.colophon .sub + .sub { margin-top: 12px }

/* the pile */
.pile-n { font: 400 26px var(--serif); color: var(--brass); line-height: 1; margin-bottom: 10px }
.pile h3 { font-size: 16.5px; font-weight: 500; margin-bottom: 8px }
.pile p { color: var(--ink-2); font-size: 15px; line-height: 1.68 }

/* comparison — our column is the one that should read as the answer */
.compare td { vertical-align: top }
.compare .row-k { color: var(--ink-2); font-size: 13.5px; white-space: nowrap; width: 150px }
.compare th.us, .compare td.us { background: var(--brass-wash); border-left: 1px solid rgba(227,166,60,.22); border-right: 1px solid rgba(227,166,60,.22) }
.compare th.us { color: var(--brass) }
.compare td.us { color: var(--ink) }
.compare tbody tr:last-child td.us { border-bottom: 1px solid rgba(227,166,60,.22) }
@media (max-width: 720px) { .compare .row-k { width: auto; white-space: normal } }

/* price */
.price-block h2.display { font-size: clamp(44px, 7vw, 76px); margin-top: 8px }
.price-block .sub b { color: var(--brass) }


/* ── wide content ─────────────────────────────────────────
   The flow diagram is authored at 1200px. Letting it scale to a 360px screen
   renders its 14px labels at about 4px — technically visible, actually
   unreadable. It keeps its size and scrolls instead, which is also why the
   tables no longer shrink their own font on small screens. */
.scroll-x { overflow-x: auto; -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain }
.scroll-x > table { min-width: 640px }

/* ── the flow, twice ──────────────────────────────────────
   Wide: the swim-lane SVG, which needs width to mean anything.
   Narrow: a vertical stepper, because that is the direction a thumb
   already moves and because lanes squeezed to 360px stop being lanes.
   Exactly one is in the layout at a time, so nothing is read out twice. */
.steps { display: none }

@media (max-width: 860px) {
  .scroll-x > .diagram { display: none }
  .steps { display: block; list-style: none; margin: 26px 0 0; padding: 0; position: relative }

  /* The spine runs behind the dots and stops at the last one rather than
     trailing off the end. */
  .steps::before {
    content: ''; position: absolute; left: 7px; top: 10px; bottom: 26px; width: 2px;
    background: linear-gradient(180deg, var(--dg-flow), var(--dg-flow) 62%, var(--dg-ctrl));
    opacity: .3; border-radius: 2px;
  }

  .step { position: relative; padding: 0 0 22px 34px }
  .step:last-child { padding-bottom: 0 }
  .step-dot {
    position: absolute; left: 0; top: 5px; width: 16px; height: 16px; border-radius: 50%;
    background: var(--stage); border: 2px solid var(--dg-flow);
    box-shadow: 0 0 0 4px rgba(10,10,12,.9);
  }
  .step.ctrl .step-dot { border-color: var(--dg-ctrl) }

  /* The off-ramp is a branch, not a stage: hollow dot, dashed rule, set in. */
  .step.branch { margin-left: 18px; padding-left: 30px }
  .step.branch .step-dot { width: 11px; height: 11px; top: 8px; border-style: dashed; opacity: .8 }
  .step.branch .step-b { border-left: 1px dashed var(--line-2); padding-left: 13px }

  .step-kind {
    display: inline-block; font: 500 10.5px var(--mono); letter-spacing: .12em;
    text-transform: uppercase; color: var(--dg-flow); margin-bottom: 5px;
  }
  .step.ctrl .step-kind { color: var(--dg-ctrl) }
  .step.branch .step-kind { color: var(--ink-3) }
  .step h3 { font-size: 16.5px; font-weight: 500; letter-spacing: -.01em; margin-bottom: 5px }
  .step p { font-size: 14.5px; line-height: 1.6; color: var(--ink-2); max-width: 46ch }

  /* Each step arrives as it is scrolled to, which is the organic bit: the flow
     assembles at the pace you read it rather than all at once. The class is
     added by a tiny observer in the page; without JS everything is simply
     already visible. */
  .js .step { opacity: 0; transform: translateY(10px); transition: opacity .5s var(--ease), transform .5s var(--ease) }
  .js .step.in { opacity: 1; transform: none }
}

@media (max-width: 860px) and (prefers-reduced-motion: reduce) {
  .js .step { opacity: 1; transform: none; transition: none }
}

/* ── small screens ────────────────────────────────────────
   One breakpoint, doing real work: the page was laid out for a desk and read on
   a phone. */
@media (max-width: 720px) {
  .wrap { padding: 0 18px }
  .hero { padding: 44px 18px 44px }
  .band { padding: 52px 0 }
  .lede { font-size: 16.5px }
  .turn { padding: 16px 18px; font-size: 15.5px }

  /* Stacked, so each figure keeps its number and its label on one line. */
  .proof { flex-direction: column; gap: 12px; margin-top: 32px }

  /* Full-width targets: a 46px button in a column beats two cramped side by side. */
  .cta { flex-direction: column; align-items: stretch }
  .cta .btn { justify-content: center; width: 100% }
}

/* Anything tap-driven gets a real target rather than a desktop-sized one. */
@media (hover: none) {
  .btn.sm { height: 36px; padding: 0 14px }
  .nav-links a { padding: 4px 0 }
}


/* ══ MOTION ═══════════════════════════════════════════════════════════
   House rules for everything below.

   1. Motion explains, it never decorates. Things move the way the eye
      would already travel: down the page, along the flow.
   2. Nothing animates that carries meaning on arrival. Text is readable
      the instant it paints; only its *entrance* is animated, and only by
      a few pixels.
   3. No layout shift, ever. Transforms and opacity only, so nothing
      reflows and nothing janks.
   4. One easing curve for the whole page, so it feels like one hand.
   5. All of it is off under prefers-reduced-motion, and none of it is
      required — without JS every element is simply already in place.
   ═══════════════════════════════════════════════════════════════════ */

:root { --ease-out: cubic-bezier(.22,.68,.28,1); --rise: 12px }

/* ── on arrival ───────────────────────────────────────
   The hero settles rather than appears. Runs on load, not on scroll,
   because it is already in view. */
.js .hero > * { animation: rise .62s var(--ease-out) both }
.js .hero .eyebrow { animation-delay: .04s }
.js .hero h1       { animation-delay: .10s }
.js .hero .lede    { animation-delay: .20s }
.js .hero .cta     { animation-delay: .30s }
.js .hero .proof   { animation-delay: .38s }

@keyframes rise {
  from { opacity: 0; transform: translateY(var(--rise)) }
  to   { opacity: 1; transform: none }
}

/* ── on scroll ────────────────────────────────────────
   One class, applied by the observer. Delay is set per element in JS so
   a group cascades in the order you read it. */
.js [data-r] { opacity: 0; transform: translateY(var(--rise)); will-change: opacity, transform }
.js [data-r].in {
  opacity: 1; transform: none;
  transition: opacity .55s var(--ease-out), transform .55s var(--ease-out);
}
/* Released once it has played, so nothing holds a compositor layer forever. */
.js [data-r].done { will-change: auto }

/* ── the diagram assembling ───────────────────────────
   The one deliberately theatrical moment on the page, and only the first
   time it is seen. Lanes settle, edges draw themselves along their own
   length, nodes rise, badges land, and only then does the flow start
   moving — so you watch it get built before you watch it run. */
.js .diagram .lane-band,
.js .diagram .lane-label,
.js .diagram .lane-owner,
.js .diagram .lane-tag { opacity: 0; transition: opacity .5s var(--ease-out) }

.js .diagram .edge {
  /* JS measures each path and sets --len. The fallback matters: until it does,
     an undefined var would compute to 0 and paint every edge in full, which
     then snaps back to hidden the moment the real length arrives. */
  stroke-dashoffset: var(--len, 1400);
  stroke-dasharray: var(--len, 1400);
  animation: none;
}
.js .diagram .node,
.js .diagram .badge,
.js .diagram .bg,
.js .diagram .elabel,
.js .diagram .divider,
.js .diagram .divider-label { opacity: 0 }
.js .diagram .token { opacity: 0 }

.js .diagram.drawn .lane-band,
.js .diagram.drawn .lane-label,
.js .diagram.drawn .lane-owner { opacity: 1 }
.js .diagram.drawn .lane-tag { opacity: .9 }

.js .diagram.drawn .edge {
  stroke-dashoffset: 0;
  transition: stroke-dashoffset .9s var(--ease-out);
}
/* Once drawn, the marching dashes take over from the draw-in. */
.js .diagram.ran .edge.flow {
  stroke-dasharray: 3 9; stroke-dashoffset: 0;
  animation: dgflow 1.1s linear infinite;
  transition: none;
}
.js .diagram.ran .edge.ctrl { stroke-dasharray: 5 4; transition: none }
.js .diagram.ran .edge.ctrl.flow { stroke-dasharray: 3 9 }

.js .diagram.drawn .node,
.js .diagram.drawn .bg,
.js .diagram.drawn .elabel,
.js .diagram.drawn .divider,
.js .diagram.drawn .divider-label {
  opacity: 1; transition: opacity .5s var(--ease-out);
}
.js .diagram.drawn .badge {
  opacity: 1;
  animation: land .42s var(--ease-out) both;
}
.js .diagram.ran .token { opacity: 1; transition: opacity .4s linear }
.js .diagram.ran .token.trail { opacity: .45 }
.js .diagram.ran .token.trail2 { opacity: .2 }

/* A badge lands rather than fades — it is a number arriving at a place. */
@keyframes land {
  from { opacity: 0; transform: scale(.72) }
  60%  { transform: scale(1.06) }
  to   { opacity: 1; transform: none }
}
.js .diagram .badge { transform-box: fill-box; transform-origin: center }

/* ── the nav, once you have left the top ──────────────
   A hairline and a firmer blur, so the page reads as scrolled without
   anything jumping. */
.nav { border-bottom: 1px solid transparent; transition: border-color .25s var(--ease-out), background .25s var(--ease-out) }
.nav.scrolled { border-bottom-color: var(--line); background: rgba(10,10,12,.86) }

/* ── touch ────────────────────────────────────────────
   Small, physical, on the things people click. */
.btn { transition: background .15s var(--ease-out), border-color .15s var(--ease-out), transform .12s var(--ease-out) }
.btn:active { transform: translateY(1px) }
.stat, .gh { transition: transform .25s var(--ease-out), border-color .25s var(--ease-out) }
.stat:hover, .gh:hover { transform: translateY(-2px); border-color: var(--line-2) }
.node { transition: transform .18s var(--ease-out); transform-box: fill-box; transform-origin: center }
.node:hover { transform: translateY(-1.5px) }

/* ── the override that matters ────────────────────────
   Everything above is entrance and emphasis, so removing it costs
   nothing but the theatre. */
@media (prefers-reduced-motion: reduce) {
  .js .hero > *,
  .js .diagram .badge { animation: none }
  .js [data-r],
  .js .diagram .lane-band, .js .diagram .lane-label, .js .diagram .lane-owner,
  .js .diagram .lane-tag, .js .diagram .node, .js .diagram .badge,
  .js .diagram .bg, .js .diagram .elabel, .js .diagram .divider,
  .js .diagram .divider-label {
    opacity: 1; transform: none; transition: none;
  }
  .js .diagram .edge { stroke-dashoffset: 0; stroke-dasharray: none; transition: none }
  .js .diagram .token { display: none }
  .btn:active, .stat:hover, .gh:hover, .node:hover { transform: none }
}
