/* ==========================================================================
   Mishnah — scroll animation utilities
   ==========================================================================

   Add a class, get an entrance. Drop these on anything, in a template or in
   Bricks:

     <div class="m-anim m-anim--up">…</div>
     <div class="m-anim m-anim--blur m-delay-2">…</div>
     <ul class="m-stagger">…</ul>       one wave across the children

   How it works
   ------------
   Everything starts in its "before" state and is released by a single class,
   `is-in`, added by js/mishnah-animate.js when the element scrolls into view.
   The driver is deliberately not part of the contract: the script uses GSAP
   ScrollTrigger when it is loaded and falls back to IntersectionObserver when
   it is not. Either way the classes and the result are the same, so dropping
   GSAP later is a one-line change and nothing here has to be rewritten.

   Unlike styles.css in the mock, these are NOT scoped to .mishnah-ui — the
   point is to be able to put them on Bricks elements too. Every selector is
   `m-` prefixed to stay out of the way.

   Accessibility
   -------------
   Two guards, and both matter:

     - prefers-reduced-motion removes the motion and the blur, and shows
       everything immediately. It does not merely shorten the animation:
       content that only appears after a transition would otherwise never
       appear for that visitor.

     - .m-anim is only hidden once the script has confirmed it is running, by
       putting `m-anim-ready` on <html>. With JS off, broken, or blocked, the
       opening rule never applies and all the content is simply visible.
       Hiding first and revealing later is how these systems lose content.
   ========================================================================== */


/* --------------------------------------------------------------------------
   1. Tunables
   -------------------------------------------------------------------------- */
:root {
  --m-anim-distance: 2.4rem;   /* how far --up / --down / --left / --right travel */
  --m-anim-duration: 0.7s;
  --m-anim-blur: 6px;
  --m-anim-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --m-anim-stagger: 0.08s;     /* gap between children in a .m-stagger group */
}


/* --------------------------------------------------------------------------
   2. Base
   The `html.m-anim-ready` gate is the no-JS safety net described above.
   -------------------------------------------------------------------------- */
.m-anim-ready .m-anim {
  opacity: 0;
  transition:
    opacity var(--m-anim-duration) var(--m-anim-ease),
    transform var(--m-anim-duration) var(--m-anim-ease),
    filter var(--m-anim-duration) var(--m-anim-ease);
  /* Hints the compositor before the transition starts, which is what keeps a
     long staggered list from dropping frames on a phone. Cleared by the
     script once the element has landed, because a permanent will-change on
     hundreds of nodes costs more memory than it saves. */
  will-change: opacity, transform;
}

.m-anim-ready .m-anim.is-in {
  opacity: 1;
  transform: none;
  filter: none;
}

/* Set by the script after the transition ends */
.m-anim.m-anim-done {
  will-change: auto;
}


/* --------------------------------------------------------------------------
   3. Directions
   -------------------------------------------------------------------------- */
.m-anim-ready .m-anim--up    { transform: translateY(var(--m-anim-distance)); }
.m-anim-ready .m-anim--down  { transform: translateY(calc(var(--m-anim-distance) * -1)); }

/* Logical, so they mirror in Hebrew rather than sliding the wrong way */
.m-anim-ready .m-anim--start { transform: translateX(calc(var(--m-anim-distance) * -1)); }
.m-anim-ready .m-anim--end   { transform: translateX(var(--m-anim-distance)); }

.mishnah-rtl .m-anim-ready .m-anim--start,
[dir="rtl"] .m-anim-ready .m-anim--start { transform: translateX(var(--m-anim-distance)); }

.mishnah-rtl .m-anim-ready .m-anim--end,
[dir="rtl"] .m-anim-ready .m-anim--end   { transform: translateX(calc(var(--m-anim-distance) * -1)); }


/* --------------------------------------------------------------------------
   4. Character
   -------------------------------------------------------------------------- */

/* Plain crossfade */
.m-anim-ready .m-anim--fade { transform: none; }

/* Focus-pull. Reads well on a hero or a single card; expensive across a long
   list, so keep it off grids. */
.m-anim-ready .m-anim--blur {
  filter: blur(var(--m-anim-blur));
  transform: translateY(calc(var(--m-anim-distance) * 0.5));
}

/* Settles in from slightly small. Scale, not width/height, so it composites. */
.m-anim-ready .m-anim--scale { transform: scale(0.96); }

