/*
  SUPER CAKE GAME STUDIO homepage, v3 (CORE LINK command room).
  A steel command room: one unit at a time stands on a plinth under a HUD (corner
  brackets, ruler, readout, radar ring) while the chapters scroll past. Phones show each
  unit as its own block (D23 flow). Without script, or with reduced motion, the same
  chapters show as a plain stacked page with still figures and every effect finished.
  No external requests: fonts are self-hosted subsets, every image and video is same-origin.
*/

@font-face {
  font-family: "SC Sans";
  src: url("/fonts/sc-sans-var.woff2") format("woff2");
  font-weight: 400 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "SC Display";
  src: url("/fonts/sc-display-700.woff2") format("woff2");
  font-weight: 700 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "SC Display";
  src: url("/fonts/sc-display-600.woff2") format("woff2");
  font-weight: 400 600;
  font-style: normal;
  font-display: swap;
}

:root {
  /* D28 dark steel command room (review round 1: the grey film read as plastic). Text is
     light: #eef2f5 on #3a424b is 9.1:1, the secondary #b7c1c9 is 5.6:1. --ink-dark is for
     text on light surfaces (buttons, highlighter, the attack card). */
  --stage: #3a424b;
  --tint: var(--stage);
  --steel-deep: #1d2126;   /* bands: marquee, footer */
  --line: rgba(255, 255, 255, 0.16);
  --line-light: rgba(255, 255, 255, 0.12);
  --ink: #eef2f5;
  --ink-2: #b7c1c9;
  --ink-dark: #111820;
  --paper: #ffffff;
  --plate: #000007;
  --night: #0d0e12;
  --intro-navy: #050a14;   /* the 3D intro's own background, measured on its border (5,10,20), so the band and the video meet without a seam */
  --logo-cream: #f3eadf;   /* cream of the 3D logo, header plate behind the flat logo */

  /* Accents: GramBurst yellow for highlights and HUD, warning red, void violet. */
  --cream: #f5eee5;
  --cherry: #e7777b;
  --red: #d3312b;
  --amber: #f2b32a;
  --hl: rgba(40, 222, 255, 0.62);
  --violet: #8a3fe0;
  --lavender: #cdb8f2;
  --hud: #f2b32a;

  --sans: "SC Sans", -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Malgun Gothic",
    "Noto Sans KR", "Segoe UI", sans-serif;
  /* D27: Latin from SC Display (Chakra Petch); Hangul in the same element falls back to SC Sans. */
  --display: "SC Display", var(--sans);

  --gutter: clamp(16px, 3.2vw, 40px);
  --col: calc((100vw - 2 * var(--gutter)) / 3);
  --band-h: 68px;
  --ease: cubic-bezier(0.65, 0, 0.35, 1);
  --out: cubic-bezier(0.22, 1, 0.36, 1);
}

/* Base */

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  scroll-padding-top: calc(var(--band-h) + 12px);
}

@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}

body {
  margin: 0;
  background: var(--tint);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1.0625rem;
  font-weight: 400;
  line-height: 1.7;
  letter-spacing: -0.005em;
  word-break: keep-all;
  overflow-wrap: normal;
  -webkit-font-smoothing: antialiased;
  transition: background-color 0.7s ease;
}

h1,
h2,
h3 {
  text-wrap: balance;
}

p,
dd,
li {
  text-wrap: pretty;
}

img,
video,
svg {
  display: block;
  max-width: 100%;
}

h1,
h2,
h3,
p,
ul,
dl,
dd,
figure {
  margin: 0;
}

ul {
  padding: 0;
  list-style: none;
}

a {
  color: inherit;
}

button {
  font: inherit;
  color: inherit;
}

[hidden] {
  display: none !important;
}

:focus-visible {
  outline: 2px solid var(--paper);
  outline-offset: 3px;
  box-shadow: 0 0 0 5px var(--ink-dark);
  border-radius: 6px;
}

.visually-hidden {
  position: absolute !important;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: fixed;
  top: 12px;
  left: var(--gutter);
  z-index: 50;
  padding: 0.6rem 1rem;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-dark);
  font-weight: 500;
  text-decoration: none;
  transform: translateY(-200%);
}

.skip:focus {
  transform: none;
}

main,
.site-footer {
  position: relative;
  z-index: 1;
}

/* Big words are wider than the screen on purpose; they are cut here, not at the viewport
   (clip, not hidden, so the sticky stage keeps working). */
main {
  overflow-x: clip;
}

/* Type (D27, values from the specimen review: Latin 700 -0.02em, Hangul 800 -0.035em,
   codes 600 +0.06em, small Latin labels 600 +0.08em) */

.code {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: 0.06em;
  font-variant-numeric: tabular-nums;
}

.kicker {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
  color: var(--ink);
  font-family: var(--display);
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.4;
}

.kicker--en {
  font-weight: 600;
  font-size: 0.8125rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.kicker__no {
  display: inline-grid;
  place-items: center;
  min-width: 2.1rem;
  height: 1.5rem;
  padding: 0 0.4rem;
  background: var(--hud);
  color: var(--ink-dark);
  font-size: 0.75rem;
  clip-path: polygon(0 0, 100% 0, 100% 70%, calc(100% - 6px) 100%, 0 100%);
}

.display-title,
.unit-title,
.hero-title {
  color: var(--paper);
  font-family: var(--display);
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: -0.02em;
}

.display-title {
  font-size: clamp(2.75rem, 6.6vw, 6rem);
  line-height: 0.95;
  text-transform: uppercase;
}

/* Sized to the text column, so the longest name (BattleCruiser) stays on one line. */
.unit-title {
  font-size: clamp(2.25rem, calc((var(--col) - 2.5rem) / 6.4), 5rem);
  overflow-wrap: normal;
  white-space: nowrap;
}

.section-title,
.contact__title {
  color: var(--paper);
  font-family: var(--display);
  font-size: clamp(2.1rem, 4.8vw, 3.9rem);
  font-weight: 800;
  line-height: 1.12;
  letter-spacing: -0.035em;
}

.lead {
  max-width: 34rem;
  margin-top: 1.1rem;
  font-size: clamp(1rem, 1.5vw, 1.25rem);
  font-weight: 500;
  line-height: 1.5;
}

/* Titles rise out of a mask, one line at a time (app.js adds .is-in). */
.line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.06em;
  margin-bottom: -0.06em;
}

.line > span {
  display: inline-block;
}

