@charset "UTF-8";
/* ==========================================================================
   SUGOM SEGURIDAD LTDA — ANIMACIONES
   --------------------------------------------------------------------------
   Archivo:      assets/css/animaciones.css
   Versión:      1.0
   Depende de:   styles.css (tokens de duración, curvas y color)
   --------------------------------------------------------------------------
   Regla que gobierna todo este archivo: solo se animan «transform» y
   «opacity». Ninguna declaración toca width, height, top, left, margin,
   padding ni box-shadow dentro de un @keyframes, porque esas propiedades
   fuerzan recálculo de diseño en cada fotograma.

   La única excepción deliberada es «background-position» en el degradado del
   esqueleto de carga, que se compone en la GPU y no dispara reflow.

   ÍNDICE
   01. Keyframes ............... catálogo de fotogramas clave
   02. Revelado al desplazar ... clases que activa animaciones.js
   03. Estados animados ........ piezas con movimiento propio
   04. Transición de tema ...... conmutación sin parpadeo
   05. Movimiento reducido ..... neutralización total
   ========================================================================== */


/* ==========================================================================
   01. KEYFRAMES
   ========================================================================== */

/* ----- Aparición ---------------------------------------------------------- */

@keyframes aparecer {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes aparecer-abajo {
  from { opacity: 0; transform: translate3d(0, 24px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes aparecer-arriba {
  from { opacity: 0; transform: translate3d(0, -20px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes aparecer-izquierda {
  from { opacity: 0; transform: translate3d(-28px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes aparecer-derecha {
  from { opacity: 0; transform: translate3d(28px, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

@keyframes aparecer-escala {
  from { opacity: 0; transform: scale3d(.94, .94, 1); }
  to   { opacity: 1; transform: scale3d(1, 1, 1); }
}

/* ----- Rotación y pulso --------------------------------------------------- */

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

/* Punto de estado en vivo: dos anillos que se expanden y desvanecen */
@keyframes pulso-estado {
  0%   { transform: scale(1);    opacity: 1; }
  50%  { transform: scale(1.35); opacity: .55; }
  100% { transform: scale(1);    opacity: 1; }
}

/* Halo expansivo para indicadores de monitoreo activo */
@keyframes onda-expansiva {
  0%   { transform: scale(.6); opacity: .65; }
  80%  { transform: scale(2.4); opacity: 0; }
  100% { transform: scale(2.4); opacity: 0; }
}

/* Latido discreto para llamar la atención sin resultar invasivo */
@keyframes latido {
  0%, 100% { transform: scale(1); }
  45%      { transform: scale(1.06); }
}

/* ----- Movimiento continuo ------------------------------------------------ */

/* La pista de la marquesina se duplica en el marcado; al desplazarla un 50%
   el bucle es perfectamente continuo. */
@keyframes desplazar-marquesina {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }
}

/* Flotación muy leve para las ilustraciones SVG */
@keyframes flotar {
  0%, 100% { transform: translate3d(0, 0, 0); }
  50%      { transform: translate3d(0, -8px, 0); }
}

/* Pulso que recorre las conexiones del diagrama de arquitectura */
@keyframes recorrer-trazo {
  from { stroke-dashoffset: 240; }
  to   { stroke-dashoffset: 0; }
}

/* Barrido de sensor: gira el cono de detección del icono de monitoreo */
@keyframes barrido-sensor {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* ----- Interacción -------------------------------------------------------- */

/* Reflejo que cruza el botón primario al pasar el puntero */
@keyframes barrido-brillo {
  from { transform: translateX(-120%); }
  to   { transform: translateX(120%); }
}

/* Apertura del cuerpo del acordeón */
@keyframes desplegar {
  from { opacity: 0; transform: translate3d(0, -6px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* ----- Notificaciones ----------------------------------------------------- */

@keyframes entrar-notificacion {
  from { opacity: 0; transform: translate3d(0, 14px, 0) scale(.97); }
  to   { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
}

@keyframes salir-notificacion {
  from { opacity: 1; transform: translate3d(0, 0, 0) scale(1); }
  to   { opacity: 0; transform: translate3d(0, 10px, 0) scale(.97); }
}

/* ----- Carga -------------------------------------------------------------- */

/* Único keyframe que anima background-position: se compone en GPU */
@keyframes esqueleto {
  from { background-position: 200% 0; }
  to   { background-position: -200% 0; }
}

/* Sacudida corta para campos con error de validación */
@keyframes sacudir {
  0%, 100%     { transform: translate3d(0, 0, 0); }
  20%, 60%     { transform: translate3d(-5px, 0, 0); }
  40%, 80%     { transform: translate3d(5px, 0, 0); }
}


/* ==========================================================================
   02. REVELADO AL DESPLAZAR
   --------------------------------------------------------------------------
   El módulo animaciones.js marca cada elemento con [data-revelar] y le añade
   [data-visible="true"] cuando entra en el viewport. El estado inicial se
   define aquí para que no haya destello de contenido sin estilo.

   Si JavaScript falla o está deshabilitado, la clase .sin-js del <html> se
   mantiene y todos los elementos quedan visibles: el contenido nunca se
   pierde por depender de una animación.
   ========================================================================== */

[data-revelar] {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition: opacity var(--dur-muy-lenta) var(--ease-salida),
              transform var(--dur-muy-lenta) var(--ease-salida);
}

[data-revelar="izquierda"] { transform: translate3d(-26px, 0, 0); }
[data-revelar="derecha"]   { transform: translate3d(26px, 0, 0); }
[data-revelar="escala"]    { transform: scale3d(.96, .96, 1); }
[data-revelar="fundido"]   { transform: none; }

[data-revelar][data-visible="true"] {
  opacity: 1;
  transform: translate3d(0, 0, 0);
}

[data-revelar="escala"][data-visible="true"] { transform: scale3d(1, 1, 1); }

/* Retardo escalonado dentro de una misma retícula. Se aplica con
   [data-retardo] en el marcado; el escalonado dinámico por índice lo calcula
   animaciones.js sobre la propiedad --retardo. */
[data-revelar][style*="--retardo"] {
  transition-delay: var(--retardo, 0ms);
}

[data-retardo="1"] { transition-delay: 60ms; }
[data-retardo="2"] { transition-delay: 120ms; }
[data-retardo="3"] { transition-delay: 180ms; }
[data-retardo="4"] { transition-delay: 240ms; }
[data-retardo="5"] { transition-delay: 300ms; }
[data-retardo="6"] { transition-delay: 360ms; }

/* Sin JavaScript el contenido se muestra íntegro y sin transición */
.sin-js [data-revelar] {
  opacity: 1;
  transform: none;
  transition: none;
}


/* ==========================================================================
   03. ESTADOS ANIMADOS
   ========================================================================== */

/* ----- Halo de monitoreo en vivo ------------------------------------------ */

.indicador-vivo {
  position: relative;
  display: inline-flex;
  width: 8px;
  height: 8px;
  border-radius: var(--radio-full);
  background-color: var(--exito);
  flex-shrink: 0;
}

.indicador-vivo::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background-color: var(--exito);
  animation: onda-expansiva 2.6s var(--ease-salida) infinite;
}

/* ----- Ilustraciones SVG -------------------------------------------------- */

.svg-flotante {
  animation: flotar 7s var(--ease-entrada-salida) infinite;
  will-change: transform;
}

/* Trazo que recorre las conexiones del diagrama de arquitectura */
.trazo-animado {
  stroke-dasharray: 8 14;
  animation: recorrer-trazo 3.2s linear infinite;
}

.sensor-barrido {
  transform-origin: center;
  animation: barrido-sensor 5s linear infinite;
}

/* ----- Contadores numéricos -----------------------------------------------
   El valor lo interpola animaciones.js con requestAnimationFrame; aquí solo
   se reserva el ancho para que el número al crecer no desplace el diseño.
   ------------------------------------------------------------------------ */

.contador {
  display: inline-block;
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* ----- Error de validación ------------------------------------------------ */

.campo[data-estado="error"][data-sacudir="true"] .campo__control {
  animation: sacudir var(--dur-lenta) var(--ease-entrada-salida);
}

/* ----- Esqueleto de carga ------------------------------------------------- */

.esqueleto {
  border-radius: var(--radio-sm);
  background-image: linear-gradient(
    90deg,
    var(--superficie) 0%,
    var(--superficie-alta) 50%,
    var(--superficie) 100%
  );
  background-size: 200% 100%;
  animation: esqueleto 1.4s ease-in-out infinite;
  color: transparent;
  user-select: none;
  pointer-events: none;
}

/* ----- Entrada de página --------------------------------------------------
   Solo el contenido del hero: el resto entra por el revelado al desplazar.
   ------------------------------------------------------------------------ */

.hero__distintivo { animation: aparecer-abajo var(--dur-muy-lenta) var(--ease-salida) both; }
.hero__titulo     { animation: aparecer-abajo var(--dur-muy-lenta) var(--ease-salida) 80ms both; }
.hero__texto      { animation: aparecer-abajo var(--dur-muy-lenta) var(--ease-salida) 160ms both; }
.hero__acciones   { animation: aparecer-abajo var(--dur-muy-lenta) var(--ease-salida) 240ms both; }
.hero__respaldo   { animation: aparecer-abajo var(--dur-muy-lenta) var(--ease-salida) 320ms both; }
.hero__lienzo     { animation: aparecer 1.6s var(--ease-salida) 200ms both; }

/* ----- Utilidades de animación puntual ------------------------------------ */

.anim-aparecer   { animation: aparecer          var(--dur-lenta)     var(--ease-salida) both; }
.anim-abajo      { animation: aparecer-abajo    var(--dur-muy-lenta) var(--ease-salida) both; }
.anim-arriba     { animation: aparecer-arriba   var(--dur-muy-lenta) var(--ease-salida) both; }
.anim-izquierda  { animation: aparecer-izquierda var(--dur-muy-lenta) var(--ease-salida) both; }
.anim-derecha    { animation: aparecer-derecha  var(--dur-muy-lenta) var(--ease-salida) both; }
.anim-escala     { animation: aparecer-escala   var(--dur-lenta)     var(--ease-salida) both; }
.anim-latido     { animation: latido 2.8s var(--ease-entrada-salida) infinite; }


/* ==========================================================================
   04. TRANSICIÓN DE TEMA
   --------------------------------------------------------------------------
   Al conmutar entre claro y oscuro, main.js añade [data-conmutando] al <html>
   durante 260 ms. La transición se aplica en esa ventana y solo a color y
   fondo, evitando que el resto de propiedades animen de golpe.
   ========================================================================== */

html[data-conmutando] *,
html[data-conmutando] *::before,
html[data-conmutando] *::after {
  transition: background-color var(--dur-media) var(--ease-salida),
              border-color     var(--dur-media) var(--ease-salida),
              color            var(--dur-media) var(--ease-salida),
              fill             var(--dur-media) var(--ease-salida),
              stroke           var(--dur-media) var(--ease-salida) !important;
  transition-delay: 0s !important;
}


/* ==========================================================================
   05. MOVIMIENTO REDUCIDO
   --------------------------------------------------------------------------
   Cuando el sistema declara «prefers-reduced-motion: reduce» se neutraliza
   todo el movimiento del sitio. No se oculta contenido: los elementos que
   dependían de una animación para aparecer quedan visibles de inmediato.

   Este bloque debe ser el último del archivo para ganar por especificidad de
   orden sin recurrir a selectores artificialmente pesados.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {

  /* Anula cualquier animación o transición del documento, incluidas las
     declaradas en styles.css y en estilos en línea. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0s !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }

  html { scroll-behavior: auto; }

  /* El contenido revelado por scroll aparece ya colocado */
  [data-revelar],
  [data-revelar][data-visible="true"] {
    opacity: 1 !important;
    transform: none !important;
  }

  /* Se congela la marquesina en su posición inicial */
  .marquesina__pista {
    animation: none !important;
    transform: none !important;
  }

  /* El desvanecido lateral pierde sentido sin desplazamiento: la lista se
     muestra completa y se permite desplazarla manualmente. */
  .marquesina {
    overflow-x: auto;
    -webkit-mask-image: none;
    mask-image: none;
  }

  .marquesina__pista { width: auto; }

  /* El carrusel deja de deslizar; el cambio de diapositiva es instantáneo.
     El autoplay lo desactiva slider.js consultando la misma media query. */
  .carrusel__pista {
    transition: none !important;
    will-change: auto;
  }

  /* Se detiene todo movimiento decorativo */
  .svg-flotante,
  .trazo-animado,
  .sensor-barrido,
  .indicador-vivo::after,
  .anim-latido,
  .esqueleto {
    animation: none !important;
  }

  /* El esqueleto conserva un fondo plano legible sin destello */
  .esqueleto {
    background-image: none;
    background-color: var(--superficie-alta);
  }

  /* El trazo del diagrama se muestra continuo en lugar de recorrido */
  .trazo-animado { stroke-dasharray: none; }

  /* El barrido del botón primario no se dispara */
  .boton--primario::after { display: none; }

  /* El contenido del hero entra sin desplazamiento */
  .hero__distintivo,
  .hero__titulo,
  .hero__texto,
  .hero__acciones,
  .hero__respaldo,
  .hero__lienzo {
    animation: none !important;
    opacity: 1;
    transform: none;
  }

  /* El disco de carga del botón se sustituye por un pulso de opacidad muy
     lento, que sigue comunicando actividad sin rotación. */
  .boton[data-estado="cargando"]::before {
    animation: none !important;
    border-top-color: currentColor;
    opacity: .55;
  }
}
