/* ═══════════════════════════════════════════════════════════════════════
   The reel: one pinned viewport, six acts.

   The whole upper page is a single tall track with one sticky stage on
   it. Every act is a layer on that stage, and the scroll moves between
   them rather than moving the page: for twelve screens of scrolling the
   viewport does not shift by a pixel, and what changes is what is on it.

   Each act declares its own `data-hold`, in vh of scroll. The script adds
   those up to decide the track's height, so an act's share of the scroll
   is written next to the act and nowhere else. Inside its share it
   arrives, holds, and leaves, with a beat of black at each handover —
   crossfading them one for one read as two things at once rather than as
   one becoming another.

   Nothing here sets opacity or transform on an act. The script owns both
   from the first frame, and a rule that also set them would be a second
   opinion that wins at exactly the wrong moment.
   ═══════════════════════════════════════════════════════════════════════ */

.reel{
  position:relative;
  /* A rough height for before the script has measured anything, so the
     scrollbar is about the right size on the first paint instead of
     snapping to ten times its length a moment later. The script replaces
     it with the exact sum of the acts' holds. */
  height:1010vh;
}

.reel-stage{
  position:sticky;top:0;
  height:100vh;
  /* svh, not vh: an address bar sliding away must not change how tall the
     stage is, or the whole reel resizes under the thumb scrolling it. */
  height:100svh;
  overflow:hidden;
  /* The ground, on the pinned element rather than on the track. It was
     `background-attachment:fixed` on the track, which makes the browser
     repaint the whole backdrop on every scroll event — on a page that is
     one long scroll, the most expensive thing on it. The stage does not
     move, so a gradient painted on it does not either, and costs nothing. */
  background:linear-gradient(180deg,#171b1e 0%,#101315 44%,var(--ink) 100%);
}

/* The light on the stage. One wash for the whole reel, dimmed and shifted
   by the script as the acts change, so the room the acts play in has a
   depth of its own rather than each act carrying a glow around with it. */
.reel-wash{
  position:absolute;left:50%;top:50%;z-index:0;
  width:min(1700px,165vw);height:min(1700px,165vw);
  transform:translate(-50%,-50%);
  background:radial-gradient(circle at 50% 50%,rgba(21,98,221,.30),transparent 58%);
  pointer-events:none;
}

/* ── an act ─────────────────────────────────────────────────────────  */

/* No padding for a header any more: it scrolls away with the first act,
   so every act gets the whole stage. On a phone that is seventy pixels
   back, which is the difference between the cost ledger being set at full
   size and being shrunk to fit.

   `will-change` is set by the script, and only while an act is moving.
   Declared here it would promote six full-screen layers for the length of
   the visit, which is a lot of texture to buy nothing. */
.act{
  position:absolute;inset:0;z-index:1;
  display:flex;align-items:center;
}
.act-fit{
  width:100%;
  /* Scaled by the script when the content is taller than the stage, so an
     act can never be clipped by the viewport it is pinned to. A phone in
     landscape, a large type size, six questions open at once: all of them
     set smaller rather than losing their bottom half. */
  transform-origin:50% 50%;
}
.act-body{position:relative;z-index:1}

/* The label above each act's heading. Four words that say where you are,
   which is the one thing a pinned page cannot show by position. */
.act-kind{
  font-family:var(--mono);font-weight:500;font-size:12.5px;
  letter-spacing:.18em;text-transform:uppercase;
  color:var(--signal-lit);
  margin:0 0 18px;
}

/* ── the scroll cue ─────────────────────────────────────────────────
   Bottom of the stage, on the content's own left edge, so it reads as
   part of the composition. It was a bare 1px stub hanging under the
   paragraph, which read as something that had failed to load. */
.cue{
  position:absolute;z-index:2;
  left:calc((100% - min(var(--wrap), 100% - var(--gut) * 2)) / 2 + var(--gut));
  bottom:max(26px,4vh);
  display:flex;align-items:center;gap:12px;
  margin:0;
  font-family:var(--mono);font-size:11px;font-weight:500;
  letter-spacing:.24em;text-transform:uppercase;
  color:var(--text-4);
  pointer-events:none;
}
.cue-line{
  display:block;width:46px;height:1px;
  background:var(--line-2);
  position:relative;overflow:hidden;
}
.cue-line::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(90deg,transparent,var(--signal-lit),transparent);
  animation:cue-sweep 2.8s var(--ease) infinite;
}
@keyframes cue-sweep{
  0%{transform:translateX(-100%)}
  60%,100%{transform:translateX(100%)}
}

/* ── act 1: the headline ────────────────────────────────────────────  */

/* The one act the header is over. */
.act-hero{padding-top:var(--head-h)}

