/* ==========================================================================
   Landing intro — the title sequence that opens the home page.
   --------------------------------------------------------------------------
   One timeline, and CSS owns it. Every beat below is a keyframe delay off the
   moment .intro-stage first renders, and intro-scene.js reads the clock of the
   root's `intro-life` animation rather than keeping its own, so the 3D layer
   can arrive late (slow phone, cold cache) and still land on the same beats.
   Without JavaScript the whole sequence still plays and fades itself out;
   without WebGL it plays as type alone.

     0.00  ignition line
     0.35  five discipline words, 0.40s apart (the 3D objects fly past on each)
     2.55  "clearAMS" slams in, letters 40ms apart
     3.45  "Basic is always free."
     5.30  hand-off: the title flies into the nav's wordmark (intro.js)
     5.45  the field fades under it, revealing the hero — same gradient, so
           nothing appears to change but the type
     6.15  the title lands exactly on the real wordmark; the overlay goes
     6.30  gone

   The skip control sits OUTSIDE the overlay so the overlay itself can stay
   aria-hidden: assistive tech reads the page, never the trailer. Any click,
   key, wheel or touch also skips.

   Type floor holds: the smallest thing here is --fs-micro.
   ========================================================================== */

.intro-off .intro-stage, .intro-off .intro-skip { display: none; }
/* No-JS skip: the control is a link to #main, and :target removes the overlay. */
html:has(#main:target) .intro-stage, html:has(#main:target) .intro-skip { display: none; }

.intro-stage {
  position: fixed; inset: 0; z-index: 90;
  display: grid; place-items: center;
  color: var(--on-field);
  overflow: hidden; cursor: pointer;
  -webkit-user-select: none; user-select: none;
  animation: intro-life 6.3s linear forwards;
}
/* The root stays opaque until the title has landed on the nav wordmark
   (6.15s); only then does it hand over, in the last 0.15s. What fades during
   the flight is the field behind the title (::before, intro-field) and the 3D
   canvas, which intro-scene.js fades on the same curve. */
@keyframes intro-life {
  0%, 97.6% { opacity: 1; visibility: visible; }
  100%      { opacity: 0; visibility: hidden; }
}
.intro-stage::before {
  content: ""; position: absolute; inset: 0;
  background: var(--field-gradient), var(--field-0);
  animation: intro-field 6.3s linear forwards;
}
@keyframes intro-field {
  0%, 86.5%    { opacity: 1; }
  97.6%, 100%  { opacity: 0; }
}
.intro-stage.is-skipped { animation: intro-out .45s var(--ease) forwards; }
@keyframes intro-out { to { opacity: 0; visibility: hidden; } }

.intro-gl {
  position: absolute; inset: 0; width: 100%; height: 100%;
  opacity: 0;   /* intro-scene.js owns this: fade-in on first frame, out with the field */
}

/* Soft vignette over the 3D so the type always sits on the darkest part. */
.intro-stage::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 46% at 50% 50%, rgba(2,8,15,.55), rgba(2,8,15,0) 70%);
  animation: intro-field 6.3s linear forwards;
}

/* ---- 0.00 ignition ------------------------------------------------------ */
.intro-ignite {
  position: absolute; left: 0; right: 0; top: 50%; height: 2px; margin-top: -1px;
  background: var(--ramp-accent);
  box-shadow: 0 0 24px 2px rgba(var(--accent-rgb), .7), 0 0 80px 8px rgba(255,122,26,.35);
  transform: scaleX(0); opacity: 0;
  animation: intro-ignite .7s cubic-bezier(.7,0,.2,1) forwards;
}
@keyframes intro-ignite {
  0%   { transform: scaleX(0) scaleY(1); opacity: 0; }
  15%  { opacity: 1; }
  55%  { transform: scaleX(1) scaleY(1); opacity: 1; }
  80%  { opacity: 0; }
  100% { transform: scaleX(1.2) scaleY(60); opacity: 0; }
}

