/* ==========================================================================
   Motion — scroll reveals, mask reveals, reduced-motion contract
   Elements opt in with [data-reveal]; JS adds .is-in when they enter view.
   ========================================================================== */

[data-reveal] {
  opacity: 0;
  transform: translate3d(0, 28px, 0);
  transition:
    opacity var(--dur-slow) var(--ease-soft),
    transform var(--dur-slow) var(--ease-soft),
    translate var(--dur-mid) var(--ease-out),
    box-shadow var(--dur-mid) var(--ease-out);
  transition-delay: var(--delay, 0ms);
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* Image mask reveal — a curtain in the section's own colour slides up and the
   picture settles back to 1:1. The curtain (rather than clip-path on the target)
   keeps the element's intersection rect non-empty, so the observer still fires. */
[data-reveal="mask"] {
  opacity: 1;
  transform: none;
}
[data-reveal="mask"]::after {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: 3;
  background: var(--mask-color, var(--ivory));
  transform: translate3d(0, 0, 0);
  transition: transform 1.15s var(--ease-soft);
  transition-delay: var(--delay, 0ms);
}
[data-reveal="mask"] img {
  transform: scale(1.16);
  transition: transform 1.7s var(--ease-soft);
  transition-delay: var(--delay, 0ms);
}
[data-reveal="mask"].is-in::after { transform: translate3d(0, -101%, 0); }
[data-reveal="mask"].is-in img { transform: scale(1); }

/* line-by-line type reveal — the container itself does not move */
[data-reveal="lines"] { opacity: 1; transform: none; }

/* line-by-line type reveal */
.reveal-line {
  display: block;
  overflow: hidden;
}
.reveal-line > span {
  display: block;
  transform: translate3d(0, 105%, 0);
  transition: transform 1.05s var(--ease-soft);
  transition-delay: var(--delay, 0ms);
}
.is-in .reveal-line > span,
.reveal-line.is-in > span { transform: none; }

/* hairline that draws itself in */
[data-reveal="rule"] {
  opacity: 1;
  transform: none;
  transform-origin: left center;
  scale: 0 1;
  transition: scale 1.1s var(--ease-soft);
  transition-delay: var(--delay, 0ms);
}
[data-reveal="rule"].is-in { scale: 1 1; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
  [data-reveal="mask"]::after { display: none; }
  .lift:hover, .lift:focus-visible { translate: none !important; }
  [data-reveal],
  [data-reveal="mask"],
  [data-reveal="rule"] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    scale: none !important;
  }
  .reveal-line > span { transform: none !important; }
}
