Section 05 · Foundations

Motion.

Motion exists to clarify cause and effect. Four durations, four easings, that's it. If you need a fifth, you're animating something that should be instant.

Durations

--vp-dur-instant · 80mscolor shifts on hover · selection state
--vp-dur-fast · 150msdefault · hover, focus ring, button press
--vp-dur-base · 240msenter / exit · dropdown · tooltip · toast slide-in
--vp-dur-slow · 400mslarge surfaces · modal open · panel slide
--vp-dur-pulse · 1600mslive indicators only · "server connected"

Easings

--vp-ease-standardcubic-bezier(0.2, 0.8, 0.2, 1) default · enter + exit
--vp-ease-emphasisedcubic-bezier(0.16, 1, 0.3, 1) large enter · modal · drawer
--vp-ease-incubic-bezier(0.5, 0, 0.75, 0) exit · fades only
--vp-ease-outcubic-bezier(0.25, 1, 0.5, 1) enter · used rarely

The pulse

Reserved for genuinely live state. Server connection indicator. Active probe streaming. SSE connection. Never on a "Pro!" badge or a CTA — that's spam.

/* The system pulse · 1600ms loop */
@keyframes vp-pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.4; }
}
.live-dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--vp-color-neon);
  box-shadow: 0 0 8px var(--vp-color-neon-glow);
  animation: vp-pulse var(--vp-dur-pulse) infinite;
}

Where motion is forbidden

prefers-reduced-motion

Respect it without compromise. Pulse stops. Toasts appear without slide. Modals fade only.

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