/* =============================================================================
 * stage.css (owner: STAGE builder) — the fixed WebGL stage behind the hero, the statement and "Meet Alfred": its canvas,
 * the still poster, the cluster labels (Geist, moved by the engine), the statement's word reveal, the lit specialist in
 * the list, the stacked panels below 1000 px and the pause control. No CSS mask and no backdrop-filter anywhere here:
 * the field keeps clear of the text by where it sits. Tokens come from base.css.
 * ========================================================================== */

/* ---------- the stage ---------- */
.fx-stage {
  --st-op: 1;
  opacity: var(--st-op);
  overflow: hidden;
  contain: strict;
  /* as tall as the largest viewport: a phone's address bar coming and going never resizes the canvas mid-scroll */
  bottom: auto;
  height: 100vh;
  height: 100lvh;
  container-type: size;
}
.fx-stage.is-off { display: none; }
/* without JS (the bundle never booted) nothing moves or hides the still: it stays with the hero and scrolls away */
.fx-stage:not([data-st]) { position: absolute; }

.st-canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  opacity: 0;
  transition: opacity 450ms var(--ease-out);
}
.fx-stage[data-gl="on"] .st-canvas { opacity: 1; }

/* ---------- the still poster: on screen from the first paint (no empty hole while WebGL starts), and the view itself
   when there is none. Rendered by this engine, square, the sphere's centre in the middle at radius 40 % of the side;
   shown where the live sphere sits: centre 76 cqw / 47 cqh, radius min(30 cqh, 18 cqw) (phones: 50 cqw / 27 cqh,
   radius 37 cqw). It rides with the page like the field (--st-lift). ---------- */
.fx-stage::before {
  content: "";
  position: absolute;
  --st-s: min(30cqh, 18cqw);
  left: calc(76cqw - var(--st-s) * 1.25);
  top: calc(47cqh - var(--st-s) * 1.25);
  width: calc(var(--st-s) * 2.5);
  height: calc(var(--st-s) * 2.5);
  background: url("../img/stage-still.webp") center / 100% 100% no-repeat;
  transform: translate3d(0, var(--st-lift, 0px), 0);
  transition: opacity 450ms var(--ease-out);
  pointer-events: none;
}
.fx-stage[data-gl="on"]::before { opacity: 0; visibility: hidden; transition: opacity 450ms var(--ease-out), visibility 0s 450ms; }
.fx-stage[data-arrive="open"]::before { transition: none; }

/* ---------- the GPU warm-up (warm.js): a faint copy of the sections below, painted once during load ---------- */
.st-warm { position: absolute; inset: 0; opacity: 0.01; pointer-events: none; overflow: hidden; z-index: -1; }

