/* Motion. Transform and opacity only; nothing over 300 ms; exits are entrances × 0.8.
 * Reduced motion means reduce, not remove: movement becomes an instant change, and the
 * information still arrives on time. */

/* The mark: its only tricks are breathing and stopping. */
@keyframes mx-breathe {
  0%,
  100% {
    transform: scale(1);
  }
  50% {
    transform: scale(1.22);
  }
}
@keyframes mx-ring {
  0% {
    transform: scale(0.55);
    opacity: 0.55;
  }
  100% {
    transform: scale(1.75);
    opacity: 0;
  }
}
/* Loading is shaped like what's coming, with one slow shimmer. */
@keyframes mx-shimmer {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(100%);
  }
}

/* A message arrives: rises 8 px and fades in. Geometry on the spring, opacity on enter. */
@keyframes mx-rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes mx-fade {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}
@keyframes mx-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}
/* A permission request is allowed to be more insistent: 12 px of travel, then one ring pulse. */
@keyframes mx-rise-12 {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes mx-pulse {
  0% {
    box-shadow: 0 0 0 0 color-mix(in oklch, var(--accent) 45%, transparent);
  }
  100% {
    box-shadow: 0 0 0 10px color-mix(in oklch, var(--accent) 0%, transparent);
  }
}
/* A menu grows from its origin at 96 %; the exit is a fifth faster, no bounce on the way out. */
@keyframes mx-menu-in {
  from {
    opacity: 0;
    transform: scale(0.96);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes mx-menu-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: scale(0.96);
  }
}
/* A confirmation: backdrop and card together. */
@keyframes mx-modal-in {
  from {
    opacity: 0;
    transform: translateY(10px) scale(0.98);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes mx-modal-out {
  from {
    opacity: 1;
    transform: none;
  }
  to {
    opacity: 0;
    transform: translateY(6px) scale(0.985);
  }
}
@keyframes mx-sheet-in {
  from {
    transform: translateY(100%);
  }
  to {
    transform: none;
  }
}
@keyframes mx-sheet-out {
  from {
    transform: none;
  }
  to {
    transform: translateY(100%);
  }
}
@keyframes mx-toast-in {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}
@keyframes mx-spin {
  to {
    transform: rotate(360deg);
  }
}
@keyframes mx-undo-timer {
  from {
    stroke-dashoffset: 0;
  }
  to {
    stroke-dashoffset: 56.5;
  }
}

.enter-rise {
  animation: mx-rise var(--d-message) var(--ease-spring) both;
}
.enter-fade {
  animation: mx-fade var(--d-fade) var(--ease-enter) both;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
    transition-delay: 0ms !important;
  }
  /* The mark stands still rather than breathing. */
  .mark [data-anim] {
    animation: none !important;
  }
}
