Documentation Index
Fetch the complete documentation index at: https://docs.heygaia.io/llms.txt
Use this file to discover all available pages before exploring further.
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.| Variable | Light | Dark |
|---|---|---|
--background | hsl(0 0% 100%) | hsl(224 71% 4%) |
--foreground | hsl(222.2 47.4% 11.2%) | hsl(213 31% 91%) |
--muted | hsl(210 40% 96.1%) | hsl(223 47% 11%) |
--muted-foreground | hsl(215.4 16.3% 46.9%) | hsl(215.4 16.3% 56.9%) |
--accent | hsl(210 40% 96.1%) | hsl(216 34% 17%) |
--border | hsl(214.3 31.8% 91.4%) | hsl(216 34% 17%) |
--ring | hsl(215 20.2% 65.1%) | hsl(216 34% 17%) |
--destructive | hsl(0 100% 50%) | hsl(0 63% 31%) |
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.
| Token | Family | Weights | Use |
|---|---|---|---|
font-sans | Inter | All | All UI — body, labels, buttons, inputs |
font-serif | PP Editorial New | 200, 400 | Editorial headings, landing hero text |
font-mono | Anonymous Pro | 400, 700 | Code blocks, <code>, technical content |
Specimens
Heading scale
Defined globally via@layer base — use semantic HTML tags, styles apply automatically.
| Tag | Classes | Size |
|---|---|---|
<h1> | text-3xl font-bold | 30px |
<h2> | text-2xl font-bold | 24px |
<h3> | text-xl font-bold | 20px |
<h4> | text-lg font-bold | 18px |
<h5> | text-base font-bold | 16px |
<h6> | text-sm font-bold | 14px |
Text patterns
border-radius: 10px and padding: 4px globally. Use font-mono or .monospace class.
Spacing
| Value | Use |
|---|---|
gap-1 / gap-1.5 | Icon + label pairs |
gap-2 | Standard row items |
gap-3 | Section spacing inside cards |
space-y-2 | Vertical list of items inside a card |
p-3 | Inner card item padding |
p-4 | Outer card padding |
px-3 / px-4 | Horizontal padding on inputs, buttons |
Border Radius
| Context | Class | Size |
|---|---|---|
| Dark cards — outer | rounded-2xl | 16px |
| Dark cards — inner items | rounded-2xl or rounded-xl | 12px |
| Images | rounded-3xl | 24px |
| Buttons, inputs | rounded-md | 6px |
| Badges, pills | rounded-full | — |
| Context menus | rounded-xl | 12px |
Depth & Elevation
Depth primarily from background layering and blur, not shadow.| Context | Value |
|---|---|
| Buttons, inputs | shadow-xs |
| Dialogs, sheets | shadow-lg |
| Dark cards (solid) | No shadow — flat design |
| Dark cards (glass) | bg-zinc-800/40 backdrop-blur-xl |
| Hover on dark surfaces | hover:bg-white/5 |
| Level | Class | Use |
|---|---|---|
| Moderate | backdrop-blur-lg | Glass cards |
| Standard | backdrop-blur-xl | Panels overlaying content, floating cards |
| Maximum | backdrop-blur-2xl | Search overlays, full-screen modals |
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
| Layer | Classes |
|---|---|
| Outer container | rounded-2xl bg-zinc-800 p-4 w-fit min-w-[400px] |
| Outer (accordion) | rounded-2xl bg-zinc-800 p-3 py-0 |
| Inner item | rounded-2xl bg-zinc-900 p-3 |
| Inner item compact | rounded-xl bg-zinc-900 p-3 |
| Glass variant | rounded-2xl bg-zinc-800/40 p-4 backdrop-blur-xl |
| Section header | text-sm font-semibold text-zinc-100 mb-3 |
| Item title | text-sm font-medium text-zinc-200 |
| Item title (prominent) | text-sm font-medium text-zinc-100 |
| Body text | text-xs text-zinc-400 |
| Meta / timestamp | text-xs text-zinc-500 |
| Item spacing | space-y-2 |
| Status badge | rounded-full px-2 py-0.5 text-xs + status color |
| Section divider | <Divider className="bg-zinc-700/50" /> (HeroUI) |
| Hoverable list item | p-4 transition-all hover:bg-white/5 |
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.
| Context | Value |
|---|---|
| Inline (badges, text) | height={17} |
| Action buttons | size={16} |
| Prominent / decorative | size={24} |
Animations
Available classes
| Class | Duration | Use |
|---|---|---|
animate-spin | Infinite | Loading spinner |
animate-pulse | Infinite | Skeleton placeholder |
animate-accordion-down | 0.2s ease-out | Accordion open |
animate-accordion-up | 0.2s ease-out | Accordion close |
animate-scale-in | 0.4s bounce | Element entrance |
animate-scale-in-blur | 0.5s bounce | Blurred entrance |
animate-shimmer | 2s linear | Shimmer effect |
animate-shake | 0.7s | Error shake |
Transitions
Default:transition-all duration-200. Use this everywhere unless a specific property needs targeting.
| Scenario | Classes |
|---|---|
| All properties | transition-all duration-200 |
| Color only | transition-colors duration-200 |
| Button press | active:scale-95 transition-all! duration-300 |
Easing
| Name | Value | Use |
|---|---|---|
| Default | ease | Most transitions |
| Exit / entrance | ease-out | Entrances, exits |
| Bounce | cubic-bezier(0.34, 1.56, 0.64, 1) | scale-in, scale-in-blur |
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/| Component | Key details |
|---|---|
Button | default destructive outline secondary ghost link · sizes: default sm lg icon |
Input | h-9 rounded-md shadow-xs · focus ring · aria-invalid for errors |
Textarea | Same as Input · min-h-16 · auto-height via field-sizing-content |
Dialog | Zoom + fade · use for confirmations, forms requiring focus |
Sheet | Fade-in slide panel · use for side panels, settings drawers |
Popover | Anchored overlay · use for inline pickers, contextual options |
Tooltip | Hover label only — no interactive content |
DropdownMenu / ContextMenu | Action lists |
Accordion | Animated expand/collapse |
Avatar | rounded-full, image + fallback |
Skeleton | animate-pulse rounded-md |
ScrollArea | Radix scrollable with edge shadows |
Sidebar | Collapsible · Cmd/Ctrl+B toggle · cookie-persisted |
Styling Tools
Forms & Validation
Field pattern
Input states
Error state is driven byaria-invalid={!!error} — styling applies automatically via the Input component.
| State | Visual |
|---|---|
| Default | border-input bg-transparent |
| Focus | ring-ring/50 ring-[3px] border-ring |
| Error | ring-destructive/20 border-destructive (via aria-invalid) |
| Disabled | opacity-50 cursor-not-allowed |
| Loading | cursor-wait (set disabled on the input) |
Loading & Empty States
Loading
| Pattern | When |
|---|---|
<Skeleton className="h-4 w-32 rounded-md" /> | Known content shape, replacing text/images |
animate-pulse on the container | Unknown shape, shimmer a region |
animate-spin on an icon | Inline action in progress |
Full <LoadingIndicator /> | Whole chat response pending |
bg-accent animate-pulse rounded-md. Match the skeleton shape to the content it replaces.
Empty states
No shared component — build inline:Interactive States
| State | Classes |
|---|---|
| Hover (standard) | hover:bg-accent · hover:bg-primary/90 · hover:opacity-80 |
| Hover (dark surface) | hover:bg-white/5 |
| Focus visible | focus-visible:ring-ring/50 focus-visible:ring-[3px] focus-visible:border-ring |
| Active / press | active:scale-95 |
| Disabled | disabled:opacity-50 disabled:pointer-events-none disabled:cursor-not-allowed |
| Error | aria-invalid:ring-destructive/20 aria-invalid:border-destructive |
| Hover reveal | opacity-0 transition-all group-hover:opacity-100 (parent needs group) |
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
| Breakpoint | Value | Impact |
|---|---|---|
| Mobile | max-width: 600px | Full-width layouts, larger tap targets |
| Tablet | max-width: 990px | Navbar becomes full-width strip |
md: | 768px | Text size shifts (text-base → text-sm) |
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

