/* ============================================================
   LET MARK COOK — 02 hero
   intro curtain · hero · portrait reveal · headline · marquee
   ============================================================ */

/* ---------- intro curtain ----------
   One orchestrated page-load moment: the wordmark sets, the meter
   fills, then two panels split apart to hand over to the hero. */

.curtain {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: grid;
  place-items: center;
  background: var(--ink);
  overflow: hidden;
}
.curtain.is-done { pointer-events: none; }
.curtain.is-gone { display: none; }

.curtain__panel {
  position: absolute;
  left: 0; right: 0;
  height: 50.5%;
  background: var(--ink);
  z-index: 1;
  transition: transform 1s var(--ease);
}
.curtain__panel--a { top: 0; }
.curtain__panel--b { bottom: 0; }
.curtain.is-done .curtain__panel--a { transform: translateY(-100%); }
.curtain.is-done .curtain__panel--b { transform: translateY(100%); }

.curtain__inner {
  position: relative;
  z-index: 2;
  text-align: center;
  padding-inline: var(--gutter);
  transition: opacity .45s var(--ease), transform .6s var(--ease);
}
.curtain.is-done .curtain__inner { opacity: 0; transform: translateY(-1.5rem); }

.curtain__mark {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .35em;
  font-family: var(--font-display);
  font-size: clamp(2.2rem, 11vw, 5.5rem);
  line-height: .9;
  text-transform: uppercase;
  letter-spacing: -.03em;
}
.curtain__word {
  display: block;
  opacity: 0;
  transform: translateY(.5em);
  animation: curtainWord .8s var(--ease) forwards;
}
.curtain__word:nth-child(2) { animation-delay: .1s; }
.curtain__word:nth-child(3) { animation-delay: .2s; }
.curtain__word--hot { color: var(--flame); }

@keyframes curtainWord { to { opacity: 1; transform: none; } }

.curtain__meter {
  width: min(15rem, 54vw);
  height: 2px;
  margin: 1.75rem auto .9rem;
  background: rgba(247,244,238,.14);
  overflow: hidden;
}
.curtain__fill {
  display: block;
  height: 100%;
  width: 100%;
  background: var(--flame);
  transform: scaleX(0);
  transform-origin: left;
}

.curtain__count {
  margin: 0;
  font-size: .74rem;
  font-weight: 700;
  letter-spacing: .18em;
  color: var(--smoke);
}
.curtain__pct { margin-left: .1em; }

/* the page underneath holds still until the curtain lifts */
body:not(.is-ready) { overflow: hidden; }

/* ---------- the stage ----------
   .stage is a tall scroll runway; .stage__pin is the single viewport-high
   pane that sticks inside it. Scroll position through the runway is turned
   into progress by js/07-stage.js, which writes the custom properties the
   transforms below read. Nothing animates on a timer — every value here is
   a direct function of where the page is scrolled to. */

.stage {
  position: relative;
  height: 260vh;
  height: 260svh;
  z-index: 2;
}

/* A phone runs the hero's moves one after another rather than together —
   hold, then the coat, then the shrink — so it needs more runway to give
   each phase room. See the timing constants in js/07-stage.js. */
@media (pointer: coarse) {
  .stage {
    height: 290vh;
    height: 290svh;
  }
}

.stage__pin {
  position: sticky;
  top: 0;
  height: 100vh;
  height: 100svh;
  display: grid;
  place-items: center;
  overflow: hidden;
}

/* the orbit and the portrait share one centred grid cell and are offset
   from there by transform alone, which keeps both on the compositor */
.orbit, .portrait { grid-area: 1 / 1; }

/* ---------- orbiting graphics ---------- */

.orbit {
  position: relative;
  width: min(88vw, 38rem);
  aspect-ratio: 1;
  z-index: 1;
  opacity: var(--o-o, 1);
  transform: scale(var(--o-s, 1));
  will-change: transform, opacity;
}

.orbit__glow {
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(74,13,20,.85), rgba(255,90,31,.10) 55%, transparent 72%);
  filter: blur(26px);
}

.orbit__ring {
  position: absolute;
  border-radius: 50%;
  animation: orbitSpin 42s linear infinite;
}
.orbit__ring--a {
  inset: 0;
  border: 1px dashed rgba(247,244,238,.16);
}
.orbit__ring--b {
  inset: 13%;
  border: 1px solid rgba(255,90,31,.22);
  animation-duration: 28s;
  animation-direction: reverse;
}

@keyframes orbitSpin { to { transform: rotate(360deg); } }

/* embers drifting around him */
.spark {
  position: absolute;
  width: .45rem;
  height: .45rem;
  border-radius: 50%;
  background: var(--flame);
  filter: blur(1px);
  opacity: .8;
}
.spark--1 { top: 8%;  left: 22%; animation: sparkFloat 7s ease-in-out infinite; }
.spark--2 { top: 62%; left: 4%;  animation: sparkFloat 9s ease-in-out infinite .8s; background: var(--ember); }
.spark--3 { top: 26%; right: 6%; animation: sparkFloat 8s ease-in-out infinite 1.6s; }
.spark--4 { bottom: 12%; right: 24%; animation: sparkFloat 11s ease-in-out infinite .4s; background: var(--ember); }

