/*
 * The talk engine's styles (issue #5007), in the site's language (R-13): the --hb-* tokens from
 * /site-assets/hapimatic-dark.css, the layout and movement of prototype v1 (R-36). Talk-agnostic:
 * a talk's own look is talk.css (#5009), loaded after this file.
 */

:root {
  --dur: 760ms;
  --ease: cubic-bezier(0.2, 0.8, 0.2, 1);
  --pad: clamp(20px, 5vw, 96px);
  --deep-purple: #1e0a3e;
}
html {
  /* site.css pads scrolling for its sticky header. The deck's HUD is fixed too, but each text scene
     carries its own top padding for it (a frame scene fills the screen on wide viewports), so a
     scene lands flush; a scroll padding here would land each scene lower and put the previous
     scene's tail under the HUD (#5088). */
  scroll-padding: 0;
  scroll-behavior: smooth;
}
html,
body {
  margin: 0;
  background: var(--hb-bg);
  color: var(--hb-text);
  font-family: var(--hb-font);
  -webkit-font-smoothing: antialiased;
}
body {
  display: block;
  min-height: 100svh;
}
html.is-stage,
html.is-stage body {
  overflow: hidden;
}
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur: 1ms;
  }
  html {
    scroll-behavior: auto;
  }
}

#ambient {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

/* ── HUD ── */
.hud {
  position: fixed;
  z-index: 20;
  left: 0;
  right: 0;
  top: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 22px var(--pad) 0;
  pointer-events: none;
}
.hud img {
  height: clamp(22px, 2.2vw, 30px);
  opacity: 0.9;
}
.hud-right {
  display: flex;
  align-items: center;
  gap: 14px;
}
.hud .ctr {
  font: 600 clamp(11px, 1vw, 13px) / 1 var(--hb-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--hb-muted);
}
.hud .ctr b {
  color: var(--hb-mint);
  font-weight: 700;
}
.relay-chip {
  font: 600 10px/1 var(--hb-mono);
  letter-spacing: 0.08em;
  color: var(--hb-muted);
  padding: 5px 9px;
  border-radius: var(--hb-r-pill);
  border: 1px solid var(--hb-line);
  background: rgba(28, 28, 30, 0.7);
}
.relay-chip:empty {
  display: none;
}
.relay-chip[data-state="live"] {
  color: var(--hb-mint);
  border-color: rgba(90, 230, 171, 0.35);
}
.relay-chip[data-state="down"] {
  color: var(--hb-amber);
  border-color: rgba(245, 158, 11, 0.4);
}
#talk-identity {
  pointer-events: auto;
}
#talk-identity:empty {
  display: none;
}

/* ── scenes ── */
main#deck {
  position: relative;
  z-index: 1;
}
.scene {
  position: relative;
  min-height: 100svh;
  box-sizing: border-box;
  padding: 14vh var(--pad) 12vh;
  display: grid;
  align-content: center;
  overflow: hidden;
}
.eyebrow-xl {
  font: 600 clamp(11px, 1vw, 15px) / 1 var(--hb-font);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--hb-mint);
  margin: 0 0 clamp(12px, 1.6vw, 22px);
}
.statement {
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
  font-size: clamp(34px, 5.2vw, 84px);
  max-width: 14em;
}
.statement .sentence {
  display: block; /* one sentence per line (operator ruling 2026-10-12) */
}
.statement .keep {
  white-space: nowrap; /* a phrase the scene keeps on one line (scenes.json "keep") */
}
.statement.compact {
  font-size: clamp(34px, 3.6vw, 56px);
}
.sub {
  font: 500 clamp(18px, 1.8vw, 30px) / 1.35 var(--hb-font);
  color: var(--hb-text-secondary);
  margin: clamp(14px, 1.6vw, 26px) 0 0;
  max-width: 30em;
}
.beat {
  font: 500 clamp(16px, 1.5vw, 26px) / 1.45 var(--hb-font);
  color: var(--hb-text-secondary);
  margin: clamp(14px, 1.6vw, 26px) 0 0;
  max-width: 30em;
}
.scene a {
  color: var(--hb-mint);
  text-decoration: none;
  border-bottom: 1px solid rgba(90, 230, 171, 0.4);
}

