/* PORTAL-01 Stage B — cinematic entry.
 * Uses the supplied 1672×941 image and the supplied 11.2 s MP3, unmodified.
 *
 * Layer stack (bottom → top):
 *   .ci-stage   framing + mobile over-scale (keeps the wordmark aligned & visible)
 *     .ci-frame    backdrop waves + the baked-in wordmark   (depth motion)
 *     .ci-wordmark crisp highlight of the same lettering    (locked to the frame)
 *     .ci-bloom    soft letter-shaped halo                  (breathes with the bass)
 *     .ci-flare    expanding shockwave ring                 (impact only)
 *   .ci-shade   vignette
 *   .ci-glow    ambient cyan energy field
 *   .ci-flash   single impact flash (one fade, never a strobe)
 *   .ci-sweep   light sweep used at the spoken brand name
 *   .ci-content / .ci-note / buttons
 *   .ci-login   sign-in card
 *
 * PERFORMANCE CONTRACT
 *   Only `transform` and `opacity` are animated per frame. Every `filter` is a
 *   constant, so the compositor never has to re-rasterise the supplied artwork at
 *   60 fps. All motion values come from CSS custom properties that intro.js writes
 *   from the real audio analyser.
 */
.intro-body { margin: 0; background: #03050a; color: var(--fg); overflow-x: hidden; }
.ci-root { position: fixed; inset: 0; overflow: hidden; background: #03050a; }

/* ------------------------------------------------------------- staging -- */
.ci-stage { position: absolute; inset: 0;
  transform: scale(var(--stage-scale, 1));
  transform-origin: 50% var(--stage-origin, 47.3%);
  will-change: transform; }

.ci-frame { position: absolute; inset: -2.5%; display: grid; place-items: center;
  will-change: transform;
  transform: translate3d(var(--frame-x, 0px), var(--frame-y, 0px), 0)
             scale(var(--frame-scale, 1.02));
  transform-origin: 50% var(--stage-origin, 47.3%); }
.ci-frame img { width: 100%; height: 100%; object-fit: cover; object-position: center 48%;
  user-select: none; -webkit-user-drag: none; }

/* ------------------------------------------------------ the lettering --
 * The crisp layer is ALWAYS readable: it never drops below ~0.88 opacity.
 * The bass modulates its glow (via .ci-bloom), lift and scale — never its visibility.
 *
 * `filter` lives on the inner .ci-fx wrapper and is a constant. The outer element
 * only ever animates transform/opacity, which keeps the compositor from having to
 * re-run the drop-shadows every frame (measured 306 ms vs 36 ms per frame in
 * software rendering when the filter sat on the animated element).
 */
.ci-wordmark { position: absolute; inset: -2.5%; pointer-events: none; will-change: transform, opacity;
  opacity: calc(.88 + var(--bass, 0) * .10 + var(--voice, 0) * .02);
  transform: translate3d(var(--word-x, 0px), var(--word-y, 0px), 0)
             scale(var(--word-scale, 1)) rotate(var(--word-rot, 0deg));
  transform-origin: 50% var(--stage-origin, 47.3%); }
.ci-wordmark .ci-fx {
  width: 100%; height: 100%;
  filter: brightness(1.16) contrast(1.12) saturate(1.1)
          drop-shadow(0 0 12px rgba(63,216,255,.5))
          drop-shadow(0 0 30px rgba(63,216,255,.24)); }
.ci-fx img { display: block; width: 100%; height: 100%; object-fit: cover;
  object-position: center 48%; user-select: none; -webkit-user-drag: none; }

/* Soft letter-shaped halo — the "bloom". Its opacity and scale breathe with the
 * real low-frequency energy, so the wordmark pushes light into the room. */
.ci-bloom { position: absolute; inset: -2.5%; pointer-events: none; will-change: transform, opacity;
  opacity: calc(var(--bloom, .1) * .9);
  transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0)
             scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1)));
  transform-origin: 50% var(--stage-origin, 47.3%); }
