Design Tokens
FanFest uses a structured design token system to ensure visual consistency across every surface. Each token maps to a CSS custom property and a Tailwind color utility, making them available in both raw CSS and utility-class workflows.
How Tokens Work
Every design token follows a consistent naming convention:
| Layer | Token Key (TypeScript) | CSS Custom Property | Tailwind Utility Example |
|---|---|---|---|
| Fill | fill_brand | --fill-brand | bg-fill-brand, text-fill-brand |
| Text | text_secondary | --text-secondary | text-text-secondary |
| Border | border_brand | --border-brand | border-border-brand |
| Icon | icon_emphasis | --icon-emphasis | text-icon-emphasis |
Conversion rule: Replace underscores with hyphens. The TypeScript key fill_brand_hover becomes CSS property --fill-brand-hover and Tailwind color fill-brand-hover.
Using Tokens in CSS
.my-element {
background-color: var(--fill-brand);
color: var(--text);
border: 1px solid var(--border);
}Using Tokens in Tailwind
<button class="bg-fill-brand text-text-on-brand border border-border-brand">
Action
</button>Token Versions
FanFest has two token layers:
- V2 (current) --- 64 design tokens in the
DesignThemeinterface. Use these for all new work. - V1 (legacy) --- 12 brand tokens (
--brand-*) preserved as backward-compatible aliases. These will be removed in a future migration.
Both layers are stored per-channel and loaded via the getBrandTheme GraphQL query. The V1 tokens are automatically derived from V2 values for backward compatibility.
See Legacy Token Mapping at the bottom of this page for the full V1-to-V2 correspondence.
V2 Design Tokens (64 tokens)
Background (2 tokens)
Page and app-level background colors.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
bg | --bg | #100B1E | Primary app background (dark mode base) |
bg_secondary | --bg-secondary | #100B1EB3 | Secondary background with 70% opacity |
Surface (5 tokens)
Card, container, and panel surface colors. Surfaces sit on top of backgrounds and use transparency for layering.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
surface | --surface | #875AF91A | Default surface (cards, widgets) |
surface_hover | --surface-hover | #875AF933 | Surface hover state |
surface_secondary | --surface-secondary | #FFFFFF0D | Secondary surface (light translucent white) |
surface_secondary_hover | --surface-secondary-hover | #FFFFFF1A | Hover state for secondary surfaces |
surface_accent | --surface-accent | #FF8D3A | Accent surface for highlights or alerts |
Fill (20 tokens)
Interactive element fills for buttons, toggles, badges, and system feedback states.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
fill_brand | --fill-brand | #875AF9 | Primary brand fill |
fill_brand_hover | --fill-brand-hover | #875AF9CC | Brand fill hover state |
fill_brand_pressed | --fill-brand-pressed | #875AF999 | Brand fill pressed/active state |
fill_brand_secondary | --fill-brand-secondary | #875AF94D | Secondary brand fill (subtle tint) |
fill_brand_secondary_hover | --fill-brand-secondary-hover | #875AF980 | Secondary brand fill hover |
fill_brand_secondary_pressed | --fill-brand-secondary-pressed | #875AF980 | Secondary brand fill pressed |
fill_dark | --fill-dark | #00000099 | Neutral dark overlay |
fill_dark_hover | --fill-dark-hover | #00000066 | Dark fill hover state |
fill_dark_pressed | --fill-dark-pressed | #000000CC | Dark fill pressed state |
fill_disabled | --fill-disabled | #7E7E7E66 | Disabled element fill |
fill_success | --fill-success | #0DD32D | Success / positive feedback |
fill_critical | --fill-critical | #ED3024 | Critical / error |
fill_critical_secondary | --fill-critical-secondary | #ED30244D | Secondary error overlay |
fill_warning | --fill-warning | #FF8D3A | Warning / alert |
fill_warning_secondary | --fill-warning-secondary | #FF8D3A4D | Secondary warning background |
fill_silver | --fill-silver | #7E7E7E | Silver (ranking/status) |
fill_bronze | --fill-bronze | #AB8F54 | Bronze (ranking/achievement) |
fill_gold | --fill-gold | #FFCA17 | Gold (trophies, rewards) |
fill_gold_light | --fill-gold-light | #EFEDDB | Light gold highlight |
fill_gold_dark | --fill-gold-dark | #977400 | Dark gold for contrast |
Text (14 tokens)
Typography colors for various emphasis levels and states.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
text | --text | #FFFFFF | Default text on dark backgrounds |
text_on_brand | --text-on-brand | #FFFFFF | Text on brand-colored elements |
text_inverse | --text-inverse | #000000 | Inverted text for light backgrounds |
text_secondary | --text-secondary | #FFFFFFCC | Secondary text (reduced emphasis) |
text_tertiary | --text-tertiary | #FFFFFF99 | Tertiary text (captions, metadata) |
text_disabled | --text-disabled | #FFFFFF66 | Disabled / de-emphasized text |
text_success | --text-success | #0DD32D | Success message text |
text_critical | --text-critical | #ED3024 | Error / alert text |
text_brand | --text-brand | #875AF9 | Brand-colored text |
text_accent | --text-accent | #BC5BAA | Secondary accent text |
text_accent_secondary | --text-accent-secondary | #F15C5C | Alternate accent text |
text_gold | --text-gold | #FFCA17 | Gold highlight text |
text_gold_light | --text-gold-light | #EFEDDB | Light gold text |
text_gold_dark | --text-gold-dark | #977400 | Dark gold emphasis text |
Border (15 tokens)
Border and divider colors for UI elements and interaction states.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
border | --border | #FFFFFF0D | Default subtle border |
border_hover | --border-hover | #FFFFFF1A | Hover state border |
border_pressed | --border-pressed | #FFFFFF4D | Pressed state border |
border_selected | --border-selected | #FFFFFF66 | Selected element border |
border_secondary | --border-secondary | #FFFFFF1A | Secondary divider border |
border_brand | --border-brand | #875AF9 | Brand border |
border_brand_hover | --border-brand-hover | #875AF9CC | Brand border hover |
border_brand_pressed | --border-brand-pressed | #875AF999 | Brand border pressed |
border_brand_selected | --border-brand-selected | #875AF9B3 | Brand border selected |
border_critical | --border-critical | #ED3024 | Error border |
border_success | --border-success | #0DD32D | Success border |
border_warning | --border-warning | #FF8D3A | Warning border |
border_dark | --border-dark | #100B1E | Dark background border |
border_button_shadow_light | --border-button-shadow-light | #FFFFFF66 | Button highlight shadow (light-on-dark) |
border_button_shadow_dark | --border-button-shadow-dark | #00000066 | Button inset shadow (dark-on-light) |
Icon (8 tokens)
Icon color tokens for various states and emphasis levels.
| Token | CSS Property | Default Value | Description |
|---|---|---|---|
icon | --icon | #FFFFFF80 | Default icon (medium emphasis) |
icon_emphasis | --icon-emphasis | #FFFFFF | High-emphasis icon |
icon_on_branded_surface | --icon-on-branded-surface | #FFFFFF | Icon on brand-colored surfaces |
icon_hover | --icon-hover | #FFFFFFB3 | Icon hover state |
icon_secondary | --icon-secondary | #FFFFFF66 | Secondary (low emphasis) icon |
icon_secondary_hover | --icon-secondary-hover | #FFFFFF80 | Secondary icon hover |
icon_disabled | --icon-disabled | #FFFFFF66 | Disabled icon |
icon_brand | --icon-brand | #875AF9 | Brand-colored icon |
Legacy Token Mapping (V1 to V2)
The 12 legacy brand tokens are preserved for backward compatibility. New work should always use V2 tokens.
| Legacy CSS Variable | V2 Equivalent | Notes |
|---|---|---|
--brand-bg-main | --bg | Main app background |
--brand-strong-bg-overlay-80 | --bg-secondary | Strong background overlay |
--brand-light-bg-overlay-50 | --bg-secondary | Light background overlay (similar usage) |
--brand-primary | --fill-brand / --text-brand / --border-brand / --icon-brand | Primary brand color across all categories |
--brand-surface-hover | --surface-hover | Surface hover state |
--brand-bgdivider-10 | --surface | Subtle surface / divider bg |
--brand-bgdivider-20 | --surface-hover | Slightly stronger divider bg |
--brand-quaternary-40 | --fill-brand-secondary | 40% opacity brand fill |
--brand-secondary-80 | --fill-brand-hover | 80% opacity brand (hover) |
--brand-tertiary-60 | --fill-brand-pressed | 60% opacity brand (pressed) |
--brand-fill-dark | --fill-dark | Dark fill overlay |
--brand-icon-emphasis | --icon-emphasis | Emphasized icon color |
Additional legacy --basics-* tokens are also mapped:
| Legacy CSS Variable | V2 Equivalent |
|---|---|
--basics-primary | --text |
--basics-secondary-80 | --text-secondary |
--basics-tertiary-60 | --text-tertiary |
--basics-quaternary-40 | --text-disabled |
--basics-bgdivider-5 | --border |
--basics-bgdivider-10 | --border-hover |
--basics-bgdivider-20 | --border-pressed |
--basics-accent-orange | --fill-warning |
--basics-accent-red | --fill-critical |
--basics-accent-green | --fill-success |
--basics-accent-gold | --fill-gold |
Source Reference
The canonical token definition lives in:
- Interface:
apps/frontend/src/utils/theme.ts---DesignThemeinterface andDESIGN_TOKEN_KEYSarray - Tailwind config:
apps/frontend/tailwind.config.ts--- V2 tokens registered undertheme.extend.colors - Default values:
apps/frontend/src/stores/theme.store.ts---DEFAULT_BRAND_THEMEobject - Conversion helpers:
tokenToCssVar()andtokenToTailwindKey()intheme.ts
