/* Marionette project page.

   The palette and type are lifted directly from the demo film's Overview and
   Pipeline scenes (demo_video/html_src/*.jsx) so the page and the video read as
   one piece of design. The four stage colours are load-bearing, not decoration:
   the same colour marks the same stage everywhere.

     ActionGPT   decision     periwinkle  #8A93FF
     PoseGPT     state        mint        #59E6BE
     Bridge      geometry     gold        #E7C36A
     Observation appearance   coral       #F26D5B
*/

:root {
  --bg: #0a0a0d;
  --bg-2: #101015;
  --surface: #14141a;
  --line: rgba(236, 231, 219, 0.10);
  --line-2: rgba(236, 231, 219, 0.20);
  --ink: #ece7db;
  --mute: #9a978d;
  --faint: #6a6862;

  --neural: #8a93ff;
  --harness: #59e6be;
  --gold: #e7c36a;
  --red: #f26d5b;

  --disp: 'Space Grotesk', 'Segoe UI', -apple-system, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;
  --sans: 'Instrument Sans', 'Segoe UI', -apple-system, sans-serif;
  --col: 1160px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0; background: var(--bg); color: var(--ink);
  font-family: var(--sans); font-size: 16.5px; line-height: 1.66;
  -webkit-font-smoothing: antialiased;
}
a { color: var(--harness); text-decoration: none; }
a:hover { text-decoration: underline; }

.wrap { max-width: var(--col); margin: 0 auto; padding: 0 24px; }
.narrow { max-width: 820px; margin-left: auto; margin-right: auto; }

.kicker {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.26em;
  text-transform: uppercase; color: var(--neural); margin-bottom: 12px;
}
h2 {
  font-family: var(--disp); font-size: clamp(24px, 3.2vw, 34px);
  font-weight: 600; color: var(--ink); margin: 0 0 10px; letter-spacing: -0.01em;
  line-height: 1.18;
}
h3 { font-family: var(--disp); font-size: 19px; font-weight: 600; margin: 38px 0 10px; }
.lede { color: var(--mute); margin: 0 0 26px; max-width: 760px; }
p { margin: 0 0 16px; }

