/* ============================================================
   Animations — All keyframes and reusable motion
   ============================================================ */

/* The status dots flash by opacity only (the compositor runs it): pulse-working, -waiting and -stuck. There is no expanding ring around any dot (the operator, #5140). */
@keyframes pulse-working { 0%, 100% { opacity: 1; }    50% { opacity: 0.8; } }
@keyframes pulse-waiting { 0%, 100% { opacity: 1; }    50% { opacity: 0.6; } }
@keyframes pulse-stuck   { 0%, 100% { opacity: 1; }    50% { opacity: 0.85; } }


@keyframes pulse {
    0%, 100% { opacity: 0.4; }
    50%      { opacity: 1; }
}

@keyframes slideIn {
    from { transform: translateY(20px); opacity: 0; }
    to   { transform: translateY(0); opacity: 1; }
}

@keyframes fadeOut {
    from { opacity: 1; }
    to   { opacity: 0; }
}

@keyframes spin {
    to { transform: rotate(360deg); }
}

@keyframes task-spin {
    to { transform: rotate(360deg); }
}

/* prefers-reduced-motion (#5140): nothing loops and nothing slides. Every animation runs once and at once, so a spinner is a static ring, a pulsing dot is its resting
   state, the shimmer stops, and a toast appears where it stays; explicit smooth scrolls choose "auto" (motion.js). Written with the universal selector so a new animation is
   covered without a line of its own (the browser check reduced_motion_browser fails when an infinite one is still running). */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        animation-delay: 0s !important;
        scroll-behavior: auto !important;
    }
}