/* Highlighter, drawn left to right. On the dark steel a band behind only the lower 55%
   left either the top of dark letters or the bottom of light letters unreadable, so the
   band covers 84% of the line with dark letters, like a marker swipe. */
mark.hl {
  padding: 0 0.16em;
  margin: 0 -0.06em;
  background: linear-gradient(transparent 56%, var(--hl) 56%, var(--hl) 96%, transparent 96%) no-repeat 0 0 / 100% 100%;
  color: inherit;
}

/* D36: owner disliked the yellow block. Now a translucent neon cyan marker under the lower
   40% of the line; letters stay light (the band is see-through, so they stay readable).
   Cost: less loud than the block. Escape hatch: --hl back to #ffcf3f and the 10%-94% band
   with --ink-dark letters. */
mark.hl {
  color: var(--ink);
  text-shadow: none;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.chapter--void mark.hl,
.faction--void mark.hl {
  --hl: rgba(190, 140, 255, 0.7);
}

.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 0 1.5rem;
  overflow: hidden;
  border: 0;
  border-radius: 999px;
  background: var(--paper);
  color: var(--ink-dark);
  font-family: var(--display);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.2s;
}

/* Hover: the label slides up and its copy (a text shadow 2.4em below, past the padding)
   slides in. */
.button > span,
.nav a > span {
  display: inline-block;
  text-shadow: 0 2.4em 0 currentColor;
  transition: transform 0.28s var(--out);
}

.button:hover > span,
.nav a:hover > span {
  transform: translateY(-2.4em);
}

.button:hover {
  background: var(--cream);
}

.button--ghost {
  border: 1px solid rgba(255, 255, 255, 0.55);
  background: transparent;
  color: var(--paper);
}

.button--ghost:hover {
  background: rgba(255, 255, 255, 0.12);
}

/* Header: cream logo plate left, menu pill right, a band of the stage colour behind. */

.site-header {
  position: fixed;
  top: 14px;
  left: var(--gutter);
  right: var(--gutter);
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  pointer-events: none;
}

.brand,
.nav {
  pointer-events: auto;
}

.site-header::before {
  content: "";
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: -1;
  height: var(--band-h);
  background: var(--tint);
  pointer-events: auto;
  transition: background-color 0.7s ease;
}

/* Scroll progress: a hairline at the foot of the band. */
.progress {
  position: fixed;
  top: calc(var(--band-h) - 2px);
  left: 0;
  right: 0;
  height: 2px;
  pointer-events: none;
}

.progress span {
  display: block;
  height: 100%;
  background: var(--hud);
  transform: scaleX(var(--page, 0));
  transform-origin: left;
}

/* D25: flat symbol + lettering on a cream plate. */
.brand {
  display: flex;
  align-items: center;
  padding: 6px 14px 6px 8px;
  border-radius: 999px;
  background: var(--logo-cream);
  box-shadow: 0 6px 18px -8px rgba(0, 0, 0, 0.45);
}

.brand img {
  display: block;
  width: auto;
  height: 28px;
}

.nav ul {
  display: flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  background: rgba(18, 18, 20, 0.72);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
}

.nav a {
  display: block;
  overflow: hidden;
  padding: 0.55rem 0.95rem;
  border-radius: 999px;
  color: var(--paper);
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  transition: background-color 0.2s;
}

.nav a:hover {
  background: rgba(255, 255, 255, 0.14);
}

.nav .nav__cta {
  background: var(--paper);
  color: var(--ink-dark);
}

.nav .nav__cta:hover {
  background: var(--cream);
}

/* Story: static layout first (no script, or reduced motion) */

.story {
  position: relative;
  /* D27: the column guides belong to the unit stage only, not to the sections below. */
  --g1: calc(var(--gutter) + (100% - 2 * var(--gutter)) / 3);
  --g2: calc(var(--gutter) + (100% - 2 * var(--gutter)) * 2 / 3);
}

.story::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(90deg, transparent calc(var(--g1) - 0.5px), var(--line-light) 0,
      var(--line-light) calc(var(--g1) + 0.5px), transparent 0,
      transparent calc(var(--g2) - 0.5px), var(--line-light) 0,
      var(--line-light) calc(var(--g2) + 0.5px), transparent 0);
}

.stage,
.unit-stage {
  display: none;
}

.chapter {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: center;
  gap: 2rem;
  max-width: 1200px;
  margin-inline: auto;
  padding: clamp(5rem, 10vw, 7rem) var(--gutter) clamp(2.5rem, 6vw, 4rem);
}

.chapter__text {
  max-width: 30rem;
}

.chapter__figure {
  justify-self: center;
  width: auto;
  max-height: 340px;
  filter: drop-shadow(0 18px 14px rgba(0, 0, 0, 0.28));
}

.chapter--hero {
  min-height: 0;
  padding-top: clamp(6.5rem, 14vw, 9rem);
}

.hero-title {
  font-size: clamp(3.25rem, calc((var(--col) - 2.5rem) / 5.2), 6rem);
  text-transform: uppercase;
  white-space: nowrap;
}

.hero-sub {
  max-width: 26rem;
  margin: 1rem 0 1.75rem;
  font-size: clamp(1rem, 1.4vw, 1.25rem);
  font-weight: 500;
  line-height: 1.5;
}

.unit-head {
  display: flex;
  align-items: baseline;
  gap: 0.9rem;
  margin-bottom: 0.9rem;
}

.unit-index {
  display: none;
  color: var(--ink-2);
  font-size: 0.8125rem;
}

.unit-role {
  margin-bottom: 1rem;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: -0.02em;
}

.specs {
  margin: 0;
  border-top: 1px solid var(--line);
}

/* One row per term: the rule runs unbroken under both columns, text on one baseline. */
.specs div {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr);
  align-items: baseline;
  padding: 0.45rem 0;
  border-bottom: 1px solid var(--line);
}

.specs dt,
.specs dd {
  line-height: 1.4;
}

.specs dt {
  color: var(--ink-2);
  font-size: 0.8125rem;
  font-weight: 500;
}

.specs dd {
  font-size: 0.9375rem;
  font-weight: 600;
}

.gimmick,
.scroll-cue {
  display: none;
}

.gimmick__portrait {
  width: 64px;
  height: auto;
  border-radius: 6px;
}

.gimmick__title {
  font-family: var(--display);
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.3;
}

.gimmick__title .code {
  margin-left: 0.3rem;
  color: var(--red);
  font-size: 0.8125rem;
}

.gimmick {
  color: var(--ink-dark);
}