/* ---------- top bar ---------- */
.topbar {
  position: sticky; top: 0; z-index: 60;
  background: rgba(10, 10, 13, 0.86); backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.topbar .wrap { display: flex; align-items: center; justify-content: space-between; height: 54px; }
.brand {
  font-family: var(--mono); font-size: 12px; letter-spacing: 0.22em;
  text-transform: uppercase; color: var(--mute);
}
.brand a { color: inherit; }
.topnav { display: flex; gap: 22px; font-size: 14px; }
.topnav a { color: var(--mute); }
.topnav a:hover { color: var(--ink); text-decoration: none; }
@media (max-width: 760px) { .topnav { display: none; } }

/* ---------- hero ---------- */
.hero { padding: 74px 0 26px; text-align: center; }
h1 {
  font-family: var(--disp); font-size: clamp(32px, 5.4vw, 58px); line-height: 1.08;
  margin: 0; font-weight: 600; letter-spacing: -0.02em; color: var(--ink);
}
h1 em { font-style: normal; color: var(--harness); }
.subtitle {
  font-size: clamp(16px, 2vw, 20px); color: var(--mute);
  max-width: 760px; margin: 18px auto 0; line-height: 1.55;
}
.authors { margin: 28px auto 4px; font-size: 16px; }
.affil { color: var(--faint); font-size: 14px; }
.pending {
  display: inline-block; font-family: var(--mono); font-size: 12px; color: var(--faint);
  border: 1px dashed var(--line-2); border-radius: 5px; padding: 2px 9px;
}

.buttons { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; margin: 26px 0 4px; }
.btn {
  display: inline-flex; align-items: center; gap: 8px; padding: 9px 19px;
  border-radius: 999px; background: var(--surface); border: 1px solid var(--line-2);
  color: var(--ink); font-size: 14.5px; font-weight: 500; font-family: var(--sans);
}
.btn:hover { background: #1c1c24; text-decoration: none; }
.btn.disabled { opacity: 0.4; pointer-events: none; }
.btn .ico { font-size: 13px; opacity: 0.8; }

/* ---------- hero film band ----------
   The band is not a rectangle dropped onto the page: the scrim fades its top edge into the
   header's black and its bottom edge into the spec strip below, so it reads as the page
   opening out rather than as an embed sitting on top. That is the whole trick here. */
.film {
  position: relative; margin: 34px 0 0; border-radius: 14px; overflow: hidden;
  border: 1px solid var(--line); background: #000; aspect-ratio: 1100 / 606;
  isolation: isolate;
}
.filmbed { width: 100%; height: 100%; object-fit: cover; display: block; }
/* The radial is doing real work, not decoration. This clip is a sunlit sand basin whose
   centre sits at luma 95-135 for its whole 16 s, so there is no frame at which pale text
   would read against it unaided, and no choice of poster fixes that. The radial gives the
   play cluster its own ground; the linear one blends the band's edges into the page. */
.filmscrim {
  position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(ellipse 44% 48% at 50% 52%, rgba(10, 10, 13, 0.62), transparent 74%),
    linear-gradient(to bottom,
      rgba(10, 10, 13, 0.72) 0%, rgba(10, 10, 13, 0.10) 26%,
      rgba(10, 10, 13, 0.10) 58%, rgba(10, 10, 13, 0.86) 100%);
  transition: opacity 0.35s ease;
}
.filmplay {
  position: absolute; inset: 0; z-index: 2; display: flex; cursor: pointer;
  flex-direction: column; align-items: center; justify-content: center; gap: 0;
  background: none; border: 0; color: var(--ink); font-family: var(--sans);
}
.filmplay .ring {
  width: 66px; height: 66px; border-radius: 50%; display: grid; place-items: center;
  border: 1.5px solid rgba(236, 231, 219, 0.75); background: rgba(10, 10, 13, 0.34);
  backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px);
  transition: transform 0.28s cubic-bezier(0.2, 0.8, 0.2, 1),
              border-color 0.28s ease, background 0.28s ease;
}
.filmplay .tri {
  width: 0; height: 0; margin-left: 4px;                 /* optical centring */
  border-left: 15px solid var(--ink);
  border-top: 9.5px solid transparent; border-bottom: 9.5px solid transparent;
  transition: border-left-color 0.28s ease;
}
.filmplay .lbl {
  margin-top: 15px; font-family: var(--disp); font-size: 15.5px; font-weight: 500;
  letter-spacing: 0.01em; text-shadow: 0 1px 14px rgba(0, 0, 0, 0.75);
}
.filmplay .sub {
  margin-top: 5px; font-family: var(--mono); font-size: 11px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--mute);
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.85);
}
.film:hover .filmscrim { opacity: 0.72; }
.filmplay:hover .ring, .filmplay:focus-visible .ring {
  transform: scale(1.08); border-color: var(--harness); background: rgba(10, 10, 13, 0.5);
}
.filmplay:hover .tri, .filmplay:focus-visible .tri { border-left-color: var(--harness); }
.filmplay:focus-visible { outline: 2px solid var(--harness); outline-offset: -4px; }
/* Once the real film is in, the bed and its furniture are gone and the iframe owns the box. */
.film.playing .filmbed, .film.playing .filmscrim, .film.playing .filmplay { display: none; }
.film iframe { width: 100%; height: 100%; border: 0; display: block; }
@media (max-width: 640px) {
  .filmplay .ring { width: 54px; height: 54px; }
  .filmplay .tri { border-left-width: 12px; border-top-width: 8px; border-bottom-width: 8px; }
  .filmplay .lbl { font-size: 14px; }
  .filmplay .sub { font-size: 10px; letter-spacing: 0.1em; }
}
/* Someone who has asked for less motion should not be handed an autoplaying loop. They get
   the poster frame and the same play button, which still works. */
