/* ==========================================================================
   reveals.css  —  entrance animation layer (last in the cascade)
   Only opacity + transform are animated, so every reveal composites on the
   GPU and never triggers layout.
   ========================================================================== */

/* Nothing hides until JS confirms it can un-hide it again. */
.js [data-reveal] {
  opacity: 0;
  transition:
    opacity    var(--t-reveal) var(--ease-out),
    transform  var(--t-reveal) var(--ease-out),
    clip-path  var(--t-reveal) var(--ease-out),
    /* A reveal target that is also a hover component — the product cards —
       would otherwise lose its own background transition to this one. */
    background var(--t-base)   var(--ease-out);
  transition-delay: var(--reveal-delay, 0ms);
}

/* ---- Variants ------------------------------------------------------------ */
.js [data-reveal="up"],
.js [data-reveal=""]       { transform: translate3d(0, var(--reveal-shift), 0); }
.js [data-reveal="down"]   { transform: translate3d(0, calc(-1 * var(--reveal-shift)), 0); }
.js [data-reveal="left"]   { transform: translate3d(calc(-1 * var(--reveal-shift)), 0, 0); }
.js [data-reveal="right"]  { transform: translate3d(var(--reveal-shift), 0, 0); }
.js [data-reveal="fade"]   { transform: none; }
.js [data-reveal="scale"]  { transform: scale(0.94); }

/* Images wipe open instead of sliding. */
.js [data-reveal="clip"] {
  transform: none;
  clip-path: inset(0 0 100% 0);
}

/* ---- Revealed ------------------------------------------------------------ */
.js [data-reveal].is-in {
  opacity: 1;
  transform: none;
}

/* Only the wipe un-clips. A clip-path here on every variant would keep
   clipping anything an element paints outside its own box — the hero card's
   corner ears, for one. */
.js [data-reveal="clip"].is-in { clip-path: inset(0 0 0 0); }

/* Cards drive their own hover motion once they are in. The entrance transition
   above would otherwise govern the lift too, at 760ms, which is what makes a
   hover feel slack. Opacity keeps the slower curve; the lift is on `translate`
   so it never contends with the reveal's own transform. */
.js .p-card.is-in,
.js .v-card.is-in,
.js .ind-card.is-in,
.js .industries-list .app-card.is-in {
  transition:
    opacity    var(--t-reveal) var(--ease-out),
    translate  var(--t-base)   var(--ease-out),
    clip-path  var(--t-base)   var(--ease-smooth);
}

/* ---- Hero: runs on load, not on scroll ----------------------------------- */
.js .hero [data-reveal] { transition-duration: var(--t-reveal); }

/* ---- Counter/line accents ------------------------------------------------ */
.js [data-reveal] .eyebrow::before { transform: scaleX(0); }
.js [data-reveal].is-in .eyebrow::before {
  transform: scaleX(1);
  transition: transform var(--t-slow) var(--ease-out) 240ms;
}

/* ==========================================================================
   Reduced motion — no entrance animation, no smooth scroll, no hover travel
   ========================================================================== */
@media (prefers-reduced-motion: reduce) {
  .js [data-reveal],
  .js [data-reveal].is-in {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }

  .js [data-reveal] .eyebrow::before { transform: scaleX(1); }

  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}
