/* SALTA — motion language.
   Deliberately NOT one fade-up everywhere: each variant says something
   different (water rises, speed enters sideways, depth wipes open).
   Everything animates transform/opacity/clip-path only. */

/* Elements start hidden only once JS confirms it can drive them, so a failed
   script never leaves the page blank. */
.js [data-reveal] { opacity: 0; }
.js [data-reveal].is-in { opacity: 1; }

/* 1. rise — the default: content surfacing */
[data-reveal='rise'] {
  translate: 0 clamp(18px, 3vh, 40px);
  transition: opacity var(--dur-slow) var(--ease-out),
              translate var(--dur-slow) var(--ease-out);
}
[data-reveal='rise'].is-in { translate: 0 0; }

/* 2. mask — headline lines slide out from behind their own edge */
.mask { display: block; overflow: hidden; }
.mask > span {
  display: block;
  translate: 0 105%;
  transition: translate var(--dur-slow) var(--ease-out);
}
.js [data-reveal='mask'] { opacity: 1; }
[data-reveal='mask'].is-in .mask > span { translate: 0 0; }
[data-reveal='mask'] .mask:nth-child(2) > span { transition-delay: .09s; }
[data-reveal='mask'] .mask:nth-child(3) > span { transition-delay: .18s; }
[data-reveal='mask'] .mask:nth-child(4) > span { transition-delay: .27s; }

/* 3. drift — speed: enters horizontally */
[data-reveal='drift-left'],
[data-reveal='drift-right'] {
  transition: opacity var(--dur-slow) var(--ease-out),
              translate var(--dur-slow) var(--ease-out);
}
[data-reveal='drift-left']  { translate: clamp(-90px, -8vw, -40px) 0; }
[data-reveal='drift-right'] { translate: clamp(40px, 8vw, 90px) 0; }
[data-reveal='drift-left'].is-in,
[data-reveal='drift-right'].is-in { translate: 0 0; }

/* 4. wipe — depth: photography opens from the waterline down.
   The clip sits on the image, never on the observed element: an element
   clipped to zero height reports an empty intersection rectangle, so a clipped
   frame can never trigger its own reveal. The frame keeps the settle-in
   scale, which does not affect intersection. */
[data-reveal='wipe'] {
  scale: 1.04;
  transition: opacity .5s linear, scale 1.6s var(--ease-out);
}
[data-reveal='wipe'] img {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 1.25s var(--ease-out),
              scale var(--dur-image) var(--ease-out),
              filter var(--dur-image) var(--ease-out);
}
[data-reveal='wipe'].is-in { scale: 1; }
[data-reveal='wipe'].is-in img { clip-path: inset(0 0 0 0); }

/* 5. sink — photography settles down into place */
[data-reveal='sink'] {
  scale: 1.08;
  transition: opacity var(--dur-slow) var(--ease-out), scale 1.4s var(--ease-out);
}
[data-reveal='sink'].is-in { scale: 1; }

/* 6. count — 01/02/03 numbers revealed by their own clipping mask */
[data-reveal='count'] { opacity: 1; }
[data-reveal='count'] .num-mask { display: inline-block; overflow: hidden; vertical-align: bottom; }
[data-reveal='count'] .num-mask > span {
  display: block;
  translate: 0 110%;
  transition: translate .8s var(--ease-out);
}
[data-reveal='count'].is-in .num-mask > span { translate: 0 0; }

/* stagger: children of a revealed group inherit an index-based delay */
[data-stagger] > * { transition-delay: calc(var(--i, 0) * 110ms); }

/* --- reduced motion ---------------------------------------------------
   Everything resolves to its final state instantly; scroll-linked effects
   are switched off in JS as well. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js [data-reveal],
  .js [data-reveal].is-in { opacity: 1; }
  [data-reveal] {
    translate: none !important;
    scale: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  [data-reveal='wipe'] img { clip-path: none !important; transition: none !important; }
  .mask > span,
  [data-reveal='count'] .num-mask > span { translate: none !important; transition: none !important; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}
