/* ==========================================================================
   NOFAIL · Effets partagés (landing + app)
   --------------------------------------------------------------------------
   Inspirés des dashboards SaaS type vinteer.io :
     1. halos bleus diffus en fond de page ;
     2. apparition « fondu + montée + flou » des blocs, en cascade ;
     3. bordure lumineuse qui tourne autour des cartes mises en avant ;
     4. reflet qui traverse les éléments en chargement (shimmer).
   Les couleurs viennent toutes de tokens.css. Rien ne bouge si
   l'utilisateur a demandé à réduire les animations.
   ========================================================================== */

/* ---------- 1. Halos de fond ---------- */
.ambient {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  overflow: hidden;
}
.ambient::before, .ambient::after {
  content: "";
  position: absolute;
  width: 70vmax;
  height: 70vmax;
  border-radius: 50%;
  filter: blur(80px);
  opacity: .5;
}
.ambient::before { top: -45vmax; left: -15vmax; background: radial-gradient(circle, rgba(31, 107, 255, .35), transparent 65%); animation: drift 24s ease-in-out infinite alternate; }
.ambient::after { top: -40vmax; right: -25vmax; background: radial-gradient(circle, rgba(56, 189, 248, .22), transparent 65%); animation: drift 30s ease-in-out infinite alternate-reverse; }
:root[data-theme="light"] .ambient::before, :root[data-theme="light"] .ambient::after { opacity: .35; }
@keyframes drift { to { transform: translate(6vmax, 4vmax) scale(1.08); } }

/* Grille fine estompée, façon cockpit */
.ambient__grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(var(--line) 1px, transparent 1px),
    linear-gradient(90deg, var(--line) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(ellipse 80% 55% at 50% 0%, #000 20%, transparent 75%);
  -webkit-mask-image: radial-gradient(ellipse 80% 55% at 50% 0%, #000 20%, transparent 75%);
  opacity: .5;
}

/* ---------- 2. Apparition en cascade ----------
   [data-stagger] : ses enfants apparaissent l'un après l'autre quand
   le bloc entre à l'écran (classe .is-in posée par js/ui/effects.js).
   Sans JavaScript, la classe fx n'est pas posée et tout reste visible. */
@keyframes rise-in {
  from { opacity: 0; transform: translateY(18px) scale(.985); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: none; }
}
.fx [data-stagger] > * { opacity: 0; }
.fx [data-stagger].is-in > * {
  animation: rise-in .7s var(--ease-out) both;
  animation-delay: calc(var(--n, 0) * 80ms);
}

/* ---------- 3. Bordure lumineuse tournante ---------- */
@property --angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }
.glow-border { position: relative; }
.glow-border::after {
  content: "";
  position: absolute;
  inset: -1px;
  padding: 1px;
  border-radius: inherit;
  background: conic-gradient(from var(--angle), transparent 0 60%, var(--c-ai) 75%, var(--c-signal) 85%, transparent 95%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
  animation: spin-border 5s linear infinite;
  pointer-events: none;
}
@keyframes spin-border { to { --angle: 360deg; } }

/* ---------- 4. Shimmer de chargement ---------- */
.shimmer {
  background: linear-gradient(90deg, var(--bg-elev-2) 0%, var(--line-strong) 50%, var(--bg-elev-2) 100%);
  background-size: 200% 100%;
  animation: shimmer 1.6s linear infinite;
}
@keyframes shimmer { to { background-position: -200% 0; } }

@media (prefers-reduced-motion: reduce) {
  .ambient::before, .ambient::after, .glow-border::after { animation: none; }
  .fx [data-stagger] > * { opacity: 1; }
  .fx [data-stagger].is-in > * { animation: none; }
}
