/* ============================================================================
   NetPro BD — animations.css
   Scroll reveals, keyframes, 3D tilt, reduced-motion guard
   -------------------------------------------------------------------------- */

/* ------------------------------ 1. SCROLL REVEAL -------------------------- */
/* Only hide content when JS is available (html.js) — no-JS users see everything */
.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 34px, 0);
  transition:
    opacity .75s var(--ease),
    transform .75s var(--ease);
  transition-delay: var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.js [data-reveal].is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

/* Directional variants */
.js [data-reveal="left"]  { transform: translate3d(-44px, 0, 0); }
.js [data-reveal="right"] { transform: translate3d(44px, 0, 0); }
.js [data-reveal="zoom"]  { transform: scale(.9); }
.js [data-reveal="left"].is-visible,
.js [data-reveal="right"].is-visible,
.js [data-reveal="zoom"].is-visible { transform: none; }

/* Word-by-word headline split (built by JS) */
.split-words .word {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
}
.split-words .word > span {
  display: inline-block;
  transform: translateY(110%);
  animation: wordUp .8s var(--ease) forwards;
  animation-delay: var(--w-delay, 0ms);
}

/* ------------------------------ 2. TILT / MAGNETIC ------------------------ */
.tilt { transform-style: preserve-3d; transition: transform .25s var(--ease); }
.tilt.is-tilting { transition: none; }

.magnetic { transition: transform .3s var(--ease), box-shadow var(--t), color var(--t), background var(--t), border-color var(--t); }

/* ------------------------------ 3. KEYFRAMES ------------------------------ */
@keyframes wordUp {
  from { transform: translateY(110%); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

@keyframes gradShift {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}

@keyframes dotPulse {
  0%   { box-shadow: 0 0 0 0 rgba(34, 211, 238, .55); }
  70%  { box-shadow: 0 0 0 9px rgba(34, 211, 238, 0); }
  100% { box-shadow: 0 0 0 0 rgba(34, 211, 238, 0); }
}

@keyframes floatY {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-14px); }
}

@keyframes orbFloat {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  33%      { transform: translate3d(40px, -34px, 0) scale(1.08); }
  66%      { transform: translate3d(-30px, 26px, 0) scale(.95); }
}

@keyframes gridDrift {
  from { background-position: 0 0, 0 0; }
  to   { background-position: 56px 56px, 56px 56px; }
}

@keyframes scan {
  0%   { transform: translateY(-120%); }
  100% { transform: translateY(320%); }
}

@keyframes scrollLine {
  0%   { top: -40%; opacity: 0; }
  30%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-100%); }
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

@keyframes blink {
  0%, 49% { opacity: 1; }
  50%, 100% { opacity: 0; }
}

