/* ── Star Wars Intro Crawl ── */

#crawl-overlay {
  position: fixed;
  inset: 0;
  z-index: 200;
  background: #000;
  overflow: hidden;
  /* Cierre tipo wipe de Star Wars: el overlay se recorta de derecha a
     izquierda y la página aparece debajo como cambio de "diapositiva". */
  clip-path: inset(0 0 0 0);
  transition: clip-path 1.15s ease-in-out;
}

#crawl-overlay.crawl-exit {
  clip-path: inset(0 100% 0 0);
  pointer-events: none;
}

#crawl-canvas {
  position: absolute;
  inset: 0;
  display: block;
}

/*
  The scene establishes 3D perspective.
  perspective-origin sits roughly at the "horizon" — upper-center of the screen
  so text appears to recede into the starfield above.
*/
#crawl-scene {
  position: absolute;
  inset: 0;
  overflow: hidden;
  perspective: 400px;
  perspective-origin: 50% 40%;

  /*
    Safety-net clip: some mobile WebKit/Chromium engines fail to apply
    overflow:hidden above to descendants inside the 3D perspective context
    below (#crawl-plane's rotateX + preserve-3d), letting crawl text bleed
    past this box's bottom edge on certain devices. mask-image is a
    paint-time compositing step, not the layout-time clip chain, so it
    isn't subject to that 3D-escape bug — it reliably discards anything
    painted outside this box regardless of the underlying clip failure.
    The gradient stays opaque across the box and only drops to transparent
    in the final 1%, giving a hard cutoff at the real edge with no visible
    fade (real, non-trivial stops on purpose — a flat mask can get
    optimized away by some engines and skip the fix entirely).
  */
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 99%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 99%, transparent 100%);
  -webkit-mask-repeat: no-repeat;
  mask-repeat: no-repeat;
}

/*
  Top fade — text dissolves into stars as it climbs toward the vanishing point.
  This is a SCREEN-FIXED mask so text fades as it scrolls behind it.
*/
#crawl-scene::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 55%;
  background: linear-gradient(to bottom, #000 20%, transparent 100%);
  z-index: 2;
  pointer-events: none;
}

/*
  Bottom mask — a direct child of overlay (not the 3D scene) so it sits
  above the perspective-transformed plane. This hides the "entrance" of text
  at the bottom edge so new lines appear smoothly rather than popping in.
*/
#crawl-bottom-mask {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 12%;
  background: linear-gradient(to top, #000 0%, transparent 100%);
  z-index: 205;
  pointer-events: none;
}

/*
  The plane is a flat surface tilted back into 3D space.
  - Anchored at the bottom of the viewport
  - rotateX tilts the top edge away from the viewer (classic crawl tilt)
  - transform-origin at bottom edge so the bottom stays near the camera
  - Height is explicitly set to allow the text to overflow upward
*/
#crawl-plane {
  position: absolute;
  bottom: 0;
  left: 50%;
  width: 85%;
  max-width: 1000px;
  height: 0;
  transform: translateX(-50%) rotateX(22deg);
  transform-origin: 50% 100%;
  transform-style: preserve-3d;
  overflow: visible;
}

/*
  The text block lives inside the tilted plane.
  It starts fully off-screen below (100% = 100% of the text's own height
  below the plane's anchor point at the viewport bottom).
  Then it animates upward past the vanishing point.
*/
#crawl-text {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  font-family: var(--font);
  font-size: clamp(1.4rem, 3.2vw, 2.6rem);
  font-weight: 900;
  color: #FFD700;
  text-align: center;
  line-height: 1.9;
  letter-spacing: 0.06em;
  /* Distancia y duración las fija el JS midiendo el texto real, para que
     el crawl termine justo cuando la última línea cruza el desvanecido y
     no quede pantalla muerta. Los fallbacks replican el valor histórico. */
  animation: crawl-rise var(--crawl-dur, 80s) linear forwards;
  /* Pre-rasteriza la capa completa del plano 3D: sin esto, algunos motores
     pintan el texto por mosaicos y las palabras aparecen de golpe. */
  will-change: transform;
}

#crawl-text p {
  margin-bottom: 2em;
}