/* reveal builds */
[data-at] {
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
[data-at].on {
  opacity: 1;
  transform: none;
}

/* one statement, one object */
.two {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr);
  gap: clamp(20px, 4vw, 64px);
  align-items: center;
}
.object {
  margin: 0;
  border-radius: 18px;
  overflow: hidden;
}
.object img,
.object video {
  display: block;
  width: 100%;
  height: auto;
  max-height: 62vh;
  object-fit: contain;
  border-radius: 18px;
}
.object table {
  width: 100%;
  border-collapse: collapse;
  font: 500 clamp(14px, 1.3vw, 22px) / 1.3 var(--hb-font);
}
.object th,
.object td {
  text-align: left;
  padding: 10px 12px;
  border-top: 1px solid var(--hb-line);
}
.object th {
  color: var(--hb-muted);
  font: 600 clamp(11px, 0.9vw, 13px) / 1 var(--hb-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-top: 0;
}
.object .credit {
  margin: 10px 0 0;
  font: 500 clamp(11px, 0.85vw, 14px) / 1.4 var(--hb-mono);
  color: var(--hb-muted);
}
.placeholder {
  aspect-ratio: 4 / 3;
  border: 1px solid var(--hb-line-strong);
  background: linear-gradient(
    135deg,
    rgba(44, 44, 46, 0.9),
    rgba(22, 22, 24, 0.9)
  );
  display: grid;
  place-items: center;
  color: var(--hb-muted);
  font: 500 12px/1.4 var(--hb-mono);
  text-align: center;
  padding: 20px;
  box-sizing: border-box;
}
.placeholder b {
  display: block;
  color: var(--hb-text-secondary);
  font: 700 clamp(14px, 1.2vw, 18px) / 1.2 var(--hb-font);
  margin-bottom: 8px;
}

/* the stamp and the info button */
.stamp {
  position: absolute;
  left: var(--pad);
  bottom: 24px;
  display: flex;
  align-items: center;
  gap: 10px;
  font: 500 clamp(11px, 0.8vw, 13px) / 1.4 var(--hb-mono);
  color: var(--hb-muted);
}
.info-btn {
  display: inline-grid;
  place-items: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border-radius: 50%;
  border: 1px solid var(--hb-line-strong);
  background: transparent;
  color: var(--hb-text-secondary);
  font: 600 11px/1 var(--hb-mono);
  cursor: pointer;
}
.info-btn:hover,
.info-btn:focus-visible {
  color: var(--hb-mint);
  border-color: var(--hb-mint);
}

/* the validation panel: a bad entry is visible in rehearsal, never silent (R2) */
#talk-errors {
  position: fixed;
  z-index: 40;
  left: 16px;
  bottom: 16px;
  max-width: min(640px, calc(100vw - 32px));
  padding: 12px 14px;
  border-radius: 12px;
  background: rgba(44, 20, 20, 0.94);
  border: 1px solid rgba(248, 113, 113, 0.5);
  color: var(--hb-text);
  font: 500 12px/1.45 var(--hb-mono);
}
#talk-errors[hidden] {
  display: none;
}
#talk-errors b {
  display: block;
  color: var(--hb-red);
  margin-bottom: 4px;
}
#talk-errors ul {
  margin: 0;
  padding-left: 18px;
}

/* phone reading mode: the plain vertical spine of the same scenes (R-21). The projector wins, so
   this applies to the browse page only; a phone opened as a stage keeps the projector layout. The
   one exception is the HUD paint at the end of this block, which a phone-width stage gets too (#5113). */
@media (max-width: 760px) {
  html:not(.is-stage) .two {
    grid-template-columns: 1fr;
  }
  html:not(.is-stage) .scene {
    min-height: 0;
    padding: calc(84px + env(safe-area-inset-top, 0px)) 20px 48px;
    overflow: visible;
  }
  html:not(.is-stage) .statement,
  html:not(.is-stage) .statement.compact {
    font-size: clamp(32px, 9.5vw, 44px);
  }
  html:not(.is-stage) [data-at] {
    opacity: 1;
    transform: none;
  }
  html:not(.is-stage) .stamp {
    position: static;
    margin-top: 24px;
    flex-wrap: wrap;
  }
  /* a chart mount grows with its legend and marker list on the phone; at a fixed 40vh the flex
     column overflowed into the counts row below it (Matt's phone review, 2026-10-12) */
  html:not(.is-stage) .chart-box [data-talk="timeline"],
  html:not(.is-stage) .chart-box [data-talk="hours"] {
    height: auto;
  }
  html:not(.is-stage) .chart-box .tc-plot,
  html:not(.is-stage) .chart-box .tc-hplot {
    min-height: 240px;
  }
  /* The HUD paint applies to the stage page too: a phone opened as a stage keeps the projector
     layout, but between scenes its text still scrolls under the fixed HUD (#5113). The band is
     opaque behind the wordmark and the counter (#5088), and a 24 px strip below it fades the
     scrolled content into the band, as the chat thread fades under the session-info bar. The chat
     masks its scrolling viewport; this page scrolls the document, so a mask on the deck would
     move with the text, and the strip is a fixed overlay on the HUD instead. With the account
     control hidden, 24 px ends above the first line of a landed scene, which starts 28 to 30 px
     below the band; signed in, the band is about 10 px taller and only the strip's faint tail
     reaches the top of that first line. */
  .hud {
    padding-top: 16px;
    padding-bottom: 14px;
    background: var(--hb-bg);
  }
  .hud::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    height: 24px;
    background: linear-gradient(to bottom, var(--hb-bg), transparent);
    pointer-events: none;
  }
}

