/* Home-page cinematic intro (index.html only).
   Defaults describe the finished, static hero, which is what no-JS and reduced-motion visitors see:
   the frame sits at its resting inset and scrolls away with the hero. js/intro/intro.js adds
   .intro-live to switch to the fixed, scroll-driven frame, and .intro-pending / .is-locked hide
   the late-arriving pieces and hold scroll while the intro plays. */

.has-intro { scroll-snap-type: none; }   /* snapping fights the scroll-scrubbed frame */
.is-locked { overflow: hidden; }

/* ---------- frame + particle canvas (behind content, above the rings) ----------
   The frame's resting geometry is defined here only, as unitless custom properties. intro.js reads
   them to animate the frame and to clip the particles to it, so the drawn frame and the GL clip
   always agree. --frame-y / --frame-x: inset, % of the viewport; --frame-r: corner radius, px;
   --frame-top-min: the top edge never rises above this (clears the nav pill), px. */
.intro-frame {
  --frame-y: 15; --frame-x: 10; --frame-r: 22; --frame-top-min: 0;
  position: absolute; z-index: -1;
  top: max(calc(var(--frame-y) * 1%), calc(var(--frame-top-min) * 1px));
  bottom: calc(var(--frame-y) * 1%);
  left: calc(var(--frame-x) * 1%); right: calc(var(--frame-x) * 1%);
  border-radius: calc(var(--frame-r) * 1px); overflow: hidden; pointer-events: none;
  background: radial-gradient(ellipse 85% 75% at 62% 45%, #071510 0%, #030806 62%, #020403 100%);
  box-shadow: 0 0 0 1px var(--hairline), 0 30px 80px -30px rgba(0, 0, 0, 0.6);
}
/* Fills the hero (static) or the viewport (live); intro.js sizes the drawing buffer to match. */
#intro-field {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  z-index: 0; pointer-events: none; display: block;
}
.intro-live .intro-frame,
.intro-live #intro-field { position: fixed; }
.intro-pending .intro-frame { inset: 0; border-radius: 0; }

/* No WebGL2: a soft CSS seed glows in the frame instead of the particle field. */
.no-gl #intro-field { display: none; }
.no-gl .intro-frame::after {
  content: ""; position: absolute; left: 62%; top: 45%; width: 360px; height: 360px; translate: -50% -50%;
  background: radial-gradient(circle, rgba(95, 227, 194, 0.22) 0%, rgba(95, 227, 194, 0.07) 38%, transparent 70%);
}

/* ---------- hero: one viewport of copy, plus one viewport of scroll to close the frame ----------
   svh, not vh: on iOS 100vh is the toolbars-hidden height, taller than the visible area the fixed
   frame and canvas use, which pushed the copy below the frame. */
.hero--intro {
  max-width: none; margin: 0; padding: 0;
  min-height: 0; height: 100vh; height: 100svh;
  display: block; overflow: visible;        /* sticky needs a non-clipping ancestor */
}
.intro-live .hero--intro { height: 200vh; height: 200svh; }
.hero__stage {
  position: sticky; top: 0; height: 100vh; height: 100svh;
  display: flex; align-items: center;
}
.hero--intro .hero__content {
  max-width: none;
  padding: 0 calc(10vw + clamp(1.5rem, 4vw, 4rem));
}
.hero--intro .hero__name {
  position: relative;
  font-size: clamp(3rem, 8.6vw, 8.5rem);
  margin: 0 0 1.4rem;
  text-shadow: none;
}
.hero__ghost { display: block; }
.hero__typed { position: absolute; inset: 0; }
.intro-live .hero__ghost,
.intro-pending .hero__ghost { visibility: hidden; }   /* the typed layer carries the visible name */
.hero--intro .hero__thesis {
  margin: 0 0 1.2rem; font-size: clamp(1.05rem, 1.6vw, 1.4rem);
  color: var(--silver-dim);
}
.hero--intro .hero__thesis em { color: var(--amber); }
/* Cycling phrase (intro.js): block cursor, solid while typing, blinking during the holds. */
.hero__cursor {
  display: none; width: 1ch; height: 1em; margin-left: 0.06em; vertical-align: -0.12em;
  font-family: var(--mono); background: currentColor;
}
.is-cycling .hero__cursor { display: inline-block; animation: cursor-blink 1s steps(1) infinite; }
.is-typing .hero__cursor { animation: none; }
@keyframes cursor-blink { 50% { opacity: 0; } }
.hero--intro .hero__actions { margin-top: 2rem; }
.hero--intro .hero__scroll { bottom: calc(15vh + 1rem); bottom: calc(15svh + 1rem); }

/* Pieces that arrive late in the intro start hidden (GSAP fades them in). */
.intro-pending #nav,
.intro-pending .hero--intro .hero__thesis,
.intro-pending .hero--intro .hero__creds,
.intro-pending .hero--intro .hero__actions,
.intro-pending .hero--intro .hero__scroll { opacity: 0; }

@media (max-width: 860px) {
  /* Phones get a roomier frame whose top clears the nav pill; the copy sits a fixed gap above the
     frame's bottom edge so it fits short screens too. */
  .intro-frame { --frame-y: 10; --frame-x: 6; --frame-r: 18; --frame-top-min: 78; }
  .hero__stage { align-items: flex-end; padding-bottom: calc(10vh + 1.75rem); padding-bottom: calc(10svh + 1.75rem); }
  .hero--intro .hero__content { padding: 0 calc(6vw + 1.25rem); }
  .hero--intro .hero__name { font-size: clamp(2.6rem, 13vw, 4.5rem); }
  .hero--intro .hero__actions { margin-top: 1.4rem; }
  .hero--intro .hero__scroll { display: none; }
  /* the narrow frame can't hold one line of credentials: stack them, no separators */
  .hero--intro .hero__creds { flex-direction: column; gap: 0.2rem; font-size: 0.78rem; }
  .hero--intro .hero__creds li + li::before { content: none; }
}

/* Short screens (phones in landscape, short windows): the frame is wide but low, so the pill floats
   over its top edge, the name is sized by height, and the tagline and credentials run on long lines. */
@media (max-height: 500px) {
  .intro-frame { --frame-y: 10; --frame-x: 6; --frame-r: 18; --frame-top-min: 0; }
  .hero__stage { align-items: flex-end; padding-bottom: calc(10vh + 0.9rem); padding-bottom: calc(10svh + 0.9rem); }
  .hero--intro .hero__content { padding: 0 calc(6vw + 1.25rem); }
  .hero--intro .hero__scroll { display: none; }
  .hero--intro .hero__name { font-size: 13vh; font-size: 13svh; margin-bottom: 0.6rem; }
  .hero--intro .hero__thesis { max-width: 48ch; margin: 0 0 0.6rem; font-size: 0.95rem; }
  .hero--intro .hero__creds { flex-direction: row; flex-wrap: wrap; gap: 0; font-size: 0.72rem; }
  .hero--intro .hero__creds li + li::before { content: "·"; }
  .hero--intro .hero__actions { margin-top: 0.8rem; }
  .hero--intro .hero__actions .btn { padding: 0.7rem 1.5rem; }
}