/* Same yellow as the body crawl — only marginally larger to stand out */
.crawl-finale {
  font-size: calc(1em + 1px);
}

/*
  The animation uses viewport units for positioning:
  - Starts at 0 — #crawl-text's own top:0 already sits flush with the
    viewport bottom (the plane's anchor edge), so its content flows
    downward from there and is fully off-screen with no transform needed.
    A negative value here pulls the first line up INTO view, which is
    visible year-round through the empty space of the paused gate splash
    screen (not just the mobile 3D-clip bug) — keep this at 0 or positive.
  - Ends at a large negative value to scroll all text past the vanishing point
*/
@keyframes crawl-rise {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(var(--crawl-end, -350vh));
  }
}

/* Skip button */
#crawl-skip {
  position: fixed;
  top: 1.5rem;
  right: 1.5rem;
  z-index: 210;
  background: var(--accent, #555);
  color: #e8eaf0;
  font-family: var(--font);
  font-size: 0.8125rem;
  font-weight: 900;
  letter-spacing: 0.04em;
  padding: 8px 20px;
  border-radius: 50px;
  border: none;
  cursor: pointer;
  opacity: 0;
  animation: crawl-btn-in 0.4s ease forwards;
  animation-delay: 2s;
  transition: transform 0.15s cubic-bezier(0.25, 1, 0.5, 1),
    box-shadow 0.15s cubic-bezier(0.25, 1, 0.5, 1);
}

#crawl-skip:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 18px color-mix(in srgb, var(--accent, #555) 45%, transparent);
}

#crawl-skip:active {
  transform: translateY(0);
  box-shadow: none;
}

@keyframes crawl-btn-in {
  to {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  #crawl-text {
    animation: none;
    transform: none;
  }

  #crawl-skip {
    animation: none;
    opacity: 1;
  }
}

/* ── Pre-title Card ── */

/*
  The quiet phrase on black before the crawl, à la Star Wars.
  pointer-events: none + z below #crawl-skip (210) keep the skip
  button clickable while the card is up.
*/
#crawl-pretitle {
  position: absolute;
  inset: 0;
  z-index: 208;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 0 8vw;
  pointer-events: none;
}

#crawl-pretitle.pretitle-active {
  display: flex;
}

#crawl-pretitle p {
  max-width: 640px;
  font-family: var(--font);
  font-size: clamp(1.6rem, 4.5vw, 2.75rem);
  font-weight: 600;
  color: #4BD5EE;
  text-align: left;
  line-height: 1.45;
  letter-spacing: 0.02em;
  opacity: 0;
  animation: pretitle-show 2s ease-in-out forwards;
}

@keyframes pretitle-show {
  0% { opacity: 0; }
  15% { opacity: 1; }
  75% { opacity: 1; }
  100% { opacity: 0; }
}

/* ── Splash Gate Screen ── */

#crawl-gate {
  position: absolute;
  inset: 0;
  z-index: 220;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  transition: opacity 0.8s ease;
}

#crawl-gate.gate-exit {
  opacity: 0;
  pointer-events: none;
}

/* Positioning context for the logo + its streaks, sized to the logo itself
   (not #crawl-gate's full-screen box) so the streaks fan out from the
   logo's actual center regardless of where flex layout places it. */
.gate-logo-wrap {
  position: relative;
  line-height: 0;
}

.gate-logo {
  height: clamp(3rem, 10vw, 7rem);
  width: auto;
  filter: drop-shadow(0 0 30px rgba(255, 215, 0, 0.3)) drop-shadow(0 0 60px rgba(255, 215, 0, 0.15));
  animation:
    gate-logo-hyperspace 2.6s cubic-bezier(0.16, 1, 0.3, 1) both,
    gate-glow 3s ease-in-out 2.6s infinite alternate;
}

