/* ─────────────────────────────────────────────────────────────────────────
   AeroSol — an instrument, not a brochure.

   Dark only. The page ground is the app's own 3-D canvas colour, so a render
   dropped onto the page has no visible edge; the plot panels sit a shade above
   it and are edge-masked instead of framed. The only large saturated areas on
   this page are real solver output.
   ───────────────────────────────────────────────────────────────────────── */

:root {
  --bg:        #0b1222;   /* the app's 3-D canvas background, measured off the renders */
  --bg-2:      #0c1222;
  --surface:   #0f172a;
  --surface-2: #121d33;
  --hairline:  rgba(120, 140, 175, 0.16);
  --hairline-2:rgba(120, 140, 175, 0.32);

  --ink:   #eef2f8;
  --ink-2: #9fb0c8;
  /* #64748b measured 3.94:1 against the page ground - below the 4.5:1 that small
     text needs. This is the same hue, lifted to 4.99:1, and still clearly a step
     down from --ink-2 (8.4:1) so the hierarchy survives. */
  --ink-3: #74859d;

  --blue:    #3b82f6;
  --cyan:    #06b6d4;
  --rose:    #f43f5e;
  --amber:   #f59e0b;
  --emerald: #10b981;

  --sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, Consolas, monospace;

  --gut: clamp(20px, 5vw, 72px);
  --max: 1240px;
  --rhythm: clamp(88px, 12vh, 164px);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

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

/* Nothing on this page was reachable by keyboard in any visible way before. */
:focus-visible {
  outline: 2px solid var(--cyan);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: fixed; z-index: 100; top: 10px; left: 10px;
  transform: translateY(-160%);
  background: var(--ink); color: #0b1222; font-weight: 600; font-size: 14px;
  padding: 10px 18px; border-radius: 8px; text-decoration: none;
  transition: transform .18s ease;
}
.skip:focus { transform: none; }

/* ── type ───────────────────────────────────────────────────────────────── */

h1, h2, h3 { margin: 0; font-weight: 600; letter-spacing: -0.025em; line-height: 1.04; }
h1 { font-size: clamp(40px, 6.6vw, 96px); letter-spacing: -0.04em; }
h2 { font-size: clamp(31px, 4.4vw, 62px); letter-spacing: -0.032em; }
h3 { font-size: clamp(20px, 2vw, 27px); letter-spacing: -0.02em; line-height: 1.2; }
.h2-mid { font-size: clamp(27px, 3.4vw, 46px); margin-top: 18px; }
p { margin: 0; }

.lede {
  font-size: clamp(17px, 1.55vw, 22px);
  line-height: 1.5;
  color: var(--ink-2);
  letter-spacing: -0.01em;
}

.eyebrow {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-3);
  display: flex; align-items: center; gap: 10px;
}
.eyebrow::before { content: ''; width: 22px; height: 1px; background: currentColor; opacity: 0.6; }

.hl { color: var(--ink); }

/* ── shell ──────────────────────────────────────────────────────────────── */

.wrap { max-width: var(--max); margin: 0 auto; padding: 0 var(--gut); }

.nav {
  position: fixed; inset: 0 0 auto 0; z-index: 60;
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  background: rgba(11, 18, 34, 0.62);
  border-bottom: 1px solid transparent;
  transition: background 0.3s, border-color 0.3s;
}
.nav.scrolled { background: rgba(11, 18, 34, 0.9); border-bottom-color: var(--hairline); }

.nav-in {
  max-width: var(--max); margin: 0 auto; padding: 0 var(--gut);
  height: 60px; display: flex; align-items: center; gap: 26px;
}

.brand {
  font-size: 18px; font-weight: 700; letter-spacing: -0.02em;
  text-decoration: none; display: flex; align-items: baseline;
}
.brand span { font-weight: 300; color: var(--ink-2); }

.nav-links { display: flex; gap: 26px; margin-left: auto; }
.nav-links a { font-size: 13.5px; color: var(--ink-2); text-decoration: none; transition: color 0.2s; }
.nav-links a:hover { color: var(--ink); }
.nav-links a.is-here { color: var(--ink); }
.nav-cta { margin-left: 4px; }
@media (max-width: 760px) { .nav-links { display: none; } .nav-cta { margin-left: auto; } }

/* the solver-convergence hairline */
.nav-bar { height: 1px; background: var(--hairline); position: relative; }
.nav-bar i {
  position: absolute; inset: 0 auto 0 0; width: 0;
  background: linear-gradient(90deg, var(--blue), var(--cyan) 55%, var(--emerald));
  box-shadow: 0 0 12px rgba(59, 130, 246, 0.5);
}

