Motion
Animation and transition guidelines that create fluid, purposeful motion. Every animation serves to orient users, provide feedback, or establish spatial relationships.
Transitions
Standard transition applied to most interactive elements: all 0.2s ease. Individual properties may use custom durations for more refined behavior.
| Property | Duration | Easing | Usage |
|---|---|---|---|
background |
0.3s |
ease | Theme switching, hover state backgrounds |
color |
0.3s |
ease | Theme switching, link/text color changes |
transform |
0.2s |
ease | Card hover lift, button press, scale effects |
box-shadow |
0.2s |
ease | Elevation changes on hover, focus rings |
opacity |
0.15s |
ease | Fade in/out, tooltip visibility, drag handles |
border-color |
0.15s |
ease | Input focus states, card hover borders, theme transitions |
/* Standard transition — most interactive elements */
transition: all 0.2s ease;
/* Theme transition — slower for comfortable switch */
transition: background 0.3s ease, color 0.3s ease;
/* Micro-interaction — quick response */
transition: opacity 0.15s ease, border-color 0.15s ease;Animations
Keyframe animations used throughout the design system. Each serves a specific purpose.
Cards and content blocks appear by sliding up 8px with a subtle scale from 0.98. The primary entry animation for dashboard content.
@keyframes glassIn {
from { opacity: 0; transform: translateY(8px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Usage */
animation: glassIn 0.35s ease both;Simple opacity transition from 0 to 1. Used for overlays, tooltips, and supplementary content.
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
animation: fadeIn 0.3s ease both;Status badge dots pulse between scale 1 and 1.3 with opacity changes. Conveys a live, active state.
@keyframes dotPulse {
0%, 100% { transform: scale(1); opacity: 1; }
50% { transform: scale(1.3); opacity: 0.7; }
}
.badge-dot { animation: dotPulse 2s ease-in-out infinite; }Notification bell icon scales up to 1.15 with an expanding box-shadow ring. Draws attention to unread notifications.
@keyframes bellPulse {
0%, 100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(186,26,26,0.5); }
50% { transform: scale(1.15); box-shadow: 0 0 0 6px rgba(186,26,26,0); }
}Loading placeholder that oscillates opacity between 0.6 and 0.3. Used for content skeletons while data loads.
@keyframes skeleton-pulse {
0% { opacity: 0.6; }
50% { opacity: 0.3; }
100% { opacity: 0.6; }
}
.skeleton-line { animation: skeleton-pulse 1.5s ease-in-out infinite; }Toast notifications slide in from the right edge and slide out the same direction when dismissed.
@keyframes toastSlideIn {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}
@keyframes toastSlideOut {
from { opacity: 1; transform: translateX(0); }
to { opacity: 0; transform: translateX(100%); }
}Simple 360-degree rotation for loading spinners. Duration is typically 1s with linear easing.
@keyframes spin {
to { transform: rotate(360deg); }
}
animation: spin 1s linear infinite;Staggered Entry
Cards use incrementing animation-delay values to create a cascading entrance. Each subsequent card appears 30ms after the previous one.
/* Staggered entry — 30ms increment per card */
.card { animation: glassIn 0.35s ease both; }
.card:nth-child(1) { animation-delay: 0.03s; }
.card:nth-child(2) { animation-delay: 0.06s; }
.card:nth-child(3) { animation-delay: 0.09s; }
.card:nth-child(4) { animation-delay: 0.12s; }
/* ... continue incrementing by 0.03s */Hover States
Interactive elements provide visual feedback on hover through transform, shadow, and border changes. Hover over each element below to see the effect.
.card:hover {
transform: translateY(-2px) scale(1.005);
box-shadow: var(--shadow-lg);
}.inline-row:hover {
transform: translateY(-1px);
box-shadow: var(--shadow-md);
border-color: var(--outline-variant);
}.btn-blue:hover {
background: var(--accent-dark);
box-shadow: var(--shadow);
}.widget:hover {
transform: translateY(-1px);
box-shadow: 0 3px 8px rgba(0,0,0,0.12);
}Easing Curves
Two easing functions are used throughout the system. The default ease for most interactions, and a Material Design cubic-bezier for panel transitions.
Used for buttons, cards, badges, toggles, and all standard hover/active states. Equivalent to cubic-bezier(0.25, 0.1, 0.25, 1.0).
Used for sidebar panel slide transitions. Provides a quick start with a gentle deceleration, creating a natural-feeling entrance/exit.
/* Default easing — all interactive elements */
transition: all 0.2s ease;
/* Material decelerate — sidebar panel slide */
.docs-sidebar {
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Linear — continuous animations (spinners) */
animation: spin 1s linear infinite;Reduced Motion
Respect user preferences for reduced motion. When the prefers-reduced-motion media query matches, animations and transitions should be minimized or removed entirely.
@media (prefers-reduced-motion: reduce) {
/* Remove all animations */
*, *::before, *::after {
animation-duration: 0.01s !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01s !important;
}
/* Stop infinite pulsing animations */
.badge-dot { animation: none; }
.skeleton-line { animation: none; opacity: 0.4; }
/* Remove hover transforms */
.card:hover,
.inline-row:hover,
.widget:hover {
transform: none;
}
}