Files
boc/docs/design/LANDVEX_DESIGN_SPECIFICATION.md
T
Bernt b0a1808b2b docs: AI Principles restructured + Compliance Matrix + Platform governance + RFC-001 Button
- 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.
2026-07-02 09:06:08 +00:00

1096 lines
32 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 100900)
- **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 H1H6.
**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.21.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 (510% 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