.gimmick__button {
  min-height: 36px;
  padding: 0 0.95rem;
  border: 0;
  border-radius: 999px;
  background: var(--ink-dark);
  color: var(--paper);
  font-family: var(--display);
  font-size: 0.8125rem;
  font-weight: 700;
  white-space: nowrap;
  cursor: pointer;
}

.gimmick__button:hover,
.gimmick__button[aria-busy="true"] {
  background: var(--red);
}

/* Stage furniture (shared by the pinned stage and the phone blocks) */

.figure {
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 2;
  background-repeat: no-repeat;
  opacity: 0;
  transform: translate(-50%, 6%) scale(0.97);
  transform-origin: 50% 100%;
  transition: opacity 0.45s ease, transform 0.6s var(--ease);
  will-change: opacity, transform;
}

.figure.is-active {
  opacity: 1;
  transform: translate(-50%, 0) scale(1);
}

.figure.is-active[data-hover] {
  animation: hover-bob 3.2s ease-in-out infinite alternate;
}

@keyframes hover-bob {
  from {
    margin-bottom: 0;
  }
  to {
    margin-bottom: 10px;
  }
}

/* Radar ring behind the unit: two still rings and one dashed ring that turns slowly. */
.radar {
  position: absolute;
  left: 50%;
  z-index: 0;
  width: 92%;
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  overflow: visible;
  pointer-events: none;
}

.radar__ring {
  fill: none;
  stroke: var(--hud);
  stroke-opacity: 0.11;
  stroke-width: 0.6;
  vector-effect: non-scaling-stroke;
}

.radar__ring--dash {
  stroke-opacity: 0.2;
  stroke-width: 1.4;
  stroke-dasharray: 3 9;
  transform-box: fill-box;
  transform-origin: center;
  animation: radar-turn 28s linear infinite;
}

.radar__ring--thin {
  stroke-opacity: 0.22;
}

.radar__cross {
  stroke: var(--hud);
  stroke-opacity: 0.5;
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

@keyframes radar-turn {
  to {
    transform: rotate(360deg);
  }
}

/* Guide light on the floor under the plinth. */
.stage__floor {
  position: absolute;
  left: 50%;
  bottom: -6%;
  z-index: 0;
  width: 128%;
  height: 46%;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(255, 214, 120, 0.42), rgba(255, 214, 120, 0.12) 55%, transparent);
  transform: translateX(-50%);
  pointer-events: none;
}

.stage__plinth {
  position: relative;
  z-index: 1;
  width: 100%;
  height: auto;
}

/* Story: pinned stage (script running, motion allowed) */

@media (prefers-reduced-motion: no-preference) {
  .js .stage {
    position: sticky;
    top: 0;
    display: block;
    height: 100vh;
    height: 100svh;
    overflow: hidden;
  }

  .js .chapters {
    position: relative;
    margin-top: -100vh;
    margin-top: -100svh;
  }

  .js .chapter {
    display: flex;
    align-items: center;
    min-height: 100vh;
    min-height: 100svh;
    max-width: none;
    padding: 6rem var(--gutter) 4rem;
    pointer-events: none;
  }

  .js .chapter__text {
    width: calc(var(--col) - 2.5rem);
    max-width: 30rem;
    pointer-events: auto;
  }

  .js .gimmick {
    max-width: calc(var(--col) - 2.5rem);
    pointer-events: auto;
  }

  .js .chapter--void {
    justify-content: flex-end;
  }

  /* The stage that shows the unit is aria-hidden, so each chapter keeps its still in the
     accessibility tree (its alt carries the appearance) but off screen. */
  .js .chapter__figure {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    filter: none;
  }

  .js .chapter--scrub {
    align-items: flex-start;
    min-height: 260vh;
  }

  /* Last unit: the card sits level with the plinth (70% down), so when the story ends the
     card and the stage scroll away together instead of drifting apart. */
  .js .chapter:last-child {
    align-items: flex-end;
    padding-bottom: 20vh;
    padding-bottom: 20svh;
  }

  .js .chapter--scrub .chapter__text {
    position: sticky;
    top: 34vh;
  }

  .js .chapter--hero {
    flex-direction: column;
    align-items: flex-start;
    justify-content: space-between;
    padding-top: clamp(6.5rem, 15vh, 9.5rem);
    padding-bottom: 2rem;
  }

  .js .gimmick {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 10px 14px 10px 10px;
    border-radius: 14px;
    background: rgba(255, 255, 255, 0.55);
    transition: opacity 0.3s, visibility 0.3s;
  }

  .js .gimmick.is-away {
    opacity: 0;
    visibility: hidden;
  }

  .js .scroll-cue {
    position: absolute;
    right: var(--gutter);
    bottom: 2rem;
    display: block;
    width: 1px;
    height: 32px;
    background: var(--ink);
    transition: opacity 0.4s;
    opacity: 0.7;
  }

  .js .scroll-cue::after {
    content: "";
    position: absolute;
    left: -3px;
    bottom: 0;
    width: 7px;
    height: 7px;
    border-right: 1px solid var(--ink);
    border-bottom: 1px solid var(--ink);
    transform: rotate(45deg);
  }

  .js.is-scrolled .scroll-cue {
    opacity: 0;
  }

  /* Reveal motion: titles rise, spec rows step in, highlighters draw (app.js adds .is-in). */
  .js .line > span {
    transform: translateY(105%);
    transition: transform 0.6s var(--out);
  }

  .js .is-in .line > span,
  .js .line.is-in > span {
    transform: none;
  }

  .js .specs div {
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.45s ease, transform 0.45s var(--out);
  }

  .js .is-in .specs div {
    opacity: 1;
    transform: none;
  }

  .js .is-in .specs div:nth-child(2) { transition-delay: 0.06s; }
  .js .is-in .specs div:nth-child(3) { transition-delay: 0.12s; }
  .js .is-in .specs div:nth-child(4) { transition-delay: 0.18s; }
  .js .is-in .specs div:nth-child(5) { transition-delay: 0.24s; }

  /* Light letters until the band is drawn, then dark on the band. */
  .js mark.hl {
    background-size: 0% 100%;
    color: var(--ink);
    transition: background-size 0.7s var(--out) 0.25s, color 0.35s ease 0.45s;
  }

  .js .is-in mark.hl,
  .js mark.hl.is-in {
    background-size: 100% 100%;
    color: var(--ink);
  }
}

/* The command room behind the pinned stage (D23): hangar picture under a steel film,
   thin grid, a slow scan line. Loaded only when the stage shows (CSS background). */
