/* ============================================================
   VEILBORN — ANIMATION SYSTEM
   Performance-first keyframes and utility classes.
   Only animates transform and opacity.

   Tokens from tokens.css:
     --ease-out: cubic-bezier(.16,1,.3,1)
     --ease-spring: cubic-bezier(.34,1.56,.64,1)
     --c-gold, --c-gold-hi, --c-veil, --c-hp, --c-mp, --c-xp
   ============================================================ */


/* ─────────────────────────────────────────────────────────────
   1. VIEW TRANSITIONS
   Used by app.js: adds 'view-leaving' then 'view-entering'
   on #view-container during AJAX view swaps.
   ───────────────────────────────────────────────────────────── */

@keyframes view-leave {
    from { opacity: 1; transform: translateY(0); }
    to   { opacity: 0; transform: translateY(6px); }
}

@keyframes view-enter {
    from { opacity: 0; transform: translateY(10px); }
    to   { opacity: 1; transform: translateY(0); }
}

@keyframes shell-shimmer {
    100% { transform: translateX(100%); }
}

.view-leaving {
    animation: view-leave 180ms var(--ease-out) both;
    pointer-events: none;
}

.view-entering {
    animation: view-enter 300ms var(--ease-out) both;
}

.view-entering-gsap {
    opacity: 0;
}


/* ─────────────────────────────────────────────────────────────
   2. STAGGER ENTRANCE
   JS sets class 'stagger-child' and --i on each child
   for cascaded fade-up entrance.
   ───────────────────────────────────────────────────────────── */

@keyframes stagger-fade-up {
    from { opacity: 0; transform: translateY(12px); }
    to   { opacity: 1; transform: translateY(0); }
}

.stagger-child {
    opacity: 0;
    animation: stagger-fade-up 300ms var(--ease-out) both;
    animation-delay: calc(var(--i, 0) * 40ms);
}


/* ─────────────────────────────────────────────────────────────
   3. COMBAT ANIMATIONS
   Dice system, hit/heal effects, and entity card reactions.
   ───────────────────────────────────────────────────────────── */

/* ── Dice: roll / land ─────────────────────────────────────── */

@keyframes dice-roll {
    0%   { transform: scale(1) rotate(0deg); opacity: .9; }
    25%  { transform: scale(1.1) rotate(90deg); opacity: 1; }
    50%  { transform: scale(.95) rotate(180deg); opacity: .9; }
    75%  { transform: scale(1.08) rotate(270deg); opacity: 1; }
    100% { transform: scale(1) rotate(360deg); opacity: .9; }
}

@keyframes dice-land {
    0%   { transform: translateY(-12px) scale(1.15); opacity: .8; }
    50%  { transform: translateY(3px) scale(.93); opacity: 1; }
    75%  { transform: translateY(-2px) scale(1.03); opacity: 1; }
    100% { transform: translateY(0) scale(1); opacity: 1; }
}

/* ── Dice: containers and elements ─────────────────────────── */

.dice-pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
    justify-items: center;
    align-items: center;
}

.dice-pair-left {
    justify-self: start;
}

.dice-pair-right {
    justify-self: end;
}

.dice {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: repeat(3, 1fr);
    place-items: center;
    width: 40px;
    height: 40px;
    border: 2px solid rgba(255, 255, 255, .15);
    border-radius: 6px;
    padding: 3px;
    background: rgba(0, 0, 0, .3);
}

.dice .dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: transparent;
}

.dice .dot.filled {
    background: var(--c-gold);
}

.dice.spinning {
    animation: dice-roll .08s linear infinite;
    will-change: transform;
}

.dice.landing {
    animation: dice-land 300ms var(--ease-out) both;
}

/* ── Hit / Damage / Heal effects on entity cards ───────────── */

@keyframes hit-flash {
    0%   { opacity: 1; }
    30%  { opacity: .5; }
    60%  { opacity: 1; }
    100% { opacity: 1; }
}