/* ---------- cluster labels (Geist, crisp DOM; the engine places them) ---------- */
.st-labels { position: absolute; inset: 0; pointer-events: none; }
.st-lbl {
  position: absolute;
  left: 0;
  top: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  white-space: nowrap;
  opacity: 0;
  transition: opacity 280ms ease;
  will-change: transform;
}
.st-lbl[data-align="r"] { align-items: flex-end; text-align: right; }
.st-lbl[data-align="c"] { align-items: center; text-align: center; }
.st-lbl__n { font: 500 16px/1.2 var(--sans); letter-spacing: -0.01em; color: var(--ink); background: var(--canvas); padding: 0 3px; }
.st-lbl[data-active="1"]::after {
  content: "";
  display: block;
  width: 100%;
  height: 1px;
  margin-top: 6px;
  background: var(--lapis);
  transform-origin: left;
  animation: st-draw 520ms var(--ease-out) both;
}
.st-lbl[data-align="r"]::after { transform-origin: right; }
.st-lbl[data-align="c"]::after { transform-origin: center; }
@keyframes st-draw { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ---------- statement: words rise in with the scroll (JS sets each word's opacity / offset) ---------- */
.st-w { display: inline-block; }

/* ---------- hero ---------- */
.hero { position: relative; }
.hero-in { position: relative; }
.st-space { display: none; }
.st-pause {
  position: fixed;
  z-index: 4;
  right: max(var(--gutter), env(safe-area-inset-right));
  bottom: max(26px, env(safe-area-inset-bottom));
  width: 36px;
  height: 36px;
  border: 0;
  padding: 0;
  border-radius: 50%;
  background: rgba(250, 249, 246, 0.92);
  box-shadow: 0 0 0 1px var(--rule-2), 0 1px 0 rgba(255, 255, 255, 0.7) inset;
  color: var(--ink-2);
  cursor: pointer;
  transition: box-shadow var(--dur-ui) ease, color var(--dur-ui) ease, visibility 0s;
}
.st-pause[hidden] { display: none; }
.st-pause.is-gone { visibility: hidden; transition: visibility 0s 300ms; }
.st-pause:hover { color: var(--ink); box-shadow: 0 0 0 1px var(--rule-3), 0 1px 0 rgba(255, 255, 255, 0.7) inset; }
/* two bars (playing) · a triangle (held) */
.st-pause::before,
.st-pause::after {
  content: "";
  position: absolute;
  top: 12px;
  width: 3px;
  height: 12px;
  border-radius: 1px;
  background: currentColor;
}
.st-pause::before { left: 13px; }
.st-pause::after { left: 20px; }
.st-pause[aria-pressed="true"]::after { display: none; }
.st-pause[aria-pressed="true"]::before {
  left: 14px;
  top: 11px;
  width: 0;
  height: 0;
  border-radius: 0;
  background: none;
  border-style: solid;
  border-width: 7px 0 7px 11px;
  border-color: transparent transparent transparent currentColor;
}

/* ---------- Meet Alfred: the lit specialist ---------- */
.agent { position: relative; }
.agent::after {
  content: "";
  position: absolute;
  inset: 0 auto auto 0;
  width: 100%;
  height: 1px;
  background: var(--lapis);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 700ms var(--ease-out);
}
.agent.is-on::after { transform: scaleX(1); }
.agent .agent-name { transition: color 400ms ease; }
.st-scrolly.has-on .agent:not(.is-on) .agent-name { color: var(--ink-3); }
.st-scrolly.has-on .agent:not(.is-on) p { color: var(--ink-3); }
.agent p { transition: color 400ms ease; }

/* ---------- below 1000 px: Meet Alfred is stacked — the field on top, the specialists rise below it as panels ---------- */
@media (max-width: 999px) {
  .st-scrolly { display: grid; gap: 24svh; margin-top: 42svh; }
  .st-scrolly .agent {
    padding: 22px 22px 24px;
    border-radius: 22px;
    background: rgba(250, 249, 246, 0.9);
    box-shadow: 0 0 0 1px rgba(20, 20, 15, 0.09), 0 1px 0 rgba(255, 255, 255, 0.8) inset;
  }
  .st-scrolly .agent + .agent::before { display: none; }
  .st-scrolly .agent::after { inset: 0 22px auto 22px; width: auto; }
}

/* ---------- phones ---------- */
@media (max-width: 759px) {
  .st-space { display: block; height: 42svh; }
  /* the statement keeps a breath under its lines: the streams flow into it before the Meet head arrives */
  .statement { padding-bottom: calc(var(--section-pad) + 30svh); }
  /* over the field: its bottom-right (the choreography keeps it there as the field moves) */
  .st-pause { bottom: auto; top: calc(var(--hdr-h) + 48px + 42svh - 52px); }
  .st-lbl__n { font-size: 15px; }
  .fx-stage::before {
    --st-s: 37cqw;
    left: calc(50cqw - var(--st-s) * 1.25);
    top: calc(27cqh - var(--st-s) * 1.25);
    background-image: url("../img/stage-still-phone.webp");
  }
}

@media (prefers-reduced-motion: reduce) {
  .st-canvas,
  .fx-stage::before { transition: none; }
  .st-lbl { transition: none; }
  .st-lbl[data-active="1"]::after { animation: none; }
  .agent::after,
  .agent .agent-name,
  .agent p { transition: none; }
}
