/* ============================================================
   Scenes: layered over the sticky stage via the scroll track
   Each scene gets its computed height from JS (based on data-range).
   ============================================================ */

.track {
  position: relative;
  width: 100%;
  z-index: 2;
  margin-top: -100vh;
  pointer-events: none;
}

.scene {
  position: relative;
  width: 100%;
  padding: 0;
}

/* Scene inner is the pinned reading column that follows the viewport
   while the scroll range of the scene is active. Headline anchors near
   the top (flex-start) so it stays visually rock-steady while the body
   content reveals beneath it. */
.scene-inner {
  position: static;
  min-height: 0;
  display: block;
  padding: clamp(1.2rem, 3vw, 2.2rem) var(--gutter);
  pointer-events: auto;
}

.scene-inner--centered {
  align-items: center;
  text-align: center;
}

.scene-head {
  max-width: 58ch;
  /* Tight margin below the head block — the scene rule and lede are part
     of the header and sit close to the body. */
  margin-bottom: clamp(0.8rem, 1.6vh, 1.4rem);
  flex: 0 0 auto;
}

/* Lane offset — reserve the left third for the stage illustration and
   give the right-hand reading column a proper newspaper measure.
   Reading column width lands around 45–55ch on typical desktops. */
@media (min-width: 520px) {
  .scene:not(.scene-liftoff) .scene-inner {
    padding-left: calc(var(--lane) + 2.5vw);
    padding-right: clamp(2rem, 4vw, 5rem);
    padding-top: clamp(3rem, 9vh, 6rem);
    padding-bottom: clamp(2rem, 5vh, 4rem);
    max-width: none;
  }
  .scene:not(.scene-liftoff) .scene-inner > * {
    max-width: 58ch;
  }
  /* Cards/grids can go a bit wider than running text */
  .scene:not(.scene-liftoff) .scene-inner > .pillars,
  .scene:not(.scene-liftoff) .scene-inner > .actors,
  .scene:not(.scene-liftoff) .scene-inner > .gaps,
  .scene:not(.scene-liftoff) .scene-inner > .scenarios,
  .scene:not(.scene-liftoff) .scene-inner > .open-questions,
  .scene:not(.scene-liftoff) .scene-inner > .treaties,
  .scene:not(.scene-liftoff) .scene-inner > .act-article,
  .scene:not(.scene-liftoff) .scene-inner > .counter-panel {
    max-width: 64ch;
  }
  /* Infomedia + governance matrix break slightly past the reading column
     but stay anchored to it — they should feel like sidebars of the same
     article, not a different layout. */
  .scene:not(.scene-liftoff) .scene-inner > .orbital-map,
  .scene:not(.scene-liftoff) .scene-inner > .gov-matrix {
    max-width: 78ch;
  }
}

/* Scene fade mechanics: only opacity, driven directly by JS via
   --scene-active (0..1). No transform, no CSS transition — JS writes
   the value every scroll frame, and fighting it with a transition just
   creates lag and jitter. */
.scene-inner {
  opacity: var(--scene-active, 1);
  will-change: opacity;
}

.scene-whyNow .scene-inner {
  padding-top: clamp(3rem, 7vh, 5rem);
  padding-bottom: clamp(6rem, 12vh, 10rem);
}

/* ---------- Scene 0: Liftoff (masthead / front-page treatment) ---------- */

.scene-liftoff .scene-inner {
  justify-content: flex-start;
  align-items: center;
  text-align: center;
  padding-top: clamp(1.5rem, 4vh, 3rem);
  padding-bottom: clamp(2rem, 5vh, 4rem);
  gap: 0.8rem;
}
.scene-liftoff .display {
  max-width: 22ch;
  font-size: clamp(1.7rem, 5vw, 3.2rem);
  letter-spacing: -0.022em;
  margin: 0.2rem 0 0;
}
.scene-liftoff .subtitle {
  margin-top: 0.7rem;
  max-width: 36ch;
  font-size: clamp(0.98rem, 1.7vw, 1.15rem);
  color: var(--ink);
  line-height: 1.35;
}
.scene-liftoff .byline {
  margin-top: 1rem;
  max-width: 50ch;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
}
.scene-liftoff .kicker {
  justify-content: center;
}

/* Video embed right under the headline — hero-style preview of the op-ed.
   Max height is capped so the frame never reaches the mountain/horizon layer. */
.hero-video {
  margin: 0.7rem 0 0;
  padding: 0;
  width: 100%;
  /* Wide enough to feel prominent but must stay above the mountain silhouettes */
  max-width: clamp(340px, 68vw, 680px);
}
.hero-video-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  /* Hard ceiling so the bottom of the frame never reaches the mountains (~15vh from bottom) */
  max-height: calc(75vh - 7rem);
  border-radius: 8px;
  overflow: hidden;
  background: #000;
  border: 1px solid var(--rule-strong);
  box-shadow: 0 20px 40px -20px rgba(0, 0, 0, 0.9),
    0 0 0 1px rgba(255, 255, 255, 0.04) inset;
}
.hero-video-frame iframe,
.hero-video-frame video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
  object-fit: cover;
}

/* Two-column layout: masthead text on the left, rocket claiming the right */
@media (min-width: 520px) {
  .scene-liftoff .scene-inner {
    align-items: flex-start;
    text-align: left;
    padding-left: clamp(1.5rem, 5vw, 4rem);
    padding-right: clamp(6rem, 28vw, 18rem);
    padding-bottom: clamp(2rem, 4vh, 3.5rem);
    justify-content: flex-start;
    padding-top: clamp(2rem, 5vh, 4rem);
  }
  .scene-liftoff .display {
    max-width: none;
    font-size: clamp(1.9rem, 3.8vw, 3.2rem);
    line-height: 1.02;
  }
  .scene-liftoff .subtitle {
    max-width: 40ch;
    font-size: clamp(0.95rem, 1.3vw, 1.1rem);
  }
  .scene-liftoff .byline {
    max-width: 44ch;
    font-size: 0.68rem;
  }
  .hero-video {
    max-width: clamp(340px, 68vw, 680px);
  }
  /* Thin red rule under the byline — front-page masthead accent */
  .scene-liftoff .byline::before {
    content: "";
    display: block;
    width: 2.4rem;
    height: 2px;
    background: var(--economist-red);
    margin-bottom: 0.7rem;
  }
}

/* ---------- Scene 1: Why Now (pillars) ---------- */

.pillars {
  list-style: none;
  margin: 0.8rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.8rem;
  row-gap: 1rem;
  counter-reset: pillar;
}
/* Each pillar reads like a miniature sub-article divided by a hairline. */
.pillar {
  position: relative;
  padding: 0.7rem 0 0.2rem;
  border-top: 1px solid var(--rule-strong);
  background: transparent;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 520ms var(--ease-out),
    transform 580ms var(--ease-out);
  transition-delay: calc(var(--pillar-delay, 0) * 70ms);
}
.pillar.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.pillar-big {
  display: block;
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(2rem, 3.2vw, 2.8rem);
  line-height: 1;
  color: var(--economist-red);
  margin: 0 0 0.25rem;
  letter-spacing: -0.02em;
  font-feature-settings: "lnum";
}
.pillar-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.08rem;
  letter-spacing: -0.005em;
  color: #fafbfc;
  margin: 0 0 0.35rem;
}
.pillar-body {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.95rem;
  line-height: 1.45;
  color: var(--ink);
}

/* Counter / pull-quote treatment for the "None of this is free" aside.
   A classic indented pull quote with italic serif and a red rule. */
.counter-panel {
  position: relative;
  margin-top: 1.1rem;
  padding: 0.9rem 0 0.6rem 1.4rem;
  border-left: 3px solid var(--economist-red);
  background: transparent;
  max-width: 60ch;
}
.counter-label {
  margin: 0 0 0.35rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
}
.counter-body {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 1.05rem;
  line-height: 1.45;
  color: #fafbfc;
}

@media (max-width: 520px) {
  .pillars { grid-template-columns: 1fr; }
}

/* ---------- Act I editorial article ----------
   Long-form prose with an inline figure that the text wraps around,
   mirroring the PDF / newspaper layout. Stable — nothing animates
   per-paragraph. The whole block fades in/out at scene boundaries via
   --scene-active. */

.act-article {
  margin-top: 0.9rem;
  /* NOT flex: we need block-level children so the floated figure can
     interact with sibling paragraphs (float only wraps inline/block
     content, not flex items). */
}