@keyframes sparkFloat {
  0%, 100% { transform: translate(0, 0) scale(1);      opacity: .8; }
  33%      { transform: translate(1.2rem, -2rem) scale(1.4); opacity: .35; }
  66%      { transform: translate(-.8rem, -3.4rem) scale(.7); opacity: .6; }
}

/* ---------- food bubbles ----------
   Positioned and moved entirely from js/08-bubbles.js, which writes a
   transform per frame. They sit behind Mark so he stays the focal point,
   and never take pointer events — the cursor collision is measured in
   javascript, so the bubbles must not intercept a drag on the photograph
   or a click on anything underneath. */

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.bubbles {
  position: absolute;
  inset: 0;
  z-index: 2;
  overflow: hidden;
  pointer-events: none;
  opacity: var(--o-o, 1);
}

.bubble {
  position: absolute;
  top: 0;
  left: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: radial-gradient(circle at 32% 26%, rgba(247,244,238,.14), rgba(10,5,6,.62) 68%);
  border: 1px solid rgba(247,244,238,.13);
  box-shadow: 0 .5rem 1.6rem rgba(0,0,0,.35);
  will-change: transform;
}

.bubble svg {
  width: 58%;
  height: 58%;
  overflow: visible;
  filter: drop-shadow(0 1px 2px rgba(0,0,0,.5));
}

/* A cut-out photograph already has its own silhouette, so it floats free
   rather than being boxed into the glass disc — that reads as a sticker.
   What it keeps is a soft warm glow underneath, which stops the darker
   edges of a cut-out disappearing into a near-black page. */
.bubble--photo {
  background: radial-gradient(circle at 50% 55%, rgba(255,90,31,.22), transparent 68%);
  border-color: transparent;
  box-shadow: none;
}

.bubble--photo img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  filter: drop-shadow(0 .35rem .7rem rgba(0,0,0,.55));
}

/* ---------- the portrait ----------
   The container carries the photograph's own aspect ratio, so the whole of
   him fits with nothing cropped — the coat in particular, which the old
   cover-fit was cutting off at the bottom. */

.portrait {
  position: relative;
  z-index: 3;
  height: min(72vh, 40rem);
  height: min(72svh, 40rem);
  aspect-ratio: 768 / 1344;
  /* --p-y is the scroll lift, --sp-x/--sp-y the spring bounce. The
     translate sits outside the scale, so the bounce keeps the same size
     in pixels however small he shrinks — otherwise it would fade out
     exactly when he is at his smallest and needs it most. */
  transform:
    translate3d(var(--sp-x, 0px), calc(var(--p-y, 0px) + var(--sp-y, 0px)), 0)
    scale(var(--p-s, 1));
  will-change: transform;
  -webkit-tap-highlight-color: transparent;
  touch-action: pan-y;        /* a vertical swipe still scrolls the page */

}

/* The canvas is deliberately bigger than the photograph it holds.

   Smoke lives on the same canvas as Mark, so when the two were the same
   size the smoke could only ever fade out inside the picture — it died
   at the frame edge instead of drifting off it. The canvas now bleeds
   past the portrait on every side (most of the extra above, since smoke
   rises), the photograph is drawn into the middle of it, and the smoke
   has somewhere to go. .stage__pin clips it at the viewport, which is
   the only boundary that should ever be visible.

   The feathered edge on the photograph is no longer a CSS mask, because
   a mask on the element would take the smoke with it. It is composited
   into the photo buffers instead, in js/02-portrait.js. */
/* Sized with explicit percentages, not four insets: a canvas is a replaced
   element, so width/height:auto resolves to its intrinsic attribute size and
   the insets are quietly ignored — which collapsed it and clipped Mark away.
   158% wide = 100 + 29 + 29, 156% tall = 100 + 38 + 18. The margin has to be
   comfortably wider than the smoke's fade band, or the fade gets compressed
   against the photograph and reads as an edge again. */
.portrait__canvas {
  position: absolute;
  top: -38%;
  left: -29%;
  width: 158%;
  height: 156%;
  /* the global `canvas { max-width: 100% }` reset would clamp it straight
     back to the portrait's width and undo the horizontal bleed */
  max-width: none;
  touch-action: pan-y;
}