.stage__room {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px) 0 0 / 64px 64px,
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px) 0 0 / 64px 64px,
    radial-gradient(ellipse 17% 30% at 50% 58%, rgba(255, 236, 200, 0.16), transparent 100%),
    radial-gradient(ellipse at 50% 58%, transparent 40%, rgba(6, 8, 11, 0.28) 100%),
    linear-gradient(var(--room-film, rgba(52, 60, 69, 0.52)), var(--room-film, rgba(52, 60, 69, 0.52))),
    url("/media/stage/hangar-1600.webp") center 40% / cover no-repeat;
  transition: background-color 0.7s ease;
}

.stage__room::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 0;
  height: 22%;
  background: linear-gradient(transparent, rgba(255, 255, 255, 0.07) 50%, transparent);
  animation: scan 9s linear infinite;
}

@keyframes scan {
  from {
    transform: translateY(-100%);
  }
  to {
    transform: translateY(560%);
  }
}

/* The unit name, very large and faint behind the unit; letters rise when it changes. */
.stage__bigname {
  position: absolute;
  left: 0;
  right: 0;
  top: 46%;
  z-index: 0;
  overflow: hidden;
  color: transparent;
  font-family: var(--display);
  font-size: clamp(5rem, 15vw, 15rem);
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.03em;
  text-align: center;
  white-space: nowrap;
  -webkit-text-stroke: 1.5px rgba(255, 255, 255, 0.12);
  transform: translate(var(--drift, 0px), -50%);
}

.bigname {
  display: inline-block;
}

.bigname > span {
  display: inline-block;
  transform: translateY(0);
  transition: transform 0.55s var(--out), opacity 0.4s ease;
}

.bigname.is-leaving > span {
  transform: translateY(-110%);
  opacity: 0;
}

.bigname.is-entering > span {
  transform: translateY(110%);
  opacity: 0;
  transition: none;
}

/* HUD: corner brackets, ruler, readout, hazard band, blinking lamp. */
.hud {
  position: absolute;
  inset: calc(var(--band-h) + 18px) var(--gutter) 22px;
  pointer-events: none;
}

.hud__corner {
  position: absolute;
  width: 26px;
  height: 26px;
  border: 0 solid var(--hud);
  opacity: 0.85;
}

.hud__corner--tl { top: 0; left: 0; border-top-width: 2px; border-left-width: 2px; }
.hud__corner--tr { top: 0; right: 0; border-top-width: 2px; border-right-width: 2px; }
.hud__corner--bl { bottom: 0; left: 0; border-bottom-width: 2px; border-left-width: 2px; }
.hud__corner--br { bottom: 0; right: 0; border-bottom-width: 2px; border-right-width: 2px; }

.hud__ruler {
  position: absolute;
  top: 18%;
  bottom: 18%;
  left: -28px;
  width: 10px;
  background:
    repeating-linear-gradient(var(--hud) 0 1px, transparent 1px 12px) left / 6px 100% no-repeat,
    repeating-linear-gradient(var(--hud) 0 1px, transparent 1px 60px) left / 10px 100% no-repeat;
  opacity: 0.55;
}

.hud__readout {
  position: absolute;
  top: 12px;
  right: 40px;
  color: var(--paper);
  font-size: 0.75rem;
  line-height: 1.7;
  text-align: right;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
}

.hud__readout p {
  margin: 0;
}

.hud__key {
  color: var(--hud);
}

.hud__code-row:has(.stage__code:empty) {
  display: none;
}

.hud__lamp {
  display: inline-block;
  width: 7px;
  height: 7px;
  margin-right: 0.5rem;
  border-radius: 50%;
  background: #6be38b;
  box-shadow: 0 0 8px #6be38b;
  vertical-align: 1px;
  animation: blink 2.4s steps(1) infinite;
}

@keyframes blink {
  50% {
    opacity: 0.25;
  }
}

.hud__hazard {
  position: absolute;
  left: 40px;
  top: 9px;
  width: 140px;
  height: 8px;
  background: repeating-linear-gradient(-45deg, var(--hud) 0 6px, transparent 6px 12px);
  opacity: 0.6;
}

/* Void units: the room cools to violet. */
.stage[data-faction="void"] {
  --hud: #c9a8ff;
  --room-film: rgba(58, 50, 74, 0.54);
}

/* The card beside the unit already names it (review round 1): the plinth label stays
   for narrow screens only. */
@media (min-width: 900px) {
  .stage .stage__caption {
    display: none;
  }
}

/* top is where the plinth's top surface sits (the -21.9% shift lines it up). */
.stage__display {
  position: absolute;
  left: 50%;
  top: 70%;
  z-index: 1;
  width: min(calc(var(--col) * 0.94), 520px);
  transform: translate(-50%, -21.9%);
  transform-origin: 50% 24%;
  transition: top 0.6s var(--ease), transform 0.3s var(--ease);
}

/* D39: while the attack plays and does not fit across the screen, the scene pulls back and
   slides about the robot's feet (app.js aim() sets the two values). */
.stage__display.is-aimed {
  transform: translate(-50%, -21.9%) translateX(var(--cam-x, 0px)) scale(var(--cam-k, 1));
}

.stage__display .radar {
  top: -86%;
}

/* The figures stand on the top surface of the plinth. D40: the line is the middle of the
   top face, 24% down the plinth picture (face from y 3 to the front rim at y 121 of 263 in
   the middle column, measured on plinth.webp; was 21.9%, nearer the back). app.js sinks
   each unit by its own ground line (gy) onto it. */
.stage__figures {
  position: absolute;
  left: 50%;
  top: 24%;
  z-index: 2;
  width: 0;
  height: 0;
}

/* D40: soft contact shadow under the feet, on the line (app.js place()). It shows with its
   figure; floating units get a fainter one. Escape hatch: display: none. */
.figure-shadow {
  position: absolute;
  bottom: 0;
  left: 0;
  z-index: 1;
  border-radius: 50%;
  background: radial-gradient(closest-side, rgba(8, 10, 14, 0.55), rgba(8, 10, 14, 0.3) 55%, rgba(8, 10, 14, 0));
  opacity: 0;
  transform: translate(-50%, 50%);
  transition: opacity 0.45s ease;
  pointer-events: none;
}

.figure.is-active + .figure-shadow {
  opacity: 1;
}

.figure[data-hover].is-active + .figure-shadow {
  opacity: 0.45;
}