/* ---- 0.35 the disciplines ---------------------------------------------- */
.intro-words { position: absolute; inset: 0; display: grid; place-items: center; z-index: 2; pointer-events: none; }
.intro-words > span {
  grid-area: 1 / 1; white-space: nowrap;
  font-family: var(--font-mono); font-weight: 700; text-transform: uppercase;
  font-size: clamp(44px, 14vw, 184px); letter-spacing: -0.05em; line-height: 1;
  opacity: 0;
  animation: intro-word .5s calc(.35s + var(--i) * .4s) both;
}
.intro-words > span.serif {
  font-family: var(--font-serif); font-style: italic; font-weight: 400;
  text-transform: none; letter-spacing: -0.03em;
  background: var(--ramp-accent); -webkit-background-clip: text; background-clip: text;
  color: transparent; padding: 0 .08em;   /* italic overhang stays inside the clip */
}
@keyframes intro-word {
  0%   { opacity: 0; transform: scale(1.35); filter: blur(14px); }
  22%  { opacity: 1; transform: scale(1);    filter: blur(0); }
  78%  { opacity: 1; transform: scale(.97);  filter: blur(0); }
  100% { opacity: 0; transform: scale(.9);   filter: blur(8px); }
}

/* ---- 2.55 the title ------------------------------------------------------ */
.intro-card {
  position: relative; z-index: 3; display: grid; justify-items: center; gap: clamp(14px, 2.4vh, 28px);
  padding: 0 var(--gutter); text-align: center; pointer-events: none;
}
.intro-title {
  margin: 0; white-space: nowrap;
  font-family: var(--font-mono); font-weight: 700;
  font-size: clamp(60px, 16.5vw, 228px); letter-spacing: -0.07em; line-height: .9;
  transform-origin: 0 50%;
}
.intro-title.is-flying { transition: transform .9s cubic-bezier(.65,0,.2,1), opacity .9s ease; }
.intro-title > span {
  display: inline-block; opacity: 0;
  animation: intro-slam .62s calc(2.55s + var(--i) * 40ms) cubic-bezier(.2,1.25,.3,1) both;
}
/* "AMS" in the accent ramp. Each letter paints a third of one wide gradient,
   so the three read as one continuous sweep without a shared clip parent
   (a parent's background-clip:text does not follow transformed children). */
.intro-title > .ams {
  background: var(--ramp-accent); background-size: 300% 100%;
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.intro-title > .ams.a { background-position: 0% 0; }
.intro-title > .ams.m { background-position: 50% 0; }
.intro-title > .ams.s { background-position: 100% 0; }
@keyframes intro-slam {
  0%   { opacity: 0; transform: translateY(-.28em) scale(2.3); filter: blur(16px); }
  55%  { opacity: 1; transform: translateY(0) scale(.94);      filter: blur(0); }
  100% { opacity: 1; transform: none;                           filter: blur(0); }
}

/* The impact: one shock ring and one soft bloom. A single flash, never a
   strobe — nothing on this screen blinks more than once. */
.intro-shock {
  position: absolute; left: 50%; top: 50%; width: 40vmin; height: 40vmin; margin: -20vmin 0 0 -20vmin;
  border-radius: 50%; border: 2px solid rgba(var(--accent-rgb), .9);
  box-shadow: 0 0 40px rgba(255,122,26,.5), inset 0 0 40px rgba(var(--accent-rgb), .35);
  opacity: 0; z-index: 1; pointer-events: none;
  animation: intro-shock .9s 2.62s cubic-bezier(.1,.7,.2,1) both;
}
@keyframes intro-shock {
  0%   { opacity: 0; transform: scale(.2); }
  12%  { opacity: 1; }
  100% { opacity: 0; transform: scale(3.6); border-width: 1px; }
}
.intro-bloom {
  position: absolute; inset: 0; z-index: 1; pointer-events: none; opacity: 0;
  background: radial-gradient(42% 30% at 50% 50%, rgba(var(--glow), .42), rgba(var(--accent-rgb), .12) 55%, transparent 75%);
  animation: intro-bloom 1.1s 2.6s ease-out both;
}
@keyframes intro-bloom { 0% { opacity: 0; } 12% { opacity: 1; } 100% { opacity: .18; } }

/* ---- 3.45 the promise ---------------------------------------------------- */
.intro-free {
  margin: 0; font-family: var(--font-serif); font-style: italic; font-weight: 400;
  font-size: clamp(30px, 4.6vw, 66px); line-height: 1.05; letter-spacing: -0.02em;
  clip-path: inset(-10% 100% -20% 0);
  animation: intro-wipe .8s 3.45s cubic-bezier(.65,0,.2,1) both;
}
.intro-free em {
  font-style: italic; padding-right: .06em;
  background: var(--ramp-accent); -webkit-background-clip: text; background-clip: text; color: transparent;
}
@keyframes intro-wipe {
  from { clip-path: inset(-10% 100% -20% 0); transform: translateX(-.3em); }
  to   { clip-path: inset(-10% -2% -20% 0);  transform: none; }
}
.intro-sub {
  margin: 0; font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase; color: var(--on-field-2);
  text-wrap: balance;
  animation: intro-rise .6s 3.95s var(--ease) both;
}
@keyframes intro-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }

