/* ============================================================================
   SINAN — 01 · THE HERO
   ----------------------------------------------------------------------------
   ONE IMAGE. assets/hero/hero.webp is the final artwork, shipped byte-for-byte
   from ref/hero.webp. The architecture, the chambers, the figures, the lighting
   and the floor reflections are all in the photograph. Nothing here cuts it into
   layers, composites anything into it, or paints light over it — at rest the
   only things on top of the artwork are four words of navigation and a name.

   The camera push into the central chamber is GONE. The hero holds still; the
   record comes to it.

   Sections 03..07 live in site.css; tokens and type in base.css.
   ========================================================================= */

/* ═══════════════════════════════════════════════════════════════════════
   SHELL
   ═══════════════════════════════════════════════════════════════════════ */

.page { position: relative; }
.stick { position: relative; }

/* The pin is exactly the length of the vinyl beat — 120vh, down from 230.
   js/hero.js measures this element, so changing it here re-times everything. */
.travel { height: 120vh; }

.hero {
  --p: 0;      /* progress across the pin                        */
  --rec: 0;    /* how far the artwork has receded                */
  --dp: 0;     /* the disc                                       */
  --np: 0;     /* section 03's ground arriving                   */
  --dx: 0;     /* the disc being lifted away at the very end     */
  --disc-scale: .3;
  --disc-o: 1;
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
  background: var(--ink);
  isolation: isolate;
}

/* ═══════════════════════════════════════════════════════════════════════
   THE ARTWORK
   Cover-fitted so it fills the viewport without ever being stretched — the
   file is a true 16:9, so on most desktops this is an exact fit and nothing
   is cropped at all. The scroll gives it a 3% drift and a darkening pass,
   which is the whole of the movement: no dolly, no zoom into anything.
   ═══════════════════════════════════════════════════════════════════════ */

/* NOT transformed and NOT promoted. A 3840x2160 plate under will-change is a
   33-megapixel composited layer — ~130MB of GPU texture — and it will drop
   frames or fail to paint outright. The artwork holds still, which is what the
   hero wants anyway; the recede below is an opacity on a small gradient and
   costs nothing. */
.hero__art {
  position: absolute; inset: 0;
}
.hero__art img {
  display: block;
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: 50% 50%;
}

/* The ONLY thing ever laid over the artwork, and it is zero until the reader
   scrolls. It is what lets the record read against the picture without any
   glow, border or added light on the artwork itself. */
.hero__recede {
  position: absolute; inset: 0; z-index: 1;
  pointer-events: none;
  background:
    radial-gradient(76% 60% at 50% 46%, rgba(9,1,34,.28), rgba(9,1,34,.72) 88%),
    linear-gradient(180deg, rgba(2,6,102,.26), transparent 34%);
  opacity: calc(var(--rec) * .52);
}

/* ═══════════════════════════════════════════════════════════════════════
   02 · THE RECORD, in the same frame
   It starts arriving almost as soon as the page moves, so the hero does not
   have to finish before anything happens. Section 03's ground comes up
   BEHIND it, and the disc is lifted away rather than switched off — there is
   no scroll position at which the viewport holds a flat colour on its own.
   ═══════════════════════════════════════════════════════════════════════ */

.disc-stage {
  position: absolute; inset: 0; z-index: 3;
  pointer-events: none;
  opacity: clamp(0, calc(var(--dp) / .12), 1);
  transform: translateY(calc(var(--dx) * -7vh)) scale(calc(1 - var(--dx) * .06));
}
.record__next {
  position: absolute; inset: 0; z-index: 2;
  pointer-events: none;
  /* flat, and identical to section 03's first stop — a sliding section edge
     over a patterned ground always shows a line */
  background: #5D001D;
  opacity: var(--np);
}

/* ═══════════════════════════════════════════════════════════════════════
   INTERFACE
   Navigation, the name, and one word of affordance. Nothing else: the
   artwork already carries the complexity.
   ═══════════════════════════════════════════════════════════════════════ */

.nav, .title, .hero__cue { position: absolute; z-index: 4; }

.nav {
  top: 0; left: 0; right: 0;
  display: grid; grid-template-columns: 1fr auto 1fr; align-items: center;
  padding: clamp(20px, 2.6vw, 38px) var(--gut);
  opacity: calc(1 - var(--p) * 4.5);
}
.nav__mark {
  justify-self: start;
  font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .24em; text-transform: uppercase;
  color: var(--paper);
}
.nav__links { justify-self: center; display: flex; gap: clamp(18px, 2.4vw, 40px); }
.nav__links a {
  font-family: var(--mono);
  font-size: 10.5px; letter-spacing: .24em; text-transform: uppercase;
  color: rgba(243,243,248,.68);
  position: relative; padding-bottom: 4px;
  transition: color .5s var(--ease);
}
.nav__links a::after {
  content: ""; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .6s var(--ease);
}
.nav__links a:hover { color: var(--paper); }
.nav__links a:hover::after { transform: scaleX(1); }

