Frontend Theming
The frontend supports both light and dark themes through CSS variables in frontend/src/index.css.
Theme architecture
Theme state is stored in the app store and applied as the dark class on the document root. Light theme values live in :root; dark theme overrides live in .dark.
Components should use semantic tokens, not hardcoded dark colors.
Core tokens
Backgrounds:
--base: page background--surface: cards, panels, menus--surface-2: nested panels and subdued blocks--surface-3: hover states and controls
Text:
--text-1: primary text--text-2: secondary text--text-3: muted text and placeholders
Borders:
--border: normal borders--border-2: stronger borders and controls
Status:
--success--warning--danger--info
Special surfaces:
--overlayand--overlay-textfor modals/previews--chart-bgand--chart-borderfor chart tooltips--graph-*tokens for the asset graph canvas
Utility classes
Prefer existing semantic classes:
cardinputbtn-primary,btn-secondary,btn-ghost,btn-dangertable-rowtext-primary,text-secondary,text-mutedbg-base,bg-surface,bg-surface-2,bg-surface-3border-theme- severity/status badge classes
For hover variants, use Tailwind arbitrary values because custom class variants are not generated automatically:
className="hover:bg-[var(--surface-3)] hover:text-[var(--text-1)]"
Component guidance
Do not use dark-only classes such as text-white, bg-gray-900, bg-black, or border-gray-800 for normal UI surfaces. Use semantic tokens instead.
Colored status elements may use fixed hue families, but text must remain readable in both themes. Prefer the badge/status classes or text-success, text-warning, text-danger, and text-info.
Charts and canvas code should read CSS variables with getComputedStyle(document.documentElement) rather than embedding dark colors.
Checklist for new UI
- Text is readable in light and dark themes.
- Cards and nested panels use
surfacetokens. - Tables use
table-row,border-theme, and semantic text colors. - Inputs use
input. - Empty/loading/error states use semantic text and status tokens.
- Modals use
--overlayand readable overlay/header text.