.act-para {
  margin: 0 0 0.9em;
  font-family: var(--serif);
  font-size: clamp(0.92rem, 1.1vw, 1.02rem);
  line-height: 1.62;
  color: var(--ink);
}

.act-subhead {
  margin: 1.15rem 0 0.55rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.05rem, 1.45vw, 1.22rem);
  letter-spacing: -0.005em;
  color: #fafbfc;
}
.act-subhead::before {
  content: "";
  display: block;
  width: 2rem;
  height: 2px;
  background: var(--economist-red);
  margin-bottom: 0.55rem;
}

/* The closer paragraph — Act I's kicker sentence. A red left-rule gives
   it a final beat without changing the PDF's wording or structure. */
.act-para--closer {
  margin-top: 1.1rem;
  padding: 0.15rem 0 0.15rem 1rem;
  border-left: 3px solid var(--economist-red);
  font-style: italic;
  color: #fafbfc;
}

/* Figure floats right within the prose so text wraps around it,
   as it would in a newspaper column. On narrow screens it collapses
   back to a full-width block. */
.act-figure {
  float: right;
  width: clamp(220px, 38%, 340px);
  margin: 0.2rem 0 0.9rem 1.4rem;
  padding: 0;
  shape-outside: inset(0 round 6px);
}
.act-figure img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 6px;
  border: 1px solid var(--rule-strong);
  box-shadow: 0 18px 40px -20px rgba(0, 0, 0, 0.8);
}
.act-figure figcaption {
  margin-top: 0.4rem;
  font-family: var(--sans);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-dim);
  text-align: right;
}

/* Clear the float before a new section begins so subheads start on
   a fresh baseline if the figure is still floating. */
.act-subhead {
  clear: right;
}

/* Wide variant: a panel-width diagram that caps a section rather than
   floating alongside prose. It clears any prior floats and spans the
   full column width with its caption beneath. */
.act-figure--wide {
  float: none;
  clear: both;
  width: 100%;
  max-width: none;
  margin: 1.2rem 0 0.4rem;
  padding: 0;
  shape-outside: none;
}
.act-figure--wide img {
  width: 100%;
  max-height: 60vh;
  object-fit: contain;
  background: #06090f;
  padding: 0.6rem;
}
.act-figure--wide figcaption {
  text-align: left;
  margin-top: 0.55rem;
  font-family: var(--serif);
  font-size: 0.78rem;
  font-style: italic;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-dim);
}
.act-figure--wide figcaption a {
  color: var(--economist-red);
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
}
.act-figure--wide figcaption a:hover {
  color: #ff7a5c;
}

@media (max-width: 640px) {
  .act-figure {
    float: none;
    width: 100%;
    margin: 0.9rem 0;
  }
  .act-figure figcaption {
    text-align: left;
  }
}

/* ---------- Scene 1.5: Pinned gallery ----------
   Split layout parked against the viewport while the reader scrolls
   through the scene's range. The stage (rocket/cluster) is muted during
   this moment via `body.stage-muted`, set by the scene controller. */

.scene-gallery {
  /* Tall enough that the sticky inner pins for roughly one extra viewport
     of scroll beyond its own 100vh — enough dwell for the four images to
     cycle without dragging. Shrinks on narrow screens where the sticky
     releases and the grid flows normally. */
  min-height: 220vh;
  pointer-events: auto;
  padding: 0;
}
.gallery-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(2rem, 6vh, 5rem) clamp(1.2rem, 4vw, 3rem);
  box-sizing: border-box;
  pointer-events: auto;
}
.gallery-split {
  width: 100%;
  max-width: 1280px;
  display: grid;
  grid-template-columns: minmax(260px, 34%) 1fr;
  gap: clamp(1.5rem, 3vw, 3rem);
  align-items: center;
}
.gallery-text {
  position: relative;
  padding: 1.4rem 1.3rem 1.4rem 1.6rem;
  background: rgba(7, 14, 34, 0.72);
  border-left: 3px solid var(--economist-red);
  border-radius: 2px;
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 28px 70px -30px rgba(0, 0, 0, 0.8);
}
.gallery-kicker {
  margin: 0 0 0.5rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
}
.gallery-heading {
  margin: 0 0 0.65rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.15rem, 1.7vw, 1.5rem);
  line-height: 1.15;
  letter-spacing: -0.008em;
  color: #fafbfc;
  text-wrap: balance;
}
.gallery-body {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(0.92rem, 1.1vw, 1.02rem);
  line-height: 1.6;
  color: var(--ink);
}
.gallery-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: clamp(0.6rem, 1.1vw, 1rem);
}
.gallery-cell {
  margin: 0;
}
.gallery-figure {
  position: relative;
  margin: 0;
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: 4px;
  border: 1px solid var(--rule-strong);
  background: #0a0e1a;
  opacity: 0.48;
  transform: translateY(10px) scale(0.985);
  transition:
    opacity 520ms var(--ease-out),
    transform 520ms var(--ease-out),
    box-shadow 520ms var(--ease-out),
    border-color 520ms var(--ease-out);
}
.gallery-cell.is-active .gallery-figure {
  opacity: 1;
  transform: translateY(0) scale(1);
  border-color: rgba(227, 18, 11, 0.75);
  box-shadow:
    0 26px 70px -28px rgba(0, 0, 0, 0.85),
    0 0 0 1px rgba(227, 18, 11, 0.55);
}
.gallery-figure img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 700ms var(--ease-out);
}
.gallery-cell.is-active .gallery-figure img {
  transform: scale(1.03);
}
.gallery-caption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 0.55rem 0.8rem 0.5rem;
  background: linear-gradient(
    to top,
    rgba(0, 0, 0, 0.85) 0%,
    rgba(0, 0, 0, 0.55) 60%,
    rgba(0, 0, 0, 0) 100%
  );
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #fafbfc;
}

@media (max-width: 860px) {
  .scene-gallery {
    min-height: auto;
  }
  .gallery-sticky {
    position: relative;
    height: auto;
    padding: clamp(1.5rem, 6vh, 3rem) clamp(1rem, 4vw, 2rem);
  }
  .gallery-split {
    grid-template-columns: 1fr;
    gap: 1.2rem;
  }
  .gallery-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Reduced-motion users read linearly — release the sticky pin, show all
   images at full opacity, and let the gallery flow as a normal block. */
.reduced-motion .gallery-sticky {
  position: relative;
  height: auto;
}
.reduced-motion .gallery-figure {
  opacity: 1;
  transform: none;
}

/* Stage mute: while the gallery's sticky panel is pinned in the viewport,
   fade the cluster out so the image grid carries the frame. Stars and sky
   stay on — they're the cosmos backdrop the images sit in front of. The
   rocket is already gone by this point (faded permanently in stage.js),
   so only the cluster needs muting here — and only the cluster comes
   back when the pin releases. */
body.stage-muted .cluster {
  opacity: 0 !important;
  transition: opacity 360ms var(--ease-out);
}

/* ---------- Scene 2: Actors (briefing-card format) ---------- */

.actors {
  margin-top: 0.8rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.8rem;
  row-gap: 1rem;
}
.actor-card {
  position: relative;
  padding: 0.7rem 0 0.3rem;
  border-top: 1px solid var(--rule-strong);
  background: transparent;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 520ms var(--ease-out),
    transform 580ms var(--ease-out);
  transition-delay: calc(var(--actor-delay, 0) * 80ms);
}
.actor-card.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.actor-card-head {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  margin-bottom: 0.25rem;
}
/* Actor code becomes a small-caps byline-style country tag */
.actor-code {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.7rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--economist-red);
  padding: 0;
  border: 0;
  background: none;
}
.actor-name {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.2rem;
  margin: 0;
  letter-spacing: -0.008em;
  color: #fafbfc;
}
.actor-stance {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: 0.96rem;
  color: var(--ink);
  margin: 0.15rem 0 0.55rem;
  line-height: 1.3;
}
.actor-projects {
  list-style: none;
  margin: 0.35rem 0 0.55rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}
.actor-projects li {
  font-family: var(--serif);
  font-size: 0.9rem;
  line-height: 1.35;
  color: var(--ink);
  padding-left: 1rem;
  position: relative;
}
.actor-projects li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 0.55rem;
  height: 1px;
  background: var(--economist-red);
}
.actor-wants-label {
  margin: 0.45rem 0 0.2rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.actor-wants {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--ink);
}

@media (max-width: 720px) {
  .actors { grid-template-columns: 1fr; }
}

