/* ---------- SCROLL REVEAL ----------
   Elements start in a hidden state defined by their data-reveal
   direction, then transition to natural position once scroll-reveal.js
   adds .is-visible (via IntersectionObserver). Images and their
   accompanying text use staggered delays so text settles in just
   after the image, rather than everything popping in at once. */

[data-reveal]{
  opacity:0;
  transition:opacity .9s var(--ease-out), transform .9s var(--ease-out);
  transition-delay:var(--reveal-delay, 0ms);
  will-change:transform, opacity;
}
[data-reveal="up"]{transform:translateY(36px);}
[data-reveal="left"]{transform:translateX(-46px);}
[data-reveal="right"]{transform:translateX(46px);}
[data-reveal="scale"]{transform:scale(.94);}
[data-reveal].is-visible{opacity:1;transform:none;}

@media(prefers-reduced-motion:reduce){
  [data-reveal]{transition:none;opacity:1;transform:none;}
}

/* ---------- PARALLAX ----------
   Applied via inline transform by scroll-reveal.js's parallax pass.
   The CSS just needs to make sure the transform has somewhere calm
   to live (no layout shift, GPU-friendly). */
[data-parallax]{
  will-change:transform;
}
