Design System
The complete CSS foundation powering Vayu UI — tokens, semantics, and keyframes in a single stylesheet.
Overview
This is the complete CSS source that powers every Vayu UI component. It defines color tokens, semantic layers, radius / shadow / blur scales, typography, transitions, animations, and keyframes — all in one place.
Design Tokens
Browse the individual pages for usage guidance, or reference the raw CSS below.
global.css
@import 'tailwindcss';
@import './animations.css';
@custom-variant dark (&:where(.dark, .dark *));
:root {
--canvas: #f4f4f5; /* Neutral light gray to make the white surfaces pop */
--canvas-content: #09090b; /* Near-black text for maximum readability */
--surface: #fff; /* Pure white */
--surface-content: #09090b;
--sidebar: #fafafa; /* Just barely off-white */
--sidebar-content: #18181b;
--elevated: #fff; /* Pure white (relies on shadow for depth) */
--elevated-content: #09090b;
--brand: #84cc16; /* Bright, electric lime */
--brand-content: #052e16; /* Very dark green text for WCAG compliance on the bright button */
--success: #10b981;
--success-content: #fff;
--warning: #f59e0b;
--warning-content: #fff;
--destructive: #ef4444;
--destructive-content: #fff;
--info: #0ea5e9;
--info-content: #fff;
--muted: #e4e4e7; /* Neutral gray for disabled states */
--border: #d4d4d8; /* Neutral gray border */
--field: #a1a1aa;
--focus: #84cc16;
--shadow: #000;
}
:root.dark {
--canvas: #000; /* Pure OLED black */
--canvas-content: #fafafa; /* Crisp white text */
--surface: #0a0a0a; /* Just one step above pure black */
--surface-content: #fff;
--sidebar: #121212; /* Standard dark mode navigation gray */
--sidebar-content: #e4e4e7;
--elevated: #1a1a1a; /* Lightest gray for dropdowns/modals */
--elevated-content: #fff;
--brand: #bef264; /* Ultra-bright neon lime */
--brand-content: #000; /* Pure black text for aggressive, sharp contrast */
--success: #34d399;
--success-content: #000;
--warning: #facc15;
--warning-content: #000;
--destructive: #f87171;
--destructive-content: #000;
--info: #38bdf8;
--info-content: #000;
--muted: #27272a; /* Deep, dark gray */
--muted-content: #a1a1aa;
--border: #27272a; /* Barely visible borders to separate dark areas */
--field: #3f3f46;
--focus: #bef264;
--shadow: #fff;
}
@theme {
/* --- Base Layers --- */
--color-canvas: var(--canvas);
--color-canvas-content: var(--canvas-content);
--color-surface: var(--surface);
--color-surface-content: var(--surface-content);
--color-sidebar: var(--sidebar);
--color-sidebar-content: var(--sidebar-content);
--color-elevated: var(--elevated);
--color-elevated-content: var(--elevated-content);
/* ── Semantic Colors ── */
--color-brand: var(--brand);
--color-brand-content: var(--brand-content);
--color-success: var(--success);
--color-success-content: var(--success-content);
--color-warning: var(--warning);
--color-warning-content: var(--warning-content);
--color-destructive: var(--destructive);
--color-destructive-content: var(--destructive-content);
--color-info: var(--info);
--color-info-content: var(--info-content);
--color-muted: var(--muted);
--color-muted-content: var(--muted-content);
/* ── Structural ── */
--color-border: var(--border);
--color-field: var(--field);
--color-focus: var(--focus);
/* base radius */
--radius: 6px;
/* scale */
--radius-sm: calc(var(--radius) - 2px);
--radius-md: var(--radius);
--radius-lg: calc(var(--radius) + 2px);
/* semantic (minimal & stable) */
--radius-control: var(--radius-sm); /* inputs, buttons */
--radius-surface: var(--radius-md); /* cards, containers */
--radius-overlay: var(--radius-lg); /* modals, popovers */
--radius-full: 9999px;
/* base shadow */
--shadow-color: var(--shadow);
/* base scale (hidden/internal) */
--shadow-sm: 0 1px 2px rgb(var(--shadow-color) / 0.05);
--shadow-md: 0 4px 6px -1px rgb(var(--shadow-color) / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(var(--shadow-color) / 0.1);
/* semantic (like radius) */
--shadow-control: var(--shadow-sm); /* buttons, inputs Interactive UI */
--shadow-surface: var(
--shadow-sm
); /* Use: Cards, List items, Table rows. Subtle lift to separate from canvas. */
--shadow-elevated: var(
--shadow-md
); /* Use: Modals, Popovers, Dropdowns. Strong depth to imply floating above UI. */
--shadow-focus: var(
--shadow-lg
); /* Use: Keyboard focus rings. Can be combined with --brand color if needed. */
--shadow-inner: inset 0 2px 4px rgb(var(--shadow-color) / 0.1); /* Use: Pressed buttons, Active inputs (sunken effect). */
--drop-shadow-subtle: 0 1px 2px rgb(0 0 0 / 0.12); /* subtle - icons - illustration */
--drop-shadow-elevated: 0 4px 6px rgb(0 0 0 / 0.18); /* elevated -floating icons, illustrations */
/* base text shadow */
--text-shadow: 0px 1px 2px rgb(0 0 0 / 0.2);
/* scale */
--text-shadow-sm: 0px 1px 1px rgb(0 0 0 / 0.15);
--text-shadow-md: var(--text-shadow);
--text-shadow-lg: 0px 2px 4px rgb(0 0 0 / 0.25);
/* semantic (minimal & stable) */
--text-shadow-subtle: var(--text-shadow-sm); /* small labels */
--text-shadow-surface: var(--text-shadow-md); /* headings */
--text-shadow-overlay: var(--text-shadow-lg); /* hero text on images */
/* base blur */
--blur: 12px;
/* scale */
--blur-sm: calc(var(--blur) - 4px);
--blur-md: var(--blur);
--blur-lg: calc(var(--blur) + 8px);
/* semantic (minimal & stable) */
--blur-control: var(--blur-sm); /* subtle UI, bg on hover effects (use sparingly) */
--blur-surface: var(--blur-md); /* cards, glass UI */
--blur-overlay: var(--blur-lg); /* modals, heavy backdrop */
/* fonts */
--font-primary: 'Oswald', sans-serif; /* Headings */
--font-secondary: 'Mulish', sans-serif; /* UI Body */
--font-tertiary: 'Geist Mono', monospace; /* Code */
--font-size: 1rem; /* base = 16px */
/* scale */
--text-xs: calc(var(--font-size) * 0.75); /* 12px */
--text-sm: calc(var(--font-size) * 0.875); /* 14px */
--text-md: var(--font-size); /* 16px */
--text-lg: calc(var(--font-size) * 1.125); /* 18px */
--text-xl: calc(var(--font-size) * 1.25); /* 20px */
--text-2xl: calc(var(--font-size) * 1.5); /* 24px */
--text-3xl: calc(var(--font-size) * 1.875); /* 30px */
/* semantic */
--text-h1: var(--text-3xl); /* Use: Hero headings, Page titles. Maximum visual weight. */
--text-h2: var(--text-2xl); /* Use: Section headings. Strong hierarchy. */
--text-h3: var(--text-xl); /* Use: Card headings, Subsection titles. */
--text-h4: var(--text-lg); /* Use: Form field labels, Important inline text. */
--text-h5: var(--text-md); /* Use: Navigation links, Button text. */
--text-h6: var(--text-sm); /* Use: Secondary labels, Captions. */
--text-para: var(--text-sm); /* Use: Body copy, Paragraphs. */
--transition-fast: 150ms ease-in-out;
--transition-medium: 300ms ease-in-out;
--transition-slow: 500ms ease-in-out;
/* Animations */
--animate-marquee-scroll: marquee-scroll linear infinite;
--animate-marquee-ping-pong: marquee-ping-pong linear infinite alternate;
--animate-fade-in: fade-in 1s ease-out;
--animate-float: float 6s ease-in-out infinite;
--animate-float-particle: float-particle 15s linear infinite;
--animate-morph-blob: morph-blob 20s ease-in-out infinite;
--animate-orbit: orbit 20s linear infinite;
--animate-slide-in-left: slide-in-left 1s both;
--animate-slide-in-right: slide-in-right 1s both;
--animate-slide-in-up: slide-in-up 1s both;
--animate-slide-in-down: slide-in-down 1s both;
--animate-bounce-in: bounce-in 1s ease;
--animate-bounce-in-small: bounce-in-small 1s ease;
--animate-bounce-in-large: bounce-in-large 1s ease;
--animate-flip-in-x: flip-in-x 1s ease-in;
--animate-flip-in-y: flip-in-y 1s ease-in;
--animate-rotate-in: rotate-in 1s ease-out;
--animate-zoom-in: zoom-in 1s ease-out;
--animate-zoom-in-small: zoom-in-small 1s ease-out;
--animate-zoom-in-large: zoom-in-large 1s ease-out;
--animate-roll-in: roll-in 1s ease-out;
--animate-roll-in-right: roll-in-right 1s ease-out;
--animate-roll-in-up: roll-in-up 1s ease-out;
--animate-roll-in-down: roll-in-down 1s ease-out;
--animate-jack-in-the-box: jack-in-the-box 1s ease-out;
--animate-hinge: hinge 2s ease-in-out;
--animate-spin-slow: spin-slow 60s linear infinite;
--animate-reverse-spin: reverse-spin 40s linear infinite;
--animate-toast-enter: toast-enter 300ms cubic-bezier(0.22, 1, 0.36, 1) both;
--animate-toast-exit: toast-exit 300ms ease-in both;
}
@media (prefers-reduced-motion: reduce) {
* {
animation: none !important;
}
}animations.css
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes marquee-scroll {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-50%);
}
}
@keyframes marquee-ping-pong {
0% {
transform: translateX(0%);
}
100% {
transform: translateX(-50%);
}
}
@keyframes float {
0%,
100% {
transform: translateY(0);
}
50% {
transform: translateY(-20px);
}
}
@keyframes float-particle {
0% {
opacity: 0;
}
10%,
90% {
opacity: 1;
}
100% {
opacity: 0;
transform: translateY(-100vh) translateX(20px);
}
}
@keyframes orbit {
from {
transform: rotate(0);
}
to {
transform: rotate(360deg);
}
}
@keyframes morph-blob {
0%,
100% {
transform: scale(1);
}
33% {
transform: scale(1.1);
}
66% {
transform: scale(0.8);
}
}
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes slide-in-left {
from {
transform: translateX(-100%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes slide-in-right {
from {
transform: translateX(100%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes slide-in-up {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes slide-in-down {
from {
transform: translateY(-100%);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes bounce-in {
0% {
opacity: 0;
transform: scale(0.3);
}
60% {
opacity: 1;
transform: scale(1.03);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-in-small {
0% {
opacity: 0;
transform: scale(0.5);
}
60% {
opacity: 1;
transform: scale(1.02);
}
100% {
transform: scale(1);
}
}
@keyframes bounce-in-large {
0% {
opacity: 0;
transform: scale(0.1);
}
50% {
opacity: 1;
transform: scale(1.08);
}
70% {
transform: scale(0.95);
}
100% {
transform: scale(1);
}
}
@keyframes flip-in-x {
from {
transform: rotateX(90deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes flip-in-y {
from {
transform: rotateY(90deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes rotate-in {
from {
transform: rotate(-200deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes zoom-in-small {
from {
transform: scale(0.7);
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes zoom-in {
from {
transform: scale(0.3);
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes zoom-in-large {
from {
transform: scale(0.1);
opacity: 0;
}
to {
opacity: 1;
}
}
@keyframes roll-in {
from {
transform: translateX(-100%) rotate(-120deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes roll-in-right {
from {
transform: translateX(100%) rotate(120deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes roll-in-up {
from {
transform: translateY(100%) rotate(120deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes roll-in-down {
from {
transform: translateY(-100%) rotate(-120deg);
opacity: 0;
}
to {
transform: none;
opacity: 1;
}
}
@keyframes jack-in-the-box {
from {
opacity: 0;
transform: scale(0.1) rotate(30deg);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes hinge {
to {
transform: translateY(700px);
opacity: 0;
}
}
@keyframes spin-slow {
to {
transform: rotate(360deg);
}
}
@keyframes reverse-spin {
to {
transform: rotate(0);
}
}
@keyframes toast-enter {
from {
opacity: 0;
transform: translateX(100%);
}
to {
opacity: 1;
transform: none;
}
}
@keyframes toast-exit {
from {
opacity: 1;
}
to {
opacity: 0;
transform: translateX(100%);
}
}
@keyframes skeleton-wave {
100% {
transform: translateX(100%);
}
}
.skeleton-wave {
position: relative;
overflow: hidden;
}
.skeleton-wave::after {
position: absolute;
inset: 0;
transform: translateX(-100%);
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.4) 20%,
rgba(255, 255, 255, 0.6) 60%,
rgba(255, 255, 255, 0)
);
animation: skeleton-wave 1.5s infinite;
content: '';
}
:root.dark .skeleton-wave::after {
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.05) 20%,
rgba(255, 255, 255, 0.1) 60%,
rgba(255, 255, 255, 0)
);
}