/* ---------- Scene 3: Governance ---------- */

/* Treaties form a timeline-like inline list with year in red. */
.treaties {
  list-style: none;
  margin: 0.8rem 0 1rem;
  padding: 0.7rem 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 1.4rem;
  border-top: 1px solid var(--rule-strong);
  border-bottom: 1px solid var(--rule-strong);
}
.treaty {
  display: inline-flex;
  align-items: baseline;
  gap: 0.45rem;
  font-family: var(--serif);
  font-size: 0.98rem;
  color: var(--ink);
}
.treaty-year {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  color: var(--economist-red);
}
.treaty-name {
  color: var(--ink);
}

.gaps {
  margin-top: 0.4rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.8rem;
  row-gap: 0.8rem;
}
.gap-card {
  position: relative;
  padding: 0.7rem 0 0.15rem;
  border-top: 1px solid var(--rule-strong);
  background: transparent;
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 480ms var(--ease-out), transform 520ms var(--ease-out);
  transition-delay: calc(var(--gap-delay, 0) * 80ms);
}
.gap-card.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.gap-crack { display: none; }
.gap-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.05rem;
  letter-spacing: -0.005em;
  color: #fafbfc;
  margin: 0 0 0.3rem;
}
.gap-body {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--ink);
}
/* Governance closer — the "kicker paragraph" of the section. Ranged right
   with a thin rule above, set italic. */
.governance-closer {
  margin: 1.1rem 0 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1.1rem, 1.6vw, 1.4rem);
  line-height: 1.35;
  color: #fafbfc;
  max-width: 52ch;
  text-wrap: balance;
  border-top: 1px solid var(--rule-strong);
  padding-top: 0.9rem;
  position: relative;
}
.governance-closer::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 3rem;
  height: 2px;
  background: var(--economist-red);
}

@media (max-width: 720px) {
  .gaps { grid-template-columns: 1fr; }
}

/* ---------- Scene 4: Futures ---------- */

/* Numbered prose shifts that sit inside .act-article — shares the
   editorial voice of the act paragraphs but gets a counter rule so
   each shift reads as a distinct beat. */
.geo-shifts {
  counter-reset: shift;
  list-style: none;
  margin: 0.6rem 0 0.3rem;
  padding: 0;
}
.geo-shift {
  counter-increment: shift;
  position: relative;
  padding: 0.75rem 0 0.1rem 2.6rem;
  border-top: 1px solid var(--rule-strong);
  margin-top: 0.6rem;
}
.geo-shift:first-child {
  border-top: 0;
  margin-top: 0;
}
.geo-shift::before {
  content: counter(shift, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.85rem;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.05rem;
  color: var(--economist-red);
  font-feature-settings: "lnum";
}
.geo-shift-title {
  margin: 0 0 0.35rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1rem, 1.35vw, 1.14rem);
  line-height: 1.25;
  letter-spacing: -0.005em;
  color: #fafbfc;
}
.geo-shift-body {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(0.92rem, 1.1vw, 1.02rem);
  line-height: 1.62;
  color: var(--ink);
}
.geo-shift-indicator {
  margin: 0.75rem 0 0;
  padding: 0;
  border: 0;
  background: transparent;
  border-radius: 0;
  font-family: var(--serif);
  font-size: clamp(0.92rem, 1.1vw, 1.02rem);
  line-height: 1.62;
  font-style: normal;
  color: #fafbfc;
}

.scenarios {
  margin-top: 0.8rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  column-gap: 1.8rem;
  row-gap: 1rem;
  background: transparent;
  border: 0;
  border-radius: 0;
}
.scenario {
  position: relative;
  padding: 0.7rem 0 0.15rem;
  border-top: 1px solid var(--rule-strong);
  background: transparent;
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 520ms var(--ease-out),
    transform 580ms var(--ease-out);
  transition-delay: calc(var(--scenario-delay, 0) * 85ms);
}
.scenario.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.scenario-n {
  font-family: var(--serif);
  font-weight: 500;
  font-size: 1.2rem;
  letter-spacing: -0.01em;
  color: var(--economist-red);
  font-feature-settings: "lnum";
}
.scenario-title {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.08rem;
  margin: 0.15rem 0 0.35rem;
  line-height: 1.2;
  text-wrap: balance;
  letter-spacing: -0.005em;
  color: #fafbfc;
}
.scenario-body {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.92rem;
  line-height: 1.4;
  color: var(--ink);
}

.open-questions {
  margin-top: 1.1rem;
  padding: 0.9rem 0 0;
  border-top: 2px solid var(--economist-red);
  background: transparent;
}
.oq-heading {
  font-family: var(--serif);
  font-weight: 600;
  font-size: 1.15rem;
  letter-spacing: -0.008em;
  color: #fafbfc;
  margin: 0 0 0.5rem;
}
.oq-list {
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: oq;
}
.oq-item {
  counter-increment: oq;
  position: relative;
  padding: 0.4rem 0 0.5rem 2.4rem;
  border-top: 1px solid var(--rule);
  font-family: var(--serif);
  font-size: 0.94rem;
  line-height: 1.4;
  color: var(--ink);
}
.oq-item:first-child {
  border-top: 0;
}
.oq-item::before {
  content: counter(oq, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.5rem;
  font-family: var(--serif);
  font-weight: 500;
  font-size: 0.95rem;
  color: var(--economist-red);
  font-feature-settings: "lnum";
}

.closer {
  margin-top: 1.2rem;
  padding-top: 0.9rem;
  border-top: 1px solid var(--rule-strong);
  position: relative;
}
.closer::before {
  content: "";
  position: absolute;
  left: 0;
  top: -1px;
  width: 3rem;
  height: 2px;
  background: var(--economist-red);
}
.closer-line {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.3rem, 2.2vw, 1.9rem);
  line-height: 1.15;
  letter-spacing: -0.012em;
  margin: 0;
  text-wrap: balance;
  color: #fafbfc;
}
.closer-cta {
  font-family: var(--serif);
  font-style: italic;
  font-weight: 400;
  font-size: clamp(1rem, 1.5vw, 1.3rem);
  color: var(--economist-red);
  margin: 0.25rem 0 0;
}
.colophon {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin: 0;
}

@media (max-width: 720px) {
  .scenarios { grid-template-columns: 1fr; }
}

/* ============================================================
   Act II — Orbital-compute ecosystems infomedia
   Lean 3-column briefing. No heavy backgrounds; hairline rules
   and compact type keep it reading as part of the article.
   ============================================================ */

.orbital-map {
  margin: 1.6rem 0 0.4rem;
  padding: 0;
  background: transparent;
}
.map-head {
  margin: 0 0 0.8rem;
  padding-bottom: 0.6rem;
  border-bottom: 1px solid var(--rule-strong);
}
.map-kicker {
  margin: 0 0 0.25rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
}
.map-heading {
  margin: 0 0 0.3rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.1rem, 1.6vw, 1.35rem);
  letter-spacing: -0.008em;
  color: #fafbfc;
  line-height: 1.15;
}
.map-sub {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--ink-muted);
}
.map-grid {
  margin-top: 0.2rem;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* 5 rows per card: accent bar · header · approach · public block · private block.
     row-gap is inherited by the subgrid children so all columns stay in sync. */
  grid-auto-rows: auto;
  row-gap: 0.5rem;
  column-gap: 0;
  border-top: 1px solid var(--rule);
}
.region-card {
  /* Span all 6 implicit rows: accent · header · stance · approach · public · private */
  grid-row: span 6;
  display: grid;
  grid-template-rows: subgrid;
  align-content: start;
  padding: 0.7rem 0.9rem 0.8rem;
  border-right: 1px solid var(--rule);
  background: transparent;
}
.region-card:last-child {
  border-right: 0;
}
.region-card::before {
  content: "";
  display: block;
  width: 1.6rem;
  height: 2px;
  background: var(--economist-red);
  align-self: end;
  margin-bottom: 0;
}
.region-head {
  display: flex;
  flex-wrap: nowrap;
  align-items: baseline;
  gap: 0.4rem;
  padding-bottom: 0.2rem;
  /* no border here — the stance row carries the separator */
  align-self: end;
}
.region-code {
  font-family: var(--mono);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  color: var(--economist-red);
}
.region-name {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: -0.006em;
  color: #fafbfc;
  flex: 1 0 auto;
}
.region-stance {
  margin: 0;
  padding-bottom: 0.35rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.56rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-muted);
  align-self: start;
}
.region-approach {
  margin: 0 0 0.15rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.82rem;
  line-height: 1.42;
  color: var(--ink);
}
.region-block {
  padding-top: 0.2rem;
}
.region-label {
  margin: 0 0 0.2rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.54rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.region-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.12rem;
}
.region-list li {
  position: relative;
  padding-left: 0.7rem;
  font-family: var(--serif);
  font-size: 0.78rem;
  line-height: 1.35;
  color: var(--ink);
}
.region-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.58em;
  width: 0.35rem;
  height: 1px;
  background: var(--economist-red);
}

