/* Scroll-reveal — pure CSS state, toggled by a tiny IntersectionObserver.
   Content is ALWAYS revealed (observer + safety net), so nothing can get stuck hidden. */
.js [data-anim]{opacity:0;transform:translateY(16px);transition:opacity .6s var(--ease),transform .6s var(--ease);}
.js [data-anim].is-in{opacity:1;transform:none;}

/* Staggered children for grids */
.js [data-anim="stagger"]>*{opacity:0;transform:translateY(16px);transition:opacity .5s var(--ease),transform .5s var(--ease);}
.js [data-anim="stagger"].is-in>*{opacity:1;transform:none;}
.js [data-anim="stagger"].is-in>*:nth-child(2){transition-delay:.06s;}
.js [data-anim="stagger"].is-in>*:nth-child(3){transition-delay:.12s;}
.js [data-anim="stagger"].is-in>*:nth-child(4){transition-delay:.18s;}
.js [data-anim="stagger"].is-in>*:nth-child(5){transition-delay:.24s;}
.js [data-anim="stagger"].is-in>*:nth-child(6){transition-delay:.30s;}
.js [data-anim="stagger"].is-in>*:nth-child(n+7){transition-delay:.34s;}

/* Respect reduced-motion: never hide, never move. */
@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto;}
  .js [data-anim],
  .js [data-anim].is-in,
  .js [data-anim="stagger"]>*,
  .js [data-anim="stagger"].is-in>*{opacity:1!important;transform:none!important;transition:none!important;}
}