@keyframes termLine {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes ledBlink {
  0%, 100% { opacity: 1; }
  45%      { opacity: .25; }
  60%      { opacity: .9; }
}

@keyframes barDance {
  0%, 100% { transform: scaleY(.55); }
  50%      { transform: scaleY(1.25); }
}

@keyframes markPulse {
  0%, 100% { transform: scale(1);   box-shadow: 0 0 0 0 rgba(34,211,238,.45); }
  50%      { transform: scale(1.06); box-shadow: 0 0 0 14px rgba(34,211,238,0); }
}

@keyframes waPulse {
  0%   { box-shadow: 0 12px 28px rgba(37,211,102,.45), 0 0 0 0 rgba(37,211,102,.5); }
  70%  { box-shadow: 0 12px 28px rgba(37,211,102,.45), 0 0 0 18px rgba(37,211,102,0); }
  100% { box-shadow: 0 12px 28px rgba(37,211,102,.45), 0 0 0 0 rgba(37,211,102,0); }
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20%      { transform: translateX(-6px); }
  40%      { transform: translateX(6px); }
  60%      { transform: translateX(-4px); }
  80%      { transform: translateX(4px); }
}

@keyframes popIn {
  from { opacity: 0; transform: scale(.92) translateY(14px); }
  to   { opacity: 1; transform: scale(1) translateY(0); }
}

@keyframes fadeSlideUp {
  from { opacity: 0; transform: translateY(20px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* ------------------------------ 4. ACCESSIBILITY -------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  html { scroll-behavior: auto; }
  .js [data-reveal] { opacity: 1 !important; transform: none !important; }
  .split-words .word > span { transform: none !important; opacity: 1 !important; }
  .cursor-glow, .netpanel__scan, .theme-sweep { display: none; }
  .cov-radar__sweep { animation: none; }
  .marquee__track { animation: none; width: auto; flex-wrap: wrap; justify-content: center; }
}

/* Pause decorative loops when the tab is hidden (battery friendly) */
.is-tab-hidden .orb,
.is-tab-hidden .marquee__track,
.is-tab-hidden .hero__grid,
.is-tab-hidden .netpanel__scan { animation-play-state: paused; }

/* ------------------------------ 5. PREMIUM MOTION -------------------------- */
/* Line-mask + blur reveal for section headings.
   NOTE: the clip lives on an inner .mask-box wrapper (injected by JS) because
   Chrome's IntersectionObserver reports an element that clips ITSELF as
   non-intersecting — which would dead-lock the reveal. */
.js [data-reveal="mask"] .mask-box {
  display: block;
  clip-path: inset(-30% -10% 110% -10%);
  filter: blur(8px);
  transition: clip-path 1s var(--ease-out), filter 1s var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}
.js [data-reveal="mask"].is-visible .mask-box {
  clip-path: inset(-30% -10% -30% -10%);
  filter: blur(0);
}

/* Soft focus-in for media panels */
.js [data-reveal="focus"] { filter: blur(14px) saturate(.6); transform: scale(.94); opacity: 0; }
.js [data-reveal="focus"].is-visible { filter: blur(0) saturate(1); transform: scale(1); opacity: 1; }

/* Navbar entrance, staggered per link */
@keyframes navIn {
  from { opacity: 0; transform: translateY(-10px); filter: blur(4px); }
  to   { opacity: 1; transform: translateY(0);    filter: blur(0); }
}
.js .nav__list .nav__link { animation: navIn .6s var(--ease-out) backwards; }
.js .nav__list li:nth-child(1) .nav__link { animation-delay: .30s; }
.js .nav__list li:nth-child(2) .nav__link { animation-delay: .36s; }
.js .nav__list li:nth-child(3) .nav__link { animation-delay: .42s; }
.js .nav__list li:nth-child(4) .nav__link { animation-delay: .48s; }
.js .nav__list li:nth-child(5) .nav__link { animation-delay: .54s; }
.js .nav__list li:nth-child(6) .nav__link { animation-delay: .60s; }
.js .nav__list li:nth-child(7) .nav__link { animation-delay: .66s; }
.js .nav__list li:nth-child(8) .nav__link { animation-delay: .72s; }

/* Rotating conic border */
@keyframes orbitSpin { to { --orbit-angle: 360deg; } }

/* Button press ripple */
@keyframes ripple {
  from { transform: scale(0); opacity: .9; }
  to   { transform: scale(1); opacity: 0; }
}

/* Global theme cross-fade (fallback path when View Transitions unavailable) */
/* --------------------------- THEME MORPH COHERENCE ------------------------- */
/* While the tokens interpolate, descendants must NOT run their own colour
   transitions: hundreds of them would each lag behind the token and fight it.
   Motion (transform/opacity) is preserved so nothing else feels interrupted. */
html.theme-morph *,
html.theme-morph *::before,
html.theme-morph *::after {
  transition-property: transform, opacity !important;
}
html.theme-morph .glow-orbit,
html.theme-morph .cursor-glow { animation-play-state: paused; }

/* Expensive paint effects go OFF for the morph window: backdrop-filter and
   blend modes force a full-viewport recomposite on EVERY interpolated frame,
   which is exactly what makes a theme switch feel choppy on real hardware. */
html.theme-morph .navbar,
html.theme-morph .topbar,
html.theme-morph .btn--glass,
html.theme-morph .badge-glass,
html.theme-morph .lang-fab,
html.theme-morph .netpanel,
html.theme-morph .float-chip { backdrop-filter: none !important; -webkit-backdrop-filter: none !important; }
html.theme-morph body::after { opacity: 0 !important; }   /* grain blend off */

html.theme-morph .hero__visual::before { opacity: 0 !important; }  /* photo mask off */

html.is-theming,
html.is-theming *,
html.is-theming *::before,
html.is-theming *::after {
  transition:
    background-color .55s var(--ease),
    border-color .55s var(--ease),
    color .55s var(--ease),
    fill .55s var(--ease),
    stroke .55s var(--ease),
    box-shadow .55s var(--ease) !important;
}

/* View-Transition circular theme reveal */
::view-transition-old(root),
::view-transition-new(root) { animation: none; mix-blend-mode: normal; }
::view-transition-old(root) { z-index: 1; }
::view-transition-new(root) { z-index: 999; }

@media (prefers-reduced-motion: reduce) {
  .glow-orbit::after { animation: none; }
  .js .nav__list .nav__link { animation: none; }
  .js [data-reveal="mask"] .mask-box, .js [data-reveal="focus"] { clip-path: none; filter: none; }
}

/* Partner marquee */


@keyframes cueDrop {
  0%   { transform: scaleY(0); opacity: 0; }
  35%  { transform: scaleY(1); opacity: 1; }
  100% { transform: scaleY(1) translateY(14px); opacity: 0; }
}

/* Touch: the sweep layer becomes a solid page-colour VEIL. It fades up, the
   palette snaps underneath while fully covered, then it lifts revealing the
   finished theme — a compositor-only opacity animation, zero jank. */
html.is-touch .theme-sweep,
html.is-lowpow .theme-sweep { background: var(--bg); }