@media (max-width: 720px) {
  .map-grid {
    grid-template-columns: 1fr;
    /* On mobile each card stacks vertically; drop the shared row tracks */
    grid-auto-rows: auto;
    row-gap: 0;
    border-top: 0;
  }
  .region-card {
    grid-row: auto;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    border-right: 0;
    border-top: 1px solid var(--rule);
    padding-left: 0;
    padding-right: 0;
  }
  .region-card:first-child { border-top: 0; }
  .region-head { align-self: auto; }
}

/* ============================================================
   Act III — Governance matrix
   Flat briefing rows with a severity left-rule. No heavy cards.
   Reads as a structured table, not a grid of tiles.
   ============================================================ */

.gov-matrix {
  margin: 1.4rem 0 0.4rem;
}
.matrix-head {
  margin-bottom: 0.9rem;
  padding-bottom: 0.7rem;
  border-bottom: 1px solid var(--rule-strong);
}
.matrix-kicker {
  margin: 0 0 0.25rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
}
.matrix-heading {
  margin: 0 0 0.3rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1.1rem, 1.6vw, 1.35rem);
  letter-spacing: -0.008em;
  color: #fafbfc;
  line-height: 1.15;
  text-wrap: balance;
}
.matrix-sub {
  margin: 0 0 0.55rem;
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.82rem;
  line-height: 1.45;
  color: var(--ink-muted);
}
.matrix-legend {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.6rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.matrix-legend li {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}
.sev-dot {
  display: inline-block;
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
}
.sev-dot--critical { background: #ff4a3a; }
.sev-dot--significant { background: #f0a53a; }

.gov-group {
  margin-top: 1rem;
}
.gov-group-label {
  margin: 0 0 0.4rem;
  padding-bottom: 0.25rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: #fafbfc;
  border-bottom: 1px solid var(--rule);
}
.gov-grid {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.treaty-card {
  position: relative;
  padding: 0.65rem 0.8rem 0.7rem 0.9rem;
  border-top: 1px solid var(--rule);
  border-left: 3px solid var(--rule-strong);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr);
  column-gap: 1.2rem;
  row-gap: 0.35rem;
  background: transparent;
}
.treaty-card:first-child { border-top: 0; }
.treaty-card[data-severity="critical"] { border-left-color: #ff4a3a; }
.treaty-card[data-severity="significant"] { border-left-color: #f0a53a; }

.tc-head {
  grid-column: 1;
  grid-row: 1 / span 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.15rem;
  padding-right: 0.4rem;
  border-right: 1px solid var(--rule);
}
.tc-name {
  margin: 0;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 0.92rem;
  letter-spacing: -0.004em;
  color: #fafbfc;
  line-height: 1.2;
}
.tc-meta {
  font-family: var(--sans);
  font-size: 0.6rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
}
.tc-severity {
  margin-top: 0.15rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.54rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 0.12rem 0.4rem;
  border-radius: 2px;
  white-space: nowrap;
}
.treaty-card[data-severity="critical"] .tc-severity {
  background: rgba(255, 74, 58, 0.12);
  color: #ff6f61;
}
.treaty-card[data-severity="critical"] .tc-severity::before {
  content: "● Critical";
}
.treaty-card[data-severity="significant"] .tc-severity {
  background: rgba(240, 165, 58, 0.1);
  color: #f2b66a;
}
.treaty-card[data-severity="significant"] .tc-severity::before {
  content: "▲ Significant";
}

.tc-body {
  grid-column: 2;
  grid-row: 1;
  margin: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: 0.6rem;
  row-gap: 0.2rem;
}
.tc-body dt {
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.5rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-muted);
  padding-top: 0.15rem;
}
.tc-body dd {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.8rem;
  line-height: 1.4;
  color: var(--ink);
}

.tc-gaps {
  grid-column: 2;
  grid-row: 2;
  padding-top: 0.35rem;
  border-top: 1px dashed var(--rule);
}
.tc-gaps-label {
  margin: 0 0 0.2rem;
  font-family: var(--sans);
  font-weight: 700;
  font-size: 0.5rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--economist-red);
}
.tc-gaps-list {
  margin: 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.tc-gaps-list li {
  position: relative;
  padding-left: 0.85rem;
  font-family: var(--serif);
  font-size: 0.78rem;
  line-height: 1.38;
  color: var(--ink);
}
.tc-gaps-list li::before {
  content: "→";
  position: absolute;
  left: 0;
  top: -0.04em;
  color: var(--economist-red);
  font-weight: 700;
  font-size: 0.78rem;
}

.matrix-note {
  margin: 1.2rem 0 0.2rem;
  padding: 0.6rem 0.85rem;
  border-left: 2px solid var(--economist-red);
  font-family: var(--serif);
  font-size: 0.78rem;
  font-style: italic;
  line-height: 1.48;
  color: var(--ink-muted);
}

@media (max-width: 720px) {
  .treaty-card {
    grid-template-columns: 1fr;
  }
  .tc-head {
    grid-row: auto;
    border-right: 0;
    padding-right: 0;
    padding-bottom: 0.3rem;
    border-bottom: 1px solid var(--rule);
    flex-direction: row;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.5rem;
  }
  .tc-body, .tc-gaps { grid-column: 1; }
  .tc-body { grid-template-columns: 1fr; }
  .tc-body dt { padding-top: 0.35rem; }
}

/* ---------- Scene 4.5: Upcoming developments timeline ----------
   Pinned full-screen chart between Act IV and the closer. Same sticky
   pattern as the gallery — the cluster is muted while the chart is
   pinned, so the timeline owns the screen edge to edge. */

.scene-timeline {
  /* Tall enough for a comfortable sticky dwell, but not so tall that
     the cards below feel detached from the chart above. */
  min-height: 170vh;
  pointer-events: auto;
  padding: 0;
}
/* Pull the futures scene's bottom padding in so the timeline sits
   close to the end of Act IV rather than after a tall gap. */
.scene-futures .scene-inner {
  padding-bottom: clamp(0.5rem, 1.5vh, 1.5rem);
}
.timeline-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
  /* Anchor near the top so the heading sits right under where the
     previous section ends, rather than floating in the middle of the
     viewport. */
  justify-content: flex-start;
  padding: clamp(1.2rem, 3.5vh, 2.4rem) clamp(1.5rem, 4vw, 3.5rem) clamp(2rem, 5vh, 4rem);
  gap: clamp(0.9rem, 2vh, 1.4rem);
}
.timeline-head {
  max-width: 78rem;
  margin: 0 auto;
  width: 100%;
}
.timeline-kicker {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
  margin: 0 0 0.4rem;
}
.timeline-heading {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.6rem, 3.2vw, 2.4rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: #fafbfc;
  margin: 0;
  border-bottom: 2px solid var(--economist-red);
  padding-bottom: 0.55rem;
  max-width: 28ch;
}
.timeline-chart {
  position: relative;
  width: 100%;
  max-width: 88rem;
  margin: 0 auto;
  display: grid;
  grid-template-rows: auto 1fr auto;
  row-gap: 0.6rem;
}
.timeline-band-label {
  font-family: var(--mono);
  font-size: 0.72rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(220, 230, 255, 0.55);
  margin: 0;
}
.timeline-band-top { justify-self: start; }
.timeline-band-bottom { justify-self: start; }

.timeline-grid {
  position: relative;
  width: 100%;
}
.tl-columns {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(var(--n, 8), minmax(0, 1fr));
  align-items: stretch;
  position: relative;
}
/* The horizontal axis line — drawn through the year labels. */
.tl-columns::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(220, 230, 255, 0.28);
  transform: translateY(-0.5px);
}
.tl-column {
  grid-column: var(--col, auto);
  display: grid;
  grid-template-rows: 1fr auto 1fr;
  align-items: stretch;
  padding: 0 clamp(0.35rem, 0.9vw, 0.85rem);
  position: relative;
}
.tl-stack {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  font-family: var(--serif);
  font-size: clamp(0.72rem, 0.85vw, 0.84rem);
  line-height: 1.28;
  color: var(--ink);
}
.tl-stack--top {
  justify-content: flex-end;
  padding-bottom: 0.7rem;
}
.tl-stack--bottom {
  justify-content: flex-start;
  padding-top: 0.7rem;
  font-style: italic;
}
.tl-event {
  position: relative;
}
.tl-event.is-red {
  color: var(--economist-red);
}
/* AI / orbital data-centre milestones — picked out with a cyan accent
   so the reader can scan the chart for the AI thread without losing
   the broader space context. Kept lightweight (no border, just a
   small inline tag) so it doesn't widen the column or overlap the
   neighbouring stack. */
.tl-event.is-ai {
  color: #d8f7fa;
}
.tl-event.is-ai .tl-event-text::before {
  content: "AI · ";
  font-family: var(--mono);
  font-size: 0.7em;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: #7df9ff;
  margin-right: 0.2em;
  font-weight: 500;
}
.tl-event.is-ai.is-red {
  color: var(--economist-red);
}
.tl-event-text {
  display: block;
}
/* One dashed connector per column — runs vertically through the centre,
   crossing the axis where the year label sits. */
.tl-column::before,
.tl-column::after {
  content: "";
  position: absolute;
  left: 50%;
  width: 1px;
  border-left: 1px dashed rgba(220, 230, 255, 0.32);
  transform: translateX(-0.5px);
  z-index: 0;
}
.tl-column::before { top: 0; bottom: 50%; }
.tl-column::after { top: 50%; bottom: 0; }
.tl-column.is-empty-top::before,
.tl-column.is-empty-bottom::after { display: none; }
.tl-column[data-highlight-year]::before,
.tl-column[data-highlight-year]::after {
  border-left-color: rgba(227, 18, 11, 0.55);
}
.tl-year {
  font-family: var(--serif);
  font-weight: 600;
  font-size: clamp(1rem, 1.5vw, 1.3rem);
  letter-spacing: -0.01em;
  color: #fafbfc;
  margin: 0;
  text-align: center;
  padding: 0.25rem 0.4rem;
  position: relative;
  z-index: 2;
  /* Match the panel backdrop so the year label cleanly breaks the dashed
     connector and the axis line where it sits. */
  background: var(--sky-bottom, #050a1a);
}
.tl-year.is-red { color: var(--economist-red); }

/* Narrow viewports keep the horizontal chart but let it scroll
   horizontally — the chart's visual identity stays intact, the
   reader pans through years instead of seeing a vertical list. */
@media (max-width: 760px) {
  .scene-timeline { min-height: auto; }
  .timeline-sticky {
    position: relative;
    height: auto;
    padding: clamp(1.5rem, 4vh, 2.5rem) 0;
    gap: clamp(0.6rem, 1.5vh, 1rem);
  }
  .timeline-head {
    padding: 0 clamp(1rem, 4vw, 2rem);
  }
  .timeline-chart {
    padding: 0 clamp(1rem, 4vw, 2rem);
    /* The grid scrolls underneath, but band labels and chart
       structure stay aligned with the article's gutter. */
  }
  .timeline-grid {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    /* Hairline scroll cue so the reader sees the chart is
       scrollable without a heavy native scrollbar. */
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, 0.18) transparent;
    /* Edge fade hints that more chart sits beyond the right edge. */
    -webkit-mask-image: linear-gradient(to right,
      transparent 0,
      #000 1.5rem,
      #000 calc(100% - 1.5rem),
      transparent 100%);
    mask-image: linear-gradient(to right,
      transparent 0,
      #000 1.5rem,
      #000 calc(100% - 1.5rem),
      transparent 100%);
  }
  .timeline-grid::-webkit-scrollbar { height: 6px; }
  .timeline-grid::-webkit-scrollbar-thumb {
    background: rgba(255, 255, 255, 0.18);
    border-radius: 3px;
  }
  .tl-columns {
    /* Force a readable column width; container scrolls horizontally
       to reveal the rest. ~720px = 8 columns × ~90px each. */
    min-width: 720px;
    width: max-content;
  }
  .tl-stack {
    font-size: clamp(0.66rem, 1.6vw, 0.78rem);
    line-height: 1.25;
    gap: 0.4rem;
  }
  .tl-year { font-size: clamp(0.92rem, 2.6vw, 1.1rem); }
  .timeline-heading { font-size: clamp(1.25rem, 5vw, 1.7rem); }
  .timeline-band-label { font-size: 0.62rem; letter-spacing: 0.18em; }
  .tl-column { padding: 0 clamp(0.3rem, 1vw, 0.6rem); }
  /* Hint text under the chart so users know the chart scrolls. */
  .timeline-chart::after {
    content: "Scroll the chart sideways →";
    display: block;
    font-family: var(--mono);
    font-size: 0.6rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: rgba(220, 230, 255, 0.45);
    margin-top: 0.6rem;
    padding: 0 clamp(1rem, 4vw, 2rem);
  }
}
.reduced-motion .timeline-sticky {
  position: relative;
  height: auto;
}

/* Stage mute: while a pinned panel (gallery or timeline) is in view,
   fade the cluster out so the panel carries the frame. The rocket is
   already permanently faded by stage.js earlier in the scroll. */
body.stage-muted .cluster {
  opacity: 0 !important;
  transition: opacity 360ms var(--ease-out);
}

/* ---------- Scene 4.75: Open Questions (3x2 flip cards) ---------- */

/* Pull the cards up close under the timeline AND drop the inherited
   sticky 100vh — the cards are short, so without this the scene
   leaves a viewport of empty starfield below them before the closer.*/
.scene-openq .scene-inner {
  position: static;
  min-height: 0;
  padding-top: clamp(0.5rem, 1.5vh, 1.5rem) !important;
  padding-bottom: clamp(2rem, 4vh, 3rem) !important;
}
.oq-hint {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(220, 230, 255, 0.55);
  margin: 0.9rem 0 0;
}
.oq-grid {
  list-style: none;
  margin: clamp(1.2rem, 3vh, 2rem) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: clamp(0.8rem, 1.5vw, 1.4rem);
  perspective: 1400px;
  max-width: 78ch !important;
}
.oq-card {
  position: relative;
  aspect-ratio: 4 / 3;
}
.oq-flipper {
  position: relative;
  width: 100%;
  height: 100%;
  background: transparent;
  border: 0;
  padding: 0;
  margin: 0;
  cursor: pointer;
  text-align: left;
  font: inherit;
  color: inherit;
  transform-style: preserve-3d;
  transition: transform 620ms var(--ease-out);
}
.oq-flipper:focus-visible {
  outline: 2px solid var(--economist-red);
  outline-offset: 4px;
}
.oq-flipper.is-flipped {
  transform: rotateY(180deg);
}
.oq-face {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  padding: clamp(0.9rem, 1.6vw, 1.3rem);
  border: 1px solid var(--rule-strong);
  background: rgba(7, 14, 34, 0.78);
  backdrop-filter: blur(10px);
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  border-radius: 4px;
  overflow: hidden;
  transition: background 320ms var(--ease-out), border-color 320ms var(--ease-out);
}
.oq-face--front {
  justify-content: space-between;
  border-left: 3px solid var(--economist-red);
}
.oq-flipper:hover .oq-face--front {
  background: rgba(13, 22, 48, 0.88);
  border-color: rgba(227, 18, 11, 0.55);
}
.oq-face--back {
  transform: rotateY(180deg);
  gap: 0.6rem;
  overflow-y: auto;
  background: rgba(11, 18, 38, 0.92);
}
.oq-corner {
  font-family: var(--mono);
  font-size: 1rem;
  color: var(--economist-red);
  align-self: flex-end;
  opacity: 0.75;
}
.oq-title {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.05rem, 1.7vw, 1.4rem);
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: #fafbfc;
  display: block;
}
.oq-cue {
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(220, 230, 255, 0.5);
  display: block;
}
.oq-question {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(0.92rem, 1.2vw, 1.05rem);
  line-height: 1.3;
  color: #fafbfc;
  display: block;
}
.oq-body {
  font-family: var(--serif);
  font-size: clamp(0.78rem, 0.95vw, 0.9rem);
  line-height: 1.45;
  color: var(--ink);
  display: block;
}
@media (max-width: 900px) {
  .oq-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 600px) {
  .oq-grid { grid-template-columns: 1fr; }
  .oq-card { aspect-ratio: 3 / 2; }
}
.reduced-motion .oq-card { aspect-ratio: auto; height: auto; }
.reduced-motion .oq-flipper {
  transform: none !important;
  transform-style: flat;
  height: auto;
}
.reduced-motion .oq-face {
  position: relative;
  inset: auto;
  backface-visibility: visible;
}
.reduced-motion .oq-face--back {
  transform: none;
  margin-top: 0.6rem;
}
.reduced-motion .oq-cue { display: none; }

/* The closer scene is a quiet outro. Default scene-inner is sticky
   with min-height 100vh which leaves a full viewport of starfield
   below the closing line — drop those defaults so the page actually
   ends right after the closer text.
   !important is needed because .scene:not(.scene-liftoff) .scene-inner
   has higher specificity than this selector. */
.scene-closer .scene-inner {
  position: static;
  min-height: 0;
  padding-top: clamp(2rem, 6vh, 4rem) !important;
  padding-bottom: 0 !important;
}
.scene-closer {
  /* Reset any inherited margin/padding on the section element too. */
  padding: 0 !important;
  margin: 0 !important;
}
/* Last child of body — make sure the document ends here. */
.scene-closer:last-of-type::after {
  content: none;
}

/* ---------- Scene 3.5: Regulation network (the severed web) ----------
   Two clusters of frameworks either side of a chasm. Solid edges are
   the formal ties that exist; ghost edges are the bridges that don't.
   Driven by `data-beat` on .regnet-frame; CSS handles the rest. */

.scene-regnet {
  /* Five reading beats while pinned. Total scroll ~360vh gives the
     reader ~52vh per beat once the panel pins — about half a viewport
     of scrolling before each beat advances, which is enough time to
     read the chasm labels at the end without rushing. */
  min-height: 360vh;
  pointer-events: auto;
  /* Padding-bottom creates a brief calm after the network unsticks
     and before Act IV begins, so the closer reads as a verdict
     rather than crashing into the next heading. */
  padding: 0 0 clamp(4rem, 10vh, 8rem);
}
.regnet-sticky {
  position: sticky;
  top: 0;
  height: 100vh;
  display: grid;
  grid-template-rows: auto auto auto;
  align-content: start;
  gap: clamp(0.6rem, 1.2vh, 1rem);
  padding: clamp(1.2rem, 3vh, 2rem) clamp(1.5rem, 4vw, 3rem) clamp(1.2rem, 3vh, 2rem);
}
.regnet-head {
  max-width: 86rem;
  width: 100%;
  margin: 0 auto;
}
.regnet-kicker {
  font-family: var(--mono);
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
  margin: 0 0 0.4rem;
}
.regnet-heading {
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.5rem, 2.8vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.015em;
  color: #fafbfc;
  margin: 0;
  border-bottom: 2px solid var(--economist-red);
  padding-bottom: 0.5rem;
  max-width: 28ch;
}
.regnet-lede {
  margin: 0.7rem 0 0;
  font-family: var(--serif);
  font-size: clamp(0.92rem, 1.1vw, 1rem);
  line-height: 1.5;
  color: var(--ink);
  max-width: 70ch;
}

.regnet-frame {
  position: relative;
  width: 100%;
  max-width: 96rem;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  /* Reserve space at the top for the absolutely-positioned cluster
     labels so they don't overlap the SVG content. */
  padding-top: 3rem;
}
.regnet-cluster-label {
  position: absolute;
  top: clamp(0.4rem, 0.8vh, 0.8rem);
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  margin: 0;
  pointer-events: none;
  z-index: 4;
}
.regnet-cluster-label--space { left: clamp(0.5rem, 2vw, 2rem); }
.regnet-cluster-label--ai { right: clamp(0.5rem, 2vw, 2rem); text-align: right; align-items: flex-end; }
.rn-cluster-name {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(220, 230, 255, 0.7);
}
.rn-cluster-sub {
  font-family: var(--serif);
  font-style: italic;
  font-size: 0.78rem;
  line-height: 1.3;
  color: rgba(220, 230, 255, 0.55);
  max-width: 28ch;
}

/* Wrap that anchors the stage and the absolutely-positioned tooltip. */
.regnet-stage-wrap {
  position: relative;
  width: 100%;
  /* Clamped so the SVG doesn't fill enormous heights on tall viewports
     and crowd the closer underneath. */
  height: clamp(360px, 56vh, 640px);
}
.regnet-stage {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}
.regnet-svg {
  width: 100%;
  height: 100%;
  display: block;
  filter: drop-shadow(0 0 16px rgba(0, 0, 0, 0.55));
}

/* Chasm column wash — quiet vertical tint, no border. */
.rn-chasm-bg {
  fill: rgba(227, 18, 11, 0.05);
  stroke: none;
}

/* ---- Nodes ---- */
.rn-node {
  cursor: pointer;
  outline: none;
}
.rn-node:focus-visible .rn-node-dot {
  stroke: var(--economist-red);
  stroke-width: 3;
}
.rn-node-hit {
  fill: transparent;
  pointer-events: all;
}
.rn-node:hover .rn-node-dot {
  fill: rgba(227, 18, 11, 0.22);
  stroke: var(--economist-red);
}
.rn-node--ai:hover .rn-node-dot {
  fill: rgba(125, 249, 255, 0.18);
  stroke: #7df9ff;
}
.rn-node-dot {
  fill: rgba(7, 14, 34, 0.9);
  stroke: rgba(220, 230, 255, 0.55);
  stroke-width: 1.5;
  transition: fill 360ms var(--ease-out), stroke 360ms var(--ease-out), opacity 360ms var(--ease-out);
}
.rn-node--space.is-anchor .rn-node-dot {
  stroke: var(--economist-red);
  stroke-width: 2.5;
  fill: rgba(227, 18, 11, 0.18);
}
.rn-node--ai.is-anchor .rn-node-dot {
  stroke: #7df9ff;
  stroke-width: 2.5;
  fill: rgba(125, 249, 255, 0.14);
}
.rn-node.is-soft .rn-node-dot {
  stroke-dasharray: 3 3;
}
.rn-node-label {
  font-family: var(--serif);
  font-size: 13px;
  font-weight: 500;
  fill: #fafbfc;
  paint-order: stroke;
  stroke: rgba(7, 14, 34, 0.85);
  stroke-width: 4;
  stroke-linejoin: round;
  pointer-events: none;
}
.rn-node-year {
  font-family: var(--mono);
  font-size: 10px;
  letter-spacing: 0.08em;
  fill: rgba(220, 230, 255, 0.6);
  pointer-events: none;
}
.rn-node--space.is-anchor .rn-node-label,
.rn-node--ai.is-anchor .rn-node-label {
  font-size: 15px;
  font-weight: 600;
}

/* ---- Cluster edges ---- */
.rn-edge {
  stroke-width: 1.4;
  fill: none;
  transition: opacity 360ms var(--ease-out);
}
.rn-edge--space { stroke: rgba(227, 18, 11, 0.55); }
.rn-edge--ai { stroke: rgba(125, 249, 255, 0.45); }
.rn-edge.is-soft { stroke-dasharray: 5 5; opacity: 0.65; }
.rn-edge.is-weak { opacity: 0.38; }

/* ---- Ghost edges (the bridges that don't bind) ---- */
.rn-ghost {
  stroke: rgba(227, 18, 11, 0.32);
  stroke-width: 1;
  stroke-dasharray: 3 6;
  fill: none;
  opacity: 0.18;
  transition: opacity 480ms var(--ease-out), stroke 480ms var(--ease-out);
}

/* ---- Chasm labels ---- */
/* The whole row (markers + text) animates together. Hidden by default,
   surfaces faintly at beat 4 (when bridges fail), full strength at
   beat 5. Each row is staggered so they cascade in. */
.rn-chasm-row {
  opacity: 0;
  transition: opacity 700ms var(--ease-out);
}
.rn-chasm-row:nth-child(1) { transition-delay: 0ms; }
.rn-chasm-row:nth-child(2) { transition-delay: 110ms; }
.rn-chasm-row:nth-child(3) { transition-delay: 220ms; }
.rn-chasm-row:nth-child(4) { transition-delay: 330ms; }
.rn-chasm-row:nth-child(5) { transition-delay: 440ms; }
.rn-chasm-label {
  font-family: var(--serif);
  font-style: italic;
  font-size: 17px;
  font-weight: 500;
  fill: #fafbfc;
  paint-order: stroke;
  stroke: rgba(7, 14, 34, 0.92);
  stroke-width: 4.5;
  stroke-linejoin: round;
}
.rn-chasm-marker {
  stroke: var(--economist-red);
  stroke-width: 1.5;
  stroke-linecap: round;
}
.rn-chasm-header {
  font-family: var(--mono);
  font-size: 11px;
  letter-spacing: 0.32em;
  text-transform: uppercase;
  fill: var(--economist-red);
  font-weight: 600;
  opacity: 0;
  transition: opacity 700ms var(--ease-out);
}
[data-beat="4"] .rn-chasm-header { opacity: 0.7; }
[data-beat="5"] .rn-chasm-header { opacity: 1; }
.reduced-motion .rn-chasm-header { opacity: 1; }

/* ---- Beat-driven highlights ---- */
/* Beat 1: both clusters dim, just establish the picture. */
[data-beat="1"] .rn-node,
[data-beat="1"] .rn-edge { opacity: 0.55; }
[data-beat="1"] .rn-ghost { opacity: 0; }
[data-beat="1"] .rn-chasm-row { opacity: 0; }

/* Beat 2: space cluster rises, AI dims further. */
[data-beat="2"] .rn-cluster--space .rn-node,
[data-beat="2"] .rn-cluster--space .rn-edge { opacity: 1; }
[data-beat="2"] .rn-cluster--ai .rn-node,
[data-beat="2"] .rn-cluster--ai .rn-edge { opacity: 0.22; }
[data-beat="2"] .rn-ghost { opacity: 0; }

/* Beat 3: AI cluster rises, space dims. */
[data-beat="3"] .rn-cluster--ai .rn-node,
[data-beat="3"] .rn-cluster--ai .rn-edge { opacity: 1; }
[data-beat="3"] .rn-cluster--space .rn-node,
[data-beat="3"] .rn-cluster--space .rn-edge { opacity: 0.22; }
[data-beat="3"] .rn-ghost { opacity: 0; }

/* Beat 4: both clusters visible, ghost edges flicker in red — the
   bridges being attempted, and not holding. */
[data-beat="4"] .rn-node,
[data-beat="4"] .rn-edge { opacity: 0.75; }
[data-beat="4"] .rn-ghost {
  opacity: 0.85;
  stroke: rgba(255, 60, 30, 0.9);
  animation: rn-ghost-flicker 2.4s var(--ease-out) 1;
}
@keyframes rn-ghost-flicker {
  0%   { opacity: 0; stroke-width: 0.5; }
  18%  { opacity: 1; stroke-width: 2; }
  35%  { opacity: 0.5; stroke-width: 1; }
  55%  { opacity: 1; stroke-width: 2.2; }
  75%  { opacity: 0.4; stroke-width: 1; }
  100% { opacity: 0.85; stroke-width: 1; }
}

/* Beat 4: ghost edges have failed; the chasm labels (the actual
   threats) start to surface in faint preview. */
[data-beat="4"] .rn-chasm-row { opacity: 0.55; }

/* Beat 5: ghost edges settle dim again; chasm labels are now the
   focal point — full strength, staggered cascade in. */
[data-beat="5"] .rn-node,
[data-beat="5"] .rn-edge { opacity: 0.55; }
[data-beat="5"] .rn-ghost {
  opacity: 0.32;
  stroke: rgba(227, 18, 11, 0.45);
}
[data-beat="5"] .rn-chasm-row { opacity: 1; }

/* Caption rail under the chart. */
.regnet-caption-rail {
  max-width: 86rem;
  width: 100%;
  margin: 0 auto;
  padding: 0 0.2rem;
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
}
.regnet-beat-label {
  font-family: var(--mono);
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--economist-red);
  margin: 0;
}
.regnet-caption {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(0.92rem, 1.15vw, 1.05rem);
  line-height: 1.45;
  color: #fafbfc;
  margin: 0;
  max-width: 78ch;
  min-height: 2.6em;
}
.regnet-closer {
  max-width: 60ch;
  /* Big breathing room either side so the closer reads as a
     standout pull-quote, not a caption. ~3–4cm of space above and
     below on typical screens. */
  margin: clamp(3.5rem, 8vh, 6rem) auto clamp(3.5rem, 8vh, 6rem);
  font-family: var(--serif);
  font-weight: 500;
  font-size: clamp(1.1rem, 1.8vw, 1.55rem);
  line-height: 1.35;
  color: #fafbfc;
  text-align: center;
  padding: clamp(3rem, 7vh, 5rem) 0 clamp(3rem, 7vh, 5rem);
  border-top: 1px solid rgba(255, 255, 255, 0.18);
  border-bottom: 1px solid rgba(255, 255, 255, 0.18);
  /* Hidden until the network has been walked through. The selector
     below ([data-beat="5"]) lifts it into view at the final beat. */
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 700ms var(--ease-out), transform 700ms var(--ease-out);
  pointer-events: none;
}
.regnet-sticky[data-beat="5"] .regnet-closer {
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
/* When the closer takes the screen, dim AND shrink the network so
   the verdict has room to breathe without overflowing the sticky
   panel. The closer block grows ~6–10rem of padding/margin combined
   either side; the stage gives up roughly that much height. */
.regnet-sticky[data-beat="5"] .regnet-stage-wrap {
  opacity: 0.35;
  height: clamp(160px, 26vh, 280px);
  transition: opacity 700ms var(--ease-out), height 700ms var(--ease-out);
}
/* Slightly trim the regnet head at beat 5 so the verdict has more
   room. The lede still reads but the chart isn't fighting for height. */
.regnet-sticky[data-beat="5"] .regnet-lede {
  opacity: 0.5;
}
.regnet-sticky[data-beat="5"] .regnet-caption {
  opacity: 0.55;
}
.regnet-sticky[data-beat="5"] .regnet-beat-label {
  opacity: 0.7;
}

/* Narrow viewports: collapse the network into a stacked summary so
   the editorial point survives without the SVG geometry. */
@media (max-width: 980px) {
  .scene-regnet { min-height: auto; }
  .regnet-sticky {
    position: relative;
    height: auto;
    grid-template-rows: auto auto auto;
  }
  .regnet-frame { min-height: 80vh; }
  .rn-chasm-label { font-size: 11px; }
  .rn-node-label { font-size: 11px; }
  .rn-node-year { font-size: 9px; }
  .regnet-cluster-label--ai .rn-cluster-sub,
  .regnet-cluster-label--space .rn-cluster-sub { display: none; }
}

.reduced-motion .regnet-sticky {
  position: relative;
  height: auto;
}
.reduced-motion .rn-ghost { opacity: 0.3; animation: none; }
.reduced-motion .rn-chasm-row { opacity: 1; }
.reduced-motion .rn-node,
.reduced-motion .rn-edge { opacity: 1 !important; }

/* ---- Tooltip ----
   Hover/focus a node and a small panel surfaces with the analysis
   copy (relevance + gaps), positioned just above the node. */
.rn-tooltip {
  position: absolute;
  left: 0;
  top: 0;
  width: clamp(240px, 28vw, 340px);
  padding: 0.7rem 0.9rem 0.85rem;
  background: rgba(7, 14, 34, 0.96);
  border: 1px solid rgba(227, 18, 11, 0.6);
  border-left-width: 3px;
  border-radius: 4px;
  box-shadow: 0 18px 40px -16px rgba(0, 0, 0, 0.85);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
  z-index: 10;
}
.rn-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}
.rn-tooltip-name {
  margin: 0 0 0.15rem;
  font-family: var(--serif);
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.2;
  color: #fafbfc;
}
.rn-tooltip-meta {
  margin: 0 0 0.5rem;
  font-family: var(--mono);
  font-size: 0.62rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(220, 230, 255, 0.6);
}
.rn-tooltip-text {
  margin: 0;
  font-family: var(--serif);
  font-size: 0.84rem;
  line-height: 1.45;
  color: var(--ink);
}

