/* =========================================================
   ANIMATIONS.CSS
   Keyframes and motion utility classes.
   ========================================================= */

/* ---------- Page load ---------- */

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

.generator {
  animation: fadeSlideUp var(--duration-slow) var(--ease-out) both;
}

/* ---------- QR result appearance: fade + scale ---------- */

@keyframes resultAppear {
  0%   { opacity: 0; transform: scale(0.82); }
  60%  { opacity: 1; transform: scale(1.03); }
  100% { opacity: 1; transform: scale(1); }
}

.preview__frame.is-animating-in canvas {
  animation: resultAppear var(--duration-slow) var(--ease-spring) both;
}

/* ---------- Scan line sweep, plays once per generation ---------- */

@keyframes scanSweep {
  0%   { top: 12%; opacity: 0; }
  15%  { opacity: 1; }
  85%  { opacity: 1; }
  100% { top: 88%; opacity: 0; }
}

.preview__scanline.is-scanning {
  animation: scanSweep 900ms var(--ease-in-out) both;
}

/* ---------- Ripple (buttons) ---------- */

@keyframes ripple {
  to { transform: scale(3); opacity: 0; }
}

/* ---------- Toast enter / exit ---------- */

@keyframes toastIn {
  from { opacity: 0; transform: translateY(10px) scale(0.96); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes toastOut {
  from { opacity: 1; transform: translateY(0) scale(1); }
  to   { opacity: 0; transform: translateY(6px) scale(0.96); }
}

.toast {
  animation: toastIn var(--duration-base) var(--ease-spring) both;
}

.toast.is-leaving {
  animation: toastOut var(--duration-fast) var(--ease-in-out) both;
}

/* ---------- Shake, for invalid input ---------- */

@keyframes shake {
  10%, 90% { transform: translateX(-1px); }
  20%, 80% { transform: translateX(2px); }
  30%, 50%, 70% { transform: translateX(-4px); }
  40%, 60% { transform: translateX(4px); }
}

.is-shaking {
  animation: shake 420ms var(--ease-in-out);
}

/* ---------- Loading spinner (Generate button busy state) ---------- */

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

.spinner {
  width: 18px;
  height: 18px;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #FFFFFF;
  border-radius: 50%;
  animation: spin 650ms linear infinite;
}

/* ---------- Segmented control thumb pulse on first paint ---------- */

@keyframes softPulse {
  0%, 100% { box-shadow: var(--shadow-sm); }
  50% { box-shadow: 0 0 0 4px rgba(79, 70, 229, 0.08); }
}

/* ---------- Reduced motion ---------- */

@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;
  }
}