/* ── rail: right is time ── */
.scene-rail .head {
  margin-bottom: clamp(14px, 2.4vh, 32px);
}
.scene-rail .window {
  position: relative;
  overflow: hidden;
}
.scene-rail .track {
  display: flex;
  transition: transform var(--dur) var(--ease);
  will-change: transform;
}
.scene-rail .station {
  flex: 0 0 var(--panel, 62vw);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr);
  gap: clamp(16px, 2.4vw, 40px);
  align-items: center;
  padding-right: clamp(20px, 3vw, 56px);
  box-sizing: border-box;
  opacity: 0.35;
  transition: opacity var(--dur) var(--ease);
}
.scene-rail .station.lit {
  opacity: 1;
}
.scene-rail .station .object {
  max-height: 32vh;
}
.scene-rail .station .placeholder {
  aspect-ratio: 16 / 10;
}
.scene-rail .axis {
  position: relative;
  height: 2px;
  background: rgba(255, 255, 255, 0.18);
  margin: clamp(12px, 1.8vh, 22px) 0;
}
.scene-rail .axis::after {
  content: "";
  position: absolute;
  /* inside the axis: at -2px the window's clip cut the ring's left edge (Matt, 2026-10-19) */
  left: 0;
  top: -5px;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--hb-bg);
  border: 2px solid var(--hb-mint);
}
.scene-rail .month {
  font: 600 clamp(11px, 0.9vw, 13px) / 1 var(--hb-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--hb-mint);
}
.scene-rail h3 {
  margin: 0;
  font: 800 clamp(24px, 2.6vw, 42px) / 1.1 var(--hb-font);
  letter-spacing: -0.015em;
}
.scene-rail .bar {
  position: relative;
  height: 3px;
  background: rgba(255, 255, 255, 0.12);
  border-radius: 2px;
  margin-top: clamp(14px, 2.4vh, 28px);
}
.scene-rail .bar i {
  position: absolute;
  left: 0;
  top: 0;
  height: 100%;
  background: var(--hb-mint);
  border-radius: 2px;
  transition: width var(--dur) var(--ease);
}
.pipeline {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(110px, 1fr));
  gap: 8px;
  margin-top: clamp(14px, 2.4vh, 28px);
}
.pipeline .cell {
  display: grid;
  gap: 6px;
  padding: 10px 12px;
  border-radius: 14px;
  background: rgba(44, 44, 46, 0.8);
  border: 1px solid var(--hb-line);
}
.pipeline .n {
  font: 600 11px/1 var(--hb-mono);
  color: var(--hb-muted);
}
.pipeline .s {
  font: 600 clamp(13px, 1vw, 17px) / 1.2 var(--hb-font);
}
.chip {
  justify-self: start;
  display: inline-flex;
  padding: 5px 11px;
  border-radius: var(--hb-r-pill);
  font: 600 12px/1 var(--hb-font);
  border: 1px solid var(--hb-line-strong);
  color: var(--hb-text);
  background: rgba(255, 255, 255, 0.04);
  transition: all var(--dur) var(--ease);
}
.chip.ai {
  color: var(--hb-mint);
  border-color: rgba(90, 230, 171, 0.45);
  background: rgba(90, 230, 171, 0.08);
  box-shadow: 0 0 0 4px rgba(90, 230, 171, 0.12);
}

/* ── chart ── */
.chart-box {
  margin-top: clamp(16px, 2.4vh, 32px);
  display: grid;
  gap: 14px;
}
/* #4940's timeline and #5030's hours chart fill their box (charts-harness.html gives each
   the scene's rest). */
.chart-box [data-talk="timeline"],
.chart-box [data-talk="hours"] {
  height: 40vh;
}
/* charts.js did not load: a labelled box, never an empty one. */
.chart-missing {
  margin: 0;
  padding: 18px 20px;
  border-radius: 18px;
  border: 1px dashed var(--hb-line-strong);
  color: var(--hb-muted);
  font: 600 clamp(14px, 1.2vw, 18px) / 1.3 var(--hb-font);
}