.intro-sub > span { white-space: nowrap; }
.intro-stage.is-leaving .intro-free,
.intro-stage.is-leaving .intro-sub,
.intro-stage.is-leaving .intro-bloom,
.intro-stage.is-leaving .intro-progress { opacity: 0 !important; transition: opacity .35s ease; }

/* ---- progress ------------------------------------------------------------ */
.intro-progress {
  position: absolute; left: 0; right: 0; bottom: 0; height: 3px; z-index: 3;
  background: var(--ramp-accent); transform-origin: 0 50%;
  animation: intro-progress 5.3s linear both;
}
@keyframes intro-progress { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* ---- skip ------------------------------------------------------------------ */
.intro-skip {
  position: fixed; z-index: 91;
  right: calc(var(--gutter) + env(safe-area-inset-right, 0px));
  bottom: calc(22px + env(safe-area-inset-bottom, 0px));
  display: inline-flex; align-items: center; gap: 10px;
  padding: 12px 18px; border-radius: var(--r-pill);
  font-family: var(--font-mono); font-size: var(--fs-micro); font-weight: 600;
  letter-spacing: var(--ls-eyebrow); text-transform: uppercase; text-decoration: none;
  color: var(--on-field); background: var(--glass-bg); border: 1px solid var(--hair-strong);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-edge);
  animation: intro-life 6.3s linear forwards, intro-rise .5s .5s var(--ease) both;
}
.intro-skip:hover { border-color: var(--accent); }
.intro-skip:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.intro-skip.is-gone { display: none; }

/* ---- the still card -------------------------------------------------------
   Under reduced motion there is no sequence at all: the end card is simply
   there, with four discipline stills set around it, then it cross-fades
   away (opacity only) or goes on any input. The 3D scene is never loaded. */
.intro-stills { display: none; }

@media (prefers-reduced-motion: reduce) {
  .intro-stage { animation: intro-still 3.4s linear forwards; }
  @keyframes intro-still {
    0%, 82% { opacity: 1; visibility: visible; }
    100%    { opacity: 0; visibility: hidden; }
  }
  .intro-stage *, .intro-stage::before, .intro-stage::after, .intro-skip { animation: none !important; }
  .intro-skip { animation: intro-still 3.4s linear forwards !important; }
  .intro-ignite, .intro-words, .intro-shock, .intro-bloom, .intro-progress, .intro-gl { display: none; }
  .intro-title > span, .intro-sub { opacity: 1; }
  .intro-free { clip-path: none; }
  .intro-stage.is-skipped { animation: intro-out .3s linear forwards !important; }
  .intro-title.is-flying { transition: none; }

  .intro-stills { display: block; position: absolute; inset: 0; pointer-events: none; }
  .intro-stills img {
    position: absolute; width: clamp(76px, 11vw, 168px); height: auto; opacity: .92;
    filter: drop-shadow(0 18px 30px rgba(0,0,0,.55));
  }
  .intro-stills img:nth-child(1) { left: 5%;  top: 7%;  transform: rotate(-8deg); }
  .intro-stills img:nth-child(2) { right: 5%; top: 7%;  transform: rotate(7deg); }
  .intro-stills img:nth-child(3) { left: 6%;  bottom: 8%; transform: rotate(6deg); }
  .intro-stills img:nth-child(4) { right: 6%; bottom: 9%; transform: rotate(-6deg); }
}
