/* ============================================================
   JigPic Solitaire — animations & transitions
   ============================================================ */

/* Card shake on invalid moves */
@keyframes card-shake {
    0%, 100% { transform: translateX(0); }
    20% { transform: translateX(-6px); }
    40% { transform: translateX(5px); }
    60% { transform: translateX(-4px); }
    80% { transform: translateX(3px); }
}

/* Pulsing glow on a valid drop target */
@keyframes target-pulse {
    0% { box-shadow: 0 0 0 2px var(--green), 0 0 18px rgba(107, 255, 184, 0.35); }
    100% { box-shadow: 0 0 0 3px var(--green), 0 0 30px rgba(107, 255, 184, 0.6); }
}

/* Card lift as it is picked up */
@keyframes drag-lift {
    0% { transform: scale(1) translateZ(0); }
    60% { transform: scale(calc(var(--drag-elevate) * 1.04)) translateZ(40px); }
    100% { transform: scale(var(--drag-elevate)) translateZ(30px); }
}

/* Card landing snap — uses scale property to coexist with inline transform */
@keyframes drop-snap {
    0% { scale: 1.06; opacity: 0.88; }
    55% { scale: 0.98; opacity: 1; }
    100% { scale: 1; opacity: 1; }
}

.card.landing {
    animation: drop-snap 0.32s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

/* Card flipping face-up (used on tableau reveals — avoids rotateY
   to coexist with the inline translateY used by tableau stacking) */
@keyframes card-flip {
    0% { scale: 1 1; opacity: 0.6; }
    40% { scale: 1.08 0.92; opacity: 1; }
    70% { scale: 0.97 1.02; }
    100% { scale: 1 1; opacity: 1; }
}

.card.flip-anim {
    animation: card-flip 0.38s cubic-bezier(0.3, 0.8, 0.4, 1);
}

/* New card appearing during the initial deal / stock draw —
   staggered by the inline --deal-delay var. Uses scale only to
   coexist with the inline translateY used by tableau stacking. */
@keyframes deal-slot {
    0% {
        scale: 0.82;
        opacity: 0.4;
    }
    60% {
        opacity: 1;
        scale: 1.03;
    }
    100% {
        scale: 1;
        opacity: 1;
    }
}

.card.dealing {
    animation: deal-slot 0.34s cubic-bezier(0.2, 0.8, 0.3, 1.1) backwards;
    animation-delay: var(--deal-delay, 0s);
}

/* Generic pop-in for board-wide re-renders */
@keyframes pop-in {
    0% { transform: scale(0.92); opacity: 0.7; }
    100% { transform: scale(1); opacity: 1; }
}

/* Picture piece reveal */
@keyframes piece-reveal {
    0% {
        transform: scale(0.55) rotate(4deg);
        opacity: 0.3;
    }
    60% {
        transform: scale(1.08) rotate(-1deg);
        opacity: 1;
    }
    100% {
        transform: scale(1) rotate(0);
        opacity: 1;
    }
}

.piece.revealed {
    animation: piece-reveal 0.5s cubic-bezier(0.2, 0.9, 0.3, 1.2);
}

/* Particles */
@keyframes particle-fly {
    0% {
        opacity: 1;
        transform: translate(0, 0) scale(1) rotate(0deg);
    }
    100% {
        opacity: 0;
        transform: translate(var(--dx), var(--dy)) scale(0.3) rotate(var(--rot, 360deg));
    }
}

@keyframes confetti-fly {
    0% {
        opacity: 1;
        transform: translate(0, 0) rotate(0deg) scale(1);
    }
    100% {
        opacity: 0.1;
        transform: translate(var(--dx), var(--dy)) rotate(var(--rx, 720deg)) scale(0.85);
    }
}

/* Foundation completion glow */
.found-complete [data-pile] {
    animation: found-pulse 0.8s ease;
}

@keyframes found-pulse {
    0% { box-shadow: 0 0 0 4px var(--gold), 0 0 40px var(--gold); }
    100% { box-shadow: 0 0 0 0 transparent; }
}

/* Combo punch when active */
.combo-stat.active b {
    animation: combo-pop 0.3s ease;
}

@keyframes combo-pop {
    0% { transform: scale(1); }
    50% { transform: scale(1.3); }
    100% { transform: scale(1); }
}

/* Banner pop */
#banner.show {
    animation: banner-pop 0.3s ease;
}

@keyframes banner-pop {
    0% { transform: translate(-50%, -50%) scale(0.7); }
    60% { transform: translate(-50%, -50%) scale(1.06); }
    100% { transform: translate(-50%, -50%) scale(1); }
}

/* ---------------- Settings: no animations ---------------- */
body.no-anim *,
body.no-anim *::before,
body.no-anim *::after {
    animation-duration: 0.001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001s !important;
}

/* ---------------- Reduced motion ---------------- */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.001s !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001s !important;
        scroll-behavior: auto !important;
    }
}