/* ==========================================================================
   sections — hero → statement → reel → ticker → bay → contact → footer
   ========================================================================== */

/* ── hero ──────────────────────────────────────────────────────────────────
   The hero is type over a live WebGL scene. It has to hold to 100svh with
   room to spare on a laptop, so the display size is capped hard and the
   footer row is allowed to wrap rather than push the fold.
   ------------------------------------------------------------------------ */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  align-items: flex-end;
  padding: calc(var(--gut) * 2 + 3rem) var(--gut) clamp(1.4rem, 4vh, 2.6rem);
}

.hero__inner { width: 100%; display: grid; gap: clamp(1.1rem, 3vh, 2.2rem); }

.hero__eyebrow { display: flex; align-items: center; gap: 0.6em; }

.dot {
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 0 0 var(--cyan-dim);
  animation: pulse 2.6s var(--ease-io) infinite;
}

@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(77, 227, 255, 0.5); }
  70%  { box-shadow: 0 0 0 9px rgba(77, 227, 255, 0); }
  100% { box-shadow: 0 0 0 0 rgba(77, 227, 255, 0); }
}

.hero__title { font-size: var(--t-hero); }

/* The one italic in the build. It marks the word the sentence turns on and
   nothing else — no gradient, no glow, no outline. The rule under it is
   drawn on once, by script. */
.hero__em {
  position: relative;
  font-style: italic;
  font-variation-settings: "wdth" 96;
  color: var(--cyan);
}

.hero__em::after {
  content: "";
  position: absolute;
  left: 0.03em; right: 0.02em; bottom: 0.1em;
  height: 2px;
  background: var(--cyan);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 1.1s var(--ease);
}

.hero__em.is-drawn::after { transform: scaleX(1); }

.hero__foot {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: clamp(1.2rem, 3vw, 3rem);
  padding-top: clamp(0.8rem, 2vh, 1.4rem);
  border-top: 1px solid var(--line);
}

.hero__sub { max-width: 46ch; color: var(--silver-2); }

.hero__stats { display: flex; gap: clamp(1.4rem, 3.5vw, 3.2rem); margin: 0; }
.hero__stats div { display: grid; gap: 0.25rem; }
.hero__stats dd {
  margin: 0;
  font-family: var(--f-display);
  font-weight: 700;
  font-variation-settings: "wdth" 108;
  font-size: clamp(1.4rem, 2.4vw, 2.2rem);
  line-height: 1;
  letter-spacing: -0.03em;
}

.hero__cue { display: flex; align-items: center; gap: 0.8em; }

.hero__cue-line {
  display: block;
  width: clamp(40px, 8vw, 90px); height: 1px;
  background: var(--line-2);
  overflow: hidden;
  position: relative;
}

.hero__cue-line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--cyan);
  transform-origin: left;
  animation: sweep 2.8s var(--ease-io) infinite;
}

@keyframes sweep {
  0%   { transform: scaleX(0); transform-origin: left; }
  45%  { transform: scaleX(1); transform-origin: left; }
  55%  { transform: scaleX(1); transform-origin: right; }
  100% { transform: scaleX(0); transform-origin: right; }
}

/* ── statement ─────────────────────────────────────────────────────────── */

.statement {
  position: relative;
  padding: var(--sec) var(--gut);
  display: grid;
  gap: clamp(2.5rem, 7vh, 5rem);
}

/* Sized down from --t-h2 and widened from 26ch. At the larger setting the
   paragraph ran to seven lines and filled the viewport top to bottom, which
   reads as a wall of text rather than as a statement — the point of setting
   a sentence this large is that you can take it in at once. */
.statement__body {
  max-width: 30ch;
  font-family: var(--f-display);
  font-weight: 500;
  font-variation-settings: "wdth" 92;
  font-size: clamp(1.7rem, 4.2vw, 3.7rem);
  line-height: 1.06;
  letter-spacing: -0.035em;
  text-transform: none;
}

