/* ==========================================================================
   Homepage intro — a one-time logo reel shown on load, before the real
   page is revealed. Every shape below shares the same flat dark-blue fill
   as the real body background (--color-bg), so the closing "hero-x" launch
   only has to grow large enough to cover the viewport — the colour match
   between the X and the page underneath is what sells the mask handoff,
   no actual clip-path/mask trickery needed.
   ========================================================================== */

.intro {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--color-white);
  overflow: hidden;
  transition: opacity 380ms ease;
}

.intro[hidden] {
  display: none;
}

/* Fades the whole overlay out together (giant X, backdrop and the small
   wordmark it's covering) once the launch lands, rather than just the X
   on its own — fading the X alone would peel back to the white backdrop
   still sitting behind it instead of to the real page. */
.intro.is-hiding {
  opacity: 0;
}

body.intro-lock {
  overflow: hidden;
}

.intro__logo {
  display: block;
  width: 50vw;
  max-width: 900px;
  height: auto;
  overflow: visible;
}

@media (max-width: 640px) {
  .intro__logo {
    width: calc(100% - 48px);
    max-width: none;
  }
}

.intro__u,
.intro__x,
.intro__factor,
.intro__suffix {
  opacity: 0;
  transform: translateY(-14px);
}

.intro__u.is-in,
.intro__x.is-in,
.intro__factor.is-in {
  animation: intro-drop 420ms ease-out forwards;
}

.intro__suffix.is-in {
  transform-box: fill-box;
  transform-origin: center;
  animation: intro-drop-spin 460ms ease-out forwards;
}

@keyframes intro-drop {
  from {
    opacity: 0;
    transform: translateY(-14px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes intro-drop-spin {
  from {
    opacity: 0;
    transform: translateY(-14px) rotate(0deg);
  }
  to {
    opacity: 1;
    transform: translateY(0) rotate(360deg);
  }
}

/* Standalone stand-in for .intro__suffix, sized/positioned via JS to sit
   exactly on top of it the instant step 4 lands — swapping to this copy is
   what lets step 5 scale/centre just the X without dragging the rest of
   the wordmark's box (and its off-centre pivot math) along with it. */
.intro__hero-x {
  position: absolute;
  top: 0;
  left: 0;
  opacity: 0;
  pointer-events: none;
}

.intro__hero-x.is-launching {
  animation: intro-launch 750ms cubic-bezier(0.7, 0, 0.84, 0) forwards;
}

/* The box itself is sized/positioned (via JS) at its full launch size from
   the start, not just scaled up to it — so the browser rasterises the
   shape at that resolution up front. Scale then runs from a small
   fraction (matching the natural tiny on-screen size) up to 1 (the box's
   own true size) — the compositor is only ever shrinking that raster or
   holding it at native size, never stretching it past the resolution it
   was drawn at, which is what made it look jagged/pixelated before.
   A touch of blur peaks mid-flight to sell the speed, clearing back to
   0 by the end so it settles perfectly sharp rather than staying soft. */
@keyframes intro-launch {
  0% {
    transform: translate(var(--start-x, 0px), var(--start-y, 0px)) scale(var(--start-scale, 1)) rotate(0deg);
    filter: blur(0px);
  }
  70% {
    filter: blur(5px);
  }
  100% {
    transform: translate(0, 0) scale(1) rotate(360deg);
    filter: blur(0px);
  }
}