.ci-bloom .ci-fx {
  width: 100%; height: 100%;
  filter: brightness(1.55) saturate(1.2) blur(11px); }

/* Expanding energy ring fired at the real impact (5.40 s of the supplied MP3). */
.ci-flare { position: absolute; left: 50%; top: var(--stage-origin, 47.3%);
  width: min(46vh, 460px); aspect-ratio: 1; margin: 0; pointer-events: none;
  border-radius: 50%; opacity: 0;
  border: 1px solid rgba(150,235,255,.5);
  box-shadow: 0 0 42px rgba(63,216,255,.32), 0 0 90px rgba(63,216,255,.16),
              inset 0 0 46px rgba(63,216,255,.18);
  transform: translate(-50%, -50%) scale(.34); }
@keyframes ci-flare-out {
  0%   { opacity: .62; transform: translate(-50%,-50%) scale(.34); }
  100% { opacity: 0;   transform: translate(-50%,-50%) scale(2.75); } }

/* ---------------------------------------------------------- ambience -- */
.ci-shade { position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(ellipse at 50% 47%, transparent 26%, rgba(3,5,10,.32) 66%, rgba(3,5,10,.88) 100%),
              linear-gradient(180deg, rgba(3,5,10,.58), transparent 24%, transparent 72%, rgba(3,5,10,.92)); }
.ci-glow { position: absolute; inset: 0; pointer-events: none; will-change: opacity;
  opacity: calc(var(--glow, .18) * .9);
  background: radial-gradient(ellipse 62% 22% at 50% var(--stage-origin, 47.3%), rgba(63,216,255,.30), transparent 72%),
              radial-gradient(ellipse 90% 40% at 50% 58%, rgba(255,179,71,.09), transparent 76%); }
.ci-flash { position: absolute; inset: 0; pointer-events: none; opacity: 0; will-change: opacity;
  background: radial-gradient(ellipse 70% 26% at 50% var(--stage-origin, 47.3%),
              rgba(160,238,255,.5), rgba(63,216,255,.14) 46%, transparent 74%); }
@keyframes ci-flash { 0% { opacity: .42; } 100% { opacity: 0; } }

.ci-sweep { position: absolute; inset: 0; pointer-events: none; opacity: 0; will-change: opacity;
  background: linear-gradient(105deg, transparent 38%, rgba(150,235,255,.2) 50%, transparent 62%);
  background-size: 240% 100%; background-position: 120% 0; }
@keyframes ci-sweep-run {
  0%   { opacity: 0;   background-position: 130% 0; }
  22%  { opacity: .8; }
  100% { opacity: 0;   background-position: -30% 0; } }

/* --------------------------------------------------- cue choreography --
 * brand  — the spoken "GROUNDTRUTH": a highlight that gathers and settles.
 * impact — the real hit at 5.40 s: punch, shockwave ring, single flash.
 * Only transform/opacity animate, so these never stall the compositor.
 */
.ci-root.is-brand .ci-bloom { animation: ci-bloom-focus 1.25s cubic-bezier(.22,.68,.24,1); }
@keyframes ci-bloom-focus {
  0%   { opacity: calc(var(--bloom, .1) * 2.1);  transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1) * 1.16)); }
  60%  { opacity: calc(var(--bloom, .1) * 1.25); transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1) * 1.05)); }
  100% { opacity: calc(var(--bloom, .1) * .9);   transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1))); } }
.ci-root.is-brand .ci-wordmark { animation: ci-word-focus 1.25s cubic-bezier(.22,.68,.24,1); }
@keyframes ci-word-focus {
  0%   { opacity: .97; transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(calc(var(--word-scale,1) * 1.012)); }
  60%  { opacity: 1;   transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(calc(var(--word-scale,1) * 1.004)); }
  100% { opacity: calc(.88 + var(--bass, 0) * .10); transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(var(--word-scale,1)); } }
