Source of truth is
DESIGN.md at the repo root. This page renders it visually. Keep them in sync when tokens change.Philosophy
GAIA’s UI is dark-first, flat, and single-accent. Every decision flows from five constraints:- Dark-first. Primary experience is dark mode (
#111111background). Light mode is supported via CSS variables but is secondary. - Flat depth. Depth comes from layered backgrounds (
zinc-800→zinc-900) only. Never borders, rings, or outlines. - Single accent. One primary action color:
#00bbff. Everything else is zinc-scale neutrals. - Borderless cards. Data cards use background-only separation, no
border-,ring-, oroutline-in the card tree. - Subtle motion. Animations serve entrance, exit, and state changes only. Never decorative. Keep durations ≤ 300ms.
Colors
Brand Tokens
Primary
Selection
--color-primary for CTAs, user chat bubbles, selection highlights, and links. Use --color-primary-bg / --color-secondary-bg for the main app canvas and sidebar. Never use these on dark card surfaces, use zinc directly there.
Semantic Variables (Shadcn / Radix)
Use on layout surfaces and standard components. Switch automatically between light and dark.Zinc Scale, Dark Card Surfaces
Use zinc directly on dark card surfaces, not the CSS variables above.Surfaces
Text
Status Colors
Always use/10 opacity background paired with matching foreground text. Never solid.
Status
Priority
Typography
Three font families. Never setfont-family inline, use the Tailwind token class.
Specimens
Heading scale
Defined globally via@layer base, use semantic HTML tags, styles apply automatically.
Text patterns
border-radius: 10px and padding: 4px globally. Use font-mono or .monospace class.
Spacing
Border Radius
Depth & Elevation
Depth primarily from background layering and blur, not shadow.Dark Card System
All data cards, tool sections, and info panels use this contract. Two-tone zinc depth, no borders.Template
Live preview
Recent Activity4 items
Deploy pipelineSuccess
2 minutes ago
Memory syncWarning
12 minutes ago
Email batchInfo
1 hour ago
Layer reference
Constraints: Never
border-, ring-, outline- anywhere in the card tree. rounded-2xl on outer containers always. zinc-800 outer → zinc-900 inner is the entire separation mechanism. Status colors always use /10 opacity backgrounds.
Icons
All icons come from@icons (@theexperiencecompany/gaia-icons). Never raw SVGs.
className, height, width, and size props.
Animations
Available classes
Transitions
Default:transition-all duration-200. Use this everywhere unless a specific property needs targeting.
Easing
Framer Motion
Import frommotion/react, not framer-motion. AnimatePresence is required for exit animations. Keep durations ≤ 300ms for micro-interactions, ≤ 500ms for entrances.
Toast / Notifications
Sileo, already mounted globally. Call the toast function directly. Never add<Toaster> or import from sonner / react-hot-toast.
Toast style: dark fill (#262626), white title, white/75 description, top-right position. Action button colors apply automatically by type: error → red, warning → amber, success → green, info → blue.
Component Library
- Shadcn UI
- HeroUI
- Overlay hierarchy
Style preset:
new-york · Base color: zinc · CSS variables: on · Located at src/components/ui/Styling Tools
Forms & Validation
Field pattern
Input states
Error state is driven byaria-invalid={!!error}, styling applies automatically via the Input component.
Loading & Empty States
Loading
Skeleton inherits:
bg-accent animate-pulse rounded-md. Match the skeleton shape to the content it replaces.
Empty states
No shared component, build inline:Interactive States
Dark / Light Mode
Class-based:.dark on <html>. Tailwind dark: modifier works everywhere.
- Layout surfaces →
bg-background text-foreground(auto-switches via CSS vars) - Dark cards →
bg-zinc-800 / bg-zinc-900(always dark, nodark:needed) - Explicit overrides → only when CSS variables don’t cover it
- Brand cyan (
#00bbff) is the same in both modes
Responsiveness
Core layout does not use
lg:, xl:, or 2xl: breakpoints.
Scrollbars
Global scrollbar is already styled (8px, pill-shaped, zinc-700 thumb). Use.no-scrollbar to suppress chrome on scroll areas where it would be distracting.
Rules
Do
rounded-2xlon all outer card containerszinc-800outer →zinc-900inner for card depth/10opacity backgrounds for all status colors- Import icons from
@icons cn()for all conditional class mergingtransition-all duration-200as the default transitionAnimatePresencefor exit animations- Import from
motion/react import { toast } from "@/lib/toast"
Don’t
border-,ring-, oroutline-anywhere in a card treerounded-lgon card containers- Solid backgrounds for status badges
- Unicode symbols in JSX (
→,•,✓), use icons - Add
<Toaster>, already mounted globally - Import from
sonnerorreact-hot-toast - CSS variables on dark card surfaces, use zinc directly
- Set
font-familyinline, use Tailwind token classes - Import from
framer-motion, usemotion/react

