/* ============================================================
   AVANTY — Sistema de diseño
   Animaciones — Fase 1, Archivo 9
   Depende de variables.css, reset.css, components.css y layout.css.

   El bloque de movimiento reducido en reset.css ya fuerza
   animation-duration a 0.01ms con !important sobre *, *::before,
   *::after — eso alcanza para todo lo que este archivo define con
   @keyframes o transition, sin repetir la condición en cada bloque.
   La excepción son los efectos controlados por JavaScript (brillo
   que sigue al cursor y parallax): no son animation ni transition
   de CSS, así que reset.css no los alcanza — animations.js debe
   revisar prefers-reduced-motion antes de activarlos. Lo resuelvo
   ahí cuando entregue ese archivo.
   ============================================================ */

:root {
  --duration-reveal: 700ms;
  --distancia-reveal: 28px;
}

/* ------------------------------------------------------------
   REVELADO AL HACER SCROLL — sección 8, "animaciones de entrada".
   animations.js agrega "is-visible" cuando el elemento entra en
   el viewport (IntersectionObserver).
   ------------------------------------------------------------ */
.reveal {
  opacity: 0;
  transform: translateY(var(--distancia-reveal));
  transition: opacity var(--duration-reveal) var(--easing-standard),
              transform var(--duration-reveal) var(--easing-standard);
}

/* is-visible siempre termina en transform: none sin importar la
   variante (--fade, --izquierda, --derecha) porque .reveal.is-visible
   tiene más especificidad que cualquiera de ellas — no hace falta
   repetir "transform: none" en cada una. */
.reveal.is-visible {
  opacity: 1;
  transform: none;
}

.reveal--fade {
  transform: none;
}

.reveal--izquierda {
  transform: translateX(calc(var(--distancia-reveal) * -1));
}

.reveal--derecha {
  transform: translateX(var(--distancia-reveal));
}

/* Si JavaScript no corre, <html> se queda con la clase "no-js"
   (utilities.js la quita apenas carga) y todo se ve de inmediato,
   sin depender de una clase que nunca va a llegar. */
.no-js .reveal {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Escalonado para grupos de tarjetas — se combina con .reveal en
   cada item de una cuadrícula para que no aparezcan todos a la vez. */
.reveal-delay-1 { transition-delay: 0.1s; }
.reveal-delay-2 { transition-delay: 0.2s; }
.reveal-delay-3 { transition-delay: 0.3s; }
.reveal-delay-4 { transition-delay: 0.4s; }

/* ------------------------------------------------------------
   BRILLOS AMBIENTALES — sección 8: "efectos luminosos azules",
   "destellos dorados discretos", "fondos con movimiento suave".
   Pensados para uno o dos por sección como máximo, detrás del
   contenido, nunca debajo de texto sin contraste suficiente.
   ------------------------------------------------------------ */
@keyframes pulso-azul {
  0%, 100% { opacity: 0.35; transform: scale(1); }
  50%      { opacity: 0.55; transform: scale(1.06); }
}

@keyframes pulso-dorado {
  0%, 100% { opacity: 0.15; }
  50%      { opacity: 0.30; }
}

@keyframes flotar-suave {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-14px); }
}

@keyframes gradiente-en-movimiento {
  0%   { background-position: 0% 50%; }
  50%  { background-position: 100% 50%; }
  100% { background-position: 0% 50%; }
}

.glow-ambiental {
  position: absolute;
  border-radius: var(--radius-full);
  filter: blur(60px);
  pointer-events: none;
}

.glow-ambiental--azul {
  background-color: var(--color-interactivo);
  animation: pulso-azul 6s var(--easing-standard) infinite;
}

.glow-ambiental--dorado {
  background-color: var(--color-acento);
  animation: pulso-dorado 8s var(--easing-standard) infinite;
}

.flotante {
  animation: flotar-suave 5s ease-in-out infinite;
}

/* El gradiente en sí (colores, ángulo) se define en pages.css,
   sección por sección — aquí solo va el movimiento, muy lento
   a propósito (18s por ciclo) para que se sienta "suave". */
.fondo-gradiente-animado {
  background-size: 200% 200%;
  animation: gradiente-en-movimiento 18s ease-in-out infinite;
}

/* ------------------------------------------------------------
   BRILLO QUE SIGUE AL CURSOR — sección 8: "reacciones sutiles al
   cursor en escritorio". animations.js escribe --mouse-x/--mouse-y
   en cada mousemove, solo con mouse real y solo sin movimiento
   reducido. Sin JS esta capa no se mueve — no es necesaria para
   leer nada.
   ------------------------------------------------------------ */
.brillo-cursor {
  position: relative;
  overflow: hidden;
}

.brillo-cursor::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(
    500px circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
    rgba(58, 158, 216, 0.12),
    transparent 60%
  );
  opacity: 0;
  transition: opacity var(--transition-slow) var(--easing-standard);
  pointer-events: none;
}

.brillo-cursor:hover::before {
  opacity: 1;
}

@media (hover: none), (pointer: coarse) {
  .brillo-cursor::before {
    display: none;
  }
}

/* ------------------------------------------------------------
   PARALLAX MUY LIGERO — sección 8. animations.js calcula un valor
   pequeño según el scroll y lo escribe en --parallax-y (en px).
   El multiplicador se mantiene bajo ahí mismo a propósito, para
   que sea "muy ligero" y no un efecto marcado.
   ------------------------------------------------------------ */
.parallax {
  transform: translateY(var(--parallax-y, 0px));
  will-change: transform;
}

/* ------------------------------------------------------------
   APARICIÓN DE CONTENIDO CARGADO —