.btn {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 10px 20px; border-radius: 999px;
  font-size: 14px; font-weight: 500; letter-spacing: -0.005em;
  text-decoration: none; border: 1px solid transparent;
  transition: transform 0.18s cubic-bezier(.2,.8,.3,1), background 0.2s, border-color 0.2s;
  white-space: nowrap;
}
.btn:hover { transform: translateY(-1px); }
.btn-primary { background: var(--ink); color: #0b1222; font-weight: 600; }
.btn-primary:hover { background: #fff; }
.btn-ghost { border-color: var(--hairline-2); color: var(--ink); }
.btn-ghost:hover { border-color: var(--ink-2); background: rgba(255,255,255,0.04); }
.btn-lg { padding: 14px 28px; font-size: 15px; }

/* ── the pair of buttons the first frame carries ─────────── */

.hero-cta { display: flex; flex-wrap: wrap; gap: 12px; }


/* ── the opening film ───────────────────────────────────────────────────── */

/* Four markets, cross-fading, with a slow push on the live frame. The nav floats
   over it on purpose — the first thing on the page should be the machines. */
.show {
  position: relative;
  height: min(88vh, 900px);
  height: min(88svh, 900px);
  min-height: 480px;
  overflow: hidden;
  isolation: isolate;
}
.show-stage { position: absolute; inset: 0; z-index: 0; }

.show-slide {
  position: absolute; inset: 0; margin: 0;
  opacity: 0; visibility: hidden;
  transition: opacity .9s ease, visibility 0s linear .9s;
}
.show-slide.is-on { opacity: 1; visibility: visible; transition: opacity .9s ease, visibility 0s; }
.show-slide > img {
  width: 100%; height: 100%; object-fit: cover;
  transform: scale(1.015);
  transition: transform 8.5s linear;
}
.show-slide.is-on > img { transform: scale(1.075); }

/* The scrim: type sits bottom-left, so the ground is heaviest there. */
.show-stage::after {
  content: ''; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(120% 90% at 12% 88%, rgba(11,18,34,0.94) 0%, rgba(11,18,34,0.55) 38%, transparent 68%),
    linear-gradient(90deg, rgba(11,18,34,0.86) 0%, rgba(11,18,34,0.52) 32%, rgba(11,18,34,0.10) 60%, transparent 80%),
    linear-gradient(180deg, rgba(11,18,34,0.80) 0%, transparent 24%, rgba(11,18,34,0.62) 66%, var(--bg) 100%);
}

.show-slide figcaption {
  position: absolute; z-index: 2;
  left: 0; right: 0; bottom: clamp(150px, 22vh, 250px);
  max-width: var(--max); margin: 0 auto; padding: 0 var(--gut);
  display: grid; gap: 12px;
}
.show-word {
  font-size: clamp(34px, 5.4vw, 78px);
  font-weight: 600; letter-spacing: -0.035em; line-height: 1;
}
.show-lead { font-size: clamp(16px, 1.5vw, 21px); color: var(--ink); max-width: 34ch; letter-spacing: -0.01em; }
.show-line { font-size: clamp(14px, 1.15vw, 16px); color: var(--ink-2); max-width: 52ch; line-height: 1.55; }

/* Each caption arrives a beat after its frame, which is what makes it read as a cut
   rather than a slideshow. */
.show-slide figcaption > * { opacity: 0; transform: translateY(10px); transition: opacity .7s ease, transform .7s cubic-bezier(.2,.8,.3,1); }
.show-slide.is-on figcaption > * { opacity: 1; transform: none; }
.show-slide.is-on .show-word { transition-delay: .18s; }
.show-slide.is-on .show-lead { transition-delay: .30s; }
.show-slide.is-on .show-line { transition-delay: .42s; }

.show-foot { position: absolute; z-index: 3; left: 0; right: 0; bottom: clamp(28px, 4vh, 52px); }
.show-foot-in { display: flex; align-items: flex-end; justify-content: space-between; gap: 28px; flex-wrap: wrap; }
.show-claim { font-size: 14px; line-height: 1.5; color: var(--ink-2); }
.show-claim b { color: var(--ink); font-weight: 600; }

.show-rail { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

/* WCAG asks for a way to stop anything that moves on its own. Hovering pauses it,
   but a pointer is not a control - this is. */
.show-stop {
  appearance: none; background: none; cursor: pointer;
  border: 1px solid var(--hairline-2); border-radius: 50%;
  width: 26px; height: 26px; padding: 0; margin-right: 6px;
  display: grid; place-items: center; color: var(--ink-2);
  transition: border-color .2s, color .2s;
}
.show-stop:hover { border-color: var(--ink-2); color: var(--ink); }
.show-stop svg { width: 10px; height: 10px; fill: currentColor; }
.show-stop .ico-play { display: none; }
.show-stop[aria-pressed="true"] .ico-play { display: block; }
.show-stop[aria-pressed="true"] .ico-pause { display: none; }
.show-rail button {
  appearance: none; border: 0; padding: 12px 0 0; margin: 0; background: none; cursor: pointer;
  width: clamp(44px, 7vw, 84px);
}
.show-rail i { display: block; height: 2px; background: rgba(120,140,175,0.30); border-radius: 2px; overflow: hidden; }
.show-rail i::after {
  content: ''; display: block; height: 100%; width: 0; background: var(--ink);
}
.show-rail button.on i::after { width: 100%; transition: width var(--dwell, 6s) linear; }
.show-rail button.done i::after { width: 100%; }

/* With the film above it, the hero no longer needs to fill a viewport on its own. */
.show + .hero { min-height: 0; padding: clamp(84px, 11vh, 150px) 0 clamp(72px, 9vh, 120px); }
.show + .hero .hero-hint { display: none; }

.credits {
  margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--hairline);
  font-size: 11.5px; line-height: 1.65; color: var(--ink-3);
}
.credits b { color: var(--ink-2); font-weight: 500; }
.credits a { color: var(--ink-2); }

@media (max-width: 760px) {
  .show { height: min(78svh, 640px); }
  .show-slide figcaption { bottom: clamp(160px, 26vh, 230px); }
  .show-foot-in { flex-direction: column; align-items: flex-start; gap: 16px; }
}

/* ── inner pages ───────────────────────────────────────────────────────── */

.page-head { padding-top: clamp(120px, 16vh, 190px); padding-bottom: clamp(48px, 6vh, 80px); }
.page-title { font-size: clamp(34px, 5.2vw, 74px); margin-top: 18px; }
.page-lede { margin-top: 24px; max-width: 62ch; }

/* ── sections ───────────────────────────────────────────────────────────── */

section { position: relative; }
.band { padding: var(--rhythm) 0; }
.band-tight { padding: calc(var(--rhythm) * 0.6) 0; }

/* The heading sets its own measure. Constraining the whole block to a body-text
   measure made the big headings wrap a second time, which broke every hand-placed
   line break on the page. */
.sec-head { max-width: none; }
.sec-head h2 { margin-top: 18px; }
.sec-head .lede { margin-top: 20px; max-width: 58ch; }
.sec-head .eyebrow { max-width: 58ch; }

.statement { padding: calc(var(--rhythm) * 0.95) 0; }
.statement h2 { max-width: 20ch; font-size: clamp(32px, 5.1vw, 76px); }
.statement .after {
  margin-top: 26px; max-width: 52ch;
  font-size: clamp(16.5px, 1.45vw, 20px); line-height: 1.55; color: var(--ink-2);
}

.rule { height: 1px; background: var(--hairline); margin-bottom: 40px; }

/* ── media ──────────────────────────────────────────────────────────────── */

.render { position: relative; }
.render canvas, .render img { width: 100%; height: auto; display: block; }

/* .bleed marks a render whose background was shifted onto the page ground at build
   time (tools/build-media.py), so it needs no frame and no mask — it simply has no
   edge. The class stays as documentation of that contract. */
.render.bleed > img { background: var(--bg); }

/* ── recordings ─────────────────────────────────────────────────────────── */

/* These are screen captures of the tool, shipped at the pixel size they were taken
   at. max-width is each clip's own native width, so the browser never scales one up
   and softens it; on a narrower screen it scales down, which stays sharp. */
/* The figure is sized to the clip it holds, so the caption's left edge lines up with
   the video's rather than with the page gutter. */
.vidfig { margin: 40px auto 0; }
.vidfig--span   { max-width: 1072px; }
.vidfig figcaption { max-width: 68ch; }

.vid {
  width: 100%; height: auto; display: block; margin: 0 auto 14px;
  border-radius: 10px;
  background: var(--bg-2);
}
.vid.framed { border: 1px solid var(--hairline); }
.vid--span   { max-width: 1072px; }

.shot { border: 1px solid var(--hairline); border-radius: 12px; overflow: hidden; background: var(--bg-2); }

.cap {
  margin-top: 14px;
  font-family: var(--mono); font-size: 11.5px; line-height: 1.6;
  color: var(--ink-3); letter-spacing: 0.01em;
}
.cap b { color: var(--ink-2); font-weight: 500; }

/* ── the film's first frame: AeroSol itself ───────────────────────── */

.show-slide--intro { display: grid; place-items: center; padding: 72px 0 clamp(120px, 17vh, 190px); }
.intro {
  position: relative; z-index: 2;
  width: 100%; max-width: var(--max); padding: 0 var(--gut);
  display: grid; gap: clamp(30px, 4vw, 60px); grid-template-columns: 1fr; align-items: center;
}
@media (min-width: 1000px) { .intro { grid-template-columns: 1fr 1fr; } }

/* The first frame carries four panels as well as the copy, so the headline runs at a
   smaller size than a bare hero would - it still has to leave both buttons on screen. */
.show-slide--intro h1 { font-size: clamp(28px, 3.1vw, 48px); }

.intro-copy h1 { max-width: 20ch; margin-top: 16px; }
.intro-copy .lede { max-width: 48ch; margin-top: 20px; }
.intro-copy .hero-cta { margin-top: 30px; }

/* Four views of the same machine, tiled rather than stacked: the first frame is what the
   tool actually produces, so nothing here is allowed to sit on top of anything else. The
   column split is chosen so the two rows come out close to the same height. */
/* Two columns rather than a 2x2 grid, so the pair on each side can be spaced on its own
   and the two stacks centred against each other. Their totals do not match - the left
   column runs taller - and lining the tops up would leave the shorter column hanging. */
.intro-stack {
  display: flex; align-items: center; gap: 12px;
  width: 100%; max-width: 560px; margin-left: auto;
}
.ish-col { display: flex; flex-direction: column; min-width: 0; }
.ish-col--l { flex: 0.86 1 0; gap: 7px; }
.ish-col--r { flex: 1.14 1 0; gap: 12px; }
.ish {
  margin: 0; border: 1px solid var(--hairline-2); border-radius: 10px; overflow: hidden;
  background: var(--bg-2); box-shadow: 0 20px 48px rgba(0, 0, 0, 0.45);
}
.ish img { display: block; width: 100%; height: auto; }

/* On a phone the four panels sit above the copy - the visitor still meets AeroSol's own
   output first, and the headline and both buttons still fit on the frame. */
@media (max-width: 760px) {
  .show { height: min(96vh, 860px); height: min(96svh, 860px); }
  .show-slide--intro { padding: 58px 0 132px; }
  .show-slide--intro h1 { font-size: clamp(28px, 7.6vw, 40px); }
  .show-slide--intro .lede { font-size: 15px; }
  .intro { gap: 18px; }
  .intro-copy h1 { margin-top: 10px; }
  .intro-copy .lede { margin-top: 12px; }
  .intro-copy .hero-cta { margin-top: 18px; gap: 10px; }
  .hero-cta .btn { padding: 11px 18px; font-size: 13.5px; }

  .intro-stack { max-width: none; margin: 0; order: -1; gap: 8px; align-items: stretch; }
  .ish-col { gap: 8px; }
  .ish-col--l, .ish-col--r { flex: 1 1 0; }
  .ish { box-shadow: none; }
  .ish img { height: 104px; object-fit: cover; object-position: center; }
  .ish--tf img { object-position: center 28%; }
}

.show-claim b { color: var(--ink); font-weight: 600; }

.show-rail { display: flex; gap: 8px; flex: 0 0 auto; }
.show-rail button {
  appearance: none; border: 0; padding: 12px 0 0; margin: 0; background: none; cursor: pointer;
  width: clamp(44px, 7vw, 84px);
}
.show-rail i { display: block; height: 2px; background: rgba(120,140,175,0.30); border-radius: 2px; overflow: hidden; }
.show-rail i::after {
  content: ''; display: block; height: 100%; width: 0; background: var(--ink);
}
.show-rail button.on i::after { width: 100%; transition: width var(--dwell, 6s) linear; }
.show-rail button.done i::after { width: 100%; }

/* With the film above it, the hero no longer needs to fill a viewport on its own. */
.show + .hero { min-height: 0; padding: clamp(84px, 11vh, 150px) 0 clamp(72px, 9vh, 120px); }
.show + .hero .hero-hint { display: none; }

.credits {
  margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--hairline);
  font-size: 11.5px; line-height: 1.65; color: var(--ink-3);
}
.credits b { color: var(--ink-2); font-weight: 500; }
.credits a { color: var(--ink-2); }

@media (max-width: 760px) {
  .show { height: min(78svh, 640px); }
  .show-slide figcaption { bottom: clamp(160px, 26vh, 230px); }
  .show-foot-in { flex-direction: column; align-items: flex-start; gap: 16px; }
}

/* ── the agent flow diagram ─────────────────────────────────── */

.agents-title { margin-top: 18px; }
.agents-lede { margin-top: 22px; max-width: 66ch; }

.flow { margin-top: clamp(40px, 5vw, 62px); overflow-x: auto; }
.flow svg { width: 100%; min-width: 720px; height: auto; display: block; }

.fnode rect {
  fill: var(--surface); stroke: var(--hairline-2); stroke-width: 1;
  transition: stroke .4s, fill .4s, filter .4s;
}
.fnode text { font-family: var(--mono); }
.fnode-t { font-size: 17px; font-weight: 700; fill: var(--ink); text-anchor: middle; letter-spacing: -0.01em; }
.fnode-s { font-size: 11px; fill: var(--ink-3); text-anchor: middle; }
/* A stylesheet outranks a presentation attribute, so `text-anchor="start"` in the markup
   was being overruled and the agent labels were centring on their own left edge. */
.fnode--left .fnode-t, .fnode--left .fnode-s { text-anchor: start; }
.fnode-k { font-size: 10px; letter-spacing: 0.18em; fill: var(--ink-3); }

.fnode--pm  { --c: var(--amber); }
.fnode--a1  { --c: var(--blue); }
.fnode--a2  { --c: var(--cyan); }
.fnode--a3  { --c: var(--rose); }
.fnode--opt { --c: var(--emerald); }
.fnode.hot rect { stroke: var(--c); stroke-width: 1.6; filter: drop-shadow(0 0 12px var(--c)); }
.fnode.hot .fnode-k { fill: var(--c); }

.edge-base { stroke: var(--hairline-2); stroke-width: 1.4; color: var(--hairline-2); marker-end: url(#ah); }
.edge--peer .edge-base { stroke-dasharray: 5 6; marker-start: url(#ah); }
.edge--dot .edge-base { stroke-dasharray: 2 7; marker-end: none; }
.edge--back .edge-base { stroke: rgba(244, 63, 94, 0.42); color: rgba(244, 63, 94, 0.42); }

.edge-flow {
  stroke: var(--ink); stroke-width: 2.6; stroke-linecap: round;
  stroke-dasharray: 15 100; stroke-dashoffset: 115; opacity: 0;
}
.edge.on .edge-flow { opacity: 1; animation: edgeflow 1.5s linear; }
.edge--back.on .edge-flow { stroke: var(--rose); }
@keyframes edgeflow { from { stroke-dashoffset: 115; } to { stroke-dashoffset: 0; } }

.edge-label {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.16em;
  text-transform: uppercase; fill: var(--ink-3); text-anchor: middle;
}

.flow-state {
  margin-top: 18px; min-height: 26px;
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.04em; color: var(--ink-2);
}
.flow-state span { border-left: 2px solid var(--emerald); padding-left: 12px; }

.steps--agents { margin-top: 44px; }
.steps--agents .step { grid-template-columns: 46px 1fr; }
.steps--agents .step .k { letter-spacing: 0.12em; }
.steps--agents .step.hot h3 { color: var(--ink); }
.steps--agents .step { transition: opacity .4s; }

@media (prefers-reduced-motion: reduce) {
  .edge.on .edge-flow { animation: none; stroke-dashoffset: 0; }
}

/* ── step lists ───────────────────────────────────────────── */

.steps { display: grid; gap: 0; }
.step {
  display: grid; grid-template-columns: 30px 1fr; gap: 16px;
  padding: 16px 0; border-top: 1px solid var(--hairline);
  transition: background .4s;
}
.step:last-child { border-bottom: 1px solid var(--hairline); }
.step .k { font-family: var(--mono); font-size: 11px; color: var(--ink-3); padding-top: 3px; transition: color .35s; }
.step h3 { font-size: 17px; letter-spacing: -0.012em; font-weight: 600; }
.step p { margin-top: 5px; font-size: 14.5px; line-height: 1.55; color: var(--ink-2); }

.steps--agents .step { grid-template-columns: 52px 1fr; padding-left: 14px; }
.steps--agents .step .k { letter-spacing: 0.12em; }
.steps--agents .step.hot { background: rgba(120, 140, 175, 0.055); }
.steps--agents .step[data-node="pm"].hot  .k { color: var(--amber); }
.steps--agents .step[data-node="a1"].hot  .k { color: var(--blue); }
.steps--agents .step[data-node="a2"].hot  .k { color: var(--cyan); }
.steps--agents .step[data-node="a3"].hot  .k { color: var(--rose); }
.steps--agents .step[data-node="opt"].hot .k { color: var(--emerald); }

/* ── sticky scroller ────────────────────────────────────────────────────── */

.sticky { display: grid; grid-template-columns: 1fr; }
@media (min-width: 1000px) {
  .sticky { grid-template-columns: minmax(280px, 0.7fr) 1.3fr; gap: clamp(32px, 3.6vw, 60px); }
}

.sticky-media {
  position: sticky; top: 60px; height: calc(100svh - 60px);
  display: grid; place-items: center;
  order: -1;
}
@media (min-width: 1000px) { .sticky-media { order: 0; } }

/* Flex, not grid: an auto grid row is sized by its content, so `max-height: 100%` on a
   tall portrait capture had nothing definite to resolve against and the image ran off
   the bottom of the box. A flex line resolves it against the container's own height. */
.sticky-frame {
  width: 100%;
  height: min(70vh, 640px);
  height: min(70svh, 640px);
  display: flex; align-items: center; justify-content: center;
  gap: 18px;
}
.sticky-frame img {
  max-width: 100%; max-height: 100%; width: auto; height: auto;
  min-width: 0; object-fit: contain;
}
/* A step that names two drawings gets them side by side, each fitted to the same box,
   so neither can push the other off the screen. */
.sticky-frame[data-count="2"] img { max-width: calc(50% - 9px); }

/* Unless the pair is a wide panel and a tall one. Side by side those have to share the
   width and both end up too small to read, so they go diagonally instead: the wide panel
   top-left, the tall one bottom-right, each using a dimension the other is not. */
.sticky-frame[data-diag] { display: block; position: relative; }
.sticky-frame[data-diag] img { position: absolute; max-width: none; max-height: none; }
.sticky-frame[data-diag] img:first-child { top: 0; left: 0; width: 82%; z-index: 1; }
.sticky-frame[data-diag] img:last-child  { bottom: 0; right: 0; width: 53%; z-index: 2;
  box-shadow: 0 22px 54px rgba(0, 0, 0, 0.55); }
/* main.js swaps to per-step media below 1000 px, but it decides that once, at load. If a
   desktop window is dragged narrow afterwards the frame is still here, so undo the
   diagonal rather than leave one panel floating over the text. */
@media (max-width: 999px) {
  .sticky-frame[data-diag] { display: flex; flex-direction: column; position: static; }
  .sticky-frame[data-diag] img { position: static; max-width: 100%; max-height: calc(50% - 7px); }
  .sticky-frame[data-diag] img:first-child,
  .sticky-frame[data-diag] img:last-child { width: auto; box-shadow: none; }
}

/* UI captures have edges of their own, so they get a frame; renders do not. */
.sticky-frame img.framed { border: 1px solid var(--hairline); border-radius: 10px; }

.sticky-steps { display: grid; }
.sticky-step {
  min-height: 60vh;
  min-height: 60svh;
  display: grid; align-content: center;
  padding: 32px 0;
  opacity: 0.26; transition: opacity .5s cubic-bezier(.2,.8,.3,1);
}
.sticky-step.on { opacity: 1; }
.sticky-step h3 { margin-bottom: 13px; }
.sticky-step p { color: var(--ink-2); font-size: 16px; }
.sticky-step .tag {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: .16em; text-transform: uppercase;
  color: var(--ink-3); margin-bottom: 13px;
}

/* Narrow screens do not get the shared frame at all - see main.js. Each step carries its
   own drawings above its own text, which is the only arrangement that reads on a phone. */
@media (max-width: 999px) {
  .sticky-step { min-height: 0; padding: 30px 0; opacity: 1; }
  .step-media { display: grid; gap: 10px; margin-bottom: 20px; grid-template-columns: 1fr; }
  .step-media[data-count="2"] { grid-template-columns: 1fr 1fr; align-items: center; }
  /* The wide performance panel and the tall flowpath drawing are the one pair that has to
     stack here: side by side on a phone leaves the numbers on the left unreadable. */
  .step-media[data-diag] { grid-template-columns: 1fr; }
  .step-media img { width: 100%; height: auto; border-radius: 8px; }
  .step-media img.framed { border: 1px solid var(--hairline); }
}

/* ── annotated map ──────────────────────────────────────────────────────── */

.pair.map-pair { align-items: center; }
@media (min-width: 900px) { .pair.map-pair { grid-template-columns: 1.62fr 1fr; } }

.map-wrap { position: relative; }
.map-wrap img { border-radius: 10px; border: 1px solid var(--hairline); }
.map-hot { position: absolute; inset: 0; }
.map-pin {
  position: absolute; transform: translate(-50%, -50%);
  width: 15px; height: 15px; border-radius: 50%; padding: 0;
  border: 1.5px solid rgba(255,255,255,0.85);
  background: rgba(11,18,34,0.5);
  cursor: pointer; display: grid; place-items: center;
}
.map-pin::after { content: ''; width: 5px; height: 5px; border-radius: 50%; background: #fff; }
.map-pin::before {
  content: ''; position: absolute; inset: -7px; border-radius: 50%;
  border: 1px solid rgba(255,255,255,0.35);
  animation: pulse 2.4s ease-out infinite;
}
@keyframes pulse { 0% { transform: scale(.7); opacity: .9 } 100% { transform: scale(1.5); opacity: 0 } }
.map-pin.on { border-color: var(--amber); }
.map-pin.on::after { background: var(--amber); }

.map-note { min-height: 130px; border-left: 2px solid var(--amber); padding-left: 18px; }
.map-note h3 { font-size: 19px; }
.map-note p { margin-top: 8px; color: var(--ink-2); font-size: 15px; }

/* ── structural triptych ───────────────────────────── */

/* The contour and the two panels beside it are one screen in the tool, so they are shown
   as one object. The flex-grow numbers are each panel's aspect ratio x1000, which is what
   makes three images of three different shapes come out the same height in a row. */
.stwrap {
  display: flex; flex-wrap: wrap; gap: 14px; align-items: flex-start;
  margin-top: clamp(36px, 4.5vw, 56px);
}
.st {
  margin: 0; min-width: 190px;
  border: 1px solid var(--hairline); border-radius: 10px; overflow: hidden;
  background: var(--bg-2);
}
.st img { display: block; width: 100%; height: auto; }
.st--main { flex: 1534 1 0; }
.st--mat  { flex: 861 1 0; }
.st--res  { flex: 737 1 0; }
@media (max-width: 760px) {
  .st--main { flex: 1 1 100%; }
  .st--mat, .st--res { flex: 1 1 44%; }
}

/* ── grids ──────────────────────────────────────────────────────────────── */

.cols { display: grid; gap: clamp(26px, 3.2vw, 52px); }
.cols-3 { grid-template-columns: 1fr; }
@media (min-width: 900px) { .cols-3 { grid-template-columns: repeat(3, 1fr); } }

.card { border-top: 1px solid var(--hairline); padding-top: 20px; }
.card h3 { font-size: 19px; }
.card p { margin-top: 10px; color: var(--ink-2); font-size: 15px; line-height: 1.6; }

.pair { display: grid; gap: clamp(30px, 4vw, 64px); align-items: center; grid-template-columns: 1fr; }
@media (min-width: 900px) { .pair { grid-template-columns: 1fr 1fr; } }

.spec {
  display: grid; grid-template-columns: 110px 1fr; gap: 16px; align-items: baseline;
  padding: 14px 0; border-top: 1px solid var(--hairline);
}
.spec:last-child { border-bottom: 1px solid var(--hairline); }
.spec span { font-family: var(--mono); font-size: 10.5px; letter-spacing: .14em; text-transform: uppercase; color: var(--ink-3); }
.spec b { font-weight: 500; font-size: 15px; color: var(--ink); }

/* ── validation study ───────────────────────────────── */

/* The charts are vector, so they are shown at the full content width and left to scale
   up - at 940 px of design width their own type lands around 14 px here, which is the
   whole reason they are not rasterised. */
.val-title { margin-top: 18px; font-size: clamp(22px, 2.4vw, 32px); }
.val-lede { margin-top: 18px; max-width: 68ch; }

.val-fig {
  margin: clamp(26px, 3vw, 38px) 0 0;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  overflow: hidden;
  background: #0f172a;
}
.val-fig img { display: block; width: 100%; height: auto; }

.val-read { margin-top: clamp(34px, 4vw, 50px); }
.val-note { margin-top: 26px; max-width: 82ch; }

/* ── honesty block ──────────────────────────────────────────────────────── */

.honest {
  border: 1px solid var(--hairline); border-radius: 14px;
  padding: clamp(24px, 3.2vw, 42px);
  background: linear-gradient(180deg, rgba(15,23,42,0.62), rgba(11,18,34,0.35));
}
.honest ul { margin: 20px 0 0; padding: 0; list-style: none; display: grid; gap: 13px; }
/* A grid row made every inline child its own grid item, so a <b> inside a bullet
   pushed the rest of the sentence into a one-word column. Absolute marker instead. */
.honest li {
  position: relative; padding-left: 26px;
  font-size: 15px; color: var(--ink-2); line-height: 1.55;
}
.honest li::before {
  content: ''; position: absolute; left: 3px; top: 9px;
  width: 6px; height: 6px; border-radius: 50%; background: var(--ink-3);
}
.honest li b { color: var(--ink); font-weight: 600; }

/* ── CTA / footer ───────────────────────────────────────────────────────── */

.cta { text-align: center; padding: calc(var(--rhythm) * 1.05) 0; }
.cta h2 { max-width: 22ch; margin: 18px auto 0; }
.cta .lede { max-width: 50ch; margin: 22px auto 0; }
.cta-row { display: flex; justify-content: center; flex-wrap: wrap; gap: 12px; margin-top: 36px; }

footer { border-top: 1px solid var(--hairline); padding: 44px 0 56px; font-size: 13.5px; color: var(--ink-3); }
.foot-in { display: flex; flex-wrap: wrap; gap: 18px 40px; align-items: baseline; justify-content: space-between; }
.foot-brand { color: var(--ink-2); font-weight: 500; margin-bottom: 4px; }
footer a { color: var(--ink-2); text-decoration: none; }
footer a:hover { color: var(--ink); }

/* ── early-access dialog ─────────────────────────────── */

.modal { position: fixed; inset: 0; z-index: 200; display: grid; place-items: center; padding: 20px; }
.modal[hidden] { display: none; }
.modal-scrim { position: absolute; inset: 0; background: rgba(4, 8, 16, 0.78); backdrop-filter: blur(6px); }

.modal-card {
  position: relative; z-index: 1;
  width: min(760px, 100%); max-height: min(92svh, 900px); overflow-y: auto;
  padding: clamp(24px, 3.4vw, 44px);
  background: linear-gradient(180deg, #101a2e, var(--bg));
  border: 1px solid var(--hairline-2); border-radius: 16px;
  box-shadow: 0 40px 120px rgba(0, 0, 0, 0.65);
  animation: modalIn .3s cubic-bezier(.2,.8,.3,1);
}
@keyframes modalIn { from { opacity: 0; transform: translateY(14px) scale(.98); } }

.modal-card h2 { font-size: clamp(24px, 2.6vw, 34px); margin-top: 14px; }
.modal-sub { margin-top: 14px; max-width: 62ch; color: var(--ink-2); font-size: 15px; line-height: 1.55; }

.modal-x {
  position: absolute; top: 14px; right: 14px;
  width: 36px; height: 36px; padding: 0; cursor: pointer;
  background: none; border: 1px solid var(--hairline); border-radius: 50%;
  display: grid; place-items: center; color: var(--ink-2);
  transition: border-color .2s, color .2s;
}
.modal-x:hover { border-color: var(--ink-2); color: var(--ink); }
.modal-x svg { width: 15px; height: 15px; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; fill: none; }

#accessForm { margin-top: 24px; display: grid; gap: 14px; }
.f2, .f3, .f4 { display: grid; gap: 14px; grid-template-columns: 1fr; }
@media (min-width: 640px) {
  .f2 { grid-template-columns: 1fr 1fr; }
  .f3 { grid-template-columns: 1.2fr 1fr 1fr; }
  .f4 { grid-template-columns: repeat(4, 1fr); gap: 12px; }
}

#accessForm label {
  display: grid; gap: 6px; align-content: start;
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.13em;
  text-transform: uppercase; color: var(--ink-2);
}
#accessForm label > span { display: block; line-height: 1.4; }
#accessForm label b { color: var(--cyan); font-weight: 400; }

#accessForm input,
#accessForm select,
#accessForm textarea {
  width: 100%; font: inherit; font-family: var(--sans); font-size: 15px;
  letter-spacing: normal; text-transform: none;
  color: var(--ink); background: rgba(11, 18, 34, 0.6);
  border: 1px solid var(--hairline-2); border-radius: 8px;
  padding: 10px 13px;
  transition: border-color .2s, background .2s;
}
#accessForm textarea { resize: vertical; line-height: 1.5; }
#accessForm input::placeholder, #accessForm textarea::placeholder { color: var(--ink-3); }
#accessForm input:focus, #accessForm select:focus, #accessForm textarea:focus {
  border-color: var(--cyan); background: rgba(11, 18, 34, 0.9); outline: none;
}
#accessForm .bad input, #accessForm .bad select, #accessForm .bad textarea { border-color: var(--rose); }
#accessForm select { appearance: none; cursor: pointer;
  background-image: linear-gradient(45deg, transparent 50%, var(--ink-2) 50%), linear-gradient(135deg, var(--ink-2) 50%, transparent 50%);
  background-position: calc(100% - 19px) calc(50% + 1px), calc(100% - 14px) calc(50% + 1px);
  background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
#accessForm option { background: #101a2e; }

.duty { margin: 2px 0 0; padding: 12px 14px 16px; border: 1px solid var(--hairline); border-radius: 10px; }
.duty legend {
  padding: 0 8px; font-family: var(--mono); font-size: 10.5px;
  letter-spacing: 0.13em; text-transform: uppercase; color: var(--ink-2);
}
.duty legend span { text-transform: none; letter-spacing: 0.02em; color: var(--ink-3); }

.modal-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin-top: 6px; }
.modal-note { font-size: 12.5px; line-height: 1.5; color: var(--ink-3); max-width: 44ch; }
.modal-note.bad { color: var(--rose); }
.modal-note.good { color: var(--emerald); }

@media (prefers-reduced-motion: reduce) { .modal-card { animation: none; } }

/* ── reveal ─────────────────────────────────────────────────────────────── */

.rise { opacity: 0; transform: translateY(14px); transition: opacity .55s cubic-bezier(.2,.8,.3,1), transform .55s cubic-bezier(.2,.8,.3,1); }
.rise.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .rise { opacity: 1; transform: none; transition: none; }
  .ring-sweep, .hero-hint i, .map-pin::before { animation: none; }
  .hero-stage canvas { transition: none; }
}
