@charset "UTF-8";
/* ============================================================================
   saluzzo.css — MOTION & FX LAYER for the Lappland operator terminal.
   Load AFTER style.css. Holds every @keyframes + the cinematic overlays
   (CRT grain, scanlines, decode glow, persona glitch, scroll reveal).
   All ambient motion is gated behind prefers-reduced-motion.
   ============================================================================ */

/* ---------------------------------------------------------------------------
   0) CORE KEYFRAMES (used regardless of motion preference)
--------------------------------------------------------------------------- */
@keyframes spin{ to{ transform:rotate(360deg) } }
@keyframes run{
  from{ transform:translateX(-26vw) translateY(var(--lane,0)) }
  to  { transform:translateX(150vw)  translateY(var(--lane,0)) }
}
@keyframes strikeRing{ 0%{ transform:scale(.85); opacity:.9 } 100%{ transform:scale(1.35); opacity:0 } }
@keyframes ssPop{ 0%{ transform:scale(1) } 40%{ transform:scale(1.28); color:var(--accent-2) } 100%{ transform:scale(1) } }
@keyframes odobump{ 0%{ transform:translateY(0) } 50%{ transform:translateY(-1px) } 100%{ transform:translateY(0) } }
@keyframes cueBob{ 0%,100%{ transform:rotate(45deg) translate(0,0); opacity:.5 } 50%{ transform:rotate(45deg) translate(3px,3px); opacity:1 } }
@keyframes eq{ 0%,100%{ height:30% } 50%{ height:100% } }
@keyframes toastIn{ from{ opacity:0; transform:translateY(12px) } to{ opacity:1; transform:none } }
@keyframes toastOut{ from{ opacity:1; transform:none } to{ opacity:0; transform:translateY(8px) } }
@keyframes pulseDot{ 0%,100%{ box-shadow:0 0 6px var(--accent) } 50%{ box-shadow:0 0 14px var(--accent), 0 0 4px #fff } }

/* the signal dot always breathes a little */
.persona-toggle .pt-dot{ animation:pulseDot 2.4s ease-in-out infinite }

/* ---------------------------------------------------------------------------
   1) GLOBAL CRT FILM GRADE — scanlines + grain + soft vignette.
--------------------------------------------------------------------------- */
body::after{
  content:""; position:fixed; inset:0; z-index:70; pointer-events:none;
  background:
    radial-gradient(130vmax 90vmax at 50% -10%, transparent 58%, rgba(0,0,0,.5) 100%),
    repeating-linear-gradient(0deg, rgba(0,0,0,.16) 0 1px, transparent 1px 3px);
  mix-blend-mode:multiply; opacity:.5;
}
body::before{
  content:""; position:fixed; inset:-50%; z-index:71; pointer-events:none;
  background-image:url("data:image/svg+xml;utf8,\
<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'>\
<filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/>\
<feColorMatrix type='saturate' values='0'/></filter>\
<rect width='100%' height='100%' filter='url(%23n)' opacity='0.5'/></svg>");
  opacity:.04; mix-blend-mode:overlay;
}

/* retint smoothly when persona changes */
.hud-nav,.panel,.btn,.tag,.sim,.bar i,.meter i,.bond-bar i,.howl-meter i,.hud-btn,.lvl-range{
  transition:border-color .5s ease, box-shadow .5s ease, background-color .5s ease, color .5s ease;
}

/* ---------------------------------------------------------------------------
   2) MOTION-ONLY EFFECTS
--------------------------------------------------------------------------- */
@media (prefers-reduced-motion: no-preference){
  body::before{ animation:grainShift 1.1s steps(3) infinite }
  @keyframes grainShift{
    0%{transform:translate(0,0)} 33%{transform:translate(-3%,2%)}
    66%{transform:translate(2%,-3%)} 100%{transform:translate(0,0)}
  }

  /* hero staggered entrance */
  .hud-kicker,.hero-title,.hero-sub,.tag-row,.hero-lead,.voice-ticker,.hero-actions,.sim{
    animation:heroIn .65s cubic-bezier(.2,.8,.2,1) both;
  }
  .hud-kicker{animation-delay:.05s} .hero-title{animation-delay:.12s}
  .hero-sub{animation-delay:.2s} .tag-row{animation-delay:.28s}
  .hero-lead{animation-delay:.34s} .voice-ticker{animation-delay:.4s}
  .hero-actions{animation-delay:.46s} .sim{animation-delay:.54s}
  @keyframes heroIn{ from{opacity:0; transform:translateY(16px)} to{opacity:1; transform:none} }

  /* blinking voice caret */
  .vt-caret{ animation:caretBlink 1s steps(1) infinite }
  @keyframes caretBlink{ 0%,50%{opacity:1} 51%,100%{opacity:0} }

  /* hero portrait scan sweep */
  .hero-art.is-visible ~ .ps-scan{ animation:portraitScan 5.5s ease-in-out 1.5s infinite }
  @keyframes portraitScan{ 0%{ top:-40%; opacity:0 } 8%{opacity:.7} 40%{ top:100%; opacity:0 } 100%{ top:100%; opacity:0 } }

  /* scroll reveal (only when JS present) */
  .has-js [data-reveal]{ opacity:0; transform:translateY(28px) scale(.995);
    transition:opacity .7s cubic-bezier(.2,.8,.2,1), transform .7s cubic-bezier(.2,.8,.2,1) }
  .has-js [data-reveal].is-in{ opacity:1; transform:none }

  /* decode flicker tint while a title scrambles */
  .ph-title.decoding,.hero-title.decoding{ color:var(--accent-2); text-shadow:0 0 14px var(--accent) }

  /* decadenza ember breathe */
  .decadenza{ animation:decBreathe 7s ease-in-out infinite }
  @keyframes decBreathe{
    0%,100%{ box-shadow:inset 0 0 50px rgba(232,177,58,.03) }
    50%{ box-shadow:inset 0 0 90px rgba(232,177,58,.09) }
  }
  .dec-card.ult .dc-front h4{
    background:linear-gradient(90deg,#fff,var(--gold-2),#fff); background-size:200% 100%;
    -webkit-background-clip:text; background-clip:text; color:transparent; animation:goldFlow 3.5s linear infinite;
  }
  @keyframes goldFlow{ to{ background-position:200% 0 } }

  /* sim "hot" state pulse */
  .sim-state.is-hot{ animation:hotPulse 1s ease-in-out infinite }
  @keyframes hotPulse{ 0%,100%{ box-shadow:0 0 0 0 var(--accent-soft) } 50%{ box-shadow:0 0 0 4px transparent } }
}

/* ---------------------------------------------------------------------------
   3) PERSONA GLITCH BURST (injected by JS as .glitch-burst)
--------------------------------------------------------------------------- */
.glitch-burst{ position:fixed; inset:0; z-index:160; pointer-events:none; display:grid; place-items:center;
  background:linear-gradient(0deg, color-mix(in srgb, var(--accent) 8%, transparent), transparent) }
.glitch-burst span{ font-family:var(--display); font-weight:700; letter-spacing:.2em;
  font-size:clamp(2rem,9vw,6rem); color:#fff;
  text-shadow:3px 0 var(--accent), -3px 0 var(--ice) }
@media (prefers-reduced-motion: no-preference){
  .glitch-burst{ animation:gbFade .6s ease-out forwards }
  .glitch-burst span{ animation:gbGlitch .6s steps(2) forwards }
  @keyframes gbFade{ 0%{opacity:0} 20%{opacity:1} 100%{opacity:0} }
  @keyframes gbGlitch{
    0%{ transform:translate(0) scale(.96); text-shadow:6px 0 var(--accent), -6px 0 var(--ice) }
    25%{ transform:translate(-6px,2px) }
    50%{ transform:translate(5px,-2px); text-shadow:-5px 0 var(--accent), 5px 0 var(--ice) }
    75%{ transform:translate(-3px,1px) }
    100%{ transform:translate(0) scale(1.04); text-shadow:0 0 var(--accent) }
  }
}
@media (prefers-reduced-motion: reduce){ .glitch-burst{ display:none } }

/* ---------------------------------------------------------------------------
   4) REDUCED-MOTION FALLBACKS — keep functional UI visible & static.
--------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce){
  .runner,.after,.speedline{ display:none !important }
  .fx-canvas,.carnevale-canvas{ display:none }
  .sc-arrow{ animation:none }
  .vt-caret{ opacity:1 }
  .toast{ opacity:1; transform:none }                 /* toasts must still show  */
  .toast.show{ animation:none; opacity:1 }
  .toast.hide{ animation:none; opacity:0 }
  .dc-inner{ transition:none }
  .persona-toggle .pt-dot{ animation:none }
  .fanart-card img.fade-img{ opacity:1; filter:none; transition:none }
}