/* the still fallback, shown only until the canvas has its photographs */
.portrait__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  transition: opacity .5s var(--ease);
  /* matches the canvas feather in js/02-portrait.js — kept tight to the
     frame so it never eats into his face */
  -webkit-mask-image:
    linear-gradient(to right,  transparent 0, #000 8.5%, #000 91.5%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 2%, #000 88%, transparent 100%);
  -webkit-mask-composite: source-in;
  mask-image:
    linear-gradient(to right,  transparent 0, #000 8.5%, #000 91.5%, transparent 100%),
    linear-gradient(to bottom, transparent 0, #000 2%, #000 88%, transparent 100%);
  mask-composite: intersect;
}

/* ---------- the wordmark it hands over to ---------- */

.stage__reveal {
  position: absolute;
  left: 0;
  right: 0;
  top: 40vh;
  top: 40svh;
  z-index: 4;
  padding-inline: var(--gutter);
  text-align: center;
  opacity: var(--r-o, 0);
  transform: translate3d(0, var(--r-y, 2rem), 0);
  will-change: transform, opacity;
  pointer-events: none;
}
.stage.is-lit .stage__reveal { pointer-events: auto; }

.stage__reveal .eyebrow { margin-bottom: .6rem; }

.headline {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.6rem, min(14vw, 15vh), 9rem);
  font-size: clamp(2.6rem, min(14vw, 15svh), 9rem);
  line-height: .84;
  letter-spacing: -.04em;
  text-transform: uppercase;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 .28em;
}

.word { display: flex; }
.word--hot { color: var(--flame); }

.letter {
  display: inline-block;
  transform: translateY(1.05em) rotate(6deg);
  opacity: 0;
  transition:
    transform .85s var(--ease) calc(var(--i) * .04s),
    opacity   .55s var(--ease) calc(var(--i) * .04s);
  will-change: transform;
}
.stage.is-lit .letter { transform: none; opacity: 1; }

@media (hover: hover) and (pointer: fine) {
  .stage.is-lit .letter { transition: transform .45s var(--ease), color .45s var(--ease); }
  .stage.is-lit .letter:hover { transform: translateY(-.08em) scale(1.04); color: var(--ember); }
}

.hero__tag {
  margin: clamp(.7rem, 2vh, 1.2rem) auto 0;
  margin: clamp(.7rem, 2svh, 1.2rem) auto 0;
  font-size: clamp(1rem, 2.2vw, 1.3rem);
  font-weight: 600;
  max-width: 26ch;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: .7rem;
  margin-top: clamp(1.1rem, 3vh, 2.2rem);
  margin-top: clamp(1.1rem, 3svh, 2.2rem);
}

/* ---------- scroll cue ---------- */

.hero__scroll {
  position: absolute;
  left: 50%;
  bottom: clamp(1.25rem, 4vh, 2.5rem);
  bottom: clamp(1.25rem, 4svh, 2.5rem);
  transform: translateX(-50%);
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: .6rem;
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--smoke);
  opacity: var(--cue-o, 1);
  transition: color .3s var(--ease);
}
.hero__scroll:hover { color: var(--cream); }

.hero__scroll-rail {
  display: block;
  position: relative;
  width: 1px;
  height: 2.2rem;
  background: var(--line);
  overflow: hidden;
}
.hero__scroll-rail i {
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 45%;
  background: var(--flame);
  animation: railRun 2.2s var(--ease) infinite;
}
@keyframes railRun {
  0%   { transform: translateY(-110%); }
  55%  { transform: translateY(130%); }
  100% { transform: translateY(130%); }
}

/* ---------- static fallback ----------
   Reduced motion, or no javascript: the runway collapses to one ordinary
   screen with everything already in place and nothing pinned. */

.stage.is-static { height: auto; }
.stage.is-static .stage__pin {
  position: relative;
  height: auto;
  padding-block: calc(var(--nav-h) + 3rem) 4rem;
  gap: 2rem;
}
.stage.is-static .orbit { display: none; }
.stage.is-static .portrait { transform: none; height: min(52vh, 26rem); }
.stage.is-static .portrait { transform: none; height: min(52svh, 26rem); }
.stage.is-static .stage__reveal {
  position: relative;
  top: auto;
  margin-top: 2.5rem;
  opacity: 1;
  transform: none;
  pointer-events: auto;
  grid-area: auto;
}
.stage.is-static .letter { transform: none; opacity: 1; }
.stage.is-static .hero__scroll { display: none; }

/* ---------- marquee ---------- */

.marquee {
  position: relative;
  z-index: 2;
  overflow: hidden;
  padding-block: clamp(.9rem, 2.5vw, 1.4rem);
  border-block: 1px solid var(--line);
  background: var(--char);
  user-select: none;
}

.marquee__track {
  display: flex;
  align-items: center;
  gap: 1.4rem;
  width: max-content;
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 4.5vw, 2.6rem);
  text-transform: uppercase;
  letter-spacing: -.01em;
  will-change: transform;
}
.marquee__track i {
  font-style: normal;
  font-size: .45em;
  color: var(--flame);
  transform: translateY(-.15em);
}
.marquee__track span:nth-child(4n+1) { color: var(--smoke); }
