/* ══════════════════════════════════════════════════════════════════════════
   MOVIMIENTO — «el scroll cuenta una historia»

   Dos motores, en cascada:
   1. IntersectionObserver (app.js) pone [data-reveal-in] → soporte universal.
   2. animation-timeline: view() → scrub real ligado al scroll donde el
      navegador lo soporta, sin una sola línea de JS ni librerías externas.

   Regla: el movimiento SIGNIFICA algo (jerarquía, causa-efecto, continuidad
   espacial). Nada se mueve por decoración. Y todo respeta reduced-motion
   (definido en base.css) mostrando el estado final legible.
   ══════════════════════════════════════════════════════════════════════════ */

/* ═════════════════════════════ 1. REVELADOS ══════════════════════════════ */

/* IMPORTANTE: el estado oculto SOLO existe si el JS está vivo (clase .js, que
   pone el script en línea del <head>). Sin JS —o si app.js falla— nada se
   oculta y la página se lee entera. Una animación jamás puede ser la razón
   por la que un cliente no ve tu oferta. */

.js [data-reveal] {
  opacity: 0;
  transform: translate3d(0, 26px, 0);
  transition:
    opacity var(--d-slow) var(--e-out),
    transform var(--d-slow) var(--e-out),
    filter var(--d-slow) var(--e-out);
  will-change: opacity, transform;
}

.js [data-reveal="izq"]  { transform: translate3d(-34px, 0, 0); }
.js [data-reveal="der"]  { transform: translate3d(34px, 0, 0); }
.js [data-reveal="zoom"] { transform: scale(.94); }
.js [data-reveal="blur"] { filter: blur(10px); transform: translate3d(0, 18px, 0); }

/* En móvil los revelados laterales entran DESDE ABAJO, no de lado.
   No es una preferencia estética: mientras el elemento espera a que el
   IntersectionObserver lo dispare, se queda quieto 34 px fuera de su sitio, y
   en una pantalla de 390 px eso son 34 px de página asomando por el lado. Se
   medía: la calculadora de precios daba 413 px de ancho de documento contra
   390 de pantalla, y la página se movía de lado con el dedo. En un ancho de
   móvil un deslizamiento horizontal tampoco se aprecia — el elemento ocupa
   todo el ancho—, así que no se pierde nada y se gana no romper el eje. */
@media (max-width: 640px) {
  .js [data-reveal="izq"],
  .js [data-reveal="der"] { transform: translate3d(0, 26px, 0); }
}

.js [data-reveal-in] {
  opacity: 1;
  transform: none;
  filter: none;
  will-change: auto;   /* liberar la capa GPU al terminar */
}

/* Escalonado: los hijos entran en cascada, no todos de golpe.
   El retardo lo fija app.js con --i (índice del hijo). */
.js [data-stagger] > * {
  opacity: 0;
  transform: translate3d(0, 22px, 0);
  transition:
    opacity var(--d-slow) var(--e-out),
    transform var(--d-slow) var(--e-out);
  transition-delay: calc(var(--i, 0) * 70ms);
}
.js [data-stagger][data-reveal-in] > * { opacity: 1; transform: none; }

/* ═════════════════════════════ 2. TÍTULOS POR LÍNEA ══════════════════════ */
/* Cada línea del titular sube desde detrás de una máscara. El efecto
   «editorial caro». Las líneas las envuelve app.js. */

.linea-mask { display: block; overflow: hidden; padding-block: 0.04em; }
.js .linea-mask > span {
  display: block;
  transform: translateY(105%);
  transition: transform 900ms var(--e-out);
  transition-delay: calc(var(--i, 0) * 90ms);
}
.js [data-reveal-in] .linea-mask > span { transform: translateY(0); }

/* ═════════════════════════════ 3. SCROLL-DRIVEN (progresivo) ════════════ */
/* Solo donde el navegador soporta timelines de scroll nativos. Si no, la
   página queda perfecta igualmente: esto solo AÑADE. */

@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {

    /* Parallax suave del fondo de las secciones con imagen */
    .parallax-media img {
      animation: parallax-y linear both;
      animation-timeline: view();
      animation-range: entry 0% exit 100%;
    }
    @keyframes parallax-y {
      from { transform: translateY(-6%) scale(1.12); }
      to   { transform: translateY(6%)  scale(1.12); }
    }

    /* Las tarjetas se «asientan»: entran con perspectiva y se enderezan */
    .asienta {
      animation: asentar linear both;
      animation-timeline: view();
      animation-range: entry 5% cover 34%;
    }
    @keyframes asentar {
      from { opacity: 0; transform: perspective(900px) rotateX(9deg) translateY(46px) scale(.96); }
      to   { opacity: 1; transform: perspective(900px) rotateX(0)    translateY(0)    scale(1); }
    }

    /* Barra de progreso de lectura de la página */
    .progreso-lectura {
      animation: progreso linear both;
      animation-timeline: scroll(root block);
    }
    @keyframes progreso { from { transform: scaleX(0); } to { transform: scaleX(1); } }

    /* La sinapsis se dibuja conforme bajas: refuerza «esto es una cadena» */
    .traza-sinapsis {
      animation: dibuja linear both;
      animation-timeline: view();
      animation-range: entry 20% cover 62%;
    }
    @keyframes dibuja { from { stroke-dashoffset: var(--dash, 900); } to { stroke-dashoffset: 0; } }
  }
}

/* Barra de progreso — base (sin scroll-timeline queda invisible, no molesta) */
.progreso-lectura {
  position: fixed;
  top: 0; left: 0;
  z-index: calc(var(--z-nav) + 1);
  width: 100%;
  height: 2px;
  background: var(--grad-brand);
  transform-origin: 0 50%;
  transform: scaleX(0);
  pointer-events: none;
}

/* ═════════════════════════════ 4. PIEZAS VIVAS ══════════════════════════ */

/* Órbita: puntos girando alrededor del núcleo del héroe */
@keyframes orbita { to { transform: rotate(360deg); } }

/* Respiración lenta — «el sistema está vivo pero en calma» */
@keyframes respira {
  0%, 100% { transform: scale(1);    opacity: .85; }
  50%      { transform: scale(1.06); opacity: 1; }
}

/* Barrido de luz sobre una superficie (usado en el panel de demo) */
@keyframes barrido {
  0%   { transform: translateX(-120%) skewX(-16deg); }
  100% { transform: translateX(320%)  skewX(-16deg); }
}

/* Cursor del terminal */
@keyframes cursor { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } }

/* Flotación sutil de tarjetas «suspendidas» */
@keyframes flota {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

/* Indicador de scroll del héroe */
@keyframes baja {
  0%   { transform: translateY(0);    opacity: 0; }
  35%  { opacity: 1; }
  100% { transform: translateY(14px); opacity: 0; }
}

/* ═════════════════════════════ 5. UTILIDADES ════════════════════════════ */
.anim-flota   { animation: flota 7s var(--e-inout) infinite; }
.anim-respira { animation: respira 4.5s var(--e-inout) infinite; }

/* Los elementos que flotan se detienen si el usuario prefiere menos
   movimiento (ya cubierto globalmente, pero se deja explícito por claridad) */
@media (prefers-reduced-motion: reduce) {
  .anim-flota, .anim-respira { animation: none; }
}