.m-anim-ready .m-anim--scale-up {
  transform: scale(0.96) translateY(var(--m-anim-distance));
}

/* A quieter version for dense areas — half the distance, no blur */
.m-anim-ready .m-anim--subtle {
  transform: translateY(calc(var(--m-anim-distance) * 0.4));
}


/* --------------------------------------------------------------------------
   5. Stagger
   Put .m-stagger on the parent; its direct children animate as one wave.
   The parent does not animate itself.

   Twelve steps, then it stops incrementing — past about a dozen the last item
   is waiting so long that the group stops reading as one gesture. Anything
   beyond 12 lands with the 12th.
   -------------------------------------------------------------------------- */
.m-anim-ready .m-stagger > * {
  opacity: 0;
  transform: translateY(var(--m-anim-distance));
  transition:
    opacity var(--m-anim-duration) var(--m-anim-ease),
    transform var(--m-anim-duration) var(--m-anim-ease);
  will-change: opacity, transform;
}

.m-anim-ready .m-stagger.is-in > * {
  opacity: 1;
  transform: none;
}

.m-anim-ready .m-stagger > *:nth-child(1)  { transition-delay: calc(var(--m-anim-stagger) * 0); }
.m-anim-ready .m-stagger > *:nth-child(2)  { transition-delay: calc(var(--m-anim-stagger) * 1); }
.m-anim-ready .m-stagger > *:nth-child(3)  { transition-delay: calc(var(--m-anim-stagger) * 2); }
.m-anim-ready .m-stagger > *:nth-child(4)  { transition-delay: calc(var(--m-anim-stagger) * 3); }
.m-anim-ready .m-stagger > *:nth-child(5)  { transition-delay: calc(var(--m-anim-stagger) * 4); }
.m-anim-ready .m-stagger > *:nth-child(6)  { transition-delay: calc(var(--m-anim-stagger) * 5); }
.m-anim-ready .m-stagger > *:nth-child(7)  { transition-delay: calc(var(--m-anim-stagger) * 6); }
.m-anim-ready .m-stagger > *:nth-child(8)  { transition-delay: calc(var(--m-anim-stagger) * 7); }
.m-anim-ready .m-stagger > *:nth-child(9)  { transition-delay: calc(var(--m-anim-stagger) * 8); }
.m-anim-ready .m-stagger > *:nth-child(10) { transition-delay: calc(var(--m-anim-stagger) * 9); }
.m-anim-ready .m-stagger > *:nth-child(11) { transition-delay: calc(var(--m-anim-stagger) * 10); }
.m-anim-ready .m-stagger > *:nth-child(n+12) { transition-delay: calc(var(--m-anim-stagger) * 11); }

/* Tighter and looser waves */
.m-stagger--fast { --m-anim-stagger: 0.04s; }
.m-stagger--slow { --m-anim-stagger: 0.12s; }


/* --------------------------------------------------------------------------
   6. Delays
   For holding one element back behind another — a subtitle after its
   heading. Not needed inside .m-stagger, which handles its own timing.
   -------------------------------------------------------------------------- */
.m-anim-ready .m-delay-1 { transition-delay: 0.08s; }
.m-anim-ready .m-delay-2 { transition-delay: 0.16s; }
.m-anim-ready .m-delay-3 { transition-delay: 0.24s; }
.m-anim-ready .m-delay-4 { transition-delay: 0.32s; }
.m-anim-ready .m-delay-5 { transition-delay: 0.4s; }
.m-anim-ready .m-delay-6 { transition-delay: 0.5s; }


/* --------------------------------------------------------------------------
   7. Durations
   -------------------------------------------------------------------------- */
.m-anim--fast   { --m-anim-duration: 0.45s; }
.m-anim--slow   { --m-anim-duration: 1s; }

/* Longer travel for a hero; shorter for something small */
.m-anim--far    { --m-anim-distance: 4.8rem; }
.m-anim--near   { --m-anim-distance: 1.2rem; }


/* --------------------------------------------------------------------------
   8. Reduced motion
   Show everything, immediately, with no transform, blur or delay. The
   delays are zeroed explicitly: leaving them would hold content invisible
   for up to half a second for exactly the people least able to tolerate it.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .m-anim-ready .m-anim,
  .m-anim-ready .m-stagger > * {
    opacity: 1 !important;
    transform: none !important;
    filter: none !important;
    transition: none !important;
    transition-delay: 0s !important;
    will-change: auto;
  }
}
