/* ==================================================================
   ENTRANCE MOTION

   Replaces animate.css + WOW.js.

   The previous setup was structurally unsafe: `.animate__animated`
   carried `animation-fill-mode: both`, so every animated block sat at
   `opacity: 0` until its animation had actually run, and WOW.js added
   `visibility: hidden` on top. Any condition where the animation
   timeline does not advance — a background tab, a full-page screenshot,
   a headless renderer, JS arriving late — left the page looking like a
   column of enormous blank gaps between sections. Motion was deciding
   whether content existed.

   The model here is inverted. Content is visible by default. Motion is
   opt-in and only ever applied when JavaScript has confirmed it is
   both running and appropriate:

     - The gate class `ctech-motion` is set on <html> by an inline
       script in the <head>, before first paint, and only when the
       viewport is desktop-width, the user has not asked for reduced
       motion, and IntersectionObserver exists.
     - That same inline script arms a failsafe timer which removes the
       gate. If reveal.js never loads, or the page is being captured
       rather than viewed, the gate drops and everything is simply
       visible — no transition has to complete for content to appear.
     - No gate means no `opacity: 0` rule matches at all.

   So: JS off, JS delayed, reduced motion, mobile, print, crawler or
   screenshot all get the full page immediately.
   ================================================================== */

/* Base state is deliberately empty: a `.reveal` element with no gate
   applied is a completely ordinary, fully visible element. */

@media (prefers-reduced-motion: no-preference) {

  html.ctech-motion .reveal {
    transition: opacity 620ms var(--ease, ease-out),
                transform 620ms var(--ease, ease-out);
    will-change: opacity, transform;
  }

  /* Pre-entrance state. Small offsets only — the old fadeInLeft moved
     content 100% of its own width, which also caused horizontal
     overflow on wide sections. */
  html.ctech-motion .reveal:not(.is-visible) {
    opacity: 0;
    transform: translate3d(0, 20px, 0);
  }

  html.ctech-motion .reveal--left:not(.is-visible)  { transform: translate3d(-26px, 0, 0); }
  html.ctech-motion .reveal--right:not(.is-visible) { transform: translate3d(26px, 0, 0); }
  html.ctech-motion .reveal--down:not(.is-visible)  { transform: translate3d(0, -16px, 0); }
  html.ctech-motion .reveal--fade:not(.is-visible)  { transform: none; }

  /* Short stagger for grids. Capped low on purpose: a long delay reads
     as the page being slow, not as polish. */
  html.ctech-motion .reveal--d1 { transition-delay: 70ms; }
  html.ctech-motion .reveal--d2 { transition-delay: 140ms; }
  html.ctech-motion .reveal--d3 { transition-delay: 210ms; }

  /* Once revealed, drop the compositing hint. */
  html.ctech-motion .reveal.is-visible { will-change: auto; }
}

/* Printing must never depend on a scroll position having been reached. */
@media print {
  .reveal {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* Legacy class names from the old animate.css are intentionally left
   undefined. Any markup still carrying `animate__animated
   animate__fadeInLeft` now renders as plain, visible content rather
   than an invisible block waiting for a library that is no longer
   loaded. */
