/* ===========================================================
   Motion — restrained by design. Precision, not decoration.
=========================================================== */

/* ---------------- scroll reveal ---------------- */
/* IMPORTANT: [data-reveal] elements are visible by default. reveal.js is
   responsible for BOTH hiding them (by adding .is-hidden, only once it
   has actually started running) and revealing them (.is-visible) --
   never the other way around. That means if JavaScript never runs at
   all (disabled, blocked, or -- opening this file directly via
   file:// -- an ES module script can't load there due to the browser's
   CORS rules for the "null" origin), content simply stays visible with
   no animation, instead of getting stuck invisible forever. */
[data-reveal]{
  transition: opacity var(--dur-slow) var(--ease-precise),
              transform var(--dur-slow) var(--ease-precise);
}
[data-reveal].is-hidden{
  opacity: 0;
  transform: translateY(14px);
}
[data-reveal].is-visible{
  opacity: 1;
  transform: translateY(0);
}
[data-reveal][data-reveal-delay="1"]{ transition-delay: 120ms; }
[data-reveal][data-reveal-delay="2"]{ transition-delay: 240ms; }

[data-reveal][data-reveal-variant="fade"]{
  transition: opacity 1.1s var(--ease-precise);
}

/* ---------------- header shrink ---------------- */
.site-header{ transition: box-shadow var(--dur-fast) var(--ease-precise); }

/* ===========================================================
   Scroll-motion system (see scripts/motion.js)
   Two restrained, independent behaviours -- both purely transform-based
   (no layout-triggering properties), both skipped entirely under
   prefers-reduced-motion below.

   "settle" -- a ONE-TIME transition, triggered the first time the element
   enters the viewport, then never replayed. The resting state (no
   .motion-pre class) is also the correct no-JS fallback, mirroring the
   [data-reveal] progressive-enhancement pattern above: motion.js adds
   .motion-pre immediately on init (once it knows it's actually running),
   then removes it on first intersection.
=========================================================== */
.partners-atmosphere{
  transition: transform 1.3s var(--ease-precise);
  will-change: transform;
}
.partners-atmosphere.motion-pre{
  /* Paired scale > translate distance so the settle-in never exposes the
     image's edge -- this is the one deliberate exception to "don't
     change photograph crops" the brief allows (crop only widened to
     prevent exposed edges during the animation; at rest it's uncropped). */
  transform: translateY(22px) scale(1.05);
}
/* .consulting-media no longer uses [data-reveal] (its old clip-path
   "mask" reveal permanently broke IntersectionObserver for this element
   pattern in Chromium -- see scripts/motion.js header comment) -- it now
   gets its own complete, self-contained opacity+transform settle,
   mirroring .partners-atmosphere above. */
.consulting-media{
  transition: opacity 1.3s var(--ease-precise), transform 1.3s var(--ease-precise);
  will-change: opacity, transform;
}
.consulting-media.motion-pre{
  opacity: 0;
  transform: scale(1.025) translateX(10px);
}

@media (max-width: 700px){
  .partners-atmosphere.motion-pre{ transform: translateY(12px) scale(1.03); }
  .consulting-media.motion-pre{ transform: scale(1.015) translateX(6px); }
}

/* "drift" -- continuous, scroll-linked parallax applied to the <img>
   only (never the section's text column), via direct style.transform
   writes each animation frame from a damped scroll-position loop. The
   will-change hint below is the only CSS needed; the transform values
   themselves are entirely computed in JS. */
.sourcing-media img,
.bizdev-media img{
  will-change: transform;
}

/* ---------------- reduced motion ---------------- */
@media (prefers-reduced-motion: reduce){
  [data-reveal],
  [data-reveal].is-hidden{
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
  }
  html{ scroll-behavior: auto !important; }

  /* Belt-and-suspenders: scripts/motion.js already checks this same
     query once at init and skips both settle and drift entirely, but
     this guarantees the resting/uncropped state visually regardless of
     script timing. */
  .partners-atmosphere,
  .consulting-media,
  .sourcing-media img,
  .bizdev-media img{
    transform: none !important;
    transition: none !important;
  }
  .consulting-media{
    opacity: 1 !important;
  }
}
