/* ── Opening sequence ──────────────────────────────────────────────────────
   One composition, four states: load → hold → identity → exit.
   The hairline rule is the spine and never moves; everything else
   arrives around it.
   ────────────────────────────────────────────────────────────────────────── */

.intro {
  position: fixed;
  inset: 0;                       /* fixed, so mobile browser chrome is a non-issue */
  z-index: 10;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-content: center;
  justify-items: center;
  padding-inline: var(--gutter);
  transform-origin: 50% 46%;
  transition:
    opacity 800ms var(--ease),
    transform 1000ms var(--ease),
    visibility 0s linear 1000ms;
}

/* ── The curtain ───────────────────────────────────────────────────────────
   The intro's ground, on a layer of its own rather than on the panel.

   It used to be the panel's own background, and it left by fading to
   transparent while the hero wiped itself in sideways underneath — so for
   about a second you watched a flat colour being pulled off the photograph
   rather than the photograph arriving. Now the ground rises and what is
   underneath was already whole.

   It has to be a separate layer because the name is a child of this panel and
   flies out of it into the navbar. Move the panel and the name goes with it;
   move only this, and the name stays exactly where the flight expects it. */
.intro::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--ground);
  /* The flight's own duration and the flight's own curve, deliberately.

     These were 900ms of cubic-bezier(0.16, 1, 0.3, 1) — an expo-out — against
     a name travelling on cubic-bezier(0.62, 0.02, 0.15, 1). Measured against
     each other: at 150ms the ground was 69% gone and the name had moved 4%;
     at 300ms the ground was 90% clear and the name a quarter of the way. So
     the hero stood fully uncovered for about four tenths of a second with the
     wordmark still crossing it.

     Same length, same easing: the ground now uncovers at exactly the rate the
     name travels, and the two finish on the same frame. FLIGHT in js/hero.js
     is the other half of this pair — change one and change both. */
  transition: transform 880ms cubic-bezier(0.62, 0.02, 0.15, 1);
}

.intro__core {
  position: relative;
  width: var(--measure);
  /* Lifts as the identity emerges beneath it, keeping the final frame centred */
  transform: translate3d(0, 0, 0);
  transition: transform 1200ms var(--ease);
}

/* ── Loading: mark + spine + counter ─────────────────────────────────────── */

.intro__mark {
  /* Big and centred above the spine. The 72vh term keeps the trace from
     crowding the composition on short or landscape viewports. */
  width: min(100%, 56rem, 88vh);
  aspect-ratio: 330 / 157;
  margin: 0 auto clamp(1.75rem, 3.6vw, 3rem);
  opacity: 0;
  transform: scale(0.97);
  transition: opacity 700ms var(--ease), transform 1200ms var(--ease);
}

.intro__mark svg { display: block; width: 100%; height: 100%; }

.intro__meter {
  display: flex;
  align-items: center;
  gap: clamp(0.875rem, 1.8vw, 1.5rem);
  opacity: 0;
  transition: opacity 500ms var(--ease);
}

.intro__rule {
  flex: 1 1 auto;
  height: 1px;
  background: var(--ink-12);
  overflow: hidden;
}

.intro__rule i {
  display: block;
  height: 100%;
  background: var(--ink);
  transform-origin: 0 50%;
  transform: scaleX(var(--p, 0));
}

.intro__pct {
  margin: 0;
  flex: none;
  font-size: clamp(0.6875rem, 0.85vw, 0.8125rem);
  font-weight: 500;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  /* Tracking tightens as the count climbs — set from JS */
  letter-spacing: var(--pct-track, 0.22em);
  padding-left: var(--pct-track, 0.22em);   /* offsets trailing letter-space */
  color: var(--ink);
  transition: opacity 600ms var(--ease);
}

/* ── Identity: hangs below the spine, out of flow ────────────────────────── */

.intro__reveal {
  position: absolute;
  top: calc(100% + clamp(1.75rem, 4vw, 3.25rem));
  left: 0;
  right: 0;
}

.intro__name {
  margin: 0;
  line-height: 0;
}