.stage__caption {
  position: absolute;
  left: 50%;
  bottom: 5.5vh;
  z-index: 2;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  white-space: nowrap;
  transform: translateX(-50%);
}

.stage__name {
  font-family: var(--display);
  font-size: 1.125rem;
  font-weight: 700;
}

.stage__role {
  font-size: 0.875rem;
  font-weight: 700;
}

.stage__progress {
  position: absolute;
  right: calc(var(--gutter) + 46px);
  top: calc(50% + 1.4rem);
  z-index: 2;
  width: 1px;
  height: 22vh;
  background: rgba(255, 255, 255, 0.18);
}

.stage__progress span {
  display: block;
  width: 1px;
  height: 100%;
  background: var(--ink);
  transform: scaleY(var(--progress, 0));
  transform-origin: top;
}

/* Marquee: a dark band where existing names and codes run sideways (D24). */

.marquee {
  position: relative;
  z-index: 1;
  overflow: clip;
  padding: 0.9rem 0;
  background:
    repeating-linear-gradient(-45deg, rgba(242, 179, 42, 0.9) 0 10px, transparent 10px 20px) top / 100% 6px no-repeat,
    var(--steel-deep);
  color: rgba(255, 255, 255, 0.9);
}

.marquee__track {
  display: flex;
  align-items: baseline;
  gap: 2.5rem;
  width: max-content;
  padding-top: 6px;
  font-family: var(--display);
  font-size: clamp(2rem, 5vw, 4rem);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  white-space: nowrap;
}

.marquee__track > span:nth-child(3n + 2) {
  color: var(--hud);
}

.marquee__track > span:nth-child(3n) {
  color: transparent;
  -webkit-text-stroke: 1.2px rgba(255, 255, 255, 0.75);
}

@media (prefers-reduced-motion: no-preference) {
  .marquee__track {
    animation: marquee 48s linear infinite;
  }
}

@keyframes marquee {
  to {
    transform: translateX(-50%);
  }
}

/* Sections after the story: steel panels with corner brackets (D23). */

.section {
  position: relative;
  max-width: 1200px;
  margin-inline: auto;
  padding: clamp(2.5rem, 5vw, 4.5rem) var(--gutter);
}

.section__head {
  position: relative;
  margin-bottom: clamp(1.5rem, 2.2vw, 2rem);
}

/* Very large, faint words behind a section head; they drift sideways with the scroll. */
.backword {
  position: absolute;
  left: 50%;
  top: clamp(1rem, 3vw, 2.5rem);
  width: 100vw;
  overflow: clip;
  color: transparent;
  font-family: var(--display);
  font-size: clamp(5rem, 12.5vw, 11.25rem);
  font-weight: 800;
  line-height: 0.9;
  letter-spacing: -0.04em;
  text-align: right;
  white-space: nowrap;
  -webkit-text-stroke: 1px rgba(255, 255, 255, 0.05);
  transform: translateX(-50%);
  pointer-events: none;
}

.backword span {
  display: inline-block;
  transform: translateX(var(--drift, 0px));
}

.panel {
  position: relative;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, 0.04);
}

/* Head strip: a short hazard-yellow bar on the top edge; one bracket at the far corner. */
.panel::before {
  content: "";
  position: absolute;
  top: -1px;
  left: -1px;
  width: 44px;
  height: 4px;
  background: var(--hud);
}

.panel::after {
  content: "";
  position: absolute;
  right: -1px;
  bottom: -1px;
  width: 14px;
  height: 14px;
  border-right: 2px solid rgba(255, 255, 255, 0.55);
  border-bottom: 2px solid rgba(255, 255, 255, 0.55);
}

.keyart {
  overflow: hidden;
  border-color: rgba(255, 255, 255, 0.2);
  background: var(--night);
  box-shadow: 0 40px 60px -40px rgba(0, 0, 0, 0.55);
}

.keyart::after {
  border-color: var(--hud);
}

.keyart img {
  width: 100%;
  height: auto;
}

.facts {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 1rem;
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
  padding: 1.1rem 1.25rem;
}

.facts dt {
  margin-bottom: 0.35rem;
  color: var(--ink-2);
  font-size: 0.8125rem;
  font-weight: 500;
}

.facts dd {
  font-family: var(--display);
  font-size: 1.125rem;
  font-weight: 600;
  line-height: 1.35;
  letter-spacing: -0.02em;
}

.features {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-top: clamp(1.25rem, 2.5vw, 2rem);
}

.features li {
  padding: 20px;
}

.features h3 {
  margin-bottom: 0.4rem;
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 800;
  line-height: 1.3;
  letter-spacing: -0.035em;
}

.features p {
  font-weight: 400;
  line-height: 1.5;
}

.features__tower {
  grid-row: span 2;
}

/* Tower card: text left, the install animation right, so its height never exceeds the
   two text rows beside it. */
.features__tower {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-rows: auto 1fr;
  column-gap: 1rem;
}

.features__tower h3,
.features__tower p {
  grid-column: 1;
}

.tower {
  grid-column: 2;
  grid-row: 1 / span 2;
  align-self: end;
  width: 150px;
  aspect-ratio: 283 / 250;
  background-repeat: no-repeat;
}

.tower img {
  width: 100%;
  height: auto;
}

.tower.is-animated img {
  visibility: hidden;
}

.game-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 18rem), 1fr));
  gap: 1.25rem;
  margin-top: 3rem;
}

.game-card {
  overflow: hidden;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.12);
}

.game-card__media {
  aspect-ratio: 16 / 9;
  background: var(--night);
}

.game-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.game-card__body {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  padding: 1.25rem 1.4rem 1.5rem;
}

.game-card__title {
  font-family: var(--display);
  font-size: 1.375rem;
  font-weight: 800;
  line-height: 1.3;
}

.game-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.game-card__meta li {
  padding: 0.2rem 0.65rem;
  border-radius: 999px;
  background: rgba(18, 18, 20, 0.12);
  font-size: 0.8125rem;
  font-weight: 600;
}

.game-card__link {
  font-weight: 600;
}

/* Factions: unit cards in the generated frames */

.factions__cols {
  --fgap: 3rem;
  --cgap: 1.25rem;
  position: relative;
  display: grid;
  /* Ally takes 3/5 of the width less the gaps, so (ally - 2 gaps) / 3 equals
     (void - 1 gap) / 2: the two card sizes match. */
  grid-template-columns: calc((100% - var(--fgap)) * 0.6 + var(--cgap) / 5) minmax(0, 1fr);
  gap: var(--fgap);
}