/*
  One-shot entrance: logo rushes in from a distant point, overshoots,
  flashes white at arrival, settles back to scale(1). Its final keyframe
  matches gate-glow's `from` filter exactly so the handoff at 2.6s has
  no visible seam — see the comma-separated animation above.
*/
@keyframes gate-logo-hyperspace {
  0%   { opacity: 0; transform: scale(0.08); filter: drop-shadow(0 0 0 rgba(255,255,255,0)) blur(2px) brightness(1); }
  35%  { opacity: 1; transform: scale(0.6);  filter: drop-shadow(0 0 0 rgba(255,255,255,0)) blur(0) brightness(1); }
  58%  { opacity: 1; transform: scale(1.15); filter: drop-shadow(0 0 0 rgba(255,255,255,0)) blur(0) brightness(1); }
  70%  { transform: scale(0.96); filter: drop-shadow(0 0 60px rgba(255,255,255,0.9)) blur(0) brightness(2.2); }
  100% { opacity: 1; transform: scale(1); filter: drop-shadow(0 0 30px rgba(255,215,0,0.2)) drop-shadow(0 0 60px rgba(255,215,0,0.1)) blur(0) brightness(1); }
}

@keyframes gate-glow {
  from {
    filter: drop-shadow(0 0 30px rgba(255, 215, 0, 0.2)) drop-shadow(0 0 60px rgba(255, 215, 0, 0.1));
  }

  to {
    filter: drop-shadow(0 0 40px rgba(255, 215, 0, 0.45)) drop-shadow(0 0 80px rgba(255, 215, 0, 0.2));
  }
}

/*
  Decorative hyperspace-jump light trails, fanned around the logo.
  Each carries its own angle via a modifier class + custom property.
*/
.gate-spark-streak {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 160px;
  height: 2px;
  margin-top: -1px;
  background: linear-gradient(90deg, transparent, rgba(255, 215, 0, 0.9), transparent);
  transform-origin: left center;
  pointer-events: none;
  z-index: 1;
  animation: gate-streak-fly 0.9s cubic-bezier(0.16, 1, 0.3, 1) both;
}
.gate-spark-streak--a { --streak-angle: -18deg; }
.gate-spark-streak--b { --streak-angle: 12deg; }
.gate-spark-streak--c { --streak-angle: 165deg; }

@keyframes gate-streak-fly {
  0%   { opacity: 0; transform: rotate(var(--streak-angle, 0deg)) scaleX(0.2); }
  30%  { opacity: 1; }
  55%  { opacity: 1; transform: rotate(var(--streak-angle, 0deg)) scaleX(1); }
  75%  { opacity: 0; transform: rotate(var(--streak-angle, 0deg)) scaleX(1.3); }
  100% { opacity: 0; }
}

/*
  Placed after the unconditional .gate-logo/.gate-spark-streak rules above —
  same specificity (single class), so source order decides the tie. This
  block must come after them to actually win under reduced motion.
*/
@media (prefers-reduced-motion: reduce) {
  .gate-logo {
    animation: none;
    opacity: 1;
    transform: none;
    filter: drop-shadow(0 0 30px rgba(255, 215, 0, 0.3)) drop-shadow(0 0 60px rgba(255, 215, 0, 0.15));
  }

  .gate-spark-streak {
    display: none;
  }
}

@media (max-width: 768px) {
  .gate-logo {
    width: min(85vw, 26rem);
    height: auto;
  }
}

#crawl-start {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 14px 40px;
  background: linear-gradient(135deg, #E31B23 0%, #c0161d 100%);
  color: #fff;
  font-family: var(--font);
  font-size: 1.1rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  border: none;
  border-radius: 50px;
  cursor: pointer;
  box-shadow: 0 0 24px rgba(227, 27, 35, 0.35);
  transition: transform 0.2s cubic-bezier(0.25, 1, 0.5, 1),
    box-shadow 0.2s cubic-bezier(0.25, 1, 0.5, 1);
}

#crawl-start:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 6px 32px rgba(227, 27, 35, 0.5);
}

#crawl-start:active {
  transform: translateY(0) scale(0.98);
  box-shadow: 0 0 16px rgba(227, 27, 35, 0.3);
}

.gate-speaker-icon {
  flex-shrink: 0;
}

.gate-disclaimer {
  font-family: var(--font);
  font-size: 0.8125rem;
  color: rgba(255, 255, 255, 0.68);
  letter-spacing: 0.03em;
}

/* Pause crawl animation until gate is dismissed */
.crawl-paused #crawl-text {
  animation-play-state: paused;
}