/* =====================================================================
   ANIMATIONS
   All motion uses transform + opacity only (GPU composited) and is fully
   disabled under prefers-reduced-motion.
   ===================================================================== */

/* Page-load fade in */
@keyframes page-in { from { opacity: 0; } to { opacity: 1; } }
body { animation: page-in 400ms var(--ease-out) both; }

/* Scroll reveal (IntersectionObserver adds .is-visible once) */
.reveal { opacity: 0; transform: translateY(24px); transition: opacity 600ms var(--ease-out), transform 600ms var(--ease-out); will-change: opacity, transform; }
.reveal.is-visible { opacity: 1; transform: none; will-change: auto; }
/* Stagger children: parent gets .reveal-stagger, each child .reveal */
.reveal-stagger > .reveal:nth-child(1) { transition-delay: 0ms; }
.reveal-stagger > .reveal:nth-child(2) { transition-delay: 70ms; }
.reveal-stagger > .reveal:nth-child(3) { transition-delay: 140ms; }
.reveal-stagger > .reveal:nth-child(4) { transition-delay: 210ms; }
.reveal-stagger > .reveal:nth-child(5) { transition-delay: 280ms; }
.reveal-stagger > .reveal:nth-child(6) { transition-delay: 350ms; }
.reveal-stagger > .reveal:nth-child(7) { transition-delay: 420ms; }
.reveal-stagger > .reveal:nth-child(8) { transition-delay: 490ms; }
.reveal-stagger > .reveal:nth-child(n+9) { transition-delay: 540ms; }

/* Skeleton shimmer */
@keyframes shimmer { from { transform: translateX(-100%); } to { transform: translateX(100%); } }
.skeleton::after { animation: shimmer 1.4s var(--ease-in-out) infinite; }
@keyframes shimmer-bg { from { background-position: 200% 0; } to { background-position: -200% 0; } }
.img-wrap::before { animation: shimmer-bg 1.6s linear infinite; }
.img-wrap.is-loaded::before, .img-wrap.is-error::before { animation: none; }

/* Button shine sweep */
@keyframes shine { from { transform: translateX(-120%); } to { transform: translateX(120%); } }
.btn--primary:hover::after, .btn--accent:hover::after { animation: shine 700ms var(--ease-out) forwards; }

/* Ripple (JS injects a .ripple span on pointerdown) */
@keyframes ripple { to { transform: scale(4); opacity: 0; } }
.ripple {
  position: absolute; border-radius: 50%; width: 20px; height: 20px; margin: -10px 0 0 -10px;
  background: rgba(255, 255, 255, 0.45); transform: scale(0); pointer-events: none; animation: ripple 600ms var(--ease-out) forwards;
}
.btn--outline .ripple, .btn--ghost .ripple, .btn:not(.btn--primary):not(.btn--accent):not(.btn--danger) .ripple { background: var(--primary-soft); }

/* Spinner */
@keyframes spin { to { transform: rotate(360deg); } }
.spinner { animation: spin 700ms linear infinite; }

/* Wishlist heart pop */
@keyframes heart-pop { 0% { transform: scale(1); } 40% { transform: scale(1.35); } 100% { transform: scale(1); } }
.wishlist-btn.is-popping { animation: heart-pop 400ms var(--ease-spring); }

/* Hero decoration float */
@keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } }
.hero__visual .hero-card:nth-child(1) { animation: float 7s var(--ease-in-out) infinite; }
.hero__visual .hero-card:nth-child(4) { animation: float 8s var(--ease-in-out) infinite 1s; }

/* Row highlight (admin list after save) */
@keyframes row-highlight { 0%, 60% { background-color: var(--primary-soft); } 100% { background-color: transparent; } }
.is-highlighted { animation: row-highlight 2.5s var(--ease-out) forwards; }

/* Toast bounce */
@keyframes toast-in { from { opacity: 0; transform: translateY(16px) scale(0.96); } to { opacity: 1; transform: none; } }

/* Reduced motion: switch everything off */
@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;
  }
  .reveal { opacity: 1; transform: none; }
  .hero__visual .hero-card { animation: none; }
  .btn--primary::after, .btn--accent::after { display: none; }
  .img-wrap img { filter: none; transform: none; }
}
