# Go Backend Semantic CSS Color Tokens Design

**Date:** 2026-05-10

**Goal**

Replace hardcoded colors across the co-located Go backend CSS sources with a semantic token layer defined in `go-backend/internal/web/ui/base.css`.

**Chosen Approach**

Introduce a structured set of semantic CSS custom properties in `base.css`, then update every co-located CSS file to consume those variables instead of raw hex, rgba, or hsl color literals. This keeps the styling readable, centralizes visual decisions, and prevents component files like `button.css` from hardcoding their own palette values.

**Scope**

- Add semantic color, surface, border, shadow, and overlay tokens to `go-backend/internal/web/ui/base.css`.
- Replace hardcoded color literals in all co-located CSS source files:
  - `go-backend/internal/web/ui/*.css`
  - `go-backend/internal/web/ui/catalog/catalog.css`
- Keep the existing single shipped output: `go-backend/static/styles.css`.
- Preserve the current visual appearance as closely as possible while changing only the source of truth for values.

**Out Of Scope**

- Changing component HTML contracts
- Redesigning the visual theme
- Adding dark mode
- Replacing dynamic runtime variables such as `--project-color`
- Tokenizing spacing, radii, typography, or layout values in this slice unless directly necessary for a color/shadow token

**Architecture**

The CSS should have two layers of visual definition:

1. **Semantic token layer in `base.css`**
   - neutral text, surface, and border tokens
   - brand and action tokens
   - semantic status tokens for info, warning, success, and danger
   - overlay, gradient, and shadow tokens

2. **Component and app usage layer**
   - every other CSS file references tokens from `base.css`
   - component files stop introducing their own color literals

This preserves the current compiled stylesheet shape while moving visual decisions into one place.

**Token Strategy**

Use semantic names, not raw-value names.

Good examples:

- `--color-text-primary`
- `--color-text-muted`
- `--color-surface-default`
- `--color-surface-subtle`
- `--color-border-default`
- `--color-brand-primary`
- `--color-brand-primary-hover`
- `--color-status-success-soft-bg`
- `--color-status-danger-strong`
- `--shadow-surface-md`
- `--overlay-backdrop-default`

Bad examples:

- `--color-7c3aed`
- `--purple-500`
- `--gray-200`

The token names should describe intent so components remain readable when using them.

**Token Categories**

Recommended categories in `base.css`:

1. **Core neutrals**
   - page background
   - primary text
   - muted text
   - default border
   - subtle surface
   - raised surface

2. **Brand / action**
   - primary action base, hover, active
   - accent / highlight
   - focus ring

3. **Semantic statuses**
   - info background, border, foreground
   - warning background, border, foreground
   - success background, border, foreground
   - danger background, border, foreground
   - stronger action-oriented variants where needed for buttons

4. **Effects**
   - shadows used by cards, modals, panels, and app surfaces
   - overlay/backdrop colors
   - shared gradient stops if reused in multiple places

5. **Runtime-aware fallbacks**
   - values that back `var(--project-color, ...)` should use semantic fallbacks such as `var(--project-color, var(--color-project-fallback))`

**Responsibility Boundaries**

`base.css`

- owns all reusable visual tokens
- remains the only file allowed to define shared palette decisions

Other CSS files

- consume tokens only
- may still define non-color properties such as layout and spacing
- should not introduce new raw color literals unless there is a strong, deliberate reason

`app.css`

- remains app-specific in selector ownership
- still uses the same shared semantic token layer rather than inventing app-only raw values everywhere

**Migration Strategy**

Refactor in one coherent slice:

- define the token vocabulary in `base.css`
- replace hardcoded literals in primitive CSS files
- replace hardcoded literals in `catalog.css`
- replace hardcoded literals in `app.css`
- regenerate `go-backend/static/styles.css`
- verify the generated stylesheet still exposes the expected selectors and that tests still pass

The work should preserve current behavior. This is a source-of-truth refactor, not a visual refresh.

**Testing**

Verification should cover:

- existing UI tests still passing
- catalog tests still passing
- buildstyles tests still passing
- representative token names present in the generated stylesheet
- representative component selectors still present in the generated stylesheet

Representative generated-token checks:

- `--color-text-primary`
- `--color-surface-default`
- `--color-status-warning-soft-bg`
- `--shadow-surface-md`
- `--overlay-backdrop-default`

Representative selector checks:

- `.ui-button-solid.ui-button-default`
- `.ui-badge-warning`
- `.ui-modal-panel`
- `.catalog-page`

**Risks**

Primary risks:

- introducing token names that are too literal and not reusable
- accidentally changing appearance while replacing values
- leaving scattered raw colors behind in `app.css`
- over-tokenizing one-off values that do not represent shared decisions

Mitigation:

- define token categories before replacing usages
- preserve current values exactly unless consolidation is clearly correct
- use semantic names tied to UI intent
- verify the built stylesheet and tests after the refactor

**Success Criteria**

This work is complete when:

- `base.css` defines a semantic token layer for shared colors and effects
- component and app CSS files use those tokens instead of raw color literals
- the generated `go-backend/static/styles.css` is rebuilt successfully
- the app still ships one stylesheet
- tests still pass
