/* The opening.
 *
 * The logo fills the screen, five tilted stars drop onto it and pile up, the
 * pile collapses into one star that swells and straightens, and the whole
 * mark shrinks into its seat in the header. Two seconds,
 * once per session, skipped by a click, and never for someone who asked
 * their system for reduced motion.
 *
 * Everything here is driven by transform and opacity only, so it runs on the
 * compositor and does not fight the page underneath for layout.
 *
 * --k is a speed multiplier. 1 is real; the demo sets 3 so the phases can be
 * looked at one by one.
 */

:root { --k: 1; }

/* Nothing shows unless the <html> element carries .intro, and only the
   inline script in <head> puts it there. No script, no overlay, no way to
   get stuck behind one. */
#intro { display: none; }

/* The page under the overlay must not scroll: the flight is measured
   against the header's resting position. */
.intro { overflow: hidden; }

.intro #intro {
  display: grid; place-items: center;
  position: fixed; inset: 0; z-index: 100;
  background: var(--bg);
  cursor: pointer;
}
/* Only the backdrop clears. The logo is a child of this element, so fading
   the whole overlay would fade the logo mid-flight and it would arrive at the
   header invisible, a gap the first demo showed. */
.intro #intro.is-leaving {
  transition: background-color calc(.44s * var(--k)) ease;
  background-color: transparent; pointer-events: none;
}

/* The header's own logo waits, invisible, until the flying one lands on it.
   visibility rather than opacity so the layout it occupies stays exactly
   where the measurement expects it. */
.intro .site-head .brand { visibility: hidden; }

/* The big logo is the header logo scaled up. Same ratios (star .882em, gap
   .176em), so a single uniform scale maps one onto the other exactly. */
.intro-logo {
  display: inline-flex; align-items: center; gap: .176em;
  font-size: clamp(64px, 13vw, 148px); font-weight: 700;
  letter-spacing: -.04em; line-height: 1; color: var(--text);
  will-change: transform;
  transform-origin: center center;
}
.intro-logo .word {
  opacity: 0;
  animation: intro-word calc(.3s * var(--k)) ease-out forwards;
}
@keyframes intro-word { to { opacity: 1; } }

/* The seat the stars fall into: one em-square, star sized like the header's. */
/* One angle for the whole pile: five identical stars, each a little higher
   than the last, read as a stack. Five different angles read as a mess. */
.intro-star {
  position: relative; width: .882em; height: .882em; flex: 0 0 auto;
  --tilt: -34deg;
}
.intro-star svg {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0;
  transform: translateY(-70vh) rotate(var(--tilt));
  animation: intro-drop calc(.45s * var(--k)) cubic-bezier(.22, .9, .32, 1.12) forwards;
  animation-delay: calc(var(--i) * .075s * var(--k) + .125s * var(--k));
}
/* Each star lands a little higher than the one before. */
@keyframes intro-drop {
  0%   { opacity: 0; transform: translateY(-70vh) rotate(var(--tilt)); }
  12%  { opacity: 1; }
  100% { opacity: 1; transform: translateY(calc(var(--i) * -.045em)) rotate(var(--tilt)); }
}

/* The pile becomes one. The four underneath slide into the top one and go;
   the top one straightens while it swells past size and settles. */
.intro-logo.is-merging .intro-star svg:not(:last-child) {
  animation: intro-fold calc(.25s * var(--k)) ease-in forwards;
}
/* Both start states are spelled out. Swapping the animation drops the drop's
   forwards fill, so without an explicit `from` every star would snap back to
   the base opacity of 0 and the merge would happen to nothing. */
@keyframes intro-fold {
  from { opacity: 1; transform: translateY(calc(var(--i) * -.045em)) rotate(var(--tilt)) scale(1); }
  to   { opacity: 0; transform: translateY(-.18em) rotate(0deg) scale(.55); }
}
.intro-logo.is-merging .intro-star svg:last-child {
  animation: intro-bloom calc(.5s * var(--k)) cubic-bezier(.3, 1.4, .5, 1) forwards;
}
@keyframes intro-bloom {
  0%   { opacity: 1; transform: translateY(-.18em) rotate(var(--tilt)) scale(1); }
  55%  { opacity: 1; transform: translateY(0) rotate(7deg) scale(1.38); }
  100% { opacity: 1; transform: translateY(0) rotate(0deg) scale(1); }
}

/* The flight to the header. The transform is computed at runtime from where
   the header logo actually is, so it lands right at any viewport width. */
.intro-logo.is-flying {
  transition: transform calc(.55s * var(--k)) cubic-bezier(.66, 0, .12, 1);
}

@media (prefers-reduced-motion: reduce) {
  .intro #intro { display: none; }
  .intro .site-head .brand { visibility: visible; }
}