.act-hero h1{
  font-size:var(--display);
  font-weight:700;letter-spacing:-.04em;line-height:.96;text-wrap:balance;
  background:linear-gradient(170deg,#ffffff 0%,#ffffff 44%,#cfd7db 100%);
  -webkit-background-clip:text;background-clip:text;
  color:transparent;-webkit-text-fill-color:transparent;
}
.act-hero .lede{margin-top:34px;max-width:46ch}

/* ── act 2: twelve printed cards on a strand ────────────────────────
   The geometry is a cylinder. Card i sits at (i − p) · 30° around it,
   where p is how far the act has been scrolled through, in cards. The
   card nearest the front is pulled towards the viewer and scaled up;
   everything behind falls away in opacity with depth. */

.act-styles{display:block}
/* The perspective belongs on the strand's own parent, not on the act.
   `.act-fit` sits between them and is a flat element, and a flat element
   cuts the 3D context: the cards kept their rotations and lost their
   foreshortening, so a card pushed towards the viewer came out the same
   width as one lying flat. */
.act-styles .act-fit{
  position:absolute;inset:0;
  perspective:1600px;perspective-origin:50% 50%;
}

.hx-world{
  position:absolute;left:50%;top:50%;width:0;height:0;
  transform-style:preserve-3d;
}
.hx-card{
  --w:clamp(128px,16vw,230px);
  position:absolute;left:0;top:0;width:var(--w);aspect-ratio:3/4;
  margin:calc(var(--w) * -.6667) 0 0 calc(var(--w) * -.5);
  transform-style:preserve-3d;will-change:transform;
}
.hx-card img{
  position:absolute;inset:0;width:100%;height:100%;
  backface-visibility:hidden;border-radius:4px;
  /* One shadow, not two. Twelve cards times two drop-shadows is twenty-four
     blurred copies of a 230px image re-rasterised behind every transform,
     and the second was doing little the first did not. */
  filter:drop-shadow(0 16px 24px rgba(0,0,0,.62));
}
.hx-back{
  position:absolute;inset:0;background:#e9e7e1;border-radius:4px;
  transform:rotateY(180deg);backface-visibility:hidden;
  background-image:radial-gradient(circle at 50% 50%,var(--signal) 0 7px,transparent 8px);
}

.hx-text{
  position:absolute;top:50%;transform:translateY(-50%);z-index:5000;
  width:min(32vw,30ch);color:var(--text);
}
.hx-text.on-right{right:var(--gut);text-align:left}
.hx-text.on-left{left:var(--gut);text-align:right}
/* A scrim under the words only, so they stay readable with a white card
   behind them without putting a panel on the screen. */
.hx-text::before{
  content:"";position:absolute;inset:-56px -84px;z-index:-1;pointer-events:none;
  background:radial-gradient(ellipse at 50% 50%,rgba(8,11,12,.92) 38%,rgba(8,11,12,0) 72%);
}
.hx-text h3{font-size:clamp(30px,3.9vw,50px);letter-spacing:-.035em;margin:0}
.hx-text p:last-child{
  font-size:clamp(16px,1.5vw,20px);line-height:1.55;
  color:var(--text-2);margin:16px 0 0;
}
.hx-text.is-in.on-right h3,
.hx-text.is-in.on-right p:last-child{animation:hx-from-right .55s var(--ease) both}
.hx-text.is-in.on-left h3,
.hx-text.is-in.on-left p:last-child{animation:hx-from-left .55s var(--ease) both}
.hx-text.is-in p:last-child{animation-delay:.08s}
@keyframes hx-from-right{from{opacity:0;transform:translateX(64px)}to{opacity:1;transform:none}}
@keyframes hx-from-left{from{opacity:0;transform:translateX(-64px)}to{opacity:1;transform:none}}

/* ── no script, or motion turned down ───────────────────────────────
   The reel becomes the page it is made of: every act one after another,
   the strand a row you can swipe. Nothing is hidden, nothing is pinned,
   and the only thing lost is the moving between them. */
/* The track's fallback height is for the pinned reel only; laid out as a
   page it is as tall as its acts. */
.reel:not(.is-live){height:auto}
.reel:not(.is-live) .reel-stage{position:static;height:auto;overflow:visible;background:none}
.reel:not(.is-live) .reel-wash{display:none}
.reel:not(.is-live) .act{
  position:static;display:block;
  padding:clamp(48px,7vw,96px) 0;
  opacity:1!important;visibility:visible!important;
}
.reel:not(.is-live) .act-fit{transform:none!important}
.reel:not(.is-live) .act + .act{border-top:1px solid var(--line)}
.reel:not(.is-live) .cue{display:none}
.reel:not(.is-live) .act-styles .act-fit{perspective:none}
.reel:not(.is-live) .act-styles .act-fit{position:static}
.reel:not(.is-live) .hx-world{
  position:static;width:auto;height:auto;transform:none;
  display:flex;gap:18px;overflow-x:auto;padding:12px var(--gut) 28px;
  scroll-snap-type:x proximity;scroll-padding-inline:var(--gut);
}
.reel:not(.is-live) .hx-card{
  position:static;flex:0 0 var(--w);margin:0;scroll-snap-align:start;
  transform:none!important;opacity:1!important;visibility:visible!important;
}
.reel:not(.is-live) .hx-card img{position:static}
.reel:not(.is-live) .hx-text{
  position:static;transform:none;padding:0 var(--gut);width:auto;text-align:left;
}
.reel:not(.is-live) .hx-back{display:none}
.reel:not(.is-live) .hx-text::before{display:none}

/* ── narrow ─────────────────────────────────────────────────────────  */
@media (max-width:860px){
  .act-styles .act-fit{perspective-origin:50% 36%}
  .hx-world{top:36%}
  .hx-card{--w:clamp(112px,32vw,164px)}
  .hx-text,
  .hx-text.on-left,
  .hx-text.on-right{
    left:var(--gut);right:var(--gut);top:auto;bottom:9vh;
    transform:none;width:auto;text-align:center;
  }
  .hx-text::before{inset:-28px -20px}
}
