/* =====================================================================
   motion.css: small shared motion system for epicte.ch (pairs with assets/js/motion.js)
   ---------------------------------------------------------------------
   Rules this file keeps (please keep them if you extend it):
   - Only opacity and the individual `translate` / `scale` properties are animated, so a
     component's own `transform` (hover lifts, nx.js tilt via `rotate`) still composes on top.
   - Nothing is ever hidden unless <html> has the `m-js` class AND the visitor allows motion.
     motion.js sets `m-js`; pages can also set it inline in <head> to avoid a flash (see motion.js).
   - Everything is inside `prefers-reduced-motion: no-preference`; reduced motion = static page.

   Usage (all attributes are opt-in):
     data-m="up|down|left|right|scale|fade"   reveal once when scrolled into view
     data-m-delay="120"                        extra delay in ms for one element
     data-m-stagger[="70"]                     on a parent: reveal its direct children one by one
                                               (children default to "up"; step in ms, default 70)
     data-m-count                              count up to the number already written in the text
                                               (REAL numbers only; the final text is the HTML text)
     data-m-scroll + class="m-parallax"        scroll-linked drift; --m-shift sets distance (default 40px)
                                               (desktop + fine pointer only; only elements in view are updated)
     data-m-ambient                            on a looping CSS animation: motion.js adds .m-paused while it is
                                              offscreen or the tab is hidden (CSS pauses all its animations)
     class="m-lift"                            hover lift for LINKED cards / chips (pointer devices);
                                              don't lift non-clickable cards, it implies a destination
     class="m-press"                           press feedback for any tappable element
     class="m-spot"                            cursor-following soft light on a LINKED card (pointer devices only;
                                              JS sets --m-x/--m-y; the card needs position:relative)
     class="m-trust"                           inline row of true trust cues with a check mark
   Safety: hidden states apply only under html.m-js + no reduced-motion; motion.js reveals anything in
   view even if IntersectionObserver never fires, and reveals everything at 2.5s if it never reports.
   Don't put data-m on an element that also uses .m-parallax or .nx-reveal (they share properties).
   ===================================================================== */

:root { --m-ease: cubic-bezier(.16, .8, .24, 1); --m-dur: .7s; }

/* Inline trust-cue row (green check = "true / included", the status meaning of --green). */
.m-trust { list-style: none; margin: 18px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 8px 18px; }
.m-trust li { position: relative; padding-left: 20px; font-size: .86rem; line-height: 1.45; color: var(--muted, #929aaa); }
.m-trust li::before { content: ""; position: absolute; left: 2px; top: .34em; width: 10px; height: 5px; border-left: 2px solid var(--green, #3ee3a1); border-bottom: 2px solid var(--green, #3ee3a1); transform: rotate(-45deg); }
.m-trust-center { justify-content: center; }

@media (prefers-reduced-motion: no-preference) {
  /* Reveal: hidden state only while JS is running and the element hasn't come into view. */
  .m-js [data-m]:not(.m-done) {
    transition: opacity var(--m-dur) ease var(--m-delay, 0ms),
                translate var(--m-dur) var(--m-ease) var(--m-delay, 0ms),
                scale var(--m-dur) var(--m-ease) var(--m-delay, 0ms);
  }
  .m-js [data-m]:not(.m-in) { opacity: 0; }
  .m-js [data-m="up"]:not(.m-in) { translate: 0 22px; }
  .m-js [data-m="down"]:not(.m-in) { translate: 0 -14px; }
  .m-js [data-m="left"]:not(.m-in) { translate: -28px 0; }
  .m-js [data-m="right"]:not(.m-in) { translate: 28px 0; }
  .m-js [data-m="scale"]:not(.m-in) { scale: .95; }

  /* Hover / press micro-states. */
  /* :where() = zero specificity, so a component's own `transition` is never clobbered. */
  :where(.m-lift) { transition: translate .25s var(--m-ease), border-color .25s ease, background-color .25s ease; }
  :where(.m-press) { transition: scale .15s ease; }
  /* site.css .button already declares a transition; repeat it here with `scale` added. */
  .button.m-press { transition: transform .25s cubic-bezier(.22,.85,.32,1), box-shadow .25s ease, filter .25s ease, scale .15s ease; }
  .m-press:active { scale: .97; }

  /* Scroll-linked drift (desktop only: small screens keep a still layout). */
  @media (min-width: 900px) and (hover: hover) and (pointer: fine) {
    .m-parallax { translate: 0 calc((.5 - var(--m-p, .5)) * var(--m-shift, 40px)); will-change: translate; }
  }
}
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .m-lift:hover { translate: 0 -3px; }
}
@media (prefers-reduced-motion: no-preference) {
  /* Keyboard users get the same lift as a hover (two rules: an unsupported :has() must not drop the first). */
  .m-lift:focus-visible { translate: 0 -3px; }
  .m-lift:has(:focus-visible) { translate: 0 -3px; }
}

/* Cursor spotlight: a faint purple light under the pointer, fades in on hover (opacity only). */
@media (prefers-reduced-motion: no-preference) and (hover: hover) and (pointer: fine) {
  .m-spot { position: relative; }
  .m-spot::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; z-index: 1;
    background: radial-gradient(420px circle at var(--m-x, 50%) var(--m-y, 0%), rgba(130,87,255,.10), transparent 60%);
    opacity: 0; transition: opacity .35s ease; }
  .m-spot:hover::after { opacity: 1; }
}

/* Ambient loops pause offscreen / in hidden tabs (motion.js toggles .m-paused). */
.m-paused, .m-paused * , .m-paused::before, .m-paused::after { animation-play-state: paused !important; }

/* Never leave anything hidden in print. */
@media print { .m-js [data-m] { opacity: 1 !important; translate: none !important; scale: none !important; } }