.intro__line {
  display: block;
  overflow: hidden;              /* the mask the letters rise out of */
  line-height: 1;
  /* Set in caps, so there is little below the baseline to lose — but the
     tracking still costs the last letter its right edge. */
  padding: 0 0.1em 0.06em 0;
  margin-right: -0.1em;
}

.intro__line + .intro__line { margin-top: -0.07em; }   /* restores the tight stack */

/* The rising element. Separate from the word below it so the reveal and the
   later flight into the navbar never fight over the same transform. */
.intro__rise {
  display: block;
  opacity: 0;
  transform: translate3d(0, 105%, 0);
  transition:
    transform 1050ms var(--ease) 320ms,
    opacity 850ms var(--ease) 320ms;
}

/* The measurable box. This is what flies to the navbar, so it is the same
   lockup as .nav__part — see css/nav.css — and only its width differs. */
.intro__word {
  display: grid;
  width: min(80vw, 38rem);
  transform-origin: 0 0;
}

/* ── States ──────────────────────────────────────────────────────────────── */

.intro[data-state="load"] .intro__mark,
.intro[data-state="hold"] .intro__mark { opacity: 1; transform: scale(1); }

.intro[data-state="load"]     .intro__meter,
.intro[data-state="hold"]     .intro__meter,
.intro[data-state="identity"] .intro__meter,
.intro[data-state="exit"]     .intro__meter { opacity: 1; }

/* Counter and mark step aside; the completed spine stays */
.intro[data-state="identity"] .intro__mark,
.intro[data-state="handover"] .intro__mark,
.intro[data-state="exit"] .intro__mark {
  opacity: 0;
  transform: scale(1.015) translate3d(0, -0.5rem, 0);
  transition: opacity 600ms var(--ease), transform 900ms var(--ease);
}

.intro[data-state="identity"] .intro__pct,
.intro[data-state="handover"] .intro__pct,
.intro[data-state="exit"] .intro__pct { opacity: 0; }

.intro[data-state="identity"] .intro__core,
.intro[data-state="handover"] .intro__core,
.intro[data-state="exit"] .intro__core {
  transform: translate3d(0, calc(var(--lift, 0px) * -1), 0);
}

.intro[data-state="identity"] .intro__rise,
.intro[data-state="handover"] .intro__rise,
.intro[data-state="exit"]     .intro__rise {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* ── Handover ──────────────────────────────────────────────────────────────
   The overlay sheds everything except the logo: background, spine and
   counter all go, while the logo stays lit and keeps its position, so the
   hero can take over underneath it and the logo can then fly into the
   navbar as one continuous element.
   ────────────────────────────────────────────────────────────────────────── */

.intro[data-state="handover"] { pointer-events: none; }

/* 101%, not 100%: at a fractional device pixel ratio a whole number can leave
   a hairline of ground along the bottom edge. */
.intro[data-state="handover"]::before { transform: translate3d(0, -101%, 0); }

.intro[data-state="handover"] .intro__line { overflow: visible; }

/* The ground has gone and the logo is crossing the photograph, so it changes
   to the white-type lockup on the way — the one the bar shows there. */
.intro[data-state="handover"] .brand__ink   { opacity: 0; }
.intro[data-state="handover"] .brand__light { opacity: 1; }
.intro[data-state="handover"] .brand > img  { transition-duration: 600ms; }

.intro[data-state="handover"] .intro__meter {
  opacity: 0;
  transition: opacity 420ms var(--ease);
}

/* The sequence hands the page over */
.intro[data-state="exit"] {
  opacity: 0;
  transform: scale(1.014);
  visibility: hidden;
  pointer-events: none;
}

/* ── Reduced motion: identity immediately, no cinema ─────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .intro,
  .intro__core,
  .intro__mark,
  .intro__meter,
  .intro__pct,
  .intro__rise,
  .intro__word {
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
  .intro[data-state="exit"] { transform: none; }

  /* The curtain still has to go, it just must not travel to get there. */
  .intro::before { transition: opacity 200ms var(--ease); }
  .intro[data-state="handover"]::before { transform: none; opacity: 0; }
}