/* ── map: in is detail ── */
.map-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.75fr);
  gap: clamp(16px, 3vw, 48px);
  align-items: center;
  margin-top: clamp(12px, 2vh, 24px);
}
.map-layout.map-only {
  grid-template-columns: 1fr;
}
/* Half a screen (taller than wide, wider than the phone mode): two columns left the map 522px
   wide at 960x1080, so its labels, which scale with the map (#5323), fell to about 8px. Stack the
   map over its object instead, with capped heights so the object and the caption stay on screen. */
@media (min-width: 761px) and (max-aspect-ratio: 1/1) {
  .scene-map .map-layout {
    grid-template-columns: 1fr;
    gap: 12px;
  }
  .scene-map .map-stage {
    height: 38vh;
  }
  .scene-map .map-object .object {
    max-height: 24vh;
    overflow: hidden;
  }
  .scene-map .map-object .object img,
  .scene-map .map-object .object video,
  .scene-map .map-object .object svg {
    max-height: 22vh;
    width: auto;
    max-width: 100%;
    display: block;
    margin: 0 auto;
  }
}
.map-stage {
  position: relative;
  height: clamp(300px, 52vh, 620px);
  overflow: hidden;
  border-radius: 18px;
}
.map-stage .world {
  position: absolute;
  inset: 0;
  transition: transform 900ms var(--ease);
  transform-origin: 0 0;
}
.map-stage svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
}
.plate {
  fill: rgba(44, 44, 46, 0.72);
  stroke: rgba(255, 255, 255, 0.16);
  stroke-width: 1.2;
  transition:
    fill var(--dur) var(--ease),
    stroke var(--dur) var(--ease),
    opacity var(--dur) var(--ease);
}
.plate.done {
  fill: rgba(30, 10, 62, 0.55);
  stroke: rgba(167, 139, 250, 0.35);
}
.plate.now,
.plate.lit {
  fill: rgba(90, 230, 171, 0.1);
  stroke: var(--hb-mint);
  stroke-width: 2;
}
.plate.dim {
  opacity: 0.25;
}
/* A plate's 3D icon (#5276): it dims with its plate until the plate's build */
.plate-asset {
  pointer-events: none;
  transition: opacity var(--dur) var(--ease);
}
.plate-asset.dim {
  opacity: 0.25;
}
.inst {
  fill: rgba(90, 230, 171, 0.16);
  stroke: rgba(90, 230, 171, 0.7);
  stroke-width: 1.2;
}
.inst.focus {
  fill: rgba(90, 230, 171, 0.3);
  stroke-width: 2;
}
.plabel {
  position: absolute;
  transform: translate(-50%, -50%);
  text-align: center;
  /* One line, as wide as its name (#5323). The size is in world units times the map's scale
     (--map-k, set by engine.js), so a label shrinks with its plates and the map never reflows;
     check 20 holds every label inside its plate's width at 1920, 1280, and 960 wide. */
  white-space: nowrap;
  width: max-content;
  --label-size: 42px;
  font: 800 calc(var(--label-size) * var(--map-k, 0.37)) / 1.1 var(--hb-font);
  /* A small label the dive camera then scales up: unhinted glyph advances keep its letters
     evenly spaced under the transform instead of magnifying pixel-rounded gaps. */
  text-rendering: geometricPrecision;
  pointer-events: none;
}
/* A plate label that arrives with a build keeps its centring: the generic [data-at].on rule
   clears transform, which left every lit label starting at its plate's centre (#5032). The
   slide is in world units too (about 14px at 1920 wide). */
.plabel[data-at] {
  transform: translate(-50%, calc(-50% + 38px * var(--map-k, 0.37)));
}
.plabel[data-at].on {
  transform: translate(-50%, -50%);
}
/* An asset plate's label hangs below the plate's front tip: engine.js sets its top edge (#5308),
   so it is anchored by its top, not its centre. A lit one keeps the same 14px arrival slide. */