/* Word spans are inline-block so they can be swept individually. The space
   between them must stay a real, collapsible text node — if the splitter
   emits whitespace inside a span with `white-space: pre`, every source
   newline becomes a hard line break and the paragraph shatters. */
.statement__body .sp-w { will-change: transform, opacity; }

.statement__grid {
  display: grid;
  gap: clamp(1.6rem, 4vw, 3.2rem);
  grid-template-columns: 1fr;
  max-width: 1100px;
}

@media (min-width: 760px) { .statement__grid { grid-template-columns: repeat(3, 1fr); } }

.statement__grid p { color: var(--silver-2); max-width: 38ch; }
.statement__h { margin-bottom: 0.7rem; color: var(--cyan); }

/* ── the reel ──────────────────────────────────────────────────────────────
   The section is tall; the pin box inside it is exactly one viewport. The
   ScrollTrigger must be anchored to the PIN, not to this padded section —
   trigger the section and the pin box starts already pushed down the screen
   by the section's own leading padding.
   ------------------------------------------------------------------------ */

.reel { position: relative; height: 560vh; }

.reel__pin {
  position: relative;
  height: 100svh;
  display: grid;
  align-content: space-between;
  padding: calc(var(--gut) * 2 + 3rem) var(--gut) clamp(1.4rem, 4vh, 2.6rem);
  pointer-events: none;
}

.reel__hud { display: flex; justify-content: space-between; gap: 1.5rem; }

.reel__caption { display: grid; gap: 0.4rem; max-width: 34ch; }

.reel__idx { color: var(--cyan); }

.reel__title {
  font-size: clamp(1.9rem, 5.4vw, 4.2rem);
  font-variation-settings: "wdth" 104;
}

.reel__by { color: var(--silver-2); }

.reel__hint {
  position: absolute;
  left: 50%; bottom: clamp(1.4rem, 4vh, 2.6rem);
  transform: translateX(-50%);
  color: var(--silver-4);
}

@media (max-width: 700px) { .reel__hint { display: none; } }

/* The accessible index. Off-canvas visually on wide screens (the 3D corridor
   is showing the same six films), but present in the DOM, focusable, and
   fully visible whenever WebGL is missing or the viewport is narrow. */
.reel__index {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
}

.reel__index a:focus-visible {
  position: fixed;
  top: 50%; left: 50%;
  z-index: 300;
  width: min(320px, 80vw); height: auto;
  transform: translate(-50%, -50%);
  clip-path: none;
  display: grid;
  gap: 0.3rem;
  padding: 1rem;
  background: var(--void-2);
  border: 1px solid var(--cyan);
}

/* ── ticker ────────────────────────────────────────────────────────────── */

/* From the ticker down, the sections are opaque. The fixed WebGL canvas sits
   behind the whole document, and everything past the corridor is meant to be
   read, not read through — the stage stops rendering here too. */
.ticker {
  position: relative;
  background: var(--void);
  overflow: hidden;
  padding: clamp(1rem, 2.6vh, 1.8rem) 0;
  border-top: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
}

.ticker__track {
  display: flex;
  align-items: center;
  gap: clamp(1.2rem, 3vw, 2.6rem);
  width: max-content;
  will-change: transform;
}

.ticker__track span {
  font-family: var(--f-display);
  font-weight: 600;
  font-variation-settings: "wdth" 110;
  font-size: clamp(1.3rem, 3.4vw, 2.6rem);
  line-height: 1;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--silver-3);
}

.ticker__d { color: var(--cyan) !important; }

/* ── the bay ───────────────────────────────────────────────────────────── */

.bay {
  position: relative;
  background: var(--void);
  padding: var(--sec) var(--gut);
  display: grid;
  gap: clamp(2rem, 5vh, 3.5rem);
}

.bay__head { display: grid; gap: clamp(0.9rem, 2.4vh, 1.6rem); max-width: 62ch; }
.bay__h { font-size: var(--t-h2); }
.bay__slash { color: var(--cyan); }
.bay__lead { max-width: 52ch; }

