/* Curtain layer.
   Every animated property here is opacity or transform only, so the
   browser composites on the GPU and the motion holds 60fps. Nothing
   changes layout mid-transition. */

.stage {
  position: relative;
  height: 100vh;
  overflow: hidden;
}

/* Absolute, not fixed — ScrollTrigger's pin takes care of holding the
   stage still while the curtain scrubs. */
.stage .starting {
  position: absolute;
  inset: 0;
  z-index: 1;
  will-change: transform;
}

.stage .landing {
  position: absolute;
  inset: 0;
  z-index: 2;
}

/* Waiting behind both, revealed through the fracture. */
.stage .second {
  position: absolute;
  inset: 0;
  height: 100%;
  z-index: 0;
}

/* Black interstitial. Sits above the second page and below the landing, so
   fading it in covers the workspace once the glass is gone, and fading it
   out afterwards reveals the next scene. Gives the break somewhere to
   land instead of cutting straight to the next page. */
.stage .void {
  position: absolute;
  inset: 0;
  z-index: 1;
  background: #000;
  opacity: 0;
  pointer-events: none;
  will-change: opacity;
}

/* The soft edge, riding the boundary. Warm gold — the same light as the
   sunset behind it and the brand colour ahead of it, which is what makes
   the two screens feel like one place. */
.curtain__edge {
  position: absolute;
  left: -2%;
  width: 104%;
  height: 2px;
  z-index: 4;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(
    to right,
    transparent 0%,
    rgba(230, 200, 143, 0.5) 12%,
    rgba(246, 226, 184, 0.92) 50%,
    rgba(230, 200, 143, 0.5) 88%,
    transparent 100%
  );
  box-shadow:
    0 0 1.4vw rgba(230, 200, 143, 0.5),
    0 0 4vw rgba(201, 160, 99, 0.32),
    0 0.6vw 3vw rgba(201, 160, 99, 0.18);
  filter: blur(0.5px);
  /* Positioned by transform now (transition.ts) — top: % re-laid-out the
     line every tick. */
  top: 0;
  will-change: transform;
}

/* ---- Wake ---------------------------------------------------------- */
/* One rule for everything that wakes. Same direction, same distance, same
   curve — that uniformity is what stops any single element reading as an
   animation of its own. Defaults to fully awake so each page still works
   when mounted on its own. */

[data-wake] {
  --w: 1;
  --rise: 0px;
  opacity: var(--w);
  transform: translate3d(0, var(--rise), 0);
}

.is-running [data-wake] {
  will-change: opacity, transform;
}

.is-done [data-wake] {
  will-change: auto;
}

/* ---- Starting Page exit -------------------------------------------- */

.starting__scroll,
.starting__arrow,
.starting__tagline,
.starting__wordmark,
.starting__welcome {
  --out: 0;
}

.is-running .starting__scroll,
.is-running .starting__arrow,
.is-running .starting__tagline,
.is-running .starting__wordmark,
.is-running .starting__welcome {
  animation: none; /* cancel the page's own load-in */
  opacity: calc(1 - var(--out));
  transform: translate3d(0, calc(var(--out) * 14px), 0);
}

/* The wordmark spreads very slightly as it leaves, so it dissolves into
   the room rather than switching off. */
.is-running .starting__wordmark {
  letter-spacing: calc(var(--track-display) + var(--out) * 0.05em);
}

/* ---- Persistent logo ------------------------------------------------ */
/* Not a cross-fade. This is one element that exists above both screens
   and travels between their two logo positions. */

/* The travelling logo is now the supplied wordmark rather than a lettermark
   plus live type, so it lands on exactly the artwork the header shows. It
   interpolates size and position only: large at the Starting Page (--lp: 0),
   header-sized once parked (--lp: 1). */
/* Driven entirely by `transform`, deliberately.

   Animating `left`/`top` re-runs layout on every scroll frame, and animating
   `width` on a background-image re-rasterises the PNG at a new size every
   frame — together that made the scroll from the Starting Page into the
   landing visibly stutter. Position and scale are composited instead, so the
   scrub stays on the GPU and the bitmap is rastered once. */
.morphlogo {
  --lp: 0;
  position: absolute;
  z-index: 6;
  display: flex;
  align-items: center;
  left: 34px;
  top: 57.5px;
  transform: translate3d(calc(var(--lp) * 2px), calc(-50% - var(--lp) * 25.5px), 0);
  pointer-events: none;
  will-change: transform;
}

.morphlogo__img {
  display: block;
  /* Rendered once at its largest, then scaled down — never re-rastered.
     0.7632 lands it on the header logo's 116px. */
  width: 152px;
  aspect-ratio: 1138 / 229;
  /* Same trimmed, true-alpha artwork the header uses — no blend mode needed. */
  background-image: url('/lumiq-logo.png');
  background-size: contain;
  background-position: left center;
  background-repeat: no-repeat;
  transform: scale(calc(1 - var(--lp) * 0.2368));
  transform-origin: left center;
  will-change: transform;
}

/* Both pages hand their logo duty to .morphlogo while the stage is live.
   The header is no longer inside .stage, so its brand is matched from the
   root instead — the class is set on <html> alongside the stage's own. */
.stage .starting__logo,
.stage-live .topnav__brand {
  visibility: hidden;
}

@media (prefers-reduced-motion: reduce) {
  .curtain__edge {
    display: none;
  }
}