.plabel.hung {
  transform: translate(-50%, 0);
}
.plabel.hung[data-at] {
  transform: translate(-50%, calc(38px * var(--map-k, 0.37)));
}
.plabel.hung[data-at].on {
  transform: translate(-50%, 0);
}
.plabel .pnum,
.plate-legend {
  display: none;
}
.plabel.now {
  color: var(--hb-mint);
}
.map-stage.zoomed .plabel:not(.now) {
  opacity: 0;
  transition: opacity 400ms;
}
.map-stage.zoomed .plabel.now {
  font-size: calc(var(--label-size) * 0.75 * var(--map-k, 0.37));
  opacity: 0.85;
}
.map-object .object[hidden] {
  display: none;
}
.scene-map .crumb {
  margin: 14px 0 0;
  font: 600 clamp(11px, 0.9vw, 13px) / 1 var(--hb-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hb-mint);
  min-height: 1em;
}
.scene-map .caption {
  margin: 8px 0 0;
  font: 600 clamp(20px, 2vw, 34px) / 1.25 var(--hb-font);
  min-height: 1.25em;
}
/* A dive caption and its crumb sit in the band where the mesh draws its nodes (88-96% of the
   viewport height), so at 1280x720 and half a screen the glowing lines ran through the words. A
   halo in the page colour knocks the mesh out behind the letters (#5323), as map type does. */
.scene-map .caption,
.scene-map .crumb {
  text-shadow:
    0 0 6px var(--hb-bg),
    0 0 14px var(--hb-bg),
    0 0 24px var(--hb-bg);
}
.dive-list {
  display: none;
}

/* ── console ── */
.console {
  border-radius: 18px;
  background: rgba(22, 22, 24, 0.86);
  border: 1px solid var(--hb-line-strong);
  padding: 14px 16px;
}
.console[hidden] {
  display: none;
}
.console-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font: 500 clamp(13px, 1.1vw, 17px) / 1.3 var(--hb-font);
}
.console-list li {
  display: grid;
  grid-template-columns: 28px 1fr auto;
  gap: 10px;
  align-items: center;
  padding: 9px 0;
  border-top: 1px solid var(--hb-line);
}
.console-list li:first-child {
  border-top: 0;
}
.console-list .ic {
  color: var(--hb-mint);
  font-weight: 800;
  text-align: center;
}
.console-list .when {
  color: var(--hb-muted);
  font: 500 12px/1 var(--hb-mono);
}
/* The feed could not be read: the rows keep their last times, so say it stopped. */
.console.is-stale .console-list {
  opacity: 0.55;
}
.console-stale {
  margin: 10px 0 0;
  color: var(--hb-muted);
  font: 600 12px/1.2 var(--hb-mono);
}
.console-stale[hidden] {
  display: none;
}
/* With no rows above it (the first read failed), the line is the panel's only content. */
.console-list:empty + .console-stale {
  margin-top: 0;
}

/* ── frame ── */
.scene-frame {
  padding: 0;
  align-content: stretch;
}
.scene-frame .frame {
  width: 100%;
  height: 100svh;
  border: 0;
  display: block;
  background: var(--hb-bg);
}
.frame-card {
  display: none;
}

/* ── QR ── */
.object-qr {
  display: grid;
  justify-items: start;
  gap: 12px;
}
.object-qr img {
  width: clamp(160px, 18vw, 280px);
  height: auto;
  background: #fff;
  padding: 10px;
  border-radius: 12px;
  box-sizing: border-box;
}
.qr-url {
  font: 600 clamp(13px, 1.1vw, 18px) / 1.3 var(--hb-mono);
  color: var(--hb-text-secondary);
  word-break: break-all;
}

/* ── the info dialog ── */
dialog.talk-info {
  max-width: min(560px, calc(100vw - 32px));
  padding: 24px 26px;
  border-radius: 18px;
  border: 1px solid var(--hb-line-strong);
  background: var(--hb-surface);
  color: var(--hb-text);
  font: 500 15px/1.5 var(--hb-font);
}
dialog.talk-info::backdrop {
  background: rgba(10, 10, 12, 0.7);
}
dialog.talk-info h2 {
  margin: 0 0 4px;
  font: 800 24px/1.15 var(--hb-font);
}
dialog.talk-info h3 {
  margin: 18px 0 6px;
  font: 600 12px/1 var(--hb-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hb-muted);
}
dialog.talk-info p,
dialog.talk-info ul {
  margin: 6px 0;
}
dialog.talk-info ul {
  padding-left: 18px;
}
dialog.talk-info a {
  color: var(--hb-mint);
}
.info-stamp {
  color: var(--hb-muted);
  font: 500 13px/1.4 var(--hb-mono);
}
.info-attribution {
  color: var(--hb-text-secondary);
}
.info-totals {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 4px 16px;
  margin: 8px 0 0;
}
.info-totals dt {
  color: var(--hb-text-secondary);
}
.info-totals dd {
  margin: 0;
  font: 700 15px/1.5 var(--hb-mono);
  color: var(--hb-mint);
  text-align: right;
}
.info-close {
  margin-top: 18px;
  padding: 8px 16px;
  border-radius: var(--hb-r-pill);
  border: 1px solid var(--hb-line-strong);
  background: transparent;
  color: var(--hb-text);
  font: 600 13px/1 var(--hb-font);
  cursor: pointer;
}