/* ============================================================
   Adaptive layout for pinned panels
   ------------------------------------------------------------
   The vh-based sticky panels (gallery, regnet, timeline) work
   well around 900–1100px tall, but overflow on short viewports
   and stretch awkwardly on tall ones. The blocks below tune
   their heights and panel padding for short / medium / tall /
   ultra-wide screens. Stacked from shortest → tallest, then
   widest.
   ============================================================ */

/* ---- Short viewports (panels were overflowing 100vh) ----
   Triggers on landscape phones and short laptop windows.
   Sticky panels need less internal padding and the closer at
   regnet beat 5 needs to stay within 100vh. */
@media (max-height: 720px) {
  /* Gallery: shorter pin, tighter image grid. */
  .scene-gallery { min-height: 180vh; }
  .gallery-sticky {
    padding: clamp(0.8rem, 2vh, 1.4rem) clamp(1rem, 4vw, 2.5rem);
  }
  .gallery-text { padding: 1rem 1.1rem; }
  .gallery-figure { aspect-ratio: 16 / 11; }
  .gallery-heading { font-size: clamp(1.4rem, 3vw, 1.9rem); }
  .gallery-body { font-size: 0.86rem; line-height: 1.5; }

  /* Regnet: shorter pin, smaller chart, much tighter closer. */
  .scene-regnet { min-height: 320vh; }
  .regnet-sticky {
    padding: clamp(0.7rem, 2vh, 1.3rem) clamp(1rem, 3vw, 2rem);
  }
  .regnet-stage-wrap { height: clamp(260px, 42vh, 380px); }
  .regnet-frame { padding-top: 2.2rem; }
  .regnet-heading { font-size: clamp(1.25rem, 2.4vw, 1.7rem); }
  .regnet-lede { font-size: 0.86rem; line-height: 1.4; max-width: 60ch; }
  .regnet-sticky[data-beat="5"] .regnet-stage-wrap {
    height: clamp(120px, 20vh, 200px);
  }
  .regnet-closer {
    margin: clamp(1.2rem, 3vh, 2.2rem) auto;
    padding: clamp(1.2rem, 3vh, 2.2rem) 0;
    font-size: clamp(0.95rem, 1.7vw, 1.25rem);
    max-width: 56ch;
  }

  /* Timeline: shorter pin, leaner header. */
  .scene-timeline { min-height: 150vh; }
  .timeline-sticky {
    padding: clamp(0.7rem, 2vh, 1.2rem) clamp(1rem, 3vw, 2rem) clamp(1rem, 3vh, 2rem);
  }
  .timeline-heading { font-size: clamp(1.25rem, 2.4vw, 1.7rem); }
  .timeline-chart { row-gap: 0.4rem; }
}