@media (prefers-reduced-motion: reduce) {
  .filmbed { display: none; }
  .film { background: #000 center / cover no-repeat url('../images/hero_loop_poster.jpg'); }
}

/* ---------- spec strip ---------- */
.specs {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: 12px; overflow: hidden; margin: 42px 0 0;
}
.spec { background: var(--bg-2); padding: 17px 14px; text-align: center; }
.spec b {
  display: block; font-family: var(--disp); font-size: 23px; font-weight: 600;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.spec span { font-size: 12.5px; color: var(--mute); }

section { padding: 58px 0; }
section + section { border-top: 1px solid var(--line); }

/* ============ interactive pipeline ============ */
.rail-wrap { margin: 40px 0 0; }
.rail {
  position: relative; height: 2px; margin: 0 0 0; background: transparent;
}
.rail .seg {
  position: absolute; top: 0; height: 2px;
}
.rail .seg.solid { left: 0; width: 66.667%; background: var(--line-2); }
.rail .seg.dash {
  left: 66.667%; right: 0;
  background: repeating-linear-gradient(90deg,
    rgba(242,109,91,0.45) 0 7px, transparent 7px 13px);
}
.rail .fill {
  position: absolute; top: -0.5px; left: 0; height: 3px; width: 0;
  background: var(--acc, var(--neural)); opacity: 0.9;
  transition: width 0.42s cubic-bezier(.4,0,.2,1), background 0.3s;
}
.rail .head {
  position: absolute; top: -13px; width: 0; height: 0; margin-left: -6px;
  border-left: 6px solid transparent; border-right: 6px solid transparent;
  border-top: 9px solid var(--acc, var(--neural));
  transition: left 0.42s cubic-bezier(.4,0,.2,1), border-top-color 0.3s;
}

/* The dots must sit exactly on the rail's quarter points (0 / 33.3 / 66.7 / 100),
   which flex layout will not give you: four 25%-wide columns put their centres at
   12.5 / 37.5 / 62.5 / 87.5. So the nodes are positioned absolutely, and the first
   and last are anchored by their edge so they cannot overhang the rail. */
.nodes { position: relative; height: 74px; margin-top: -7px; }
.node {
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center;
  position: absolute; top: 0; color: inherit; font: inherit;
}
.node[data-i="0"] { left: 0; align-items: flex-start; }
.node[data-i="1"] { left: 33.333%; transform: translateX(-50%); }
.node[data-i="2"] { left: 66.667%; transform: translateX(-50%); }
.node[data-i="3"] { left: 100%; transform: translateX(-100%); align-items: flex-end; }
.node .dot {
  width: 12px; height: 12px; border-radius: 50%; background: var(--bg);
  border: 2px solid var(--line-2); position: relative;
  transition: all 0.28s cubic-bezier(.4,0,.2,1);
}
.node .dot::after {
  content: ''; position: absolute; inset: -9px; border-radius: 50%;
  border: 1.5px solid var(--c); opacity: 0; transform: scale(0.7);
  transition: all 0.28s cubic-bezier(.4,0,.2,1);
}
.node:hover .dot { border-color: var(--c); }
.node.done .dot { background: rgba(236,231,219,0.5); border-color: rgba(236,231,219,0.5); }
.node.on .dot { background: var(--c); border-color: var(--c); width: 16px; height: 16px; }
.node.on .dot::after { opacity: 0.5; transform: scale(1); }
.node .nm {
  font-family: var(--disp); font-size: 19px; font-weight: 600; color: var(--mute);
  margin-top: 16px; line-height: 1.15; transition: color 0.25s;
}
.node .sb {
  font-family: var(--mono); font-size: 11px; letter-spacing: 0.15em;
  text-transform: uppercase; color: var(--faint); margin-top: 4px;
  transition: color 0.25s; white-space: nowrap;
}
.node.on .nm { color: var(--ink); }
.node.on .sb { color: var(--c); }
.node:focus-visible { outline: 2px solid var(--c); outline-offset: 6px; border-radius: 4px; }
@media (max-width: 720px) {
  .node .nm { font-size: 14px; }
  .node .sb { font-size: 9px; letter-spacing: 0.08em; }
}

/* Text beside the animation, not above it. Stacked (card 190px + glyph + 16:7 canvas)
   the section ran ~1100px, so a laptop could not show the description, the animation and
   the rail together. This layout lands around 600px. */
.stagerow { display: grid; grid-template-columns: minmax(0, 38fr) minmax(0, 62fr); gap: 18px; margin-top: 30px; align-items: stretch; }
@media (max-width: 860px) { .stagerow { grid-template-columns: 1fr; } }

.stagecard {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 2px solid var(--c, var(--neural));
  border-radius: 0 12px 12px 0; padding: 18px 20px 16px;
  display: flex; flex-direction: column; align-items: flex-start;
}
.stagecard .hd { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
.stagecard .hd h4 { font-family: var(--disp); font-size: 24px; font-weight: 600; margin: 0; color: var(--ink); }
.stagecard .hd .meta {
  font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.14em;
  text-transform: uppercase; color: var(--c);
}
.stagecard .line { font-size: 15.5px; margin: 10px 0 0; color: var(--ink); opacity: 0.94; line-height: 1.5; }
.stagecard .hand { font-family: var(--mono); font-size: 12px; color: var(--c); margin: 10px 0 0; opacity: 0.92; line-height: 1.5; }
.stagecard .syncbtn { margin-top: auto; align-self: flex-start; }
@media (max-width: 860px) { .stagecard .syncbtn { margin-top: 14px; } }

/* ============ wipe / split comparison ============ */
.gallery { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-top: 30px; }
@media (max-width: 900px) { .gallery { grid-template-columns: 1fr; } }

.wipe {
  position: relative; aspect-ratio: 1280 / 704; background: #000;
  border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  touch-action: pan-y; cursor: ew-resize; user-select: none;
}
.wipe video {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; display: block;
}
.wipe .top { clip-path: inset(0 calc(100% - var(--x, 61.8%)) 0 0); }
.wipe .bar {
  position: absolute; top: 0; bottom: 0; left: var(--x, 61.8%);
  width: 2px; margin-left: -1px; background: rgba(236, 231, 219, 0.9);
  box-shadow: 0 0 12px rgba(0, 0, 0, 0.6); pointer-events: none;
}
.wipe .grip {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
  width: 34px; height: 34px; border-radius: 50%;
  background: rgba(14, 14, 18, 0.82); border: 1.5px solid rgba(236, 231, 219, 0.9);
  display: flex; align-items: center; justify-content: center; gap: 3px;
}
.wipe .grip::before, .wipe .grip::after {
  content: ''; width: 0; height: 0; border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
}
.wipe .grip::before { border-right: 6px solid rgba(236, 231, 219, 0.9); }
.wipe .grip::after { border-left: 6px solid rgba(236, 231, 219, 0.9); }
.wipe .tag {
  position: absolute; top: 10px; font-family: var(--mono); font-size: 10px;
  letter-spacing: 0.16em; text-transform: uppercase; padding: 3px 8px;
  border-radius: 4px; background: rgba(10, 10, 13, 0.66);
  border: 1px solid rgba(236, 231, 219, 0.18); pointer-events: none;
}
.wipe .tag.l { left: 10px; color: var(--red); }
.wipe .tag.r { right: 10px; color: var(--gold); }
.hint {
  display: flex; align-items: center; gap: 9px; font-size: 13.5px;
  color: var(--faint); margin-top: 14px; font-family: var(--mono);
  letter-spacing: 0.04em;
}

/* ---------- plain media ---------- */
figure { margin: 0 0 8px; }
.media { background: #000; border: 1px solid var(--line); border-radius: 10px; overflow: hidden; line-height: 0; }
.media video, .media img { width: 100%; height: auto; display: block; }
figcaption { font-size: 13.6px; color: var(--mute); line-height: 1.58; margin-top: 11px; }
figcaption b { color: var(--ink); font-weight: 600; }
.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
@media (max-width: 820px) { .pair { grid-template-columns: 1fr; } }

/* ---------- table ---------- */
table.res { width: 100%; border-collapse: collapse; font-size: 14.5px; margin-top: 14px; }
table.res th, table.res td { padding: 10px 12px; border-bottom: 1px solid var(--line); text-align: left; }
table.res th {
  color: var(--faint); font-weight: 500; font-size: 11.5px;
  text-transform: uppercase; letter-spacing: 0.13em; font-family: var(--mono);
}
table.res td.num { font-family: var(--mono); font-variant-numeric: tabular-nums; text-align: right; }
table.res td.win { color: var(--harness); }
table.res td.na { color: var(--faint); font-size: 13px; }

/* ---------- callout ---------- */
.callout {
  background: var(--surface); border: 1px solid var(--line);
  border-left: 2px solid var(--neural); border-radius: 0 12px 12px 0;
  padding: 20px 24px; margin: 28px 0;
}
.callout p:last-child { margin-bottom: 0; }

pre.bib {
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px;
  padding: 17px 19px; overflow-x: auto; font-family: var(--mono);
  font-size: 12.6px; color: var(--ink); line-height: 1.6;
}

footer { border-top: 1px solid var(--line); padding: 36px 0 64px; color: var(--faint); font-size: 13.4px; }
footer a { color: var(--mute); }

/* ============ stage example clip (under the interactive rail) ============ */
.actwrap { margin-top: 22px; }
.actbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.actlabel {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.16em;
  text-transform: uppercase; color: var(--faint);
}
.syncbtn {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.1em;
  color: var(--ink); cursor: pointer; background: var(--surface);
  border: 1px solid var(--line-2); border-radius: 7px; padding: 5px 12px;
}
.syncbtn:hover { background: #1c1c24; }
/* the clip eases to a stop rather than cutting; the dim is driven from script */
.media.act video { transition: opacity 0.25s linear; }

/* ============ control timeline ============ */
.timeline { position: relative; height: 76px; margin: 18px 0 6px; }
.tlline {
  position: absolute; left: 0; right: 0; top: 5px; height: 2px;
  background: var(--line-2); border-radius: 2px; overflow: hidden;
}
.tlprog { height: 100%; width: 0; background: var(--harness); opacity: 0.75; }
.mark {
  position: absolute; top: 0; transform: translateX(-50%);
  appearance: none; background: none; border: 0; padding: 0; cursor: pointer;
  display: flex; flex-direction: column; align-items: center;
  color: inherit; font: inherit; white-space: nowrap;
}
.mark:first-of-type { transform: translateX(0); align-items: flex-start; }
.mark .mdot {
  width: 12px; height: 12px; border-radius: 50%; background: var(--bg);
  border: 2px solid var(--line-2); transition: all 0.2s;
}
.mark:hover .mdot { border-color: var(--harness); }
.mark.on .mdot { background: var(--harness); border-color: var(--harness); }
.mark .mlab {
  font-family: var(--disp); font-size: 14px; font-weight: 600;
  color: var(--mute); margin-top: 9px; transition: color 0.2s;
}
.mark.on .mlab { color: var(--ink); }
.mark .msub { font-size: 11.5px; color: var(--faint); }
.mark .mt {
  font-family: var(--mono); font-size: 10.5px; color: var(--faint);
  letter-spacing: 0.08em; margin-top: 2px;
}
.mark.on .mt { color: var(--harness); }
.mark:focus-visible { outline: 2px solid var(--harness); outline-offset: 5px; border-radius: 4px; }
@media (max-width: 720px) {
  .mark .mlab { font-size: 11.5px; }
  .mark .msub { display: none; }
}

/* ============ dataset stats ============ */
.statgrid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(158px, 1fr));
  gap: 1px; background: var(--line); border: 1px solid var(--line);
  border-radius: 12px; overflow: hidden; margin: 26px 0 8px;
}
.stat { background: var(--bg-2); padding: 15px 13px; text-align: center; }
.stat b {
  display: block; font-family: var(--disp); font-size: 20px; font-weight: 600;
  color: var(--ink); font-variant-numeric: tabular-nums;
}
.stat span { font-size: 12px; color: var(--mute); }

.wipe.wide { aspect-ratio: 1280 / 704; }

.note { font-size: 13.6px; color: var(--faint); line-height: 1.6; margin-top: 18px; max-width: 820px; }
.note a { color: var(--mute); }

/* ============ coded stage animation canvas ============ */
.stageviz {
  position: relative; background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 10px; overflow: hidden; aspect-ratio: 2 / 1; max-height: 420px;
}
.stageviz canvas { display: block; width: 100%; height: 100%; }
/* .src is the note that used to be a .vizlabel overlay on top of this canvas. The stage
   animations draw their own annotations, so an absolutely-positioned caption inevitably
   collided with them; it now sits in the stage card on the left instead. */
.src {
  margin: 14px 0 0; font-size: 12.2px; line-height: 1.55; color: var(--faint);
  border-top: 1px solid var(--line); padding-top: 11px;
}
@media (max-width: 700px) { .stageviz { aspect-ratio: 4 / 3; } }

/* ============ segmented control player ============ */
/* Each demo is a stack of per-marker clips; only the active one is shown, so switching is
   a class toggle rather than a seek. All of them are buffered before anything plays. */
.segplayer { margin: 4px 0 0; }
.segstack { position: relative; }
.segstack .segpane { display: none; }
.segstack .segpane.on { display: block; }
.segready {
  display: flex; align-items: center; gap: 9px; margin-top: 12px;
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--faint);
}
.segready::before {
  content: ''; width: 9px; height: 9px; border-radius: 50%;
  border: 1.5px solid var(--line-2); border-top-color: var(--harness);
  animation: segspin 0.9s linear infinite;
}
@keyframes segspin { to { transform: rotate(360deg); } }
/* the timeline is inert until the gate clears, so a click cannot start a half-buffered clip */
.segplayer .timeline { opacity: 0.45; pointer-events: none; transition: opacity 0.25s; }
.segplayer.ready .timeline { opacity: 1; pointer-events: auto; }

/* ============ insight axis ============
   One horizontal track with markers at fixed percentages, alternating above and below so the
   cards never collide. Percentages are the meaning of the figure, so they live in the HTML
   (--x) and not here. */
.axis { margin: 46px 0 26px; }
.axtrack {
  position: relative; height: 3px; border-radius: 2px;
  background: linear-gradient(90deg, var(--gold) 0%, rgba(236,231,219,0.22) 46%,
                              rgba(236,231,219,0.22) 54%, var(--red) 100%);
}
.axideal {
  position: absolute; top: -7px; width: 0; height: 17px; margin-left: -1px;
  border-left: 1px dashed rgba(236,231,219,0.5);
}
.axideal span {
  position: absolute; left: 50%; transform: translateX(-50%); top: -21px; white-space: nowrap;
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint);
}
.axus {
  position: absolute; top: -10px; left: 68%; width: 2px; height: 23px; margin-left: -1px;
  background: var(--harness); box-shadow: 0 0 12px var(--harness);
}
.axends { display: flex; justify-content: space-between; margin-top: 11px; }
.axends .e { max-width: 40%; }
.axends .e.r { text-align: right; }
.axends b {
  display: block; font-family: var(--mono); font-size: 10.5px; letter-spacing: 0.18em;
  text-transform: uppercase;
}
.axends .e.l b { color: var(--gold); }
.axends .e.r b { color: var(--red); }
.axends span { font-size: 12.5px; color: var(--faint); }

.axnodes { position: relative; margin-top: 30px; }
.ax { position: absolute; left: var(--x); width: 210px; margin-left: -105px; }
.ax .dot {
  width: 9px; height: 9px; border-radius: 50%; margin: 0 auto 10px;
  background: var(--bg); border: 2px solid var(--line-2);
}
.ax.us .dot { background: var(--harness); border-color: var(--harness); width: 12px; height: 12px; }
.ax .card {
  background: var(--surface); border: 1px solid var(--line); border-radius: 9px;
  padding: 12px 13px 13px;
}
.ax.us .card { border-color: rgba(89,230,190,0.45); background: #10171a; }
.ax .marks {
  font-family: var(--mono); font-size: 9.5px; letter-spacing: 0.1em; color: var(--faint);
  text-transform: uppercase; margin-bottom: 5px;
}
.ax.us .marks { color: var(--harness); }
.ax h3 { font-family: var(--disp); font-size: 14.5px; font-weight: 600; margin: 0 0 6px; color: var(--ink); }
.ax p { font-size: 12.4px; line-height: 1.5; color: var(--mute); margin: 0; }
.ax em { font-style: normal; color: var(--ink); }
/* Absolute layout, so the container needs an explicit height. All four cards share one row
   and one top edge; the x positions carry the meaning and are far enough apart that they do
   not collide (narrowest gap is 42px at the 1100px breakpoint, below which they stack). */
.axnodes { height: 212px; }
.ax.up, .ax.down { top: 0; }
@media (max-width: 1100px) {
  /* below this the cards overlap, so stop pretending and stack them, keeping the order */
  .axnodes { height: auto; display: grid; gap: 14px; }
  .ax { position: static; width: auto; margin: 0; }
  .ax .dot { display: none; }
}

/* ============ four-system comparison ============ */
.cmpgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; margin-top: 30px; }
@media (max-width: 900px) { .cmpgrid { grid-template-columns: 1fr; } }
.cmpitem { margin: 0; border: 1px solid var(--line); border-radius: 10px; overflow: hidden;
  background: #000; }
.cmpitem video { display: block; width: 100%; height: auto; background: #000; }
.cmpitem figcaption { padding: 10px 13px 12px; background: var(--surface);
  border-top: 1px solid var(--line); }
.cmpitem .cn { display: block; font-family: var(--disp); font-size: 15.5px; font-weight: 600;
  color: var(--ink); }
.cmpitem .cs { display: block; font-family: var(--mono); font-size: 11px; letter-spacing: 0.05em;
  margin-top: 4px; color: var(--faint); }
.cmpitem .cs.ok { color: var(--harness); }
.cmpitem .cs.no { color: var(--red); opacity: 0.85; }

/* ---- axis: uniform collapsed cards, one full-width detail panel ---- */
.ax .card {
  display: flex; flex-direction: column; width: 100%; text-align: left; cursor: pointer;
  font: inherit; color: inherit; background: var(--surface);
  border: 1px solid var(--line); border-radius: 9px; padding: 13px 14px 9px;
  /* min-height, not height: it keeps the four visually uniform while still GROWING rather
     than clipping if a title or summary wraps to another line at some width */
  min-height: 168px;
}
.ax .card:hover { border-color: var(--line-2); }
.ax .card .sum { font-size: 12.4px; line-height: 1.5; color: var(--mute); margin: 0; }
.ax .card .more {
  margin-top: auto; align-self: center; font-size: 13px; line-height: 1;
  color: var(--faint); transition: color 0.2s, transform 0.2s;
}
.ax .card:hover .more { color: var(--ink); transform: translateY(1px); }
.ax.active .card .more { color: var(--harness); transform: rotate(180deg); }
.ax .dot { cursor: pointer; }

/* expanded: the cards go, the dots stay as position markers on the track */
.axis.expanded .axnodes { height: 30px; }
.axis.expanded .ax .card { display: none; }
.axis.expanded .ax.active .dot {
  background: var(--harness); border-color: var(--harness);
  width: 14px; height: 14px; box-shadow: 0 0 14px rgba(89,230,190,0.6);
}

.axdetail {
  margin-top: 6px; border: 1px solid var(--line-2); border-radius: 12px;
  background: var(--bg-2); padding: 20px 22px 22px;
}
.axdhead { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.axdhead h3 { font-family: var(--disp); font-size: 21px; font-weight: 600; margin: 5px 0 0; color: var(--ink); }
.axdhead .marks {
  font-family: var(--mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--faint);
}
.axclose {
  background: none; border: 1px solid var(--line); color: var(--mute); border-radius: 7px;
  width: 30px; height: 30px; font-size: 17px; line-height: 1; cursor: pointer; flex: none;
}
.axclose:hover { color: var(--ink); border-color: var(--line-2); }
.axdbody { display: grid; grid-template-columns: minmax(0, 42fr) minmax(0, 58fr); gap: 22px; margin-top: 14px; }
@media (max-width: 860px) { .axdbody { grid-template-columns: 1fr; } }
.axdtext p { font-size: 14.6px; line-height: 1.65; color: var(--mute); margin: 0 0 12px; }
.axdtext em { font-style: normal; color: var(--ink); }
.axdtext .links { display: flex; flex-wrap: wrap; gap: 14px; margin: 0; }
.axdtext .links a {
  font-family: var(--mono); font-size: 11.5px; letter-spacing: 0.06em; color: var(--harness);
  border-bottom: 1px solid rgba(89,230,190,0.35);
}
.axdtext .links a:hover { text-decoration: none; border-bottom-color: var(--harness); }
.axdfig img {
  display: block; width: 100%; height: auto; border: 1px solid var(--line);
  border-radius: 8px; background: var(--bg-2);
}
/* One figure -- GameNGen's architecture diagram -- is a transparent PNG drawn in dark ink, so
   on this page's dark plate it is very nearly invisible. It gets the white ground it was drawn
   for. The padding keeps the diagram's own strokes off the border; without it the leftmost
   arrowhead sits on the rounded corner. */
.axdfig img.onwhite { background: #fff; padding: 12px; }
.axdfig figcaption { font-size: 11.8px; line-height: 1.5; color: var(--faint); margin-top: 8px; }
.axdfig figcaption a { color: var(--mute); }
.axdfig.nofig figcaption::before {
  content: 'figure unavailable from its host \00b7 '; color: var(--red); opacity: 0.85;
}