/* ── phone reading mode for the richer types (R7, R-21) ── */
@media (max-width: 760px) {
  html:not(.is-stage) .scene-rail .track {
    flex-direction: column;
    transform: none !important;
  }
  html:not(.is-stage) .scene-rail .station {
    flex: none;
    grid-template-columns: 1fr;
    padding: 0 0 22px;
    opacity: 1;
  }
  html:not(.is-stage) .scene-rail .bar {
    display: none;
  }
  html:not(.is-stage) .pipeline {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  html:not(.is-stage) .map-layout {
    grid-template-columns: 1fr;
  }
  html:not(.is-stage) .map-stage {
    height: 46vh;
  }
  html:not(.is-stage) .map-object,
  html:not(.is-stage) .scene-map .crumb,
  html:not(.is-stage) .scene-map .caption {
    display: none;
  }
  /* At phone width a map's plates sit too close together for names: each plate shows a number
     badge and the names go to the numbered legend under the map (#5032). */
  html:not(.is-stage) .scene-map .plabel .pname {
    display: none;
  }
  html:not(.is-stage) .scene-map .plabel .pnum {
    display: grid;
    place-items: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    border: 1.5px solid var(--hb-mint);
    background: var(--hb-bg);
    color: var(--hb-text);
    font: 700 12px/1 var(--hb-font);
  }
  html:not(.is-stage) .plate-legend {
    display: grid;
    gap: 6px;
    margin: 14px 0 0;
    padding-left: 1.4em;
    font: 600 16px/1.3 var(--hb-font);
    color: var(--hb-text);
  }
  html:not(.is-stage) .dive-list {
    display: grid;
    gap: 14px;
    margin-top: 18px;
  }
  html:not(.is-stage) .dive-card {
    padding: 14px 16px;
    border-radius: 14px;
    background: rgba(44, 44, 46, 0.8);
    border: 1px solid var(--hb-line);
  }
  html:not(.is-stage) .dive-card h3 {
    margin: 0;
    font: 700 18px/1.2 var(--hb-font);
  }
  html:not(.is-stage) .dive-card .beat {
    margin-top: 8px;
    font-size: 16px;
  }
  html:not(.is-stage) .scene-frame {
    padding: 84px 20px 48px;
  }
  html:not(.is-stage) .scene-frame .frame {
    display: none;
  }
  html:not(.is-stage) .frame-card {
    display: block;
    padding: 22px;
    border-radius: 18px;
    border: 1px solid var(--hb-line-strong);
    background: rgba(44, 44, 46, 0.8);
    color: var(--hb-text);
    text-decoration: none;
  }
}

/* ── v1.1 (the 2026-10-18 revision round) ── */
/* logo lockups under a scene's words (scenes.json "marks") */
.marks {
  display: flex;
  align-items: center;
  gap: clamp(22px, 2.8vw, 44px);
  margin-top: clamp(22px, 2.6vw, 40px);
  padding-top: clamp(14px, 1.8vw, 26px);
  border-top: 1px solid var(--hb-line);
}
.marks img {
  display: block;
  height: clamp(32px, 3vw, 52px);
  width: auto;
  opacity: 0.95;
}
.marks img.square {
  height: clamp(54px, 5.2vw, 88px);
  border-radius: 10px;
}
.marks .sep {
  width: 1px;
  height: clamp(34px, 3.2vw, 56px);
  background: var(--hb-line-strong);
}
/* a beat with its mark at the left (scenes.json beats[].icon) */
.beat.with-icon {
  display: flex;
  align-items: center;
  gap: 16px;
}
.beat-icon {
  flex: none;
  height: clamp(40px, 3.6vw, 60px);
  width: auto;
  border-radius: 8px;
}
.beat-icon.square {
  width: clamp(40px, 3.6vw, 60px);
  object-fit: contain;
}
/* a quoted line (scenes.json "quote"): the kicker above, the credit under */
.quote {
  margin-top: clamp(18px, 2.4vw, 34px);
}
.quote .kicker {
  margin-bottom: 10px;
}
.lyric {
  margin: 0;
  position: relative;
  padding-left: clamp(40px, 4vw, 72px);
  font: italic 700 clamp(22px, 2.2vw, 38px) / 1.3 var(--hb-font);
  color: var(--hb-text);
  letter-spacing: -0.01em;
  text-wrap: balance;
  max-width: 24em;
}
.lyric::before {
  content: "\201C";
  position: absolute;
  left: 0;
  top: -0.25em;
  font: 800 3.2em/1 var(--hb-font);
  color: var(--hb-mint);
  opacity: 0.9;
}
.lyric-credit {
  margin: 14px 0 0 clamp(40px, 4vw, 72px);
  font: 500 clamp(12px, 1vw, 16px) / 1.4 var(--hb-mono);
  color: var(--hb-muted);
  letter-spacing: 0.06em;
}
/* a photograph behind the whole scene (scenes.json "bleed"), under a gradient the words can sit on */
.scene .bleed {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  transform: none;
}
.scene .bleed.on,
.scene .bleed:not([data-at]) {
  transform: none;
}
.scene .bleed img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 60% 40%;
}
.scene .bleed::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      90deg,
      rgba(28, 28, 30, 0.96) 0%,
      rgba(28, 28, 30, 0.86) 36%,
      rgba(28, 28, 30, 0.25) 70%,
      rgba(28, 28, 30, 0.1) 100%
    ),
    linear-gradient(0deg, rgba(28, 28, 30, 0.9) 0%, rgba(28, 28, 30, 0) 40%);
}
.scene .two,
.scene .text {
  position: relative;
  z-index: 1;
}
.scene .stamp {
  z-index: 1;
}
/* a stack: layered images in one frame, the newest arrived layer on top */
.object-stack {
  position: relative;
}
.object-stack img.layer {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: 18px;
}
.object-stack img.layer:not(.base) {
  position: absolute;
  inset: 0;
  opacity: 0;
  transform: none;
  transition: opacity 1400ms var(--ease);
}
.object-stack img.layer.on {
  opacity: 1;
  transform: none;
}
/* a layer under a newer arrived layer steps back, so a drawing with a transparent ground is
   replaced, not overlaid */