/* ---- Medium-short viewports (721–900px tall) ----
   Light tuning so the regnet beat-5 closer doesn't push the
   chart off the bottom of the viewport. */
@media (max-height: 900px) and (min-height: 721px) {
  .scene-regnet { min-height: 340vh; }
  .regnet-stage-wrap { height: clamp(320px, 48vh, 520px); }
  .regnet-sticky[data-beat="5"] .regnet-stage-wrap {
    height: clamp(160px, 26vh, 280px);
  }
  .regnet-closer {
    margin: clamp(2rem, 5vh, 3.5rem) auto;
    padding: clamp(1.8rem, 4.5vh, 3rem) 0;
  }
  .scene-gallery { min-height: 200vh; }
  .scene-timeline { min-height: 160vh; }
}

/* ---- Tall viewports (≥1100px) ----
   Cap stretching so the SVG doesn't balloon and everything
   sits comfortably mid-viewport. */
@media (min-height: 1100px) {
  .regnet-stage-wrap { max-height: 720px; }
  .gallery-sticky {
    align-content: center;
  }
  .gallery-figure { max-height: 360px; }
  .timeline-chart { max-height: 580px; }
  .timeline-sticky { justify-content: center; gap: clamp(1.2rem, 2.5vh, 2rem); }
  .regnet-sticky { align-content: center; gap: clamp(1.2rem, 2.4vh, 2rem); }
}