.ci-root.is-brand .ci-sweep { animation: ci-sweep-run 1.35s cubic-bezier(.3,.6,.2,1); }

.ci-root.is-impact .ci-flare { animation: ci-flare-out .95s cubic-bezier(.16,.84,.3,1); }
.ci-root.is-impact .ci-flash { animation: ci-flash .5s ease-out; }
.ci-root.is-impact .ci-wordmark { animation: ci-word-punch 1.05s cubic-bezier(.16,.84,.28,1); }
@keyframes ci-word-punch {
  0%   { transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(var(--word-scale,1)); }
  16%  { transform: translate3d(var(--word-x,0px), calc(var(--word-y,0px) - 3px), 0) scale(calc(var(--word-scale,1) * 1.052)); }
  100% { transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(var(--word-scale,1)); } }
.ci-root.is-impact .ci-bloom { animation: ci-bloom-burst 1.05s cubic-bezier(.16,.84,.28,1); }
@keyframes ci-bloom-burst {
  0%   { opacity: calc(var(--bloom, .1) * .9); transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1))); }
  18%  { opacity: calc(var(--bloom, .1) * 2.3); transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1) * 1.2)); }
  100% { opacity: calc(var(--bloom, .1) * .9); transform: translate3d(calc(var(--word-x, 0px) * 1.25), calc(var(--word-y, 0px) * 1.25), 0) scale(calc(var(--word-scale, 1) * var(--bloom-scale, 1))); } }
.ci-root.is-impact .ci-frame { animation: ci-frame-punch .95s cubic-bezier(.16,.84,.28,1); }
@keyframes ci-frame-punch {
  0%   { transform: translate3d(var(--frame-x,0px), var(--frame-y,0px), 0) scale(var(--frame-scale, 1.02)); }
  18%  { transform: translate3d(var(--frame-x,0px), var(--frame-y,0px), 0) scale(calc(var(--frame-scale, 1.02) * 1.016)); }
  100% { transform: translate3d(var(--frame-x,0px), var(--frame-y,0px), 0) scale(var(--frame-scale, 1.02)); } }

/* ------------------------------------------------------------- intro UI */
.ci-content { position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: flex-end; padding: 0 24px 7vh; text-align: center; }
.ci-kicker { letter-spacing: .32em; text-transform: uppercase; font-size: 11px; color: var(--cyan);
  opacity: 0; transform: translateY(8px); transition: opacity .8s ease, transform .8s ease; }
.ci-root.is-ready .ci-kicker { opacity: .9; transform: none; }
.ci-controls { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-top: 14px;
  opacity: 0; transform: translateY(10px); transition: opacity .7s ease .15s, transform .7s ease .15s; }
.ci-root.is-ready .ci-controls { opacity: 1; transform: none; }
.ci-controls .btn, .ci-controls .primary { min-width: 165px; }
.ci-mute { position: absolute; right: 18px; top: 18px; z-index: 4; }
.ci-skip { position: absolute; left: 18px; top: 18px; z-index: 4; }
.ci-note { position: absolute; left: 0; right: 0; bottom: 14px; text-align: center;
  font-size: 11px; color: var(--muted); letter-spacing: .04em; }
.ci-intro-tag { position: absolute; left: 50%; top: 5vh; transform: translateX(-50%);
  font-size: 10px; letter-spacing: .34em; color: rgba(185,198,228,.7); text-transform: uppercase;
  z-index: 3; transition: opacity .5s ease; }
.ci-root.is-playing .ci-kicker { opacity: 1; }
.ci-root.is-playing .ci-controls { opacity: 0; pointer-events: none; }
.ci-root.is-playing .ci-intro-tag { opacity: .3; }

/* ------------------------------------------------- transition to login --
 * The hero lettering lifts away, the room settles and dims, and the card rises
 * into place over the same branded backdrop — continuous, never a hard cut.
 */