/* The faction titles carry no rule of their own: a label plate, not a line. */
.faction__title {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-bottom: 1rem;
  font-family: var(--display);
  font-size: 1.25rem;
  font-weight: 800;
  letter-spacing: -0.035em;
}

.faction__title::before {
  content: "";
  width: 10px;
  height: 10px;
  background: var(--hud);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}

.faction--void .faction__title::before {
  background: var(--lavender);
}

.cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--cgap, 1.25rem);
  perspective: 900px;
}

.faction--void .cards {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.card {
  position: relative;
  aspect-ratio: 5 / 7;
  background: #1b1d22 url("/media/cards/card-ally.webp") center / 100% 100% no-repeat;
  border-radius: 6%;
  box-shadow: 0 8px 16px rgba(0, 0, 0, 0.12);
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform 0.4s var(--out);
}

.card.is-tilting {
  transition: transform 0.08s linear;
}

.card--void {
  background-color: #1f1729;
  background-image: url("/media/cards/card-void.webp");
}

/* Window and title bar positions measured on the frames (tools/build_stage_assets.py notes). */
.card__figure {
  position: absolute;
  left: 9%;
  top: 8%;
  width: 82%;
  height: 62%;
  object-fit: contain;
  object-position: 50% 100%;
  filter: drop-shadow(0 8px 6px rgba(0, 0, 0, 0.25));
}

/* BattleCruiser's still keeps the width of its ship form, so the robot is small in it. */
.card__figure--wide {
  transform: scale(1.4);
  transform-origin: 50% 96%;
}

/* Name plate: the dark bar under the window; a unit code, if any, is its second line. */
.card__label {
  position: absolute;
  left: 9%;
  right: 9%;
  top: 80%;
  height: 13%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.15em;
  color: var(--paper);
  white-space: nowrap;
}

.card--void .card__label {
  top: 78%;
}

.card__name {
  font-family: var(--display);
  font-size: clamp(0.8125rem, 1.15vw, 1rem);
  font-weight: 700;
  line-height: 1.1;
}

.card__code {
  color: var(--amber);
  font-size: clamp(0.625rem, 0.8vw, 0.75rem);
  line-height: 1;
}

/* Studio: the 3D intro (1920x1080) as a full-width muted background (D32). 16:9 box, at
   most one screen tall; a box wider than 16:9 (short windows, landscape phones) switches to
   contain, so the band colour fills the sides and nothing is cut. */
.studio {
  position: relative;
  z-index: 1;
  background: var(--intro-navy);
}

.studio__video {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 9;
  max-height: 100vh;
  max-height: 100svh;
  object-fit: cover;
  background: var(--intro-navy);
}

@media (min-aspect-ratio: 16 / 9) {
  .studio__video {
    object-fit: contain;
  }
}

/* With script, below-the-fold backgrounds wait until app.js marks the section .is-near. */
.js [data-near]:not(.is-near) .card,
.js .contact[data-near]:not(.is-near) {
  background-image: none;
}

/* Contact: closing band over the generated hangar */

.contact {
  position: relative;
  z-index: 1;
  overflow: hidden;
  color: var(--paper);
  background: var(--night) url("/media/stage/hangar-1600.webp") center 60% / cover no-repeat;
  background-image: image-set(url("/media/stage/hangar-800.webp") 1x, url("/media/stage/hangar-1600.webp") 2x);
}

@media (min-width: 900px) {
  .contact {
    background-image: url("/media/stage/hangar-1600.webp");
  }
}

.contact::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(13, 14, 18, 0.6), rgba(13, 14, 18, 0.85));
}

.contact__inner {
  position: relative;
  max-width: 1200px;
  margin-inline: auto;
  padding: clamp(4rem, 9vw, 7rem) var(--gutter);
}

.contact .kicker {
  color: var(--paper);
}

.contact .kicker__no {
  background: var(--hud);
  color: var(--ink-dark);
}

.mail-wrap {
  margin-top: clamp(1.5rem, 3vw, 2.5rem);
}

.mail {
  color: var(--paper);
  font-family: var(--sans);
  font-size: clamp(1.45rem, 2.4vw, 2.125rem);
  font-weight: 600;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
  text-decoration: underline;
  text-decoration-color: var(--hl);
  text-decoration-thickness: 2px;
  text-decoration-skip-ink: none;
  text-underline-offset: 6px;
}

.mail:hover {
  color: var(--cream);
}

.contact__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1rem;
  margin-top: 2rem;
  visibility: hidden;
}

.js .contact__actions {
  visibility: visible;
}

.copy-status {
  min-height: 1.5em;
  color: var(--cream);
  font-size: 0.9375rem;
}

/* Footer: team, then the company line (on the deep steel band) */

.site-footer {
  background: var(--steel-deep);
  color: rgba(255, 255, 255, 0.92);
}