/* ---- Ultra-wide viewports (≥1800px) ----
   Cap content widths so the SVG and chart don't stretch
   past the readable zone on 4K / ultrawide monitors. */
@media (min-width: 1800px) {
  .regnet-frame { max-width: 92rem; }
  .regnet-head { max-width: 92rem; }
  .timeline-head { max-width: 84rem; }
  .timeline-chart { max-width: 84rem; }
  .gallery-split { max-width: 92rem; margin: 0 auto; }
  .regnet-closer { max-width: 56ch; }
}

/* ---- Mid-narrow (700–980px wide) ----
   Hand-off zone between desktop and the existing narrow rules.
   Panels stay pinned but content tightens. */
@media (max-width: 980px) and (min-width: 700px) {
  .gallery-split { grid-template-columns: minmax(220px, 38%) 1fr; }
  .gallery-grid { gap: 0.5rem; }
  .regnet-cluster-label--space,
  .regnet-cluster-label--ai { font-size: 0.6rem; }
  .rn-cluster-sub { display: none; }
  .regnet-stage-wrap { height: clamp(280px, 46vh, 460px); }
}

/* ---- Very narrow / portrait (<700px wide) ----
   Stacked / single-column layout for phones. The existing
   max-width: 980px rule already handles structural collapse;
   this just trims sizes further. */
