/* avatar-fx.css - hover effects for avatars (js/avatar-fx.js).
   Classes land on the avatar <img> (or the canvas overlay, when a pixel
   effect rides on a motion); .afx-layer spans sit over the image. */

@property --afx-angle {
    syntax: '<angle>';
    inherits: false;
    initial-value: 0deg;
}

.afx-canvas,
.afx-layer {
    position: absolute;
    pointer-events: none;
    z-index: 3;
}
.afx-canvas { image-rendering: pixelated; }

/* Reduced motion: a still glow, nothing moves. */
.afx-calm { filter: drop-shadow(0 0 3px #55ffff) brightness(1.15); }

/* Hue cycle: stepped, like a palette rotation */
.afx-hue { animation: afx-hue 1.2s steps(8) infinite; }
@keyframes afx-hue {
    from { filter: hue-rotate(0deg) saturate(1.7); }
    to { filter: hue-rotate(360deg) saturate(1.7); }
}

/* Neon frame */
.afx-neon { animation: afx-neon .9s ease-in-out infinite alternate; }
@keyframes afx-neon {
    from { filter: drop-shadow(0 0 1px var(--afx-c, #5ff)) drop-shadow(0 0 3px var(--afx-c, #5ff)) brightness(1.05); }
    to { filter: drop-shadow(0 0 3px var(--afx-c, #5ff)) drop-shadow(0 0 10px var(--afx-c, #5ff)) brightness(1.3); }
}

/* CRT power-on, then the odd flicker (flicker touches filter only, so it
   never fights the power-on transform) */
.afx-crt {
    transform-origin: 50% 50%;
    filter: brightness(5) saturate(0);   /* the power-on flash; flicker takes over at .45s */
    animation: afx-crt-on .45s cubic-bezier(.2, .9, .3, 1) forwards, afx-crt-flicker 2.2s steps(1) .45s infinite;
}
@keyframes afx-crt-on {
    0% { transform: scale(1, .02); }
    40% { transform: scale(1.08, .05); }
    70% { transform: scale(.98, 1.04); }
    100% { transform: scale(1, 1); }
}
@keyframes afx-crt-flicker {
    0%, 100% { filter: none; }
    7% { filter: brightness(1.5) contrast(1.3); }
    8% { filter: none; }
    51% { filter: brightness(.65); }
    52% { filter: none; }
    80% { filter: brightness(1.2) blur(.4px); }
    81% { filter: none; }
}

/* Jelly wobble */
.afx-jelly { animation: afx-jelly .8s ease infinite; }
@keyframes afx-jelly {
    0%, 100% { transform: scale(1, 1); }
    25% { transform: scale(1.15, .85); }
    50% { transform: scale(.88, 1.12); }
    75% { transform: scale(1.05, .95); }
}

/* Coin flip */
.afx-coin { animation: afx-coin 1.1s cubic-bezier(.45, .05, .55, .95) infinite; }
@keyframes afx-coin {
    0% { transform: perspective(200px) rotateY(0); }
    50% { transform: perspective(200px) rotateY(180deg) scale(1.1); filter: brightness(.6); }
    100% { transform: perspective(200px) rotateY(360deg); }
}

/* 3D tilt toward the pointer, with a specular shine layer */
.afx-tilt {
    transform: perspective(220px)
        rotateX(calc((.5 - var(--afx-py, .5)) * 30deg))
        rotateY(calc((var(--afx-px, .5) - .5) * 34deg))
        scale(1.08);
    transition: transform .08s linear;
}
img.afx-tilt,
canvas.afx-tilt {
    filter: drop-shadow(calc((.5 - var(--afx-px, .5)) * 8px) calc((.5 - var(--afx-py, .5)) * 8px + 3px) 3px rgba(0, 0, 0, .7));
}
.afx-l-shine {
    background: radial-gradient(circle at calc(var(--afx-px, .5) * 100%) calc(var(--afx-py, .5) * 100%),
        rgba(255, 255, 255, .55), rgba(255, 255, 255, 0) 55%);
    mix-blend-mode: overlay;
}

/* Holographic foil */
.afx-holo { filter: saturate(1.4) contrast(1.1); }
.afx-l-holo {
    background: conic-gradient(from var(--afx-angle) at calc(var(--afx-px, .5) * 100%) calc(var(--afx-py, .5) * 100%),
        #ff00ff, #00ffff, #ffff00, #00ff66, #ff00ff);
    mix-blend-mode: color-dodge;
    opacity: .55;
    animation: afx-spin 1.6s linear infinite;
}
@keyframes afx-spin { to { --afx-angle: 360deg; } }

/* Scanlines + rolling phosphor band */
.afx-scan { filter: contrast(1.25) brightness(1.15); }
.afx-l-scan {
    background:
        repeating-linear-gradient(to bottom, rgba(0, 0, 0, .55) 0 1px, rgba(0, 0, 0, 0) 1px 3px),
        linear-gradient(to bottom, rgba(120, 255, 200, 0) 0%, rgba(120, 255, 200, .3) 50%, rgba(120, 255, 200, 0) 100%);
    background-size: 100% 3px, 100% 30%;
    background-repeat: repeat, no-repeat;
    animation: afx-scan 1.4s linear infinite;
}
@keyframes afx-scan {
    from { background-position: 0 0, 0 -60%; }
    to { background-position: 0 3px, 0 160%; }
}

/* VHS: skew jitter, noise, tracking band */
.afx-vhs { animation: afx-vhs .5s steps(1) infinite; }
@keyframes afx-vhs {
    0% { transform: none; filter: saturate(1.8) contrast(1.15); }
    20% { transform: translateX(-1px) skewX(4deg); filter: saturate(1.8) contrast(1.15) hue-rotate(-12deg); }
    40% { transform: translateX(2px); }
    60% { transform: skewX(-3deg); filter: saturate(2.2) contrast(1.15); }
    80% { transform: translate(-1px, 1px); }
}
.afx-l-vhs {
    background:
        linear-gradient(to bottom, transparent 0 42%, rgba(255, 255, 255, .45) 47%, rgba(255, 255, 255, .1) 50%, transparent 55%),
        url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='96'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
    background-size: 100% 260%, 96px 96px;
    background-repeat: no-repeat, repeat;
    mix-blend-mode: screen;
    opacity: .4;
    animation: afx-vhs-band 1.3s linear infinite, afx-noise .24s steps(3) infinite;
}
@keyframes afx-vhs-band {
    from { background-position: 0 100%, 0 0; }
    to { background-position: 0 0%, 0 0; }
}
@keyframes afx-noise {
    0% { translate: 0 0; }
    33% { translate: -2px 1px; }
    66% { translate: 1px -1px; }
}

/* Invert strobe */
.afx-strobe { animation: afx-strobe .6s steps(1) infinite; }
@keyframes afx-strobe {
    0% { filter: invert(1); }
    15% { filter: none; }
    30% { filter: invert(1) hue-rotate(90deg); }
    45% { filter: none; }
    70% { filter: invert(1) hue-rotate(200deg); }
    80% { filter: none; }
}

/* Retro lift with stacked hard shadows */
.afx-retro {
    transform: translate(-3px, -3px);
    filter: drop-shadow(1px 1px 0 #ff55ff) drop-shadow(1px 1px 0 #ff55ff) drop-shadow(1px 1px 0 #55ffff) drop-shadow(1px 1px 0 #55ffff) drop-shadow(1px 1px 0 #ffff55);
    animation: afx-retro .25s steps(3) both;
}
@keyframes afx-retro { from { transform: none; filter: none; } }

/* Slice glitch */
.afx-clip { animation: afx-clip .9s steps(1) infinite; }
@keyframes afx-clip {
    0% { clip-path: inset(0 0 0 0); transform: none; filter: none; }
    10% { clip-path: inset(20% 0 55% 0); transform: translateX(-4px); }
    20% { clip-path: inset(60% 0 10% 0); transform: translateX(3px); }
    30% { clip-path: inset(0 0 0 0); transform: none; filter: hue-rotate(90deg); }
    45% { clip-path: inset(40% 0 35% 0); transform: translateX(5px); filter: none; }
    55% { clip-path: inset(0 0 0 0); transform: none; }
    70% { clip-path: inset(5% 0 80% 0); transform: translateX(-2px); }
    80% { clip-path: inset(0 0 0 0); transform: translateX(1px) skewX(8deg); filter: saturate(3); }
    90% { clip-path: inset(0 0 0 0); transform: none; filter: none; }
}

/* Flashlight that follows the pointer */
.afx-spot { filter: brightness(1.25) contrast(1.1); }
.afx-l-spot {
    background: radial-gradient(circle at calc(var(--afx-px, .5) * 100%) calc(var(--afx-py, .5) * 100%),
        rgba(0, 0, 0, 0) 0, rgba(0, 0, 0, 0) 18%, rgba(0, 0, 0, .85) 45%);
}

/* Beat-drop punch */
.afx-punch { animation: afx-punch .55s cubic-bezier(.2, 1.6, .4, 1) infinite; }
@keyframes afx-punch {
    0% { transform: scale(1); }
    12% { transform: scale(1.28) rotate(-4deg); filter: brightness(1.6) contrast(1.3); }
    30% { transform: scale(.96) rotate(2deg); }
    60%, 100% { transform: scale(1) rotate(0); filter: none; }
}
