/* ============================================================
   landing_intro.css — public landing splash + cascade intro
   Deploy to: website/static/css/landing_intro.css

   ISOLATION CONTRACT
   ------------------
   • Every rule is keyed on  html.lpi-armed  — the class is added by a
     tiny inline <head> script ONLY when the intro is enabled, the
     visitor hasn't seen it this session, and reduced-motion is off.
   • When that class is absent (intro off / disabled / already played /
     JS failed) NONE of these rules apply and the page renders exactly
     as it does today. Nothing here can permanently hide content.
   • Namespace is lpi-* throughout. No collision with landing.css
     (.lp-*) or landing.js state classes (.is-active / .is-green …).
   • The landing does not load base.css/layout.css, so we lean on the
     --lp-* tokens defined on #landing-root, with hex fallbacks.
   ============================================================ */

/* ---- Initial hidden state (only while armed) ------------------------ */

/* Hero copy + chrome fade up from below. */
html.lpi-armed .ih,
html.lpi-armed .ifo,
html.lpi-armed #landing-root .lp-brand-tagline,
html.lpi-armed #landing-root .lp-hero__headline,
html.lpi-armed #landing-root .lp-hero__subhead,
html.lpi-armed #landing-root .lp-hero__cta,
html.lpi-armed #landing-root .lp-hero__note,
html.lpi-armed #landing-root .lp-demo {
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;          /* don't let tab focus reach hidden controls */
}

/* The brand bars build up from the baseline. transform-box lets us scale
   each SVG <rect> about its own bottom edge. */
html.lpi-armed #landing-root .lp-brand__bars rect {
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transform: scaleY(0);
  transition: transform 0.5s cubic-bezier(0.2, 0.8, 0.25, 1);
}

/* The wordmark appears after the bars. */
html.lpi-armed #landing-root .lp-brand__word {
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* ---- Splash: brand lifted to viewport centre ------------------------ */
/* JS sets the actual translate()+scale() inline (measured per viewport);
   this just lifts the brand above the hidden page and arms the dock. */
html.lpi-armed #landing-root .lp-brand.lpi-splash {
  position: relative;
  z-index: 9999;
  will-change: transform;
}
html.lpi-armed #landing-root .lp-brand.lpi-dock {
  transition: transform 0.82s cubic-bezier(0.7, 0, 0.18, 1);
}

/* ---- Reveal: JS adds .lpi-in element-by-element --------------------- */
html.lpi-armed .ih.lpi-in,
html.lpi-armed .ifo.lpi-in,
html.lpi-armed #landing-root .lpi-in {
  opacity: 1 !important;
  transform: none !important;      /* on a <rect>, none == full height */
  pointer-events: auto;
  transition: opacity 0.6s ease, transform 0.6s ease;
}

/* ---- Defensive: if reduced-motion flips mid-session, show everything. */
@media (prefers-reduced-motion: reduce) {
  html.lpi-armed .ih,
  html.lpi-armed .ifo,
  html.lpi-armed #landing-root .lp-brand-tagline,
  html.lpi-armed #landing-root .lp-hero__headline,
  html.lpi-armed #landing-root .lp-hero__subhead,
  html.lpi-armed #landing-root .lp-hero__cta,
  html.lpi-armed #landing-root .lp-hero__note,
  html.lpi-armed #landing-root .lp-demo,
  html.lpi-armed #landing-root .lp-brand__word {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
  html.lpi-armed #landing-root .lp-brand__bars rect { transform: none; }
}