/* BUDGETGRID — motion. Transform/opacity only. */
.rv { opacity: 0; transform: translateY(14px); transition: opacity .6s var(--ease-out), transform .6s var(--ease-out); } .rv.in { opacity: 1; transform: none; } .rv-left { transform: translateX(-18px); } .rv-right { transform: translateX(18px); } .rv-scale { transform: scale(.96); } .rv-left.in, .rv-right.in, .rv-scale.in { transform: none; }
.stagger > * { opacity: 0; transform: translateY(10px); animation: fadeUp .5s var(--ease-out) forwards; } .stagger > *:nth-child(1) { animation-delay: .03s; } .stagger > *:nth-child(2) { animation-delay: .08s; } .stagger > *:nth-child(3) { animation-delay: .13s; } .stagger > *:nth-child(4) { animation-delay: .18s; } .stagger > *:nth-child(5) { animation-delay: .23s; } .stagger > *:nth-child(6) { animation-delay: .28s; } .stagger > *:nth-child(7) { animation-delay: .33s; } .stagger > *:nth-child(8) { animation-delay: .38s; } .stagger > *:nth-child(n+9) { animation-delay: .42s; }
.fade-up { animation: fadeUp .5s var(--ease-out) both; } .pop-in { animation: popIn .35s var(--ease-spring) both; } .slide-in { animation: slideIn .4s var(--ease-out) both; } .fade-in { animation: fadeIn .3s var(--ease-out) both; }
.float { animation: float 5s ease-in-out infinite; } .breathe { animation: breathe 2.4s ease-in-out infinite; } .shimmer { position: relative; overflow: hidden; } .shimmer::after { content: ''; position: absolute; inset: 0; background: linear-gradient(100deg, transparent 30%, rgba(255, 255, 255, .35) 50%, transparent 70%); transform: translateX(-100%); animation: shimmer 2.2s infinite; }
.flash-new { animation: flashNew 1.4s var(--ease-out); } .pulse-once { animation: pulseOnce .7s var(--ease-out); } .tick-in { animation: tickIn .5s var(--ease-spring) both; } .shake { animation: shake .4s var(--ease-out); }
.confetti { position: fixed; width: 8px; height: 12px; border-radius: 2px; pointer-events: none; z-index: 1100; animation: confetti 1s var(--ease-out) forwards; }
.vfade { animation: fadeIn .25s var(--ease-out) both; }
.spin { animation: spin 1s linear infinite; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes popIn { from { opacity: 0; transform: scale(.9); } to { opacity: 1; transform: none; } } @keyframes slideIn { from { opacity: 0; transform: translateX(-14px); } to { opacity: 1; transform: none; } } @keyframes float { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-8px); } } @keyframes breathe { 0%, 100% { transform: scale(1); } 50% { transform: scale(1.03); } } @keyframes shimmer { to { transform: translateX(100%); } } @keyframes flashNew { 0% { background-color: var(--grid-wash); } 100% { background-color: transparent; } } @keyframes pulseOnce { 0% { transform: scale(1); } 40% { transform: scale(1.06); } 100% { transform: scale(1); } } @keyframes tickIn { from { transform: scale(0) rotate(-20deg); opacity: 0; } to { transform: none; opacity: 1; } } @keyframes shake { 0%, 100% { transform: none; } 25% { transform: translateX(-5px); } 75% { transform: translateX(5px); } } @keyframes confetti { to { transform: translate(var(--dx), var(--dy)) rotate(var(--r)); opacity: 0; } } @keyframes ping { 0% { box-shadow: 0 0 0 0 var(--grid-wash); } 70% { box-shadow: 0 0 0 8px transparent; } 100% { box-shadow: 0 0 0 0 transparent; } } @keyframes spin { to { transform: rotate(360deg); } }
@keyframes dash { to { stroke-dashoffset: 0; } } .draw { stroke-dasharray: 1200; stroke-dashoffset: 1200; animation: dash 2.4s var(--ease-out) forwards; }
