﻿
/* ══════════════════════════════════════════════════════════
   samay-animations.css — Capa de animaciones SAMAY v2.1
   Owner: LUMA VISUAL · S-122 · 2026-06-01
   REGLA: Solo transform + opacity en GPU compositor
   REGLA: prefers-reduced-motion colapsa todo a .01ms
   Fuentes: MDN · css-tricks.com · cruip.com · chrome.dev
   ══════════════════════════════════════════════════════════ */

/* ──────────────────────────────────────────────────────────
   1. SHIMMER EN BARRAS DE PROGRESO
   Tecnica: pseudoelemento con gradiente que traversa la barra
   GPU: Si (transform: translateX)
   Soporte: 99%
   Ref: freefrontend.com/css-progress-bar
   ────────────────────────────────────────────────────────── */
.progress-fill {
  position: relative;
  overflow: hidden;
}
.progress-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255,255,255,.25) 40%,
    rgba(255,255,255,.45) 50%,
    rgba(255,255,255,.25) 60%,
    transparent 100%
  );
  transform: translateX(-100%);
  animation: shimmer-bar 2s ease-in-out infinite;
}
@keyframes shimmer-bar {
  0%   { transform: translateX(-100%); }
  60%  { transform: translateX(100%); }
  100% { transform: translateX(100%); }
}

/* Shimmer en threshold bars (DIAN) */
.threshold-fill {
  position: relative;
  overflow: hidden;
}
.threshold-fill::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(
    90deg,
    transparent 20%,
    rgba(255,255,255,.3) 50%,
    transparent 80%
  );
  transform: translateX(-100%);
  animation: shimmer-bar 2.5s ease-in-out infinite;
  animation-delay: .3s;
}

/* ──────────────────────────────────────────────────────────
   2. STAGGER ENTRY — Cards y KPIs entran escalonados
   Tecnica: CSS custom properties + animation-delay calculado
   GPU: Si (opacity + translateY)
   Soporte: 99%
   Ref: MDN animation-delay
   ────────────────────────────────────────────────────────── */
@keyframes fade-up {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Clase base para stagger — aplicar a contenedor */
.stagger-container > * {
  animation: fade-up 280ms cubic-bezier(.4,0,.2,1) both;
}

/* Delays escalonados para hasta 8 hijos */
.stagger-container > *:nth-child(1) { animation-delay: 40ms;  }
.stagger-container > *:nth-child(2) { animation-delay: 90ms;  }
.stagger-container > *:nth-child(3) { animation-delay: 140ms; }
.stagger-container > *:nth-child(4) { animation-delay: 190ms; }
.stagger-container > *:nth-child(5) { animation-delay: 240ms; }
.stagger-container > *:nth-child(6) { animation-delay: 290ms; }
.stagger-container > *:nth-child(7) { animation-delay: 340ms; }
.stagger-container > *:nth-child(8) { animation-delay: 390ms; }

/* Variante lenta para listas de tabla */
.stagger-slow > * {
  animation: fade-in 200ms ease both;
}
.stagger-slow > *:nth-child(1) { animation-delay: 20ms; }
.stagger-slow > *:nth-child(2) { animation-delay: 50ms; }
.stagger-slow > *:nth-child(3) { animation-delay: 80ms; }
.stagger-slow > *:nth-child(4) { animation-delay: 110ms; }
.stagger-slow > *:nth-child(5) { animation-delay: 140ms; }

/* ──────────────────────────────────────────────────────────
   3. ENTRY ANIMATIONS — Modales, toasts, dropdowns
   Tecnica: @starting-style (86% soporte) + fallback @keyframes
   GPU: Si (opacity + scale + translateY)
   Ref: developer.chrome.com/blog/entry-exit-animations
   ────────────────────────────────────────────────────────── */

/* Modal — ya tiene esto en design-system, mejorado */
@keyframes modal-in-v2 {
  from {
    opacity: 0;
    transform: scale(.96) translateY(10px);
  }
  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

/* Sidebar drawer slide */
@keyframes slide-in-left {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0);     opacity: 1; }
}

/* Toast — slide from right */
@keyframes toast-slide {
  from { opacity: 0; transform: translateX(16px) scale(.97); }
  to   { opacity: 1; transform: translateX(0)    scale(1);   }
}

/* Dropdown menu */
@keyframes dropdown-in {
  from { opacity: 0; transform: translateY(-6px) scale(.97); }
  to   { opacity: 1; transform: translateY(0)    scale(1);   }
}
.dropdown-menu {
  transform-origin: top center;
  animation: dropdown-in 180ms cubic-bezier(.4,0,.2,1) both;
}

/* Page transition — contenido principal */
@keyframes page-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
.page-body {
  animation: page-in 250ms cubic-bezier(.4,0,.2,1) both;
}

/* ──────────────────────────────────────────────────────────
   4. COUNTER ANIMADO — Numeros KPI se cuentan al entrar
   Tecnica: JS IntersectionObserver + CSS @property counter
   El JS esta en samay-animations.js
   GPU: No afecta (solo cambia textContent)
   Ref: css-tricks.com/animating-number-counters
   ────────────────────────────────────────────────────────── */

