/* =========================================================
   ANIMACIONES — reveal al entrar en viewport
   Tipos (atributo data-reveal):
     fade        → opacidad
     up          → opacidad + desplazamiento vertical
     text        → texto que sube desde una máscara (.mask)
     image       → recorte + scale 1.03 → 1
     hero-image  → fundido + scale 1.03 → 1 (portadas)
     line        → sin transición propia (lo maneja el componente)
   El retraso de cada elemento viene de data-d (ms) → --d.
   ========================================================= */
.js [data-reveal] {
  opacity: 0;
  transition:
    opacity var(--dur) var(--ease-out) var(--d, 0ms),
    transform var(--dur) var(--ease-out) var(--d, 0ms),
    clip-path var(--dur-slow) var(--ease-out) var(--d, 0ms);
}

.js [data-reveal="up"] { transform: translate3d(0, 28px, 0); }
.js [data-reveal="text"] { opacity: 1; }
.js [data-reveal="text"] > span {
  display: block;
  transform: translate3d(0, 105%, 0);
  transition: transform 1000ms var(--ease-out) var(--d, 0ms);
}
.js [data-reveal="text"].is-in > span { transform: none; }
.js [data-reveal="image"] { clip-path: inset(7% 0 0 0); }
.js [data-reveal="hero-image"] { transition-duration: 1100ms; }
.js [data-reveal="line"] { opacity: 1; }

.js [data-reveal="image"] .media__frame > img,
.js [data-reveal="hero-image"] .media__frame > img { transform: scale(1.03); }

.js [data-reveal].is-in { opacity: 1; transform: none; clip-path: inset(0 0 0 0); }
.js [data-reveal].is-in .media__frame > img { transform: none; }

.mask { display: block; overflow: hidden; padding-bottom: 0.03em; }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal="text"] > span,
  .js [data-reveal] .media__frame > img {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  .chapter-end__line::after { transform: scaleX(1); transition: none; }
}
