/* ==========================================================================
   motion.css — intro cover + entrance animation
   --------------------------------------------------------------------------
   REBUILT FILE — could not be located on disk and was never captured in
   full in this conversation; only two specific fixes were on record: the
   entrance line-reveal keyframes must use `animation-fill-mode: backwards`
   (an earlier bug had a `both`-fill animation override the resting
   transform), and the intro logo must never gain a background/border/scale
   transition class that could flash as a rounded square. This is a
   from-scratch reimplementation — re-check against any older backup.
   ========================================================================== */

/* ---------- Intro cover ---------------------------------------------------- */
.intro {
  position: fixed;
  inset: 0;
  z-index: 150;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  overflow: hidden;
  /* Circular-reveal mask driven from JS (intro-animation.js). Full and
     transparent-nowhere by default so the cover reads solid until entry. */
  mask-image: radial-gradient(circle at 50% 50%, black 100%, black 100%);
  -webkit-mask-image: radial-gradient(circle at 50% 50%, black 100%, black 100%);
}

.intro__blobs { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.intro__blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(60px);
  opacity: 0.35;
  background: radial-gradient(circle, rgba(255,255,255,0.9), transparent 70%);
  animation: intro-blob-float 14s ease-in-out infinite alternate;
}
.intro__blob--a { width: 40vw; height: 40vw; top: -10%; left: -8%; }
.intro__blob--b { width: 32vw; height: 32vw; bottom: -12%; right: -6%; animation-delay: -4s; }
.intro__blob--c { width: 26vw; height: 26vw; top: 40%; left: 60%; animation-delay: -8s; }
@keyframes intro-blob-float {
  from { transform: translate(0, 0) scale(1); }
  to   { transform: translate(3%, -4%) scale(1.08); }
}

.intro__grid {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  opacity: 0.12;
  background-image:
    linear-gradient(to right, rgba(255,255,255,0.5) 1px, transparent 1px),
    linear-gradient(to bottom, rgba(255,255,255,0.5) 1px, transparent 1px);
  background-size: 56px 56px;
}

.intro__icons { position: absolute; inset: 0; z-index: 0; pointer-events: none; }
.intro__icon {
  position: absolute;
  width: var(--sz, 28px);
  height: var(--sz, 28px);
  color: rgba(255, 255, 255, 0.5);
  animation: intro-icon-drift var(--dur, 10s) ease-in-out var(--delay, 0s) infinite alternate;
}
.intro__icon svg { width: 100%; height: 100%; }
@keyframes intro-icon-drift {
  from { transform: translateY(-8px) rotate(-3deg); }
  to   { transform: translateY(8px) rotate(3deg); }
}

.intro__bottom {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  padding-bottom: clamp(2rem, 5vw, 3.5rem);
}
.intro__enter {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  color: #fff;
  animation: intro-arrow-bob 2.2s ease-in-out infinite;
}
.intro__arrow { width: 20px; height: 26px; }
@keyframes intro-arrow-bob {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}
.intro__hint {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.6);
}

/* ---------- Intro logo layer -----------------------------------------------
   Sits above the cover so it survives the circular reveal, then FLIPs
   (via inline transform set by intro-animation.js) into the nav brand slot.
   No background/border/box-shadow/scale-transition classes live here — that
   was the exact cause of an earlier rounded-square flash on the nav logo. */
.intro-logo-layer {
  position: fixed;
  inset: 0;
  z-index: 160;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.intro-logo {
  display: inline-flex;
  will-change: transform;
}

/* Stacked column: symbol → SCROLLIVO wordmark → tagline, one vertical block,
   never side by side. Sits on #intro-logo-stack so the tagline can fade with
   the reveal independently of the FLIP transform on #intro-logo. */
.intro-logo-stack {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(1.1rem, 3vw, 1.85rem);
  padding-inline: clamp(1.5rem, 6vw, 4rem);
  text-align: center;
  pointer-events: none;
}

.mark--intro {
  flex-direction: column;
  align-items: center;
  gap: 0.28em;
  font-size: clamp(52px, 9vw, 88px);
}
/* SCROLLIVO — large, bold, fully opaque: the dominant word on screen. */
.mark--intro .mark__word {
  display: block;
  margin-top: 0.08em;
  font-size: 0.46em;
  font-weight: 800;
  letter-spacing: 0.01em;
  text-align: center;
}

/* Tagline — smaller and slightly transparent, secondary to the wordmark. */
.intro-logo-stack .intro__tagline {
  margin: 0 auto;
  max-width: 34ch;
  font-size: clamp(0.95rem, 1.8vw, 1.2rem);
  color: rgba(255, 255, 255, 0.7);
}

/* Impact pulse — fired by intro-animation.js when the thrown arrow lands
   back on the logo. Positioned via inline left/top set at impact time. */
.intro__ripple {
  position: fixed;
  top: 0;
  left: 0;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.85);
  opacity: 0;
  pointer-events: none;
  z-index: 165;
  transform: translate(-50%, -50%) scale(0.3);
}
.intro__ripple.is-active {
  animation: intro-ripple-pulse 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
@keyframes intro-ripple-pulse {
  0%   { opacity: 0.9; transform: translate(-50%, -50%) scale(0.3); }
  100% { opacity: 0;   transform: translate(-50%, -50%) scale(4.5); }
}

/* ---------- Header entrance -------------------------------------------------
   The header itself fades/rises in once the intro dismisses; it stays
   invisible-but-present before that so layout doesn't shift. */
.site-header { opacity: 0; transform: translateY(-12px); }
body.is-entered .site-header { opacity: 1; transform: none; }

/* ---------- Line reveal (hero / contact oversized headings) ----------------
   `backwards` fill: the element sits at the animation's FROM state until it
   actually starts, instead of an author rule elsewhere setting the resting
   transform and losing the fight against a `both`-fill animation. */
@keyframes line-reveal {
  from { transform: translateY(110%); }
  to   { transform: translateY(0); }
}
body.is-entered .line__inner {
  animation: line-reveal 0.9s cubic-bezier(0.22, 1, 0.36, 1) backwards;
}
.hero__title .line:nth-child(1) .line__inner { animation-delay: 0.05s; }
.hero__title .line:nth-child(2) .line__inner { animation-delay: 0.14s; }
.hero__title .line:nth-child(3) .line__inner { animation-delay: 0.23s; }
.contact__title .line:nth-child(1) .line__inner { animation-delay: 0s; }
.contact__title .line:nth-child(2) .line__inner { animation-delay: 0.08s; }
.contact__title .line:nth-child(3) .line__inner { animation-delay: 0.16s; }

@media (prefers-reduced-motion: reduce) {
  .intro__blob, .intro__icon, .intro__enter { animation: none !important; }
  .intro-logo { transition: none !important; }
  .intro__ripple { display: none !important; }
  .site-header { transition: none !important; }
  body.is-entered .line__inner { animation: none !important; transform: none !important; }
}