.bay__viewer {
  position: relative;
  margin: 0;
  aspect-ratio: 16 / 9;
  max-height: 76svh;
  overflow: hidden;
  background: var(--void-2);
  border: 1px solid var(--line);
  touch-action: pan-y;
}

.bay__canvas { position: absolute; inset: 0; }
.bay__canvas canvas { width: 100%; height: 100%; }

.bay__fallback { position: absolute; inset: 0; display: none; }
.bay__fallback img { width: 100%; height: 100%; object-fit: cover; }

.bay__tagl, .bay__tagr {
  position: absolute;
  bottom: clamp(0.7rem, 2vh, 1.2rem);
  z-index: 2;
  padding: 0.35em 0.7em;
  background: rgba(8, 9, 11, 0.62);
  color: var(--silver-2);
  pointer-events: none;
}

.bay__tagl { left: clamp(0.7rem, 2vw, 1.2rem); }
.bay__tagr { right: clamp(0.7rem, 2vw, 1.2rem); color: var(--cyan); }

/* The handle is positioned with a transform on a full-height zero-width
   element, so dragging never reflows the viewer. */
.bay__handle {
  position: absolute;
  top: 0; bottom: 0; left: 0;
  z-index: 3;
  width: 44px;
  margin-left: -22px;
  display: grid;
  place-items: center;
  cursor: ew-resize;
  transform: translateX(50%);
  touch-action: none;
}

.bay__stem {
  position: absolute;
  top: 0; bottom: 0; left: 50%;
  width: 1px;
  margin-left: -0.5px;
  background: var(--silver);
  opacity: 0.85;
}

.bay__grip {
  position: relative;
  width: 42px; height: 42px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--void);
  border: 1px solid var(--silver-2);
  color: var(--silver);
  transition: transform 0.4s var(--ease), border-color 0.4s var(--ease), color 0.4s var(--ease);
}

.bay__grip svg { width: 20px; height: 20px; }

.bay__handle:hover .bay__grip,
.bay__handle:focus-visible .bay__grip,
.bay__handle.is-drag .bay__grip {
  transform: scale(1.14);
  border-color: var(--cyan);
  color: var(--cyan);
}

.bay__notes {
  display: grid;
  gap: clamp(1.2rem, 3vw, 2.6rem);
  grid-template-columns: 1fr;
  max-width: 1100px;
}

@media (min-width: 760px) { .bay__notes { grid-template-columns: repeat(3, 1fr); } }

.bay__notes span { display: block; margin-bottom: 0.5rem; color: var(--cyan); }
.bay__notes p { color: var(--silver-2); max-width: 34ch; }

/* ── contact ───────────────────────────────────────────────────────────── */

.contact {
  position: relative;
  background: var(--void);
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding: var(--sec) var(--gut);
  overflow: hidden;
}

.contact__bg {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  opacity: 0.34;
}

.contact__scrim {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(120% 80% at 50% 40%, rgba(8, 9, 11, 0.2), rgba(8, 9, 11, 0.94) 72%),
    linear-gradient(to bottom, rgba(8, 9, 11, 0.85), rgba(8, 9, 11, 0.5) 40%, var(--void));
}

.contact__inner { position: relative; width: 100%; display: grid; gap: clamp(1.6rem, 4.5vh, 3rem); }

.contact__h { font-size: var(--t-hero); }

.contact__em {
  font-style: italic;
  font-variation-settings: "wdth" 96;
  color: var(--cyan);
}

.rows { display: grid; max-width: 900px; }

.rows li { border-top: 1px solid var(--line); }
.rows li:last-child { border-bottom: 1px solid var(--line); }

.row {
  display: grid;
  grid-template-columns: 9rem 1fr auto;
  align-items: baseline;
  gap: 1rem;
  padding: clamp(0.85rem, 2.4vh, 1.35rem) 0;
  transition: color 0.4s var(--ease);
}

