b0a1808b2b
- AI_DESIGN_PRINCIPLES.md:
- Restructured into 5 parts: A. Decision Process, B. Component Selection,
C. Token Usage, D. Design Review, E. Escalation
- All rules use RFC 2119 normative words (MUST/MUST NOT/SHOULD/MAY)
- Clearer escalation path: when to create DDR, when to flag uncertainty
- COMPLIANCE_MATRIX.md:
- Tracks readiness for all 29 components (Tier 1/2/3)
- 6 dimensions: Governance, Tokens, Motion, Accessibility, AI, QA
- Foundation documents tracked separately
- Button at 82% (reference for others)
- docs/platform/README.md:
- Reserved directory for cross-cutting governance
- Future: AI Governance, Product Governance, Review Process,
Quality Gates, Release Governance, Decision Frameworks
- Separates platform governance from design system
- LANDVEX_DESIGN_SPECIFICATION.md:
- Button renamed to RFC-001: Canonical Button Component
- Structured with: Cognitive Purpose, When to Use/NOT Use,
User Expectation, Interaction Contract, Failure Behaviour,
Accessibility Contract, AI Contract
- Sets standard for all future RFC component specs
Rationale: AI rules before components (AI writes components).
Compliance matrix makes progress visible. Platform governance
separates cross-cutting concerns from design system. RFC format
for components ensures production-ready specifications.
1096 lines
32 KiB
Markdown
1096 lines
32 KiB
Markdown
# LANDVEX DESIGN SPECIFICATION
|
||
|
||
**Technical Contract Between UX, UI, Frontend, AI Agents, QA, and Codebase**
|
||
|
||
| | |
|
||
|---|---|
|
||
| **Version** | 1.0-skeleton |
|
||
| **Status** | DRAFT — Under utveckling |
|
||
| **Scope** | Landvex Enterprise Platform |
|
||
| **Authority** | DESIGN_SPECIFICATION (nivå 5 i dokumenthierarkin) |
|
||
| **Parent** | `LANDVEX_DESIGN_CONSTITUTION.md` |
|
||
|
||
---
|
||
|
||
## PART A — GOVERNANCE
|
||
|
||
## 0. Token Philosophy
|
||
|
||
See `TOKEN_PHILOSOPHY.md` for the complete token governance rules.
|
||
|
||
**Quick Reference:**
|
||
- Three levels: Primitive → Semantic → Component
|
||
- Semantic first, primitive only when necessary
|
||
- DTCG JSON as canonical format
|
||
- Semantic versioning for token changes
|
||
- Deprecation policy: mark, maintain 2 versions, then remove
|
||
- Token lifecycle: Draft → Experimental → Stable → Deprecated → Removed
|
||
- Design Review Gate required before new token creation
|
||
|
||
---
|
||
|
||
> **Om detta dokument**
|
||
> Detta är ett levande kontrakt. Varje kapitel fylls på successivt.
|
||
> Ingen implementation får bryta mot en specificerad regel.
|
||
> Ospecificerade områden är fria att utforskas, men bör dokumenteras här när de stabiliseras.
|
||
|
||
---
|
||
|
||
## Innehållsförteckning
|
||
|
||
### PART A — GOVERNANCE
|
||
0. [Token Philosophy](#0-token-philosophy)
|
||
|
||
### PART B — TOKENS
|
||
1. [Design Tokens](#1-design-tokens)
|
||
- 1.1 Primitive Tokens
|
||
- 1.2 Semantic Tokens
|
||
- 1.3 Component Tokens
|
||
2. [Layout System](#2-layout-system)
|
||
3. [Typography](#3-typography)
|
||
4. [Color System](#4-color-system)
|
||
5. [Motion System](#5-motion-system)
|
||
6. [Elevation & Shadows](#6-elevation--shadows)
|
||
7. [Iconography](#7-iconography)
|
||
|
||
### PART C — COMPONENTS
|
||
8. [Component Architecture](#8-component-architecture)
|
||
- 8.0 Component Tiers (Tier 1/2/3)
|
||
- 8.1 Component Inheritance
|
||
- 8.2 New Component Rule
|
||
- 8.3 Component Specifications
|
||
9. [Maps & Geospatial Layer](#9-maps--geospatial-layer)
|
||
10. [Accessibility](#10-accessibility)
|
||
11. [Responsive Behavior](#11-responsive-behavior)
|
||
12. [Empty States](#12-empty-states)
|
||
13. [Loading States](#13-loading-states)
|
||
14. [Error States](#14-error-states)
|
||
|
||
### PART D — VALIDATION
|
||
15. [Acceptance Criteria](#15-acceptance-criteria)
|
||
16. [Design QA](#16-design-qa)
|
||
17. [Visual Regression](#17-visual-regression)
|
||
18. [Release Checklist](#18-release-checklist)
|
||
|
||
---
|
||
|
||
## PART B — TOKENS
|
||
|
||
## 1. Design Tokens
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
> **Parent:** `TOKEN_PHILOSOPHY.md`
|
||
|
||
### 1.0 Token Architecture
|
||
|
||
All tokens follow the three-level hierarchy defined in `TOKEN_PHILOSOPHY.md`:
|
||
|
||
```
|
||
Level 1: Primitive Tokens → Raw values (numbers, colors, dimensions)
|
||
Level 2: Semantic Tokens → Purpose-driven (surface-primary, text-muted)
|
||
Level 3: Component Tokens → Component-specific (button-primary-bg-hover)
|
||
```
|
||
|
||
**MUST:** Reference Level 2 (Semantic) by default. Level 3 (Component) only when component-specific override is required. **MUST NOT:** Reference Level 1 (Primitive) directly from components.
|
||
|
||
### 1.1 Primitive Tokens
|
||
|
||
#### 1.1.1 Spacing Scale
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `space-0` | 0px | — |
|
||
| `space-1` | 4px | Tight padding, icon gaps |
|
||
| `space-2` | 8px | Default element padding |
|
||
| `space-3` | 12px | Component internal spacing |
|
||
| `space-4` | 16px | Standard gap |
|
||
| `space-5` | 24px | Section spacing |
|
||
| `space-6` | 32px | Large section spacing |
|
||
| `space-7` | 48px | Page-level spacing |
|
||
| `space-8` | 64px | Major section breaks |
|
||
| `space-9` | 96px | Hero/page top |
|
||
|
||
#### 1.1.2 Border Radius
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `radius-0` | 0px | Sharp edges (data tables, maps) |
|
||
| `radius-1` | 2px | Subtle rounding |
|
||
| `radius-2` | 4px | Default (buttons, inputs) |
|
||
| `radius-3` | 8px | Cards, panels |
|
||
| `radius-4` | 12px | Large cards, modals |
|
||
| `radius-full` | 9999px | Pills, avatars |
|
||
|
||
#### 1.1.3 Z-Index Scale
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `z-base` | 0 | Default layer |
|
||
| `z-dropdown` | 100 | Dropdowns, popovers |
|
||
| `z-sticky` | 200 | Sticky headers |
|
||
| `z-modal` | 300 | Modals, dialogs |
|
||
| `z-tooltip` | 400 | Tooltips |
|
||
| `z-toast` | 500 | Notifications |
|
||
| `z-overlay` | 600 | Full-screen overlays |
|
||
|
||
#### 1.1.4 Opacity Scale
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `opacity-0` | 0% | Hidden |
|
||
| `opacity-25` | 25% | Disabled text |
|
||
| `opacity-50` | 50% | Placeholder text |
|
||
| `opacity-75` | 75% | Secondary text |
|
||
| `opacity-100` | 100% | Primary content |
|
||
|
||
#### 1.1.5 Blur Scale
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `blur-0` | 0px | No blur |
|
||
| `blur-sm` | 4px | Subtle backdrop |
|
||
| `blur-md` | 8px | Modal backdrop |
|
||
| `blur-lg` | 16px | Full-screen overlay |
|
||
|
||
#### 1.1.6 Border Width
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `border-0` | 0px | No border |
|
||
| `border-1` | 1px | Default dividers |
|
||
| `border-2` | 2px | Focus rings, active states |
|
||
| `border-4` | 4px | Emphasis, errors |
|
||
|
||
### 1.2 Semantic Tokens
|
||
|
||
#### 1.2.1 Surface Colors
|
||
|
||
| Token | Primitive Reference | Usage |
|
||
|-------|---------------------|-------|
|
||
| `surface-primary` | `neutral-0` | Main background |
|
||
| `surface-secondary` | `neutral-50` | Card background |
|
||
| `surface-elevated` | `neutral-0` + shadow | Modal, popover |
|
||
| `surface-overlay` | `neutral-1000` @ 50% | Backdrop |
|
||
|
||
#### 1.2.2 Text Colors
|
||
|
||
| Token | Primitive Reference | Usage |
|
||
|-------|---------------------|-------|
|
||
| `text-primary` | `neutral-1000` | Headings, body |
|
||
| `text-secondary` | `neutral-600` | Captions, metadata |
|
||
| `text-muted` | `neutral-400` | Placeholders |
|
||
| `text-inverse` | `neutral-0` | On dark surfaces |
|
||
|
||
#### 1.2.3 Border Colors
|
||
|
||
| Token | Primitive Reference | Usage |
|
||
|-------|---------------------|-------|
|
||
| `border-default` | `neutral-200` | Dividers |
|
||
| `border-focus` | `brand-500` | Focus rings |
|
||
| `border-error` | `semantic-red-500` | Error states |
|
||
|
||
### 1.3 Component Tokens
|
||
|
||
#### 1.3.1 Button
|
||
|
||
| Token | Semantic Reference | Usage |
|
||
|-------|-------------------|-------|
|
||
| `button-primary-bg` | `surface-primary` | Default background |
|
||
| `button-primary-bg-hover` | `brand-600` | Hover state |
|
||
| `button-primary-text` | `text-inverse` | Label color |
|
||
|
||
#### 1.3.2 Data Grid
|
||
|
||
| Token | Semantic Reference | Usage |
|
||
|-------|-------------------|-------|
|
||
| `table-row-hover` | `neutral-50` | Hover highlight |
|
||
| `table-header-bg` | `neutral-100` | Header background |
|
||
|
||
### 1.4 Export Format
|
||
|
||
Canonical: DTCG JSON. Derived: CSS custom properties, Tailwind config, Swift, Kotlin.
|
||
|
||
See `TOKEN_PHILOSOPHY.md` §3 for full specification.
|
||
|
||
---
|
||
|
||
## 2. Layout System
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 2.1 Grid
|
||
|
||
### 2.2 Breakpoints
|
||
|
||
| Name | Width | Target |
|
||
|------|-------|--------|
|
||
| `xs` | 0px | Phone portrait |
|
||
| `sm` | 640px | Phone landscape |
|
||
| `md` | 768px | Tablet portrait |
|
||
| `lg` | 1024px | Tablet landscape / small desktop |
|
||
| `xl` | 1280px | Desktop |
|
||
| `2xl` | 1536px | Large desktop |
|
||
|
||
### 2.3 Container Widths
|
||
|
||
### 2.4 Sidebar / Panel System
|
||
|
||
---
|
||
|
||
## 3. Typography
|
||
|
||
> **Status:** ✅ Specified
|
||
> **Principle:** Typography is the foundation of information hierarchy. It must be readable, scannable, and calm.
|
||
|
||
### 3.1 Font Stack
|
||
|
||
| Role | Font | Fallback | Usage |
|
||
|------|------|----------|-------|
|
||
| **Primary** | Inter | system-ui, -apple-system, sans-serif | All UI text, headings, body |
|
||
| **Monospace** | JetBrains Mono | ui-monospace, SFMono-Regular, monospace | Data, code, coordinates, tabular figures |
|
||
|
||
**Rationale:** Inter is designed for screen readability at small sizes. JetBrains Mono distinguishes similar characters (0/O, 1/l/I) — critical for geodata.
|
||
|
||
### 3.2 Font Fallback Strategy
|
||
|
||
```css
|
||
/* Primary */
|
||
font-family: 'Inter', system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
||
|
||
/* Monospace */
|
||
font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;
|
||
```
|
||
|
||
### 3.3 Variable Font
|
||
|
||
- **Inter:** Variable font enabled (weight 100–900)
|
||
- **JetBrains Mono:** Static weights only (400, 500, 700)
|
||
- **Performance:** Subset to Latin Extended + Swedish characters
|
||
|
||
### 3.4 Type Scale
|
||
|
||
| Token | Size | Line Height | Weight | Letter Spacing | Usage |
|
||
|-------|------|-------------|--------|----------------|-------|
|
||
| `text-xs` | 12px | 16px | 400 | 0.01em | Captions, metadata, timestamps |
|
||
| `text-sm` | 14px | 20px | 400 | 0 | Body small, secondary text |
|
||
| `text-base` | 16px | 24px | 400 | 0 | Body, paragraphs |
|
||
| `text-lg` | 18px | 28px | 400 | -0.01em | Lead paragraph, emphasis |
|
||
| `text-xl` | 20px | 28px | 500 | -0.02em | Section headers, card titles |
|
||
| `text-2xl` | 24px | 32px | 500 | -0.02em | Page titles, modal headers |
|
||
| `text-3xl` | 30px | 36px | 600 | -0.02em | Major headings, dashboard titles |
|
||
| `text-4xl` | 36px | 40px | 600 | -0.03em | Hero titles, empty states |
|
||
|
||
### 3.5 Information Levels
|
||
|
||
Typography is defined by **function**, not heading level.
|
||
|
||
| Level | Token | Weight | Usage | Frequency |
|
||
|-------|-------|--------|-------|-----------|
|
||
| **Display** | `text-4xl` | 600 | Landing pages, special overviews | Very rare |
|
||
| **Section Title** | `text-3xl` | 600 | Page titles, major sections | Rare |
|
||
| **Panel Title** | `text-2xl` | 500 | Card titles, modal headers | Common |
|
||
| **Data Heading** | `text-xl` | 500 | Table headers, KPI groups, map layers | Frequent |
|
||
| **Body** | `text-base` | 400 | Running text, descriptions | Default |
|
||
| **UI Label** | `text-sm` | 500 | Form labels, control labels | Frequent |
|
||
| **Metadata** | `text-sm` | 400 | Dates, status, secondary info | Frequent |
|
||
| **Caption** | `text-xs` | 400 | Help text, explanations | Common |
|
||
| **Code / Numeric** | `text-sm` | 400 | Code, coordinates, IDs, numbers | As needed |
|
||
|
||
**Rationale:** Enterprise users scan for information, not headings. Functional levels map to mental models better than H1–H6.
|
||
|
||
**Note:** When HTML heading elements are required for accessibility, map functionally:
|
||
- Display → H1 (once per page)
|
||
- Section Title → H2
|
||
- Panel Title → H3
|
||
- Data Heading → H4
|
||
- UI Label → label element (not heading)
|
||
|
||
### 3.6 Font Weights
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `font-normal` | 400 | Body, descriptions |
|
||
| `font-medium` | 500 | Emphasis, labels, buttons |
|
||
| `font-semibold` | 600 | Headings, active states |
|
||
| `font-bold` | 700 | Strong emphasis, alerts |
|
||
|
||
### 3.7 Line Height Rules
|
||
|
||
| Context | Rule | Rationale |
|
||
|---------|------|-----------|
|
||
| Body text | 1.5× font size | Readability for long text |
|
||
| Headings | 1.2–1.3× font size | Tight, scannable |
|
||
| Data/numbers | 1.25× font size | Alignment in tables |
|
||
| Captions | 1.4× font size | Small text needs air |
|
||
|
||
### 3.8 Letter Spacing
|
||
|
||
| Context | Value | Rationale |
|
||
|---------|-------|-----------|
|
||
| Body | 0 | Natural reading |
|
||
| Headings | -0.02em | Tighter, more impactful |
|
||
| All-caps labels | 0.05em | Improves legibility |
|
||
| Captions | 0.01em | Slight openness |
|
||
|
||
### 3.9 Max Line Length
|
||
|
||
| Context | Max Width | Rationale |
|
||
|---------|-----------|-----------|
|
||
| Body text | 65ch | Optimal reading width |
|
||
| Data tables | none | Full width |
|
||
| Side panels | 45ch | Narrow column readability |
|
||
|
||
### 3.10 Monospace Usage
|
||
|
||
| Context | Font | Features |
|
||
|---------|------|----------|
|
||
| Coordinates | JetBrains Mono | Tabular figures, always |
|
||
| Financial data | JetBrains Mono | Tabular figures, decimal alignment |
|
||
| Code snippets | JetBrains Mono | Ligatures disabled |
|
||
| Timestamps | JetBrains Mono | Fixed width for alignment |
|
||
|
||
### 3.11 Tabular Figures
|
||
|
||
**Always enabled for:**
|
||
- Data tables
|
||
- Financial values
|
||
- Coordinates (lat/long)
|
||
- Timestamps
|
||
- IDs and reference numbers
|
||
|
||
```css
|
||
font-variant-numeric: tabular-nums;
|
||
```
|
||
|
||
### 3.12 Numerical Typography
|
||
|
||
| Rule | Value | Example |
|
||
|------|-------|---------|
|
||
| Decimal separator | `.` (period) | `123.45` |
|
||
| Thousands separator | ` ` (space) | `1 234 567` |
|
||
| Negative numbers | `-` prefix | `-456.78` |
|
||
| Percentage | No space before `%` | `42.5%` |
|
||
| Currency | Symbol before, space after | `$ 1 234.56` |
|
||
|
||
---
|
||
|
||
## 4. Color System
|
||
|
||
> **Status:** ✅ Foundation specified, Brand & Map pending
|
||
> **Principle:** Information dominates color. Color supports, never competes.
|
||
|
||
### 4.1 Foundation Colors (Neutral Palette)
|
||
|
||
**Primitive Tokens:**
|
||
|
||
| Token | Hex | Usage |
|
||
|-------|-----|-------|
|
||
| `neutral-0` | `#ffffff` | Pure white, highest elevation |
|
||
| `neutral-50` | `#f8f9fa` | Card backgrounds, hover states |
|
||
| `neutral-100` | `#f1f3f5` | Subtle backgrounds, table headers |
|
||
| `neutral-200` | `#e9ecef` | Borders, dividers |
|
||
| `neutral-300` | `#dee2e6` | Disabled backgrounds |
|
||
| `neutral-400` | `#ced4da` | Placeholder text, inactive icons |
|
||
| `neutral-500` | `#adb5bd` | Secondary text, muted elements |
|
||
| `neutral-600` | `#868e96` | Captions, metadata |
|
||
| `neutral-700` | `#495057` | Body text secondary |
|
||
| `neutral-800` | `#343a40` | Body text primary |
|
||
| `neutral-900` | `#212529` | Headings, primary text |
|
||
| `neutral-1000` | `#0f172a` | Deepest surfaces, overlays |
|
||
|
||
**Rationale:** 12-step scale provides sufficient granularity without excess. Based on open-source neutral scales (Open Color, Tailwind) for familiarity.
|
||
|
||
### 4.2 Semantic Colors
|
||
|
||
**Rule:** Semantic colors communicate meaning. Brand colors communicate identity. Never mix the two.
|
||
|
||
#### 4.2.1 Neutral Semantic
|
||
|
||
| Token | Primitive | Usage |
|
||
|-------|-----------|-------|
|
||
| `surface-primary` | `neutral-0` | Main background |
|
||
| `surface-secondary` | `neutral-50` | Card background |
|
||
| `surface-tertiary` | `neutral-100` | Table header, subtle fill |
|
||
| `surface-overlay` | `neutral-1000` @ 50% | Modal backdrop |
|
||
| `text-primary` | `neutral-900` | Headings, body |
|
||
| `text-secondary` | `neutral-600` | Captions, metadata |
|
||
| `text-muted` | `neutral-400` | Placeholders, disabled |
|
||
| `text-inverse` | `neutral-0` | On dark surfaces |
|
||
| `border-default` | `neutral-200` | Dividers, outlines |
|
||
| `border-strong` | `neutral-300` | Focus states, active |
|
||
|
||
#### 4.2.2 Status Semantic
|
||
|
||
| Token | Primitive | Usage |
|
||
|-------|-----------|-------|
|
||
| `success-surface` | `green-50` | Success background |
|
||
| `success-border` | `green-200` | Success outline |
|
||
| `success-text` | `green-700` | Success message |
|
||
| `warning-surface` | `yellow-50` | Warning background |
|
||
| `warning-border` | `yellow-200` | Warning outline |
|
||
| `warning-text` | `yellow-700` | Warning message |
|
||
| `danger-surface` | `red-50` | Error background |
|
||
| `danger-border` | `red-200` | Error outline |
|
||
| `danger-text` | `red-700` | Error message |
|
||
| `info-surface` | `blue-50` | Info background |
|
||
| `info-border` | `blue-200` | Info outline |
|
||
| `info-text` | `blue-700` | Info message |
|
||
|
||
**Rule:** Status colors are never used for branding. Brand colors are never used for status.
|
||
|
||
### 4.3 Brand Palette
|
||
|
||
> **Status:** ⏳ Pending brand definition
|
||
|
||
Landvex brand colors are used sparingly (5–10% of surface area).
|
||
|
||
| Token | Hex | Usage |
|
||
|-------|-----|-------|
|
||
| `brand-50` | — | Lightest tint |
|
||
| `brand-100` | — | Hover backgrounds |
|
||
| `brand-200` | — | Subtle highlights |
|
||
| `brand-300` | — | — |
|
||
| `brand-400` | — | — |
|
||
| `brand-500` | — | Primary action, links |
|
||
| `brand-600` | — | Hover state |
|
||
| `brand-700` | — | Active state |
|
||
| `brand-800` | — | — |
|
||
| `brand-900` | — | Deepest shade |
|
||
|
||
**MUST NOT:** Use brand colors in data visualization or map layers. **MUST NOT:** Use brand colors to communicate status. Brand = identity. Semantic = meaning. **MUST NOT** mix.
|
||
|
||
### 4.4 Semantic Status Colors
|
||
|
||
| Token | Hex | Usage |
|
||
|-------|-----|-------|
|
||
| `semantic-green-500` | `#40c057` | Success, active, positive |
|
||
| `semantic-yellow-500` | `#fcc419` | Warning, pending, attention |
|
||
| `semantic-red-500` | `#fa5252` | Error, danger, negative |
|
||
| `semantic-blue-500` | `#339af0` | Info, neutral highlight |
|
||
|
||
### 4.5 Data Visualization Colors
|
||
|
||
> **Status:** ⏳ Pending data viz requirements
|
||
|
||
Separate palette for charts, graphs, KPIs. Must be:
|
||
- Colorblind-safe
|
||
- Distinguishable in monochrome
|
||
- Consistent across all data products
|
||
|
||
### 4.6 Map Layer Palette
|
||
|
||
> **Status:** ⏳ Pending Mapbox configuration
|
||
|
||
Dedicated palette for geospatial visualization. Defined by **layer**, not individual color:
|
||
|
||
| Layer | Token | Rationale |
|
||
|-------|-------|-----------|
|
||
| Base Surface | `map-base-surface` | Subtle, non-competing |
|
||
| Terrain | `map-terrain` | Elevation indication |
|
||
| Water | `map-water` | Consistent with cartographic convention |
|
||
| Road Network | `map-road` | Hierarchy (motorway → path) |
|
||
| Administrative Boundaries | `map-boundary` | Dashed, muted |
|
||
| Building Footprints | `map-building` | Subtle 3D effect |
|
||
| Parcel Boundaries | `map-parcel` | Land ownership |
|
||
| Mission Layer | `map-mission` | Brand color, high visibility |
|
||
| Heatmap | `map-heatmap` | Gradient from neutral to alert |
|
||
| Selection | `map-selection` | Clear, non-intrusive |
|
||
| Hover | `map-hover` | Interactive feedback |
|
||
| Overlay | `map-overlay` | Contextual information |
|
||
| Night Accent | `map-night` | Dark mode adaptation |
|
||
| Satellite Accent | `map-satellite` | Satellite imagery overlay |
|
||
|
||
**Principle:** Map colors must work in all lighting conditions and never compete with data overlays.
|
||
|
||
**Rule:** Changing map style (light/dark/satellite) should only require swapping the map layer palette, not component colors.
|
||
|
||
---
|
||
|
||
## 5. Motion System
|
||
|
||
> **Status:** ✅ Specified
|
||
> **Principle:** Motion supports understanding. It never decorates.
|
||
|
||
### 5.1 Motion Principles
|
||
|
||
**When to animate:**
|
||
- State changes that need attention (modal open, toast appear)
|
||
- Spatial relationships (drawer slide, page transition)
|
||
- Feedback on user action (button press, form submit)
|
||
- Loading and progress (skeleton, progress bar)
|
||
|
||
**When NOT to animate:**
|
||
- Static content that does not change
|
||
- Data updates that are frequent (live dashboards)
|
||
- Elements entering viewport on scroll (use Intersection Observer, not animation)
|
||
- Anything that delays user action
|
||
|
||
**Rules:**
|
||
- Animations must be interruptible
|
||
- Multiple animations must not conflict
|
||
- Motion must respect `prefers-reduced-motion`
|
||
|
||
### 5.2 Duration Tokens (Intention-Based)
|
||
|
||
Tokens are named by **intention**, not duration. AI and developers reason about purpose, not milliseconds.
|
||
|
||
| Token | Value | Intention | Usage |
|
||
|-------|-------|-----------|-------|
|
||
| `duration-instant` | 0ms | No perceived time | State changes that must feel immediate |
|
||
| `duration-interaction` | 100ms | Micro-feedback | Hover, focus, press, toggle |
|
||
| `duration-transition` | 200ms | Element state change | Appear, disappear, expand, collapse |
|
||
| `duration-navigation` | 300ms | View change | Page transition, drawer, modal |
|
||
| `duration-layout` | 400ms | Structural shift | Sidebar expand, grid reorder |
|
||
| `duration-context-change` | 500ms | Major context switch | Full-screen overlay, wizard step |
|
||
| `duration-attention` | 600ms | Draw attention | Toast, alert, notification |
|
||
| `duration-background` | 1000ms | Ambient, non-blocking | Skeleton shimmer, progress sweep |
|
||
|
||
**Mapping to traditional terms:**
|
||
- `duration-interaction` ≈ "fast"
|
||
- `duration-transition` ≈ "normal"
|
||
- `duration-navigation` ≈ "slow"
|
||
- `duration-context-change` ≈ "slower"
|
||
|
||
### 5.3 Easing Functions
|
||
|
||
| Token | Value | Usage |
|
||
|-------|-------|-------|
|
||
| `ease-linear` | linear | Continuous motion, progress bars |
|
||
| `ease-in` | cubic-bezier(0.4, 0, 1, 1) | Exit animations, dismiss |
|
||
| `ease-out` | cubic-bezier(0, 0, 0.2, 1) | Enter animations, appear |
|
||
| `ease-in-out` | cubic-bezier(0.4, 0, 0.2, 1) | Standard, symmetric |
|
||
| `ease-spring` | cubic-bezier(0.34, 1.56, 0.64, 1) | Playful, overshoot |
|
||
|
||
### 5.4 Component-Specific Motion
|
||
|
||
#### 5.4.1 Button
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Hover | Background color shift | `duration-interaction` | ease-out |
|
||
| Press | Scale to 0.98 | `duration-instant` | ease-in |
|
||
| Release | Scale to 1.0 | `duration-interaction` | ease-out |
|
||
| Loading | Spinner rotation | `duration-background` | linear infinite |
|
||
| Disabled | Opacity to 0.5 | `duration-interaction` | ease-in-out |
|
||
|
||
#### 5.4.2 Modal
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Open | Fade in + scale from 0.95 | `duration-navigation` | ease-out |
|
||
| Close | Fade out + scale to 0.95 | `duration-transition` | ease-in |
|
||
| Backdrop | Fade to 50% opacity | `duration-navigation` | ease-in-out |
|
||
|
||
#### 5.4.3 Drawer
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Open | Slide from edge | `duration-navigation` | ease-out |
|
||
| Close | Slide to edge | `duration-transition` | ease-in |
|
||
| Backdrop | Fade to 50% opacity | `duration-navigation` | ease-in-out |
|
||
|
||
#### 5.4.4 Map Transitions
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Pan | None (instant) | `duration-instant` | — |
|
||
| Zoom | Smooth interpolation | `duration-navigation` | ease-in-out |
|
||
| Layer toggle | Cross-fade | `duration-transition` | ease-in-out |
|
||
| Feature select | Highlight pulse | `duration-navigation` | ease-out |
|
||
|
||
**MUST NOT:** Animate map panning. Users need instant feedback on drag.
|
||
|
||
#### 5.4.5 Skeleton
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Loading | Shimmer sweep | `duration-background` | ease-in-out infinite |
|
||
| Complete | Fade to content | `duration-transition` | ease-out |
|
||
|
||
#### 5.4.6 Progress
|
||
|
||
| State | Animation | Duration | Easing |
|
||
|-------|-----------|----------|--------|
|
||
| Indeterminate | Sweep | `duration-background` | linear infinite |
|
||
| Determinate | Width growth | `duration-navigation` | ease-out |
|
||
| Complete | Checkmark draw | `duration-transition` | ease-out |
|
||
|
||
### 5.5 Reduced Motion
|
||
|
||
When `prefers-reduced-motion: reduce` is active:
|
||
|
||
- All animations become instant (0ms)
|
||
- Skeleton shows static placeholder (no shimmer)
|
||
- Progress shows static bar (no sweep)
|
||
- Map zoom uses instant jump (no interpolation)
|
||
- Modals and drawers appear instantly (no fade/scale)
|
||
|
||
**Exception:** Loading spinners may rotate slowly (2s per rotation) to indicate activity without motion.
|
||
|
||
### 5.6 Interruptions
|
||
|
||
**MUST:** Animations be interruptible.
|
||
|
||
- If a modal is closing and user opens another, the first must complete or reverse instantly
|
||
- If a drawer is sliding and user taps backdrop, it must reverse direction
|
||
- No animation queue buildup
|
||
|
||
### 5.7 Error and Success Animations
|
||
|
||
| Type | Animation | Duration | Purpose |
|
||
|------|-----------|----------|---------|
|
||
| Error | Subtle shake (4px, 3 cycles) | `duration-navigation` | Indicate invalid input |
|
||
| Success | Checkmark draw + fade | `duration-layout` | Confirm completion |
|
||
| Warning | Pulse border color | `duration-attention` | Draw attention without alarm |
|
||
|
||
---
|
||
|
||
## 6. Elevation & Shadows
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 6.1 Shadow Scale
|
||
|
||
### 6.2 Usage Rules
|
||
|
||
---
|
||
|
||
## 7. Iconography
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 7.1 Icon Set
|
||
|
||
### 7.2 Icon Sizes
|
||
|
||
### 7.3 Icon + Text Pairing
|
||
|
||
---
|
||
|
||
## PART C — COMPONENTS
|
||
|
||
## 8. Component Architecture
|
||
|
||
> **Status:** ✅ Specified
|
||
> **Principle:** The system shall be minimal, not maximal. Extend only when a recurring need cannot be solved with existing components.
|
||
|
||
### 8.0 Component Tiers
|
||
|
||
#### Tier 1 — Canonical Components
|
||
|
||
These define the entire design system. If these are correct, everything else follows.
|
||
|
||
| Component | Purpose | Inherits From |
|
||
|-----------|---------|---------------|
|
||
| **Button** | Primary action trigger | — |
|
||
| **Input** | Text entry, form fields | — |
|
||
| **Select** | Choice from predefined options | — |
|
||
| **Card** | Content container, elevation | — |
|
||
| **Modal** | Overlay dialog, focus trap | — |
|
||
| **Navigation** | Primary wayfinding | — |
|
||
| **Table** | Tabular data display | — |
|
||
| **Data Grid** | Complex data with sorting/filtering | Table |
|
||
| **Search** | Find and filter | Input |
|
||
| **Map Panel** | Geospatial information overlay | Card |
|
||
|
||
#### Tier 2 — Derived Components
|
||
|
||
These build primarily on Tier 1. They introduce no new visual rules.
|
||
|
||
| Component | Purpose | Inherits From |
|
||
|-----------|---------|---------------|
|
||
| **Badge** | Status indicator | — |
|
||
| **Alert** | Contextual message | Card |
|
||
| **Toast** | Transient notification | Card |
|
||
| **Tooltip** | Contextual help | — |
|
||
| **Accordion** | Collapsible content sections | Card |
|
||
| **Tabs** | Content switching | — |
|
||
| **Breadcrumb** | Location indicator | — |
|
||
| **Pagination** | Page navigation | Button |
|
||
| **Empty State** | No content placeholder | Card |
|
||
| **Skeleton** | Loading placeholder | — |
|
||
|
||
#### Tier 3 — Domain Components
|
||
|
||
Landvex-specific. They explicitly build on Tier 1 and Tier 2. No new visual rules.
|
||
|
||
| Component | Purpose | Inherits From |
|
||
|-----------|---------|---------------|
|
||
| **KPI Card** | Key metric display | Card |
|
||
| **Map Overlay Panel** | Geospatial tool panel | Map Panel |
|
||
| **Layer Selector** | Map layer toggle | Select |
|
||
| **Mission Status** | Mission state indicator | Badge |
|
||
| **Dataset Card** | Data source preview | Card |
|
||
| **Geospatial Inspector** | Feature detail view | Card |
|
||
| **Asset Summary** | Asset overview panel | Card |
|
||
| **Coordinate Picker** | Lat/long input | Input |
|
||
| **Timeline Panel** | Temporal data view | Card |
|
||
|
||
### 8.1 Component Inheritance
|
||
|
||
Components inherit visual properties, states, and behavior from their parent. Child components may add but never override parent rules.
|
||
|
||
```
|
||
Button
|
||
├── Icon Button (adds icon, keeps all Button states)
|
||
├── Split Button (adds dropdown, keeps primary action)
|
||
└── Floating Action Button (fixed position, keeps Button behavior)
|
||
|
||
Card
|
||
├── KPI Card (adds metric layout, keeps Card elevation)
|
||
├── Dataset Card (adds metadata, keeps Card structure)
|
||
└── Mission Card (adds status, keeps Card padding)
|
||
|
||
Table
|
||
├── Data Grid (adds sorting/filtering, keeps Table structure)
|
||
├── Inspection Grid (adds checkboxes, keeps Data Grid behavior)
|
||
└── Asset Grid (adds thumbnails, keeps Data Grid behavior)
|
||
```
|
||
|
||
### 8.2 New Component Rule
|
||
|
||
**New component is the last resort.**
|
||
|
||
Before a new component may be created, verify:
|
||
|
||
1. **Can an existing component be used?**
|
||
2. **Can a variant be created?**
|
||
3. **Can a modifier be used?**
|
||
4. **Can a new state solve the problem?**
|
||
|
||
Only then may a new component be defined.
|
||
|
||
**New components must:**
|
||
- Inherit from an existing component when possible
|
||
- Follow the three-tier hierarchy
|
||
- Include full specification (states, ARIA, keyboard, touch, animation, acceptance criteria)
|
||
- Pass Design Review Gate
|
||
|
||
---
|
||
|
||
## 8.3 Component Specifications
|
||
|
||
> **Princip:** Varje komponent har en egen specifikation med states, ARIA, keyboard, touch, animation och acceptance criteria.
|
||
|
||
### RFC-001: Canonical Button Component
|
||
|
||
**Status:** ✅ Approved as reference implementation
|
||
**Tier:** 1 (Canonical)
|
||
**Inherits From:** — (root component)
|
||
|
||
---
|
||
|
||
#### Cognitive Purpose
|
||
|
||
Button exists to trigger actions that modify state or advance workflow. It is the primary interface between user intent and system response.
|
||
|
||
#### When to Use
|
||
|
||
- Primary user action (submit, confirm, save)
|
||
- Form submission
|
||
- Dialog confirmation
|
||
- Action that requires explicit user commitment
|
||
|
||
#### When NOT to Use
|
||
|
||
- Navigation (use Link)
|
||
- Toggling state (use Switch)
|
||
- Selecting from options (use Select)
|
||
- Secondary information reveal (use Accordion)
|
||
|
||
#### User Expectation
|
||
|
||
- Button is clickable
|
||
- Button responds immediately to press
|
||
- Button indicates if action is in progress
|
||
- Button indicates if action is unavailable
|
||
|
||
#### Interaction Contract
|
||
|
||
| Event | Response |
|
||
|-------|----------|
|
||
| Click | Action executes |
|
||
| Hover | Visual feedback only |
|
||
| Focus | Keyboard can activate |
|
||
| Loading | Further clicks ignored |
|
||
| Disabled | Action unavailable |
|
||
|
||
#### Failure Behaviour
|
||
|
||
| Scenario | Response |
|
||
|----------|----------|
|
||
| Action fails | Button returns to default, error shown elsewhere |
|
||
| Network fails | Button remains loading until timeout, then error |
|
||
| Validation fails | Button remains enabled, form shows errors |
|
||
|
||
#### Accessibility Contract
|
||
|
||
- Screen reader announces button role and label
|
||
- Focus is visible and logical
|
||
- Disabled state is communicated
|
||
- Loading state is communicated
|
||
|
||
#### AI Contract
|
||
|
||
| Scenario | AI Choice |
|
||
|----------|-----------|
|
||
| Primary action | Button |
|
||
| Navigation | Link |
|
||
| Toolbar action | Icon Button |
|
||
| Primary + secondary options | Split Button |
|
||
|
||
---
|
||
|
||
#### Token Dependencies
|
||
- `button-primary-bg` → `brand-500`
|
||
- `button-primary-bg-hover` → `brand-600`
|
||
- `button-primary-text` → `text-inverse`
|
||
- `button-secondary-bg` → `surface-secondary`
|
||
- `button-secondary-border` → `border-default`
|
||
- `button-ghost-text` → `brand-500`
|
||
- `space-padding-button` → `space-3` (12px vertical, `space-4` horizontal)
|
||
- `radius-button` → `radius-2` (4px)
|
||
|
||
**Layout:**
|
||
- Height: 40px (default), 32px (small), 48px (large)
|
||
- Padding: 12px vertical, 16px horizontal
|
||
- Icon + text gap: 8px
|
||
- Border radius: 4px
|
||
|
||
**Sizes:**
|
||
|
||
| Size | Height | Padding | Font | Usage |
|
||
|------|--------|---------|------|-------|
|
||
| Small | 32px | 8px 12px | `text-sm` | Dense UIs, tables |
|
||
| Default | 40px | 12px 16px | `text-base` | Standard |
|
||
| Large | 48px | 16px 24px | `text-lg` | Hero actions, mobile |
|
||
|
||
**Variants:**
|
||
|
||
| Variant | Background | Border | Text | Usage |
|
||
|---------|------------|--------|------|-------|
|
||
| Primary | `brand-500` | None | White | Main action |
|
||
| Secondary | `surface-secondary` | `border-default` | `text-primary` | Alternative action |
|
||
| Ghost | Transparent | None | `brand-500` | Low emphasis |
|
||
| Danger | `semantic-red-500` | None | White | Destructive action |
|
||
| Icon-only | Any above | None | CurrentColor | Toolbar, compact |
|
||
|
||
**States:**
|
||
|
||
| State | Visual | Motion |
|
||
|-------|--------|--------|
|
||
| Default | As variant | None |
|
||
| Hover | Darken 10% | Background shift `duration-interaction` ease-out |
|
||
| Focus | 2px ring `border-focus` | Ring appear `duration-interaction` ease-out |
|
||
| Pressed | Scale 0.98 | Scale `duration-instant` ease-in |
|
||
| Loading | Spinner replaces text | Spinner `duration-background` linear infinite |
|
||
| Disabled | Opacity 0.5, no pointer | None |
|
||
|
||
**Keyboard:**
|
||
- `Tab`: Focus
|
||
- `Enter` / `Space`: Activate
|
||
- Disabled: Not focusable
|
||
|
||
**Touch:**
|
||
- Min 44x44px touch target
|
||
- Active state on press (immediate)
|
||
- No hover state on touch
|
||
|
||
**Accessibility:**
|
||
- `role="button"`
|
||
- `aria-label` for icon-only
|
||
- `aria-disabled` for disabled
|
||
- `aria-busy` for loading
|
||
- Focus ring always visible
|
||
|
||
**Anti-Patterns:**
|
||
- ❌ Two primary buttons in same view
|
||
- ❌ Disabled button without explanation
|
||
- ❌ Button that looks like link
|
||
- ❌ Loading button that remains clickable
|
||
|
||
**Related Components:**
|
||
- Split Button (extends Button)
|
||
- Icon Button (extends Button)
|
||
- Floating Action Button (extends Button)
|
||
|
||
**DDR References:**
|
||
- DDR-001: Why buttons use brand color for primary action
|
||
- DDR-002: Why ghost variant exists (low emphasis without border)
|
||
|
||
### 8.3.2 Input / Text Field
|
||
|
||
### 8.3.3 Select / Dropdown
|
||
|
||
### 8.3.4 Checkbox
|
||
|
||
### 8.3.5 Radio Button
|
||
|
||
### 8.3.6 Toggle / Switch
|
||
|
||
### 8.3.7 Card
|
||
|
||
### 8.3.8 Modal / Dialog
|
||
|
||
### 8.3.9 Toast / Notification
|
||
|
||
### 8.3.10 Tooltip
|
||
|
||
### 8.3.11 Data Table
|
||
|
||
### 8.3.12 Tabs
|
||
|
||
### 8.3.13 Navigation
|
||
|
||
### 8.3.14 Sidebar
|
||
|
||
### 8.3.15 Map Overlay
|
||
|
||
---
|
||
|
||
## 9. Maps & Geospatial Layer
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 9.1 Mapbox Configuration
|
||
|
||
### 9.2 Layer Styles
|
||
|
||
### 9.3 Interaction Patterns
|
||
|
||
### 9.4 Geometries & Coordinates Display
|
||
|
||
---
|
||
|
||
## 10. Accessibility
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 10.1 WCAG 2.1 AA Compliance
|
||
|
||
### 10.2 Keyboard Navigation
|
||
|
||
### 10.3 Screen Reader Support
|
||
|
||
### 10.4 Focus Management
|
||
|
||
### 10.5 Color Contrast
|
||
|
||
### 10.6 Reduced Motion
|
||
|
||
---
|
||
|
||
## 11. Responsive Behavior
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 11.1 Device Adaptive Principles
|
||
|
||
### 11.2 Phone (< 768px)
|
||
|
||
### 11.3 Tablet (768px - 1024px)
|
||
|
||
### 11.4 Desktop (> 1024px)
|
||
|
||
---
|
||
|
||
## 12. Empty States
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 12.1 Principles
|
||
|
||
### 12.2 Patterns by Context
|
||
|
||
---
|
||
|
||
## 13. Loading States
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 13.1 Skeleton Patterns
|
||
|
||
### 13.2 Progress Indicators
|
||
|
||
### 13.3 Stepped Loading
|
||
|
||
---
|
||
|
||
## 14. Error States
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 14.1 Error Message Structure
|
||
|
||
### 14.2 Inline Errors
|
||
|
||
### 14.3 Page-Level Errors
|
||
|
||
### 14.4 Toast Errors
|
||
|
||
---
|
||
|
||
## PART D — VALIDATION
|
||
|
||
## 15. Acceptance Criteria
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 15.1 Definition of Done (Design)
|
||
|
||
### 15.2 Checklist per Component
|
||
|
||
### 15.3 Cross-Browser Requirements
|
||
|
||
---
|
||
|
||
## 16. Design QA
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 16.1 Manual Review Process
|
||
|
||
### 16.2 Automated Checks (Future)
|
||
|
||
### 16.3 Screenshot Review
|
||
|
||
---
|
||
|
||
## 17. Visual Regression
|
||
|
||
> **Status:** ⏳ Ej påbörjad — Fas 3
|
||
|
||
### 17.1 Scope
|
||
|
||
### 17.2 Tools
|
||
|
||
### 17.3 Thresholds
|
||
|
||
---
|
||
|
||
## 18. Release Checklist
|
||
|
||
> **Status:** ⏳ Ej påbörjad
|
||
|
||
### 18.1 Pre-Release Design Review
|
||
|
||
### 18.2 Post-Release Verification
|
||
|
||
---
|
||
|
||
## ÄNDRINGSHISTORIA
|
||
|
||
| Version | Datum | Beskrivning |
|
||
|---------|-------|-------------|
|
||
| 1.0-skeleton | 2026-07-02 | Initial struktur med 18 kapitel, tomt innehåll |
|
||
|
||
---
|
||
|
||
## STATUS
|
||
|
||
**DRAFT — Under utveckling**
|
||
|
||
- Fyll på kapitel successivt
|
||
- Markera kapitel som ✅ när de är specificerade och godkända
|
||
- Brytande ändringar: Kräver Architecture Review
|