Authoring themes
A Kairos theme is a JSON manifest declaring 20 semantic tokens. The app compiles it to CSS at install time. No CSS knowledge required — just pick colours, fonts, and radii that match your visual identity.
Manifest format
A complete theme manifest — copy, modify, and paste into the custom theme uploader:
{
"schemaVersion": 1,
"id": "my-theme",
"name": "My Theme",
"description": "A custom Kairos theme.",
"author": "Your Name",
"version": "1.0.0",
"colorScheme": "dark",
"preview": {
"canvas": "#1a1b1e",
"surface": "#25262b",
"fg": "#c1c2c5",
"accent": "#7c3aed"
},
"tokens": {
"--color-canvas": "#1a1b1e",
"--color-surface": "#25262b",
"--color-surface-2": "#2c2e33",
"--color-surface-3": "#373a40",
"--color-fg": "#c1c2c5",
"--color-fg-2": "#a6a7ab",
"--color-fg-3": "#909296",
"--color-fg-4": "#5c5f66",
"--color-accent": "#7c3aed",
"--color-accent-hover": "#6d28d9",
"--color-line": "#373a40",
"--color-line-subtle": "#2c2e33",
"--color-success": "#2f9e44",
"--color-warning": "#e67700",
"--color-danger": "#e03131",
"--font-sans": "system-ui, sans-serif",
"--font-mono": "ui-monospace, monospace",
"--radius-sm": "0.25rem",
"--radius-md": "0.375rem",
"--radius-lg": "0.5rem"
}
}Required tokens
All 20 tokens below are required. A manifest missing any of them will fail validation.
| Token | Role |
|---|---|
| --color-canvas | Page background |
| --color-surface | Card / panel background |
| --color-surface-2 | Slightly elevated surface (input backgrounds) |
| --color-surface-3 | Further elevated surface (hover states, badges) |
| --color-fg | Primary text |
| --color-fg-2 | Secondary text |
| --color-fg-3 | Muted text (labels, descriptions) |
| --color-fg-4 | Placeholder / disabled text |
| --color-accent | Primary interactive colour (buttons, links, focus rings) |
| --color-accent-hover | Accent hover state |
| --color-line | Primary border colour |
| --color-line-subtle | Subtle border (dividers) |
| --color-success | Success state |
| --color-warning | Warning state |
| --color-danger | Error / destructive action |
| --font-sans | Sans-serif font stack |
| --font-mono | Monospace font stack |
| --radius-sm | Small corner radius |
| --radius-md | Medium corner radius |
| --radius-lg | Large corner radius |
Optional tokens
You can extend the manifest with any additional CSS custom properties — just add them to the tokens object. Common optional tokens:
--color-brandBrand colour (defaults to accent if unset)--color-accent-2Secondary accent colour--color-emeraldEmerald/green accent--color-task-event-bgBackground colour for calendar task events--radius-xlExtra-large corner radius--shadow-sm / --shadow-md / --shadow-lgBox shadow tokens--duration-fast / --duration-normal / --duration-slowAnimation duration tokens
Color value formats
Color token values must be valid CSS color expressions:
#1a1b1ergb(26, 27, 30)rgba(255, 255, 255, 0.08)hsl(240 5% 12%)oklch(15% 0.01 270)oklab(0.15 -0.01 -0.01)
Note: keyword colours like red or transparent are not accepted.
Font imports
To use a web font, add its @import URL to the fontImports array. Only fonts from these sources are allowed:
fonts.googleapis.comrsms.mecdn.jsdelivr.net
"fontImports": [
"https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&display=swap"
],
"tokens": {
"--font-sans": "'Inter', system-ui, sans-serif",
...
}Install your theme
Go to Settings → Appearance → Upload custom theme, paste your manifest JSON, and click "Install". The theme will appear in your pack picker immediately.
To share your theme with the community, submit a PR to the kairos-themes-registry repository.
Safety checks
Every manifest goes through these checks before install:
- ✓Schema validation — all required fields present and correctly typed
- ✓Size limit — raw JSON must be under 64KB
- ✓CSS injection scan — compiled CSS is scanned for @import outside the font allowlist, expression(), behavior:, and javascript: URIs
- ✓Font allowlist — fontImports must point to approved CDNs
- ✓ID uniqueness — theme ID must not collide with a built-in pack
- ✓Token completeness — all 20 required tokens must be present