.ci-root.is-leaving .ci-frame {
  animation: ci-frame-settle var(--leave-ms, 700ms) cubic-bezier(.3,.7,.2,1) forwards; }
@keyframes ci-frame-settle {
  0%   { transform: translate3d(var(--frame-x,0px), var(--frame-y,0px), 0) scale(var(--frame-scale, 1.02));
         opacity: 1; }
  100% { transform: translate3d(var(--frame-x,0px), calc(var(--frame-y,0px) - 10px), 0) scale(calc(var(--frame-scale, 1.02) * 1.05));
         opacity: .72; } }
.ci-root.is-leaving .ci-wordmark {
  animation: ci-word-lift var(--leave-ms, 700ms) cubic-bezier(.3,.7,.2,1) forwards; }
@keyframes ci-word-lift {
  0%   { opacity: 1;
         transform: translate3d(var(--word-x,0px), var(--word-y,0px), 0) scale(var(--word-scale,1)); }
  100% { opacity: 0;
         transform: translate3d(var(--word-x,0px), calc(var(--word-y,0px) - 26px), 0)
                    scale(calc(var(--word-scale,1) * 1.07)); } }
.ci-root.is-leaving .ci-bloom {
  animation: ci-bloom-lift var(--leave-ms, 700ms) cubic-bezier(.3,.7,.2,1) forwards; }
@keyframes ci-bloom-lift {
  0%   { opacity: calc(var(--bloom, .1) * .9); }
  100% { opacity: 0;
         transform: translate3d(calc(var(--word-x,0px) * 1.25),
                                calc(var(--word-y,0px) * 1.25 - 30px), 0)
                    scale(calc(var(--word-scale,1) * var(--bloom-scale,1) * 1.22)); } }
.ci-root.is-leaving .ci-glow {
  transition: opacity var(--leave-ms, 700ms) ease; opacity: .05; }
.ci-root.is-leaving .ci-shade {
  transition: opacity var(--leave-ms, 700ms) ease; opacity: .82; }

.ci-login { position: absolute; inset: 0; display: none; place-items: center; padding: 24px;
  background: rgba(3,5,10,.58); backdrop-filter: blur(10px); z-index: 5; }
.ci-root.login-mode .ci-login { display: grid; animation: ci-login-bg .55s ease both; }
@keyframes ci-login-bg { from { opacity: 0; } to { opacity: 1; } }
.ci-root.login-mode .ci-content, .ci-root.login-mode .ci-controls,
.ci-root.login-mode .ci-note, .ci-root.login-mode .ci-intro-tag,
.ci-root.login-mode .ci-skip, .ci-root.login-mode .ci-mute {
  pointer-events: none; opacity: 0; transition: opacity .35s ease; }
.ci-card { width: min(440px, 100%); padding: 28px 26px; border: 1px solid rgba(63,216,255,.26);
  border-radius: 14px; background: linear-gradient(180deg, rgba(11,16,32,.96), rgba(5,8,16,.98));
  box-shadow: 0 24px 80px rgba(0,0,0,.55), 0 0 0 1px rgba(63,216,255,.04) inset;
  animation: ci-card-in .52s cubic-bezier(.22,.72,.26,1) both; }
@keyframes ci-card-in {
  from { opacity: 0; transform: translateY(18px) scale(.982); }
  to   { opacity: 1; transform: none; } }
.ci-card h1 { font-size: 19px; margin: 0 0 4px; letter-spacing: .01em; }
.ci-card p.sub { margin: 0 0 18px; color: var(--muted); font-size: 13px; }
.ci-card label { display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .14em;
  color: var(--fg-2); margin: 12px 0 6px; }
