/* 11-motion.css — lightweight UI motion + a global "reduce motion" kill switch.
 *
 * Loaded LAST so the reduce-motion overrides win the cascade. Everything here
 * animates ONLY `opacity` / `transform`, which the browser composits on the GPU
 * off the main thread — effectively free even on a weak client tablet. We never
 * animate layout/paint properties (width/height/top/left/box-shadow/filter/
 * background) here, and never the hot regions (image canvas, charts, xterm, the
 * 1 Hz status chips).
 *
 * Two ways motion gets disabled:
 *   1. The OS "reduce motion" accessibility setting (prefers-reduced-motion).
 *   2. The in-app Settings → Appearance toggle, which stamps
 *      <html data-reduce-motion> (also pre-stamped by the head IIFE before first
 *      paint, so there is no flash on a device that has it off).
 */

/* ---- Main panel fade-in on tab change -------------------------------------
 * The tab panels toggle via Alpine x-show (display:none <-> block). A CSS
 * animation re-runs every time the element returns to a rendered display value,
 * so simply attaching it to .tab-panel gives a fade-in each time that tab is
 * shown — no per-panel markup, no JS. Opacity only (NOT transform): a
 * transformed ancestor becomes the containing block for any position:fixed
 * descendant, which would briefly mis-place fixed children during the animation.
 */
@keyframes panel-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.tab-panel {
    animation: panel-fade-in 160ms ease-out;
}

/* ---- Reusable GPU-only utilities (opt-in via class) ----------------------- */
@keyframes anim-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
@keyframes anim-pop-in {
    from { opacity: 0; transform: translateY(12px) scale(0.94); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}
.anim-fade { animation: anim-fade-in 160ms ease-out; }
.anim-pop  { animation: anim-pop-in 240ms cubic-bezier(0.16, 1, 0.3, 1); }

/* ---- Modals: backdrop fades, frame pops ------------------------------------
 * Two cases:
 *   1. Backdrops that carry x-show get an Alpine `x-transition.opacity` in the
 *      markup, so they fade BOTH in and out (the close reverse the user asked
 *      for). We must NOT also CSS-animate those on enter or the two opacity
 *      mechanisms fight — so they are absent from the list below.
 *   2. The FRAME inside each backdrop has no x-show of its own, so it can't use
 *      x-transition; it keeps a CSS pop on open (re-runs each time the backdrop
 *      returns to a rendered display) and simply fades out with its parent
 *      backdrop on close.
 * Modals whose backdrop is NOT x-show (nested under an x-show wrapper) keep a
 * pure-CSS enter fade here.
 */
.editor-export-modal,
.files-editor-modal-backdrop {
    animation: anim-fade-in 200ms ease-out;
}
.siril-modal-frame,
.location-setup-frame,
.files-editor-modal-panel,
.files-text-modal-inner,
.editor-export-frame,
.auth-modal,
.cert-modal,
.mosaic-modal .mosaic-frame {
    animation: anim-pop-in 240ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* ---- Reduce-motion kill switch -------------------------------------------
 * Collapse all animations/transitions to ~instant rather than `none` so any JS
 * relying on transitionend/animationend still fires. Covers both the OS setting
 * and the in-app toggle. Infinite loops (spinners, pulses) drop to a single
 * iteration so they stop churning the GPU / draining battery on weak clients.
 */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}
html[data-reduce-motion] *,
html[data-reduce-motion] *::before,
html[data-reduce-motion] *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
}
