# Theme contract Every Crema theme (`lib-theme-*`) must declare these CSS variables so the shell, AI surfaces, and shadcn primitives render correctly. Missing a variable won't crash anything — it'll just look wrong (transparent backgrounds, missing borders, broken focus rings, etc.). A theme is a single CSS file that declares variables under `:root` for light mode and under `.dark` for dark mode. Themes may also `@import url(...)` font packages at the top of the file — they ship self-contained. The shell expects the theme to be the **first** import in the consuming app's entry CSS, so any embedded font URLs land at the top of the resolved output (CSS spec requires `@import` before any other rules). ## Required tokens ### Surfaces | Token | Used for | |---|---| | `--background` | Page background | | `--foreground` | Default text color | | `--card` | Card surfaces, inputs, dropdowns | | `--card-foreground` | Text on cards | | `--popover` | Popover/menu surfaces | | `--popover-foreground` | Text on popovers | | `--muted` | Subtle backgrounds (hover states, toolbars, code blocks) | | `--muted-foreground` | Subtle text (timestamps, hints, labels) | | `--accent` | Hover/focus highlight on items | | `--accent-foreground` | Text on accent backgrounds | ### Brand & status | Token | Used for | |---|---| | `--primary` | Brand color, primary buttons, active nav, ripple | | `--primary-foreground` | Text on primary surfaces | | `--secondary` | Secondary buttons | | `--secondary-foreground` | Text on secondary | | `--destructive` | Errors, sign-out, destructive menu items | | `--success` | Confirmations | | `--success-foreground` | Text on success surfaces | ### Borders, inputs, focus | Token | Used for | |---|---| | `--border` | Dividers, default borders | | `--input` | Input field borders | | `--ring` | Focus rings | ### Sidebar (rail) | Token | Used for | |---|---| | `--sidebar` | Rail background | | `--sidebar-foreground` | Rail text | | `--sidebar-primary` | Active nav background | | `--sidebar-primary-foreground` | Active nav text | | `--sidebar-accent` | Rail hover | | `--sidebar-accent-foreground` | Text on rail hover | | `--sidebar-border` | Rail borders | | `--sidebar-ring` | Rail focus ring | ### Charts & syntax (optional but recommended) | Token | Used for | |---|---| | `--chart-1` … `--chart-5` | Chart series colors; `--chart-3` doubles as warning amber | | `--syntax-keyword`, `--syntax-string`, `--syntax-number`, `--syntax-comment`, `--syntax-function`, `--syntax-type` | Code-block highlighting | ### Typography | Token | Used for | |---|---| | `--font-heading` | Heading font stack | | `--font-sans` | Default UI font stack | | `--font-ai-prose` | Assistant prose (the AI surface uses this for replies) | | `--font-mono` | Code, tabular numbers | ### Type scale Each pair declares a size and matching line height: - `--text-display-size` / `--text-display-lh` - `--text-headline-size` / `--text-headline-lh` - `--text-title-size` / `--text-title-lh` - `--text-body-size` / `--text-body-lh` - `--text-label-size` / `--text-label-lh` - `--text-caption-size` / `--text-caption-lh` ### Motion | Token | Used for | |---|---| | `--duration-fast`, `--duration-base`, `--duration-slow`, `--duration-slower`, `--duration-spring` | Animation lengths | | `--ease-standard`, `--ease-emphasized`, `--ease-decelerate`, `--ease-accelerate` | Standard easing curves | | `--ease-spring-gentle`, `--ease-spring-snappy`, `--ease-spring-bouncy` | Spring curves | ### Radii & elevation | Token | Used for | |---|---| | `--radius` | Base radius (sm/md/lg/xl/2xl computed from this in `app.css`) | | `--elevation-0` … `--elevation-5` | Shadow scale | | `--border-width-thin`, `--border-width-base`, `--border-width-thick`, `--border-width-heavy` | Stroke widths | ## Scoping conventions - `:root { … }` — theme defaults (light mode). - `.dark { … }` — dark-mode overrides. - `[data-theme=""] { … }` — alternate-scoped theme. Only needed if a theme should coexist with another on the same page (e.g. an AI surface uses a different theme than the rest of the app). Single-theme apps don't need this scope. ## Adding a new theme 1. Clone any existing theme as a starting point — `lib-theme-mightypix` is a good reference because it's complete. 2. Edit tokens (and font `@import url` if changing fonts). 3. Update the consuming app's `app.css`: ```css @import "../../lib-theme-/theme.css"; /* CREMA:THEME */ @import "tailwindcss"; ... ``` 4. Done. Components automatically pick up the new look — no changes needed in any TSX file. ## Multi-theme apps (e.g. mightypix on AI surfaces only) If a theme defines `[data-theme=""]` instead of (or in addition to) `:root`, you can switch surfaces per route via the shell's `theme` prop: ```tsx ``` The shell wraps itself in `data-theme={theme}` so the alt theme's tokens cascade through that subtree only.