@keyframes damage-shake {
    0%, 100% { transform: translateX(0); }
    15%      { transform: translateX(-6px); }
    30%      { transform: translateX(6px); }
    50%      { transform: translateX(-4px); }
    70%      { transform: translateX(4px); }
    85%      { transform: translateX(-2px); }
}

@keyframes heal-pulse {
    0%   { transform: scale(1); opacity: 1; }
    40%  { transform: scale(1.03); opacity: .9; }
    100% { transform: scale(1); opacity: 1; }
}


/* ─────────────────────────────────────────────────────────────
   4. BAR ANIMATIONS
   Resource bar (HP, MP, XP) fill transitions and shimmer.
   ───────────────────────────────────────────────────────────── */

@keyframes bar-fill-pulse {
    0%   { opacity: 1; }
    50%  { opacity: .75; }
    100% { opacity: 1; }
}

.hp-fill,
.mp-fill {
    transition: width .5s var(--ease-out);
}

.hp-fill.bar-pulse {
    animation: bar-fill-pulse .6s ease-in-out;
}

.mp-fill.bar-pulse {
    animation: bar-fill-pulse .6s ease-in-out;
}


/* ─────────────────────────────────────────────────────────────
   5. TOAST ANIMATIONS
   Slide-in / slide-out for notification toasts.
   ───────────────────────────────────────────────────────────── */

@keyframes toast-in {
    from { opacity: 0; transform: translateX(40px); }
    to   { opacity: 1; transform: translateX(0); }
}

@keyframes toast-out {
    from { opacity: 1; transform: translateX(0); }
    to   { opacity: 0; transform: translateX(40px); }
}

.toast {
    animation: toast-in 300ms var(--ease-out) both;
}

.toast.removing {
    animation: toast-out 200ms var(--ease-out) both;
    pointer-events: none;
}


/* ─────────────────────────────────────────────────────────────
   6. MODAL ANIMATIONS
   Overlay background + modal content entrance.
   ───────────────────────────────────────────────────────────── */

@keyframes overlay-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes modal-scale-in {
    from { opacity: 0; transform: scale(.95); }
    to   { opacity: 1; transform: scale(1); }
}


/* ─────────────────────────────────────────────────────────────
   7. LOADING
   Spinner for async operations.
   ───────────────────────────────────────────────────────────── */

@keyframes spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

.loading-spinner {
    position: relative;
    width: 32px;
    height: 32px;
}

.loading-spinner::after {
    content: '';
    position: absolute;
    inset: 0;
    border: 3px solid rgba(255, 255, 255, .12);
    border-top-color: var(--c-gold);
    border-radius: 50%;
    animation: spin .8s linear infinite;
    will-change: transform;
}


/* ─────────────────────────────────────────────────────────────
   8. MICRO-INTERACTIONS
   Pulse, float, and shimmer for UI accents.
   ───────────────────────────────────────────────────────────── */

@keyframes pulse-gold {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: .85; transform: scale(1.04); }
}

@keyframes float {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-6px); }
}

@keyframes shimmer {
    from { transform: translateX(-100%); }
    to   { transform: translateX(100%); }
}

/* Wrap continuous animations in motion-safe guard */
@media (prefers-reduced-motion: no-preference) {
    .anim-pulse-gold {
        animation: pulse-gold 2s ease-in-out infinite;
        will-change: transform;
    }

    .anim-float {
        animation: float 3s ease-in-out infinite;
        will-change: transform;
    }

    .anim-shimmer {
        position: relative;
        overflow: hidden;
    }

    .anim-shimmer::after {
        content: '';
        position: absolute;
        inset: 0;
        background: linear-gradient(
            90deg,
            transparent 0%,
            rgba(255, 255, 255, .06) 50%,
            transparent 100%
        );
        animation: shimmer 1.8s linear infinite;
        will-change: transform;
    }
}


/* ─────────────────────────────────────────────────────────────
   9. REDUCED MOTION
   Respects user preference for minimal animation.
   ───────────────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
}