/* ── the name ─────────────────────────────────────────────────────────
   Neo-grotesk, uppercase, very large, lower-left. It sits over the darkest
   quarter of the artwork — the blue wall and floor — and stops well short of
   the decks and the central chamber, which begin around 41% of the frame.
   ------------------------------------------------------------------- */
.title {
  left: var(--gut);
  bottom: clamp(44px, 6vh, 74px);
  opacity: calc(1 - var(--p) * 4);
  transform: translate3d(0, calc(var(--p) * 3vh), 0);
}
.title__eyebrow {
  margin: 0 0 clamp(10px, 1.4vh, 18px) .18em;
  font-family: var(--mono);
  font-size: clamp(10px, .72vw, 11.5px); font-weight: 500;
  letter-spacing: .34em; text-transform: uppercase;
  color: rgba(243,243,248,.78);
}
.title__name {
  font-size: clamp(68px, 12.2vw, 236px);
  font-variation-settings: "opsz" 32;
  font-weight: 800;
  line-height: .8;
  letter-spacing: -.042em;
  display: flex;
  white-space: nowrap;
}
.ltr { display: block; overflow: hidden; padding: 0 0 .09em; }
.ltr b { display: block; font-weight: inherit; color: var(--paper); }

.hero__cue {
  right: var(--gut);
  bottom: clamp(22px, 3vh, 34px);
  margin: 0;
  opacity: calc(1 - var(--p) * 6);
}

/* ═══════════════════════════════════════════════════════════════════════
   ENTRANCE
   The plate arrives once and holds. No ignition, no pulsing, no black
   frames, no grain animation — the first thing the page does is stand still
   and look like the artwork.
   ═══════════════════════════════════════════════════════════════════════ */

.hero__art, .hero .nav, .hero .title, .hero .hero__cue { opacity: 0; }

.is-ready .hero__art { animation: plate 1300ms var(--ease) both; }
@keyframes plate {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.is-ready .nav          { animation: rise 900ms var(--ease) 420ms both; }
.is-ready .title__eyebrow { animation: rise 850ms var(--ease) 520ms both; }
.is-ready .title        { opacity: 1; }
.is-ready .ltr b        { animation: letter 1000ms var(--ease) both; animation-delay: calc(600ms + var(--i) * 56ms); }
.is-ready .hero__cue    { animation: rise 900ms var(--ease) 1000ms both; }

@keyframes letter { from { transform: translateY(104%); } to { transform: none; } }
@keyframes rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

/* A finished animation with `fill: both` outranks every later declaration,
   including the scroll fades above. Released once the timeline has played out
   or on the first scroll. Must sit after the .is-ready rules. */
.is-settled .hero__art, .is-settled .nav, .is-settled .title__eyebrow,
.is-settled .ltr b, .is-settled .title, .is-settled .hero__cue { animation: none; opacity: 1; }
.is-settled .nav       { opacity: calc(1 - var(--p) * 4.5); }
.is-settled .title     { opacity: calc(1 - var(--p) * 4); }
.is-settled .hero__cue { opacity: calc(1 - var(--p) * 6); }

/* ═══════════════════════════════════════════════════════════════════════
   RESPONSIVE
   Desktop is the target and the file is a true 16:9, so most desktops get
   the composition uncropped. Narrower screens crop deliberately toward the
   central chamber and the decks rather than squeezing the whole frame in.
   ═══════════════════════════════════════════════════════════════════════ */

@media (max-width: 1180px) {
  .title__name { font-size: clamp(66px, 15vw, 190px); }
}

@media (max-aspect-ratio: 1/1) {
  /* hold the centre chamber and the decks; let the outer chambers go */
  .hero__art img { object-position: 54% 44%; }
  .nav { grid-template-columns: 1fr; }
  .nav__mark { display: none; }
  .nav__links { justify-self: center; gap: 14px; }
  .nav__links a { font-size: 10px; letter-spacing: .12em; }
  .title { bottom: clamp(52px, 7vh, 86px); }
  .title__name { font-size: clamp(58px, 21vw, 180px); }
  .hero__cue { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .is-ready .hero__art, .is-ready .nav, .is-ready .title__eyebrow,
  .is-ready .ltr b, .is-ready .hero__cue { animation: fade 460ms ease both; }
}