.object-stack:has(img.layer.on) img.layer.base,
.object-stack img.layer.on:has(~ img.layer.on) {
  opacity: 0;
}
/* a group: several objects in one figure; the talk's CSS lays them out by the group's class */
.object-group {
  display: grid;
  gap: clamp(14px, 1.8vw, 30px);
  border-radius: 0;
  overflow: visible;
}
.object-group > .object {
  min-width: 0;
}
/* a chip on a drawn object (objects.json "tag"): a render is marked as a render, a live clip as live */
.object {
  position: relative;
}
.object .tag {
  position: absolute;
  right: 12px;
  top: 12px;
  z-index: 2;
  font: 700 10px/1 var(--hb-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(28, 28, 30, 0.85);
  border: 1px solid var(--hb-line-strong);
  color: var(--hb-amber, #f59e0b);
}
/* an image that fills its frame edge to edge */
.object.cover img,
.object.cover video {
  height: 100%;
  object-fit: cover;
}

/* ── answer: an informational page, the question held at the top ── */
.scene-answer {
  align-content: start;
  padding-top: 12vh;
}
.scene-answer .qband {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-bottom: clamp(12px, 1.6vh, 22px);
  border-bottom: 2px solid var(--hb-mint);
  margin-bottom: clamp(14px, 2vh, 28px);
}
.scene-answer .qtext .eyebrow-xl {
  margin-bottom: 8px;
}
.scene-answer .qtext .statement.compact {
  font-size: clamp(26px, 3vw, 50px);
}
.scene-answer .qback {
  flex: none;
  font: 600 12px/1 var(--hb-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hb-text-secondary);
  text-decoration: none;
  padding: 10px 14px;
  border-radius: 999px;
  border: 1px solid var(--hb-line-strong);
}
.scene-answer .qback:hover,
.scene-answer .qback:focus-visible {
  color: var(--hb-mint);
  border-color: var(--hb-mint);
}
.scene-answer .qbody {
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  align-items: start;
}
.scene-answer .answer {
  margin: 0 0 14px;
  font: 800 clamp(22px, 2.4vw, 40px) / 1.15 var(--hb-font);
  letter-spacing: -0.015em;
}
.scene-answer .points {
  margin: 0;
  padding-left: 1.2em;
  font: 500 clamp(16px, 1.45vw, 24px) / 1.5 var(--hb-font);
  color: var(--hb-text-secondary);
  display: grid;
  gap: 10px;
}
.scene-answer .object img,
.scene-answer .object video {
  max-height: 50vh;
  object-fit: cover;
  object-position: top;
}
@media (max-width: 760px) {
  html:not(.is-stage) .scene-answer .qband {
    flex-direction: column;
    align-items: flex-start;
  }
  html:not(.is-stage) .scene-answer .qbody {
    grid-template-columns: 1fr;
  }
  html:not(.is-stage) .scene .bleed {
    display: none;
  }
  /* the reading page shows every build at once: no slow dissolves to wait for */
  html:not(.is-stage) .object-stack img.layer {
    transition: none;
  }
  html:not(.is-stage) .object-group {
    grid-template-columns: 1fr !important;
  }
}

/* ── phone step-through (v1.2) ── */
/* The reading page's way into the stage: a mint pill in the HUD, phone widths only. */
.hud .step {
  display: none;
  pointer-events: auto;
  align-items: center;
  font: 700 11px/1 var(--hb-mono);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--hb-bg);
  background: var(--hb-mint);
  border: 0;
  border-radius: 999px;
  padding: 9px 12px;
  cursor: pointer;
}
/* shown on a phone (the reading page) and on any touch screen (a phone turned sideways is
   wider than the reading page's limit but no closer to the projector; a tablet likewise) */
@media (max-width: 760px), (pointer: coarse) {
  html:not(.is-stage) .hud .step {
    display: inline-flex;
  }
}
html.is-stepping,
html.is-stepping body {
  overflow: hidden;
}
/* the solo stage (framed): the deck is a window the scenes move under, no document scrolling */
html.is-solo #deck {
  position: fixed;
  inset: 0;
  transition: transform var(--dur) var(--ease);
  will-change: transform;
}
.stepper {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: var(--hb-bg);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: max(8px, env(safe-area-inset-top, 0px)) 0
    max(8px, env(safe-area-inset-bottom, 0px));
}
/* the stage at 1280 x 720, scaled to the phone; the frame keeps the projector's viewport */
.stepper-canvas {
  position: relative;
  overflow: hidden;
  border-radius: 6px;
  background: #000;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.6);
}
.stepper-frame {
  position: absolute;
  left: 0;
  top: 0;
  width: 1280px;
  height: 720px;
  border: 0;
  transform-origin: 0 0;
  background: var(--hb-bg);
}
.stepper-bar {
  display: flex;
  align-items: center;
  gap: 10px;
}
.stepper-bar button {
  font: 600 12px/1 var(--hb-mono);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--hb-text);
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid var(--hb-line-strong);
  border-radius: 999px;
  padding: 12px 16px;
  min-height: 44px;
  cursor: pointer;
}
.stepper-prev,
.stepper-next {
  font-size: 26px !important;
  line-height: 1 !important;
  padding: 4px 24px !important;
}
.stepper-ctr {
  font: 600 12px/1 var(--hb-mono);
  letter-spacing: 0.14em;
  color: var(--hb-muted);
  min-width: 68px;
  text-align: center;
}
.stepper-hint {
  margin: 0 24px;
  text-align: center;
  font: 400 12px/1.45 var(--hb-mono);
  color: var(--hb-muted);
}
.stepper:not(.is-portrait) .stepper-hint,
.stepper.is-turned .stepper-hint {
  display: none;
}
.stepper-turn[aria-pressed="true"] {
  color: var(--hb-mint);
  border-color: var(--hb-mint);
}

