| name | styling-architecture |
| description | Use when working with CSS variables, theming, or colors. Triggers on "CSS variable", "theme", "dark mode", "light mode", "color token", "semantic color", "--background", "--foreground", "theme()", or color questions. |
| allowed-tools | ["Read","Glob","Grep"] |
Styling Architecture & CSS Variables
This document defines our CSS architecture, color system, and styling patterns.
Color System
Principle: Tailwind Built-in Colors Only
We use only Tailwind's built-in zinc scale for all colors. No custom hex codes.
Tailwind Built-in Colors (zinc-50 to zinc-950)
-> CSS Variables (semantic tokens via theme() function)
-> Tailwind Utility Classes (bg-background, text-foreground)
Color Scale Reference
| Zinc Level | Light Mode Usage | Dark Mode Usage |
|---|
zinc-50 | Background | Foreground/Text |
zinc-100 | Muted/Secondary | - |
zinc-200 | Borders (light) | - |
zinc-300 | Border hover | - |
zinc-400 | Ring/Focus | Muted text |
zinc-500 | Muted text | Muted text |
zinc-600 | - | Ring/Focus, Border hover |
zinc-700 | - | Borders |
zinc-800 | - | Muted/Accent |
zinc-900 | Primary, Cards | Cards |
zinc-950 | Foreground/Text | Background |
CSS Variables
Location
All CSS variables are defined in one place: apps/demo/src/styles.css
Naming Convention
Variables follow Spartan UI conventions for compatibility:
--background
--foreground
--foreground-muted
--card
--card-foreground
--muted
--muted-foreground
--accent
--accent-foreground
--border
--border-hover
--input
--ring
--primary
--primary-foreground
--secondary
--secondary-foreground
--destructive
--destructive-foreground
Variable Definition Pattern
Always use theme() function to reference Tailwind colors:
--background: theme('colors.zinc.50');
--border: theme('colors.zinc.200');
--background: #fafafa;
--border: #e4e4e7;
--background: rgb(250 250 250);
Using Variables in Components
In CSS/Templates
Use var() for CSS variable references:
.my-component {
background-color: var(--card);
border: 1px solid var(--border);
color: var(--foreground);
}
In Tailwind Classes (Templates)
Use Tailwind semantic color classes directly:
<div class="border-border bg-card text-foreground">
<div class="bg-muted text-muted-foreground">Muted content</div>
</div>
<div class="border-[var(--border)] bg-[var(--card)]"></div>
<div class="bg-white text-gray-900 dark:bg-gray-900 dark:text-gray-100"></div>
<div class="border-[#3f3f46] bg-[#18181b]"></div>
In TypeScript (cn utility)
cardClasses = computed(() => {
return cn(
'rounded-lg',
'border border-border',
'bg-card',
'text-foreground',
'hover:border-border-hover'
);
});
Light/Dark Mode
How It Works
Dark mode is controlled by the .dark class on <html>. CSS variables automatically switch values:
:root {
--background: theme('colors.zinc.50');
--foreground: theme('colors.zinc.950');
}
.dark {
--background: theme('colors.zinc.950');
--foreground: theme('colors.zinc.50');
}
Component Pattern
Components automatically adapt via Tailwind semantic classes. NEVER use the dark: prefix.
containerClasses = computed(() =>
cn(
'bg-background',
'text-foreground',
'border-border'
)
);
containerClasses = computed(() =>
cn(
'bg-white dark:bg-gray-900',
'text-gray-900 dark:text-gray-100'
)
);
Why No dark: Prefix?
- CSS variables handle theme switching automatically
dark: prefix creates maintenance burden
- Components become theme-aware without extra code
- Single source of truth for colors in
styles.css
Semantic Token Usage Guide
Backgrounds
| Token | Use For |
|---|
--background | Page/app background |
--card | Card, modal, dialog backgrounds |
--popover | Tooltip, dropdown backgrounds |
--muted | Secondary/subtle backgrounds |
--accent | Hover state backgrounds |
--primary | Primary buttons |
--secondary | Secondary buttons |
Text Colors
| Token | Use For |
|---|
--foreground | Primary text |
--foreground-muted | Secondary/hint text |
--muted-foreground | Subtle text on muted bg |
--card-foreground | Text on cards |
--accent-foreground | Text on accent bg |
--primary-foreground | Text on primary buttons |
Borders
| Token | Use For |
|---|
--border | Default borders |
--border-hover | Border on hover/focus |
--input | Input field borders |
--ring | Focus rings |
What NOT to Do
NEVER Use dark: Prefix
'bg-white dark:bg-gray-900';
'text-gray-900 dark:text-gray-100';
'border-gray-200 dark:border-gray-800';
'bg-card';
'text-foreground';
'border-border';
NEVER Use var() in Tailwind Classes
'bg-[var(--card)]';
'text-[var(--foreground)]';
'border-[var(--border)]';
'bg-card';
'text-foreground';
'border-border';
Never Use Hex Codes
--background: #09090b;
--border: #27272a;
--background: theme('colors.zinc.950');
--border: theme('colors.zinc.800');
Never Create Custom Color Scales
--ai-blue-500: #3b82f6;
--ai-gray-800: #1f2937;
--primary: theme('colors.zinc.900');
--muted: theme('colors.zinc.800');
Quick Reference: Common Patterns
Card Component
cardClasses = computed(() =>
cn(
'rounded-lg',
'border border-border',
'bg-card',
'shadow-sm',
'hover:border-border-hover',
'hover:shadow-md'
)
);
Input Field
inputClasses = computed(() =>
cn(
'w-full rounded-md',
'border border-input',
'bg-transparent',
'text-foreground',
'placeholder:text-muted-foreground',
'focus:border-ring',
'focus:ring-1 focus:ring-ring'
)
);
Muted Text
<span class="text-muted-foreground">Secondary info</span>
Button Variants
'bg-primary text-primary-foreground';
'bg-secondary text-secondary-foreground';
'bg-transparent hover:bg-accent text-foreground';
Checklist: Before Committing CSS Changes