Skip to content

Color

Every color in Tomoda comes from frontend/constants/Themes.ts. The system is token-based: components reference semantic names (primary, surface, text) and the active theme decides what hex to render.

Two themes ship today: dark (default — the brand's primary mode) and light. Both are first-class — every component is built to work in either.

Surface ladder

The "tonal layering" depth model. Each step up the ladder adds about 5-8% in luminance. To create depth, place a higher-tier surface on top of a lower-tier one — no shadow required.

Dark

background #0e0e0f App root, scroll background
surface #18181a Cards, headers
surfaceContainerLow #1c1c1f Grouping containers
surfaceContainerHigh #252528 Interactive layers, inputs
surfaceContainerHighest #2e2e32 Popovers, focused inputs

Light

background / surface #ffffff App root, cards
surfaceContainerLow #f4f4f5 Grouping containers
surfaceContainerHigh #e4e4e7 Interactive layers, inputs
surfaceContainerHighest #d4d4d8 Popovers, focused inputs

Brand accents

Primary — warm gold

The signature color. Reserved for earned attention: primary CTAs, active states, brand moments.

primary (dark) #D4955A Ember gold
primaryContainer (dark) #673d00 Gradient end, deep bronze
primary (light) #d6811e Darker for contrast on white
primaryContainer (light) #fce3c5 Warm cream tint

Primary CTAs use a 135° linear gradient from primary to primaryContainer — this gives the warm gold a metallic, brushed quality. Don't stop at flat fills.

Secondary — indigo

Used for non-primary interactive accents (links in certain contexts, secondary highlights). Picked deliberately as the cool complement to the warm gold.

secondary (dark) #818CF8
secondary (light) #4F46E5

Status colors

For success, warning, error states. Sized and saturated for clear differentiation in both modes.

success (dark) #34D399
warning (dark) #FBBF24
error (dark) #F87171
success (light) #059669
warning (light) #D97706
error (light) #DC2626

Text

Three tiers per mode. Use the lowest-emphasis tier that still reads — every step up the contrast ladder is an attention cost.

text (dark) #FAFAFA Primary content
textSecondary (dark) #A1A1AA Labels, helper text
textMuted (dark) #52525B Disabled, metadata
text (light) #18181B Primary content
textSecondary (light) #71717A Labels, helper text
textMuted (light) #A1A1AA Disabled, metadata

Cozy Campfire — accent palette

A warm, autumn-toned set used for tag pills, earned-state highlights, decorative accents, and any moment where we want to gently introduce variety without leaving the brand temperature. Never use for chrome (backgrounds, app shell). Both dark- and light-mode variants are tuned for legibility against their respective base surfaces.

Dark mode

oxblood#660F09Deep ember scar — rare, high-emphasis
ember#C44A2CGlowing coal — earned / live / "now"
rust#B0623AIron oxide — secondary warm tag
amber#E89545Autumn flame — progress, attention
cedar#895129Cinnamon wood — warm filled surfaces
bronze#AD7A32Aged metal — info-warm
ochre#C19A4AAutumn leaf — landmarks, attractions
mustard#8A6E29Dried grass — quieter ochre
chestnut#5C3B22Dark warm wood — borders, depth
pinecone#3D2B1EDeepest warm brown — edges, ground

Light mode

Same palette, darkened for contrast against white surfaces. The semantic meaning of each token stays the same across modes.

oxblood#4A0A05
ember#9A3820
rust#864628
amber#B3691A
cedar#6E3E1E
bronze#7C551E
ochre#8F6E22
mustard#614B16
chestnut#3F2614
pinecone#2A1B0F

Borders

Borders are intentionally subtle. The border and outlineVariant tokens are both rendered at 15% opacity — solid lines are forbidden by the no-line rule.

  • Dark: rgba(255, 255, 255, 0.15)
  • Light: rgba(0, 0, 0, 0.10)

Map tiles

constants/MapStyles.ts ships a per-mode JSON array for Google Maps (mobile). On web, Leaflet styles are driven by the same theme tokens (custom CSS overrides on top of OpenStreetMap base tiles).

Adding a color

  1. Add the token to frontend/constants/Themes.ts in both the dark and light blocks. Every token must have both-mode parity.
  2. If it's a brand-level addition (a new accent), add a swatch entry to the appropriate section of this page in the same PR.
  3. If it's a semantic state (e.g. info), update Components to show which components use it.
  4. Run task docs:build to verify swatches render correctly.