/* v1.3: a pipeline cell before its station (cells[].from) waits invisible in its slot */
.pipeline .cell {
  transition:
    opacity var(--dur) var(--ease),
    transform var(--dur) var(--ease);
}
.pipeline .cell.off {
  opacity: 0;
  transform: translateY(10px);
}
.pipeline .chip {
  transition:
    background 500ms var(--ease),
    color 500ms var(--ease),
    border-color 500ms var(--ease);
}

/* ── v1.5 (2026-10-19): beat labels, a rail coda, a group that is one link, the lyric card, path stops ── */
.beat.with-label {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  column-gap: 10px;
  align-items: baseline;
}
.beat-label {
  font: 800 clamp(10px, 0.72vw, 12px) / 1 var(--hb-mono);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  padding: 4px 8px;
  border-radius: 6px;
  white-space: nowrap;
  color: var(--hb-text);
  border: 1px solid var(--hb-line-strong);
}
.coda {
  margin: 10px 0 0;
}
.object .group-link {
  position: absolute;
  inset: 0;
  z-index: 3;
  color: inherit;
  text-decoration: none;
}
.lyric-card {
  display: block;
}
.progress .stop {
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  pointer-events: auto;
}
.progress .stop:focus-visible .dot {
  outline: 2px solid var(--hb-mint);
  outline-offset: 2px;
}
