docs: Semantic Color System v1.0

- SEMANTIC_COLOR_SYSTEM.md (v1.0, DRAFT):
  - Three-layer architecture: Primitive → Semantic → Component Alias
  - Naming convention: color.{category}.{role}
  - Semantic tokens with contracts (purpose, allowed, not allowed):
    - Action colors (primary, secondary, ghost, disabled)
    - Surface colors (default, raised, overlay, inverted)
    - Text colors (primary, secondary, muted, inverted, link)
    - Border colors (default, focus, error, success)
    - Status colors (success, warning, danger, info)
    - Brand colors (primary, secondary)
  - State Matrix: all states for Button, Input, Select, Card with
    background, border, text, icon mappings
  - Component Aliases: button.*, input.*, select.*, card.* mapped
    to semantic tokens
  - Dark Mode: token value swapping without component code changes
  - Validation: component token audit (0 direct color references)

- COMPLIANCE_MATRIX.md: Semantic Color System 70%

Rationale: Semantic model first, not colors. Components never reference
primitives directly. Every token has a contract (purpose, allowed, forbidden).
Dark mode via token swap. State matrix derived from existing components.
This commit is contained in:
Bernt
2026-07-02 10:53:42 +00:00
parent 13fea4a301
commit 3335edeed8
2 changed files with 277 additions and 0 deletions
+1
View File
@@ -77,6 +77,7 @@
| Release Definition | 🟡 | 80% |
| Brand Palette | 🟡 | 40% |
| Grid & Elevation | 🟡 | 60% |
| Semantic Color System | 🟡 | 70% |
---
+276
View File
@@ -0,0 +1,276 @@
# SEMANTIC COLOR SYSTEM
**Semantic Token Model for Landvex Design System**
| | |
|---|---|
| **Version** | 1.0 |
| **Status** | DRAFT |
| **Scope** | All Landvex & quiXzoom products |
| **Authority** | DESIGN_SPECIFICATION (nivå 5) |
---
## 1. PRINCIPLES
**MUST NOT:** Reference primitive colors (`blue-500`, `gray-900`) from components.
**MUST:** Use semantic tokens (`color.action.primary`, `color.surface.default`) for all component styling.
**MUST:** Document purpose, allowed usage, and forbidden usage for every semantic token.
---
## 2. TOKEN ARCHITECTURE
### 2.1 Three Layers
```
Layer 1: Primitive Tokens (color values)
Layer 2: Semantic Tokens (purpose-driven)
Layer 3: Component Aliases (component-specific)
```
**Layer 1 — Primitives:** Raw color values. `blue-500`, `gray-900`, `green-600`.
**Layer 2 — Semantic:** Purpose-driven. `color.action.primary`, `color.surface.default`.
**Layer 3 — Component Aliases:** Component-specific mappings. `button.primary.background`, `card.border`.
### 2.2 Naming Convention
```
color.{category}.{role}
```
| Category | Role | Example |
|----------|------|---------|
| `action` | `primary`, `secondary`, `ghost` | `color.action.primary` |
| `surface` | `default`, `raised`, `overlay` | `color.surface.default` |
| `text` | `primary`, `secondary`, `muted` | `color.text.primary` |
| `border` | `default`, `focus`, `error` | `color.border.default` |
| `status` | `success`, `warning`, `danger`, `info` | `color.status.success` |
| `brand` | `primary`, `secondary` | `color.brand.primary` |
---
## 3. SEMANTIC TOKENS
### 3.1 Action Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.action.primary` | Primary call-to-action | Buttons, floating actions, primary navigation | Backgrounds, cards, decorative |
| `color.action.primary-hover` | Primary action hover | Button hover, link hover | Default state, backgrounds |
| `color.action.primary-active` | Primary action active | Button active, link active | Hover state, default state |
| `color.action.secondary` | Secondary action | Secondary buttons, outlined buttons | Primary actions, backgrounds |
| `color.action.ghost` | Ghost action | Ghost buttons, text buttons | Contained buttons, backgrounds |
| `color.action.disabled` | Disabled action | Disabled buttons, disabled inputs | Active elements, backgrounds |
### 3.2 Surface Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.surface.default` | Default background | Page background, card background | Text, borders, actions |
| `color.surface.raised` | Elevated surface | Cards, panels, modals | Page background, text |
| `color.surface.overlay` | Overlay surface | Dropdowns, menus, tooltips | Page background, cards |
| `color.surface.inverted` | Inverted surface | Dark mode backgrounds, dark sections | Light mode backgrounds |
### 3.3 Text Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.text.primary` | Primary text | Headings, body text, labels | Backgrounds, borders |
| `color.text.secondary` | Secondary text | Descriptions, metadata | Primary text, headings |
| `color.text.muted` | Muted text | Placeholders, disabled text, hints | Primary text, labels |
| `color.text.inverted` | Inverted text | Text on dark surfaces | Text on light surfaces |
| `color.text.link` | Link text | Text links, navigation links | Non-interactive text |
### 3.4 Border Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.border.default` | Default border | Input borders, card borders, dividers | Focus rings, error states |
| `color.border.focus` | Focus border | Focused input, focused button, focused select | Default state, hover state |
| `color.border.error` | Error border | Invalid input, error state | Default state, success state |
| `color.border.success` | Success border | Valid input, success state | Default state, error state |
### 3.5 Status Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.status.success` | Success state | Success messages, valid indicators, positive trends | Error states, warnings |
| `color.status.warning` | Warning state | Warning messages, caution indicators | Error states, success states |
| `color.status.danger` | Danger state | Error messages, destructive actions, negative trends | Success states, warnings |
| `color.status.info` | Info state | Informational messages, help text | Success states, warnings |
### 3.6 Brand Colors
| Token | Purpose | Allowed | Not Allowed |
|-------|---------|---------|-------------|
| `color.brand.primary` | Primary brand | Logo, brand accents, primary buttons (if brand = action) | Status indicators, data viz |
| `color.brand.secondary` | Secondary brand | Secondary accents, hover states | Status indicators, backgrounds |
---
## 4. STATE MATRIX
### 4.1 States by Component
#### Button States
| State | Background | Border | Text | Icon |
|-------|------------|--------|------|------|
| Default | `color.action.primary` | transparent | `color.text.inverted` | `color.text.inverted` |
| Hover | `color.action.primary-hover` | transparent | `color.text.inverted` | `color.text.inverted` |
| Focus | `color.action.primary` | `color.border.focus` | `color.text.inverted` | `color.text.inverted` |
| Active | `color.action.primary-active` | transparent | `color.text.inverted` | `color.text.inverted` |
| Disabled | `color.action.disabled` | transparent | `color.text.muted` | `color.text.muted` |
| Loading | `color.action.primary` | transparent | `color.text.inverted` | spinner |
#### Input States
| State | Background | Border | Text | Icon |
|-------|------------|--------|------|------|
| Default | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` |
| Hover | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` |
| Focus | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` |
| Active | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` |
| Disabled | `color.surface.raised` | `color.border.default` | `color.text.muted` | `color.text.muted` |
| Error | `color.surface.default` | `color.border.error` | `color.text.primary` | `color.status.danger` |
| Loading | `color.surface.default` | `color.border.default` | `color.text.muted` | spinner |
#### Select States
| State | Background | Border | Text | Icon |
|-------|------------|--------|------|------|
| Default | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` |
| Hover | `color.surface.default` | `color.border.default` | `color.text.primary` | `color.text.muted` |
| Focus | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` |
| Open | `color.surface.default` | `color.border.focus` | `color.text.primary` | `color.text.muted` |
| Option Hover | `color.surface.raised` | — | `color.text.primary` | — |
| Option Selected | `color.action.primary` (at 10%) | — | `color.action.primary` | checkmark |
| Option Disabled | `color.surface.raised` | — | `color.text.muted` | — |
| Disabled | `color.surface.raised` | `color.border.default` | `color.text.muted` | `color.text.muted` |
| Error | `color.surface.default` | `color.border.error` | `color.text.primary` | `color.status.danger` |
| Loading | `color.surface.default` | `color.border.default` | `color.text.muted` | spinner |
#### Card States
| State | Background | Border | Text | Shadow |
|-------|------------|--------|------|--------|
| Default | `color.surface.raised` | `color.border.default` | — | `shadow-sm` |
| Hover (interactive) | `color.surface.raised` | `color.border.default` | — | `shadow-md` |
| Active (interactive) | `color.surface.raised` | `color.border.default` | — | `shadow-sm` |
| Focus (interactive) | `color.surface.raised` | `color.border.focus` | — | `shadow-sm` |
| Loading | `color.surface.raised` | `color.border.default` | — | `shadow-sm` |
| Empty | `color.surface.raised` | `color.border.default` | `color.text.muted` | `shadow-sm` |
| Error | `color.surface.raised` | `color.border.error` | `color.text.primary` | `shadow-sm` |
---
## 5. COMPONENT ALIASES
### 5.1 Button Aliases
| Alias | Semantic Token |
|-------|---------------|
| `button.primary.background` | `color.action.primary` |
| `button.primary.background-hover` | `color.action.primary-hover` |
| `button.primary.background-active` | `color.action.primary-active` |
| `button.primary.text` | `color.text.inverted` |
| `button.disabled.background` | `color.action.disabled` |
| `button.disabled.text` | `color.text.muted` |
### 5.2 Input Aliases
| Alias | Semantic Token |
|-------|---------------|
| `input.background` | `color.surface.default` |
| `input.border` | `color.border.default` |
| `input.border-focus` | `color.border.focus` |
| `input.border-error` | `color.border.error` |
| `input.text` | `color.text.primary` |
| `input.placeholder` | `color.text.muted` |
| `input.disabled.background` | `color.surface.raised` |
| `input.disabled.text` | `color.text.muted` |
### 5.3 Select Aliases
| Alias | Semantic Token |
|-------|---------------|
| `select.background` | `color.surface.default` |
| `select.border` | `color.border.default` |
| `select.border-focus` | `color.border.focus` |
| `select.dropdown.background` | `color.surface.raised` |
| `select.option.hover` | `color.surface.raised` |
| `select.option.selected` | `color.action.primary` (at 10%) |
| `select.option.selected-text` | `color.action.primary` |
### 5.4 Card Aliases
| Alias | Semantic Token |
|-------|---------------|
| `card.background` | `color.surface.raised` |
| `card.border` | `color.border.default` |
| `card.shadow` | `shadow-sm` |
| `card.shadow-hover` | `shadow-md` |
| `card.header.text` | `color.text.primary` |
| `card.body.text` | `color.text.secondary` |
| `card.footer.text` | `color.text.muted` |
---
## 6. DARK MODE
### 6.1 Token Value Swapping
| Semantic Token | Light Mode | Dark Mode |
|---------------|-----------|-----------|
| `color.surface.default` | `gray-0` (#ffffff) | `gray-900` (#1a1a1a) |
| `color.surface.raised` | `gray-50` (#f8f9fa) | `gray-800` (#2d2d2d) |
| `color.surface.overlay` | `gray-0` (#ffffff) | `gray-800` (#2d2d2d) |
| `color.text.primary` | `gray-900` (#1a1a1a) | `gray-100` (#f8f9fa) |
| `color.text.secondary` | `gray-600` (#666666) | `gray-400` (#999999) |
| `color.text.muted` | `gray-400` (#999999) | `gray-600` (#666666) |
| `color.text.inverted` | `gray-0` (#ffffff) | `gray-900` (#1a1a1a) |
| `color.border.default` | `gray-200` (#e5e5e5) | `gray-700` (#4d4d4d) |
| `color.border.focus` | `blue-500` | `blue-400` |
| `color.action.primary` | `blue-500` | `blue-400` |
**Rule:** Dark mode is implemented by swapping primitive values behind semantic tokens. Component code does not change.
---
## 7. VALIDATION
### 7.1 Component Token Audit
| Component | Direct Color References | Status |
|-----------|------------------------|--------|
| Button | 0 | ✅ |
| Input | 0 | ✅ |
| Select | 0 | ✅ |
| Card | 0 | ✅ |
### 7.2 Compliance Matrix Update
When this document is complete, update Compliance Matrix:
- All components use semantic tokens exclusively
- No hardcoded colors
- All states have semantic tokens
- Dark mode implementable via token swap
---
## ÄNDRINGSHISTORIA
| Version | Datum | Beskrivning |
|---------|-------|-------------|
| 1.0 | 2026-07-02 | Initial semantic color system with state matrix and component aliases |
---
## STATUS
**DRAFT — Under development**