.ci-card input { width: 100%; box-sizing: border-box; padding: 11px 12px; border-radius: 8px;
  border: 1px solid var(--line-bright); background: #060a14; color: var(--fg); font: inherit; }
.ci-card input:focus { outline: none; border-color: var(--cyan); box-shadow: 0 0 0 3px rgba(63,216,255,.14); }
.ci-card .primary { width: 100%; margin-top: 18px; }
.ci-error { margin-top: 12px; padding: 9px 11px; border: 1px solid rgba(255,107,107,.4);
  border-radius: 8px; color: #ffd3d3; background: rgba(255,107,107,.08); font-size: 12px; }
.ci-hint { margin-top: 12px; font-size: 12px; color: var(--muted); }
.ci-hint a { color: var(--cyan); }
.ci-replay { background: none; border: 0; color: var(--cyan); cursor: pointer; font: inherit; font-size: 12px; }
.ci-replay:hover { text-decoration: underline; }

/* -------------------------------------------------------------- mobile --
 * Portrait phones get the whole 16:9 artwork fitted (no wordmark crop) and then
 * framed up a little, so the lettering is fully visible AND visually strong.
 */
@media (max-width: 700px) {
  .ci-stage { --stage-scale: 1.32; --stage-origin: 49%; }
  .ci-frame { background: #03050a; }
  .ci-frame img, .ci-fx img {
    object-fit: contain; object-position: center center; }
  /* A phone is small: the halo would read as fog. Keep the energy, tighten the spill. */
  .ci-bloom { opacity: calc(var(--bloom, .1) * .58); }
  .ci-bloom .ci-fx { filter: brightness(1.5) saturate(1.2) blur(7px); }
  .ci-glow { opacity: calc(var(--glow, .18) * .68); }
  .ci-content { padding-bottom: 12vh; }
  .ci-note { bottom: 4px; font-size: 10px; padding: 0 14px; }
  .ci-controls { flex-direction: column; width: min(360px, 100%); }
  .ci-controls .btn, .ci-controls .primary { width: 100%; }
  .ci-card { padding: 22px 18px; }
  .ci-kicker { font-size: 10px; letter-spacing: .24em; }
  .ci-flare { width: min(38vh, 300px); }
}

/* ------------------------------------------------------ reduced motion --
 * No vibration, no scale, no flash. The wordmark stays sharp and fully legible,
 * and the intro still ends on the login form.
 */
@media (prefers-reduced-motion: reduce) {
  .ci-stage, .ci-frame, .ci-wordmark, .ci-bloom, .ci-flare,
  .ci-glow, .ci-flash, .ci-sweep {
    transition: none !important; animation: none !important; }
  .ci-stage { transform: none !important; }
  .ci-frame { transform: none !important; }
  .ci-wordmark { transform: none !important; opacity: 1 !important; }
  .ci-bloom { transform: none !important; opacity: .18 !important; }
  .ci-flare, .ci-flash, .ci-sweep { display: none !important; }
  .ci-root.is-impact .ci-frame, .ci-root.is-impact .ci-wordmark,
  .ci-root.is-impact .ci-bloom, .ci-root.is-impact .ci-flare,
  .ci-root.is-impact .ci-flash, .ci-root.is-brand .ci-wordmark,
  .ci-root.is-brand .ci-bloom, .ci-root.is-brand .ci-sweep,
  .ci-root.is-leaving .ci-frame, .ci-root.is-leaving .ci-wordmark,
  .ci-root.is-leaving .ci-bloom { animation: none !important; }
  .ci-root.login-mode .ci-login, .ci-card { animation: none !important; }
}
.ci-root.reduced .ci-frame, .ci-root.reduced .ci-glow,
.ci-root.reduced .ci-bloom, .ci-root.reduced .ci-wordmark {
  transition: none !important; animation: none !important; }
.ci-root.reduced .ci-frame, .ci-root.reduced .ci-wordmark,
.ci-root.reduced .ci-bloom { transform: none !important; }
.ci-root.reduced .ci-wordmark { opacity: 1 !important; }
.ci-root.reduced .ci-bloom { opacity: .18 !important; }
.ci-root.reduced .ci-flare, .ci-root.reduced .ci-flash,
.ci-root.reduced .ci-sweep { display: none !important; }