@media (max-width: 700px) {
  .scene-gallery { min-height: auto; }
  .gallery-figure { aspect-ratio: 16 / 10; }
  .gallery-heading { font-size: 1.5rem; }

  .scene-regnet { min-height: auto; }
  .regnet-heading { font-size: 1.4rem; max-width: 22ch; }
  .regnet-lede { font-size: 0.86rem; }
  .regnet-stage-wrap { height: clamp(280px, 56vh, 460px); }
  .regnet-closer {
    font-size: 1.05rem;
    padding: 1.4rem 0;
    margin: 1.2rem auto;
  }

  .scene-timeline { min-height: auto; }
  .timeline-heading { font-size: 1.4rem; }

  /* Tooltip narrows to almost full-screen-width on phones so
     the description text is actually legible. */
  .rn-tooltip { width: calc(100vw - 2rem); max-width: 360px; }
}

/* ============================================================
   Reading-first layout for mid-size viewports
   ------------------------------------------------------------
   Below 1024px wide, the satellite cluster doesn't have enough
   horizontal room to stay in its outer lane without intruding
   on the reading column. Hide the cluster, drop the reading
   column's left lane offset, and let the article take the full
   width. Liftoff keeps its rocket — that's only visible at the
   very start of scroll. Stars + sky stay as the backdrop.
   ============================================================ */
@media (max-width: 1024px) {
  :root { --lane: 0vw; }
  /* Cluster goes away — was occupying the left margin where the
     reading column wants to live on narrow viewports. */
  .cluster { opacity: 0 !important; }
  /* Article scenes regain their full reading width. */
  .scene:not(.scene-liftoff) .scene-inner {
    padding-left: clamp(1.4rem, 4vw, 3rem) !important;
    padding-right: clamp(1.4rem, 4vw, 3rem) !important;
  }
  /* Liftoff: drop the wide right padding (no rocket lane needed
     on a viewport this size, but the rocket is still visible). */
  .scene-liftoff .scene-inner {
    padding-right: clamp(1.5rem, 5vw, 4rem) !important;
  }
}

/* ============================================================
   Timeline: keep the horizontal chart on mid-size laptops
   ------------------------------------------------------------
   The chart used to collapse to a vertical list at <1100px
   which meant most laptop windows never saw it. Drop that to
   <760px and scale the chart down for the in-between range.
   ============================================================ */
@media (max-width: 1100px) and (min-width: 761px) {
  .scene-timeline { min-height: 180vh; }
  .timeline-chart { row-gap: 0.45rem; }
  .tl-stack {
    font-size: clamp(0.66rem, 0.8vw, 0.78rem);
    line-height: 1.25;
    gap: 0.45rem;
  }
  .tl-year { font-size: clamp(0.92rem, 1.4vw, 1.15rem); }
  .timeline-heading { font-size: clamp(1.3rem, 2.6vw, 1.8rem); }
  .timeline-band-label { font-size: 0.66rem; letter-spacing: 0.18em; }
  .tl-column { padding: 0 clamp(0.25rem, 0.7vw, 0.6rem); }
}

/* ============================================================
   Regnet: more dwell so the reader actually reaches beat 5
   ------------------------------------------------------------
   Bumping min-height to 460vh gives ~72vh of scroll per beat
   once the panel is pinned — closer to a full viewport per
   beat, which is what the chasm-labels narrative needs.
   ============================================================ */
.scene-regnet {
  min-height: 460vh;
}
@media (max-height: 720px) {
  .scene-regnet { min-height: 380vh; }
}
@media (max-height: 900px) and (min-height: 721px) {
  .scene-regnet { min-height: 420vh; }
}