.site-footer > * {
  max-width: 1200px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.team {
  display: grid;
  grid-template-columns: repeat(3, max-content);
  gap: 0.75rem clamp(2rem, 6vw, 4.5rem);
  padding-top: 2.25rem;
  padding-bottom: 1.25rem;
}

.team dt {
  margin-bottom: 0.15rem;
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.8125rem;
  font-weight: 500;
}

.team dd {
  font-size: 1rem;
  font-weight: 700;
}

.site-footer__copy--solo {
  padding-top: 2.25rem;
}

.site-footer__copy {
  padding-top: 0;
  padding-bottom: 2.25rem;
  color: rgba(255, 255, 255, 0.6);
  font-size: 0.8125rem;
  font-weight: 500;
}

/* 404 */

.notfound {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  max-width: 1200px;
  min-height: 80vh;
  min-height: 80svh;
  margin-inline: auto;
  padding: 8rem var(--gutter) 4rem;
}

.notfound .display-title {
  margin-bottom: 1rem;
}

.notfound h1 {
  margin-bottom: 0.75rem;
  font-family: var(--display);
  font-size: clamp(1.5rem, 3.6vw, 2.25rem);
  font-weight: 800;
  line-height: 1.25;
  letter-spacing: -0.035em;
}

.notfound .button {
  margin-top: 2rem;
}

/* Narrow screens (900 px and below) */

@media (max-width: 899px) {
  :root {
    --col: calc((100vw - 2 * var(--gutter)) / 2);
  }

  body {
    font-size: 1rem;
  }

  .story {
    --g1: var(--gutter);
    --g2: calc(100% - var(--gutter));
  }

  .chapter {
    grid-template-columns: 1fr;
  }

  .facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .features {
    grid-template-columns: 1fr;
  }

  .features__tower {
    grid-row: auto;
  }

  .tower {
    width: 120px;
  }

  .factions__cols {
    grid-template-columns: 1fr;
    gap: 2rem;
  }

  .faction--void .cards {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .card__name {
    font-size: clamp(0.8125rem, 2.4vw, 0.9375rem);
  }

  .hud__readout {
    right: 18px;
  }

  .hud__hazard,
  .hud__ruler {
    display: none;
  }
}

@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  /* The unit card rests right under the plinth: stage 40% down, plus the part of the
     plinth below its top face (78.1% of its height; height = width x 263 / 900). */
  .js .story {
    --plinth-w: min(78vw, 420px);
    --rest: calc(40vh + var(--plinth-w) * 0.2282 + 0.75rem);
  }

  @supports (height: 1svh) {
    .js .story {
      --rest: calc(40svh + var(--plinth-w) * 0.2282 + 0.75rem);
    }
  }

  .js .stage__display {
    top: 40%;
    width: var(--plinth-w);
  }

  .js .stage__caption {
    top: calc(40% + var(--plinth-w) * 0.2282 + 0.75rem);
    bottom: auto;
    transition: top 0.6s var(--ease), opacity 0.3s;
  }

  .js .stage[data-chapter="unit"] .stage__caption {
    opacity: 0;
  }

  .js .stage[data-chapter="hero"] .stage__display {
    top: 71%;
  }

  .js .stage[data-chapter="hero"] .stage__caption {
    top: calc(71% + var(--plinth-w) * 0.2282 + 0.75rem);
  }

  .js .stage__progress {
    display: none;
  }

  .js .chapter__text,
  .js .gimmick {
    width: 100%;
    max-width: none;
  }

  /* flow-root keeps the card's top margin inside its chapter (no margin collapse). */
  .js .chapter:not(.chapter--hero) {
    display: flow-root;
    padding: 0 var(--gutter);
  }

  /* Sticky under the plinth while its chapter is on screen; app.js fades it as the
     next chapter pushes it up over the figure. */
  .js .chapter:not(.chapter--hero) .chapter__text {
    position: sticky;
    top: var(--rest);
    margin-top: var(--rest);
    padding: 1rem 1.1rem 1.1rem;
    border-radius: 12px;
    background: rgba(58, 66, 75, 0.88);
    background: color-mix(in srgb, var(--tint) 88%, transparent);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }

  .js .chapter--scrub {
    min-height: 200vh;
    min-height: 200svh;
  }

  .js .chapter--hero {
    align-items: flex-start;
    justify-content: flex-start;
    padding: 5.5rem var(--gutter) 1.5rem;
  }

  .js .chapter--hero .hero-sub {
    margin: 0.5rem 0 1rem;
  }

  .js .gimmick {
    position: absolute;
    left: var(--gutter);
    right: var(--gutter);
    bottom: 1.25rem;
    width: auto;
  }

  .js .scroll-cue {
    display: none;
  }

  .unit-title {
    font-size: clamp(2rem, 9vw, 2.75rem);
  }

  .unit-head {
    margin-bottom: 0.25rem;
  }

  .unit-role {
    margin-bottom: 0.6rem;
  }

  .specs div {
    padding-block: 0.35rem;
  }
}

/* Phones (720 px and below): compact header, one spacing rhythm, no stage guides. */

@media (max-width: 720px) {
  :root {
    --band-h: 52px;
    --rhythm-section: 2.5rem;  /* top and bottom of every section */
    --rhythm-head: 1.25rem;    /* under a section head */
    --rhythm-item: 0.75rem;    /* between items of a list */
  }

  .site-header {
    top: 9px;
  }

  .brand {
    padding: 4px 10px 4px 6px;
  }

  .brand img {
    height: 24px;
  }

  .nav ul {
    padding: 3px;
  }

  .nav a {
    padding: 0.42rem 0.62rem;
    font-size: 0.78rem;
  }

  .story::before {
    display: none;
  }

  .section {
    padding-block: var(--rhythm-section);
  }

  .section__head {
    margin-bottom: var(--rhythm-head);
  }

  .lead {
    margin-top: 0.6rem;
  }

  .facts,
  .features {
    margin-top: var(--rhythm-item);
  }

  .facts {
    gap: var(--rhythm-item);
  }

  .features {
    gap: var(--rhythm-item);
  }

  .features li {
    padding: 1rem 1.1rem 1.1rem;
  }

  .features p,
  .specs dd {
    font-size: 0.9375rem;
    line-height: 1.5;
  }

  .factions__cols {
    gap: var(--rhythm-head);
  }

  .faction__title {
    margin-bottom: var(--rhythm-item);
  }

  .contact__inner {
    padding-block: calc(var(--rhythm-section) * 1.4);
  }

  .mail-wrap {
    margin-top: var(--rhythm-head);
  }

  .contact__actions {
    margin-top: var(--rhythm-head);
  }

  .marquee {
    padding: 0.6rem 0;
  }

  .marquee__track {
    gap: 1.5rem;
  }

  .team {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.75rem 1rem;
  }

  .backword {
    font-size: clamp(5rem, 30vw, 9rem);
  }
}

/* Two cards a row on small phones, so names stay readable. */
@media (max-width: 599px) {
  .cards,
  .faction--void .cards {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--rhythm-item, 1rem);
  }

  .card__name {
    font-size: 0.875rem;
  }

  .card__code {
    font-size: 0.6875rem;
  }
}

/* Phone layout of the unit story (D23 flow). Every chapter is its own block: plinth and
   figure (app.js builds .unit-stage), then name, role and specs. No pinned stage, so no
   empty screens and no jumps when the address bar changes height.
   This media query is the single switch: app.js reads --story-mode, so changing the
   breakpoint here changes the behaviour too. Escape hatch: delete this block and the
   phone falls back to the pinned stage above. */