/* Clase para marcar numeros animables */
.count-up {
  display: inline-block;
  /* El valor se actualiza via JS con ease-out */
}

/* Indicador de "cargando" antes de que el contador inicia */
.count-up[data-counted="false"] {
  opacity: .4;
}
.count-up[data-counted="true"] {
  transition: opacity 200ms ease;
  opacity: 1;
}

/* ──────────────────────────────────────────────────────────
   5. PULSE EN ALERTAS CRITICAS
   Tecnica: box-shadow pulsante + scale
   GPU: Si (box-shadow animado es costoso — alternativa: pseudoelemento)
   Solo usar en badges criticos, NO en listas
   ────────────────────────────────────────────────────────── */
@keyframes pulse-ring {
  0%   { transform: scale(1);    opacity: 1; }
  50%  { transform: scale(1.04); opacity: .8; }
  100% { transform: scale(1);    opacity: 1; }
}

@keyframes pulse-dot {
  0%, 100% { transform: scale(1); }
  50%       { transform: scale(1.15); }
}

/* Badge critico pulsante */
.badge-danger.pulse,
.badge-warning.pulse {
  animation: pulse-ring 2s ease-in-out infinite;
  position: relative;
}

/* Punto de estado en vivo — verde pulsante */
.status-dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  position: relative;
}
.status-dot.online  { background: var(--s-success); }
.status-dot.warning { background: var(--s-warning); }
.status-dot.offline { background: var(--text-dim); }

.status-dot.online::before,
.status-dot.warning::before {
  content: '';
  position: absolute;
  inset: -3px;
  border-radius: 50%;
  border: 1.5px solid currentColor;
  animation: status-ring 2s ease-out infinite;
  opacity: 0;
}
@keyframes status-ring {
  0%   { transform: scale(.6); opacity: .6; }
  70%  { transform: scale(1.8); opacity: 0; }
  100% { transform: scale(1.8); opacity: 0; }
}

/* ──────────────────────────────────────────────────────────
   6. HOVER LIFT EN CARDS — sutil, sin saltar
   Tecnica: transform + box-shadow (shadow en CSS var para perf)
   GPU: Si
   ────────────────────────────────────────────────────────── */
.card-interactive {
  transition:
    transform 180ms cubic-bezier(.4,0,.2,1),
    box-shadow 180ms cubic-bezier(.4,0,.2,1),
    border-color 180ms cubic-bezier(.4,0,.2,1);
  cursor: pointer;
}
.card-interactive:hover {
  transform: translateY(-2px);
  box-shadow: var(--sh-md);
  border-color: var(--border-md);
}
.card-interactive:active {
  transform: translateY(0);
  box-shadow: var(--sh-xs);
}

/* KPI card interactive */
.kpi-card.card-interactive:hover::after {
  opacity: 1;
}

/* ──────────────────────────────────────────────────────────
   7. SKELETON MEJORADO — wave mas suave
   ────────────────────────────────────────────────────────── */
@keyframes skeleton-wave {
  0%   { background-position: 200% center; }
  100% { background-position: -200% center; }
}
.skeleton {
  background: linear-gradient(
    90deg,
    var(--surface)    0%,
    var(--surface-md) 30%,
    var(--surface-hi) 50%,
    var(--surface-md) 70%,
    var(--surface)    100%
  );
  background-size: 200% 100%;
  animation: skeleton-wave 1.6s ease-in-out infinite;
}

/* ──────────────────────────────────────────────────────────
   8. GRADIENT BRAND EN BORDE TOP DE CARDS AL HOVER
   (reemplaza gradient-border @property — mayor soporte)
   Tecnica: pseudoelemento con height transition
   GPU: Si (height cambia — SOLO 2px, costo minimo)
   ────────────────────────────────────────────────────────── */
.card-top-accent {
  position: relative;
  overflow: hidden;
}
.card-top-accent::before {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 0;
  background: var(--grad-brand-h);
  transition: height 200ms cubic-bezier(.4,0,.2,1);
  border-radius: var(--r-md) var(--r-md) 0 0;
}
.card-top-accent:hover::before { height: 2px; }

/* ──────────────────────────────────────────────────────────
   9. LOADING STATE — barra de carga global (top de pagina)
   ────────────────────────────────────────────────────────── */
.page-loader {
  position: fixed;
  top: 0; left: 0; right: 0;
  height: 2px;
  z-index: 9999;
  background: var(--grad-brand-h);
  transform-origin: left;
  animation: page-load 1.2s ease-in-out infinite;
}
@keyframes page-load {
  0%   { transform: scaleX(0);    opacity: 1; }
  70%  { transform: scaleX(.85);  opacity: 1; }
  90%  { transform: scaleX(1);    opacity: 0; }
  100% { transform: scaleX(1);    opacity: 0; }
}

/* ──────────────────────────────────────────────────────────
   10. ACCESIBILIDAD — reducir todo si el usuario lo pide
   CRITICO: nunca omitir esto
   ────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    animation-delay: 0ms !important;
  }
}
