2026-05-14 19:41:12 +10:00
|
|
|
import { keyframes, style } from '@vanilla-extract/css';
|
|
|
|
|
import { color, toRem } from 'folds';
|
|
|
|
|
|
2026-05-23 23:52:58 -04:00
|
|
|
const spin = keyframes({
|
|
|
|
|
from: { transform: 'rotate(0deg)' },
|
|
|
|
|
to: { transform: 'rotate(360deg)' },
|
|
|
|
|
});
|
|
|
|
|
|
2026-05-14 19:41:12 +10:00
|
|
|
const wobble = keyframes({
|
|
|
|
|
'0%': {
|
|
|
|
|
transform: 'translateX(0) rotateZ(0deg)',
|
|
|
|
|
},
|
|
|
|
|
'20%': {
|
|
|
|
|
transform: `translateX(-${toRem(4)}) rotateZ(-4deg)`,
|
|
|
|
|
},
|
|
|
|
|
'40%': {
|
|
|
|
|
transform: `translateX(${toRem(4)}) rotateZ(4deg)`,
|
|
|
|
|
},
|
|
|
|
|
'60%': {
|
|
|
|
|
transform: `translateX(-${toRem(3)}) rotateZ(-3deg)`,
|
|
|
|
|
},
|
|
|
|
|
'80%': {
|
|
|
|
|
transform: `translateX(${toRem(3)}) rotateZ(3deg)`,
|
|
|
|
|
},
|
|
|
|
|
'100%': {
|
|
|
|
|
transform: 'translateX(0) rotateZ(0deg)',
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const glowPulse = keyframes({
|
|
|
|
|
'0%': {
|
|
|
|
|
boxShadow: `0 0 0 ${toRem(0)} ${color.Success.ContainerActive}`,
|
|
|
|
|
},
|
|
|
|
|
'100%': {
|
|
|
|
|
boxShadow: `0 0 0 ${toRem(8)} ${color.Success.ContainerActive}`,
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const WobbleAnimation = style({
|
|
|
|
|
animation: `${wobble} 2000ms ease-in-out`,
|
|
|
|
|
animationIterationCount: 'infinite',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const GlowAnimation = style({
|
|
|
|
|
animation: `${glowPulse} 2000ms ease-out`,
|
|
|
|
|
animationIterationCount: 'infinite',
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const CallAvatarAnimation = style({
|
|
|
|
|
animation: `${wobble} 2000ms ease-in-out, ${glowPulse} 2000ms ease-out`,
|
|
|
|
|
animationIterationCount: 'infinite',
|
|
|
|
|
});
|
2026-05-23 23:52:58 -04:00
|
|
|
|
|
|
|
|
export const SendingSpinClass = style({
|
|
|
|
|
display: 'inline-block',
|
|
|
|
|
animation: `${spin} 900ms linear infinite`,
|
|
|
|
|
transformOrigin: 'center',
|
|
|
|
|
});
|
2026-06-04 15:51:18 -04:00
|
|
|
|
|
|
|
|
const msgAppearKeyframe = keyframes({
|
|
|
|
|
from: { opacity: 0.4, transform: 'scale(0.97)' },
|
|
|
|
|
to: { opacity: 1, transform: 'scale(1)' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
export const MsgAppearClass = style({
|
|
|
|
|
'@media': {
|
|
|
|
|
'(prefers-reduced-motion: no-preference)': {
|
|
|
|
|
animation: `${msgAppearKeyframe} 150ms ease-out both`,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
});
|
2026-06-05 11:46:16 -04:00
|
|
|
|
|
|
|
|
// Animated chat background keyframes
|
|
|
|
|
|
|
|
|
|
// Animated chat background keyframes
|
|
|
|
|
|
|
|
|
|
/** Matrix rain — two stripe layers scroll at different speeds for parallax depth */
|
|
|
|
|
export const animRainKeyframe = keyframes({
|
|
|
|
|
from: { backgroundPosition: '0 0, 0 0' },
|
|
|
|
|
to: { backgroundPosition: '0 200px, 0 100px' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Drifting stars — three layers drift diagonally */
|
|
|
|
|
export const animStarsDriftKeyframe = keyframes({
|
|
|
|
|
from: { backgroundPosition: '0 0, 65px 32px, 32px 97px' },
|
|
|
|
|
to: { backgroundPosition: '130px 130px, 195px 162px, 162px 227px' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Grid pulse — expands/contracts backgroundSize slightly */
|
|
|
|
|
export const animGridPulseKeyframe = keyframes({
|
|
|
|
|
'0%': { backgroundSize: '60px 60px, 60px 60px, 12px 12px, 12px 12px' },
|
|
|
|
|
'50%': { backgroundSize: '66px 66px, 66px 66px, 13px 13px, 13px 13px' },
|
|
|
|
|
'100%': { backgroundSize: '60px 60px, 60px 60px, 12px 12px, 12px 12px' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Aurora — sweeps backgroundPosition in large cycle */
|
|
|
|
|
export const animAuroraKeyframe = keyframes({
|
|
|
|
|
'0%': { backgroundPosition: '0% 0%' },
|
|
|
|
|
'50%': { backgroundPosition: '-50% -25%' },
|
|
|
|
|
'100%': { backgroundPosition: '0% 0%' },
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
/** Fireflies — three layers of glowing dots drift diagonally */
|
|
|
|
|
export const animFirefliesKeyframe = keyframes({
|
|
|
|
|
from: { backgroundPosition: '0 0, 120px 80px, 60px 140px' },
|
|
|
|
|
to: { backgroundPosition: '200px 150px, 320px 230px, 260px 290px' },
|
|
|
|
|
});
|