@media (prefers-reduced-motion: no-preference) and (max-width: 720px),
  (prefers-reduced-motion: no-preference) and (max-height: 560px) {
  .js .story {
    --story-mode: flow;
  }

  .js .story::before {
    display: none;
  }

  .js .stage {
    display: none;
  }

  .js .chapters {
    margin-top: 0;
  }

  .js .chapter,
  .js .chapter:not(.chapter--hero) {
    display: block;
    min-height: 0;
    max-width: none;
    padding: 2rem max(var(--gutter), (100% - 34rem) / 2);
    pointer-events: auto;
  }

  .js .chapter--scrub {
    min-height: 0;
  }

  .js .chapter:not(.chapter--hero) .chapter__text,
  .js .chapter--scrub .chapter__text {
    position: static;
    margin-top: 0;
    padding: 0;
    border-radius: 0;
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .js .chapter--void {
    background: linear-gradient(rgba(62, 54, 80, 0.92), rgba(62, 54, 80, 0.92));
  }

  .js .chapter--void .radar__ring,
  .js .chapter--void .radar__cross {
    stroke: #c9a8ff;
  }

  .js .unit-stage {
    position: relative;
    display: block;
    width: var(--pw);
    margin: 0 auto 0.5rem;
    padding-top: var(--fig-h, 60vw);
    --pw: min(78vw, 340px);
  }

  .js .unit-stage .radar {
    top: calc(var(--fig-h, 60vw) * 0.55);
    width: 96%;
  }

  .js .unit-stage__figures {
    position: absolute;
    left: 50%;
    top: calc(var(--fig-h, 60vw) + var(--pw) * 0.0701);
    z-index: 2;
    width: 0;
    height: 0;
  }

  /* The unit name, huge and faint, behind its figure (clipped to the block). */
  .js .unit-stage__name {
    position: absolute;
    left: 50%;
    top: calc(var(--fig-h, 60vw) * 0.42);
    z-index: 0;
    width: 100vw;
    overflow: clip;
    color: transparent;
    font-family: var(--display);
    font-size: clamp(4rem, 26vw, 8rem);
    font-weight: 700;
    line-height: 1;
    text-align: center;
    white-space: nowrap;
    -webkit-text-stroke: 1.2px rgba(255, 255, 255, 0.28);
    transform: translate(-50%, -50%);
  }

  .js .unit-index {
    display: inline;
  }

  .js .unit-title {
    font-size: clamp(2.25rem, 11vw, 3rem);
  }

  /* GramBurst: the first screen already shows its name and code, so its block starts
     with the role and specs (the heading stays for screen readers). */
  .js #unit-gramburst {
    padding-top: 1.25rem;
  }

  .js #unit-gramburst .unit-head {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

  /* First screen as a poster (D21): the robot is the subject, the words are short. */
  .js .chapter--hero {
    display: flex;
    flex-direction: column;
    padding: calc(var(--band-h) + 0.6rem) var(--gutter) 0.25rem;
    background:
      radial-gradient(ellipse 70% 46% at 50% 58%, rgba(255, 236, 200, 0.16), transparent 70%),
      linear-gradient(rgba(52, 60, 69, 0.7), rgba(52, 60, 69, 0.9)),
      url("/media/stage/hangar-800.webp") center 30% / cover no-repeat;
  }

  .js .chapter--hero .kicker {
    display: none;
  }

  .js .chapter--hero .chapter__text {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    column-gap: 0.75rem;
    width: 100%;
  }

  .js .hero-title {
    grid-column: 1;
    font-size: clamp(2rem, 9vw, 2.6rem);
  }

  .js .chapter--hero .hero-sub {
    grid-column: 1;
    margin: 0.3rem 0 0;
    font-size: 0.875rem;
  }

  .js .chapter--hero .button {
    grid-column: 2;
    grid-row: 1 / span 2;
    min-height: 34px;
    padding: 0 0.95rem;
    font-size: 0.8125rem;
  }

  .js .unit-stage--hero {
    --pw: min(92vw, 520px);
    margin-top: 0.25rem;
    transform-origin: 50% calc(var(--fig-h, 60vw) + var(--pw) * 0.0701);
    transition: transform 0.3s var(--ease);
  }

  /* D39: the attack camera (see .stage__display.is-aimed). */
  .js .unit-stage--hero.is-aimed {
    transform: translateX(var(--cam-x, 0px)) scale(var(--cam-k, 1));
  }

  .js .unit-stage--hero .unit-stage__name {
    font-size: clamp(6rem, 44vw, 13rem);
    -webkit-text-stroke: 1.4px rgba(255, 255, 255, 0.3);
  }

  /* Name and code with the attack button: one strip in the flow, never on top of text. */
  .js .gimmick {
    position: static;
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: auto;
    max-width: none;
    margin: 0.25rem 0 0;
    padding: 6px 6px 6px 14px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.55);
  }

  .js .gimmick__portrait {
    display: none;
  }

  .js .gimmick__title {
    flex: 1;
  }

  .js .gimmick.is-away {
    opacity: 1;
    visibility: visible;
  }

  .js .scroll-cue {
    display: none;
  }

  /* Phones carry half the HUD: radar, floor light and the big name only. */
  .js .chapter__figure {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
  }

}

/* Studio on a portrait phone (any motion setting, the poster crops the same way): a 4:5
   box with cover shows the middle 45% of the 16:9 intro. The logo in the held last frame
   spans 28.1-71.9% of the width (measured on intro_last.png), so it stays whole, about
   5 px from each side at 390 px. The big pad of the first second is wider and is cut on
   purpose. Landscape phones keep the 16:9 box (contain, above). */
@media (max-width: 720px) and (orientation: portrait) {
  .studio__video {
    /* D35: 4/5 left only 5 px beside the logo at 390 px. 1/1 gives about 43 px.
       Cost: shorter band on phones. Escape hatch: set back to 4 / 5. */
    aspect-ratio: 1 / 1;
    object-fit: cover;
  }
}

/* Landscape phones (review round 1): title left, robot and plinth right, all on one screen. */
@media (prefers-reduced-motion: no-preference) and (max-height: 560px) and (orientation: landscape) {
  .js .chapter--hero {
    display: grid;
    grid-template-columns: minmax(0, 34%) minmax(0, 1fr);
    grid-template-rows: 1fr auto;
    column-gap: 1.5rem;
    min-height: 100vh;
    min-height: 100svh;
    padding-bottom: 0.75rem;
  }

  .js .chapter--hero .chapter__text {
    grid-column: 1;
    grid-row: 1;
    align-self: center;
    grid-template-columns: 1fr;
    row-gap: 0.5rem;
  }

  .js .chapter--hero .button {
    grid-column: 1;
    grid-row: auto;
    justify-self: start;
  }

  .js .unit-stage--hero {
    --pw: min(44vw, 300px);
    grid-column: 2;
    grid-row: 1 / span 2;
    align-self: center;
  }

  .js .chapter--hero .gimmick {
    grid-column: 1;
    grid-row: 2;
  }
}

@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;
  }

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