@media (max-width: 620px) { .row { grid-template-columns: 6rem 1fr auto; } }

.row__v { font-size: clamp(1.05rem, 2.2vw, 1.65rem); letter-spacing: -0.02em; }

/* Label and value translate; the arrow stays put. Shifting the whole row
   would carry the arrow across the section's overflow clip, and animating
   padding would lay the row out on every frame. */
.row__k, .row__v { transition: transform 0.5s var(--ease); }
a.row:hover { color: var(--cyan); }
a.row:hover .row__k, a.row:hover .row__v { transform: translateX(0.75rem); }

.row__a { color: var(--silver-4); transition: color 0.4s var(--ease), transform 0.5s var(--ease); }
a.row:hover .row__a { color: var(--cyan); transform: translate(0.2rem, -0.2rem); }

/* ── footer ────────────────────────────────────────────────────────────── */

.foot {
  position: relative;
  background: var(--void);
  padding: clamp(2rem, 6vh, 4rem) var(--gut) clamp(1.5rem, 4vh, 2.5rem);
  border-top: 1px solid var(--line);
  display: grid;
  gap: 1.2rem;
}

.foot__row {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.6rem 2rem;
}

.foot__note { max-width: 62ch; color: var(--silver-4); letter-spacing: 0.09em; }

/* ── scroll-reveal primitive ───────────────────────────────────────────── */

[data-rise] { will-change: transform, opacity; }

/* ── no-WebGL fallback ─────────────────────────────────────────────────────
   Without a GL context the hero would be an empty black screen and the reel
   would be six invisible planes. Both get a real picture instead, and the
   reel index becomes the reel.
   ------------------------------------------------------------------------ */

.fallback { display: none; }

.nogl .fallback--hero {
  display: block;
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
}

.nogl .fallback--hero::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, var(--void) 8%, rgba(8, 9, 11, 0.55) 55%, rgba(8, 9, 11, 0.8));
}

.nogl .fallback--hero img { width: 100%; height: 100%; object-fit: cover; opacity: 0.6; }

.nogl .bay__fallback { display: block; }
.nogl .bay__handle, .nogl .bay__tagl, .nogl .bay__tagr { display: none; }

.nogl .reel { height: auto; padding-bottom: var(--sec); }
.nogl .reel__pin { height: auto; padding-bottom: 2rem; }
.nogl .reel__caption, .nogl .reel__hint { display: none; }

.nogl .reel__index {
  position: static;
  width: auto; height: auto;
  margin: 0;
  clip-path: none;
  overflow: visible;
  display: grid;
  gap: clamp(1.5rem, 4vw, 3rem);
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  padding: 0 var(--gut);
}

.nogl .reel__index a { display: grid; gap: 0.35rem; }
.nogl .reel__index img { width: 100%; aspect-ratio: 9 / 14; object-fit: cover; }
.nogl .reel__index-t { font-size: 1.2rem; letter-spacing: -0.02em; }

/* Narrow screens get the same honest list — a six-plane 3D corridor on a
   phone is a battery bill, not a portfolio. */
@media (max-width: 700px) {
  /* The corridor is not shown here, so the section must carry its own
     ground rather than letting the parked 3D scene show through the list. */
  .reel { height: auto; background: var(--void); padding-bottom: var(--sec); }
  .reel__pin { height: auto; padding-bottom: 2rem; }
  .reel__caption { display: none; }
  .reel__index {
    position: static;
    width: auto; height: auto;
    margin: 0;
    clip-path: none;
    overflow: visible;
    display: grid;
    gap: 2rem;
    padding: 0 var(--gut);
  }
  .reel__index a { display: grid; gap: 0.35rem; }
  .reel__index img { width: 100%; aspect-ratio: 9 / 14; object-fit: cover; }
  .reel__index-t { font-size: 1.2rem; letter-spacing: -0.02em; }
}
