docs: Typography v1 + Foundation Colors + Anti-Patterns

- LANDVEX_DESIGN_SPECIFICATION.md:
  - Typography v1 (chapter 3): Inter + JetBrains Mono, type scale,
    heading hierarchy, line height rules, letter spacing, max line length,
    tabular figures, numerical typography
  - Foundation Colors (chapter 4.1): 12-step neutral palette (neutral-0 to neutral-1000)
  - Semantic Colors (chapter 4.2): surface, text, border mappings
  - Brand Palette (chapter 4.3): placeholder for brand colors
  - Semantic Status Colors (chapter 4.4): green, yellow, red, blue
  - Map Layer Palette (chapter 4.6): dedicated geospatial palette
  - Updated primitive references from gray-* to neutral-*

- DESIGN_ANTI_PATTERNS.md (v1.0, LOCKED):
  - 19 anti-patterns across 5 categories: visual, technical, interaction,
    content, AI-specific
  - Each with: forbidden description, rationale, alternative
  - AI-specific rules: no hardcoded values, no invented components,
    no skipping token lifecycle

Rationale: Typography before colors (harder to change). Neutral palette
before brand (90% of surface area). Anti-patterns prevent recurring
mistakes and guide AI agents.
This commit is contained in:
Bernt
2026-07-02 08:42:55 +00:00
parent 16bc14cd32
commit 22be1efcd4
2 changed files with 453 additions and 32 deletions
+234
View File
@@ -0,0 +1,234 @@
# DESIGN ANTI-PATTERNS
**What Must Never Be Introduced**
| | |
|---|---|
| **Version** | 1.0 |
| **Status** | LOCKED |
| **Scope** | All Landvex & quiXzoom products |
| **Authority** | DESIGN_SPECIFICATION (nivå 5 i dokumenthierarkin) |
---
## Purpose
This document lists patterns that are **explicitly forbidden** in the Landvex design system. It exists to:
- Prevent recurring mistakes
- Guide AI agents away from bad defaults
- Accelerate design reviews ("see Anti-Pattern #7")
- Maintain consistency as the team grows
**Rule:** If a pattern is listed here, it may not be used. No exceptions without Architecture Review.
---
## Visual Anti-Patterns
### AP-001: Hero Images
**Forbidden:** Large decorative images at the top of pages or dashboards.
**Why:** Landvex is a professional tool, not a marketing site. Visual noise competes with data.
**Alternative:** Use whitespace, typography hierarchy, or data visualization to create visual interest.
### AP-002: Stock Photography
**Forbidden:** Generic stock photos of people, cities, or abstract concepts.
**Why:** Inauthentic, reduces trust, adds no information.
**Alternative:** Use maps, data visualizations, or icons.
### AP-003: Illogical Gradients
**Forbidden:** Gradients without functional purpose (e.g., blue-to-purple backgrounds).
**Why:** Visual noise. Gradients should only indicate elevation, depth, or state.
**Alternative:** Solid colors with elevation tokens (`shadow-sm`, `shadow-md`).
### AP-004: Glassmorphism Without Function
**Forbidden:** Frosted glass effects used purely for aesthetics.
**Why:** Reduces readability, performance cost, inconsistent across browsers.
**Alternative:** Opaque surfaces with subtle borders.
### AP-005: Multiple Shadow Styles
**Forbidden:** More than one shadow system in the same product.
**Why:** Inconsistent elevation language.
**Alternative:** Use the defined elevation scale (see Elevation & Shadows chapter).
### AP-006: Multiple Icon Libraries
**Forbidden:** Mixing icon sets (e.g., Font Awesome + Material Icons + custom).
**Why:** Inconsistent stroke weight, style, and metaphor.
**Alternative:** Single icon library (see Iconography chapter).
---
## Technical Anti-Patterns
### AP-007: Hardcoded Values
**Forbidden:** Any hardcoded color, spacing, or dimension in component code.
**Why:** Breaks theming, untraceable, unmaintainable.
**Example:**
`padding: 16px; color: #3b82f6;`
`padding: var(--space-4); color: var(--surface-primary);`
### AP-008: Undefined Z-Index
**Forbidden:** Arbitrary z-index values (`z-index: 9999`, `z-index: 1000000`).
**Why:** Unpredictable stacking, debugging nightmare.
**Alternative:** Use the defined z-index scale (`z-dropdown`, `z-modal`, etc.).
### AP-009: Inconsistent Border Radius
**Forbidden:** Mixing border radius styles without purpose (e.g., 4px buttons with 16px inputs).
**Why:** Visual inconsistency, amateur appearance.
**Alternative:** Use the defined radius scale (`radius-1`, `radius-2`, etc.).
### AP-010: Components Bypassing Tokens
**Forbidden:** Components that define their own colors or spacing instead of using tokens.
**Why:** Creates "shadow system", breaks governance.
**Alternative:** Always reference semantic or component tokens.
---
## Interaction Anti-Patterns
### AP-011: Falsely Clickable Elements
**Forbidden:** Elements that look clickable but are not (e.g., underlined text that is not a link).
**Why:** Violates user trust, increases cognitive load.
**Alternative:** Clear visual distinction between interactive and static elements.
### AP-012: Multiple Primary CTAs
**Forbidden:** More than one primary call-to-action in the same view.
**Why:** Dilutes user focus, increases decision fatigue.
**Alternative:** One primary action, secondary actions as text or ghost buttons.
### AP-013: Layout Shift on Load
**Forbidden:** Content that jumps or shifts as data loads.
**Why:** Disorienting, causes misclicks, feels unprofessional.
**Alternative:** Skeleton screens, fixed dimensions, reserved space.
### AP-014: Disabled Tooltips
**Forbidden:** Tooltips on disabled elements without explanation.
**Why:** User wonders "why is this disabled?" with no answer.
**Alternative:** Always explain why an action is unavailable.
---
## Content Anti-Patterns
### AP-015: Vague Error Messages
**Forbidden:** Errors like "Something went wrong" or "Error 500".
**Why:** Unhelpful, increases support burden.
**Alternative:** Explain what happened, why, and what to do next.
### AP-016: Placeholder as Label
**Forbidden:** Using placeholder text as the only field label.
**Why:** Disappears on input, inaccessible, confusing.
**Alternative:** Persistent labels above or beside fields.
---
## AI-Specific Anti-Patterns
### AP-017: AI-Generated Hardcoded Values
**Forbidden:** AI agents proposing hardcoded colors, spacing, or dimensions.
**Why:** Violates Token Philosophy, creates technical debt.
**Rule:** AI must always reference existing tokens or propose new ones through the Design Review Gate.
### AP-018: AI-Invented Components
**Forbidden:** AI agents creating new components without checking existing specifications.
**Why:** Duplication, inconsistency, bloat.
**Rule:** AI must search the component library before proposing anything new.
### AP-019: AI-Ignoring Lifecycle
**Forbidden:** AI agents introducing tokens directly as Stable.
**Why:** Bypasses governance, risks breaking changes.
**Rule:** All new tokens start as Draft. Promotion requires review.
---
## Relationship to Other Documents
| Document | Role |
|----------|------|
| `LANDVEX_DESIGN_CONSTITUTION.md` | Why these anti-patterns matter (principles 6, 7, 19) |
| `TOKEN_PHILOSOPHY.md` | How tokens prevent AP-007, AP-008, AP-009, AP-010 |
| `LANDVEX_DESIGN_SPECIFICATION.md` | What to do instead |
| `DESIGN_ANTI_PATTERNS.md` | What never to do |
---
## Adding Anti-Patterns
1. Propose with: ID, description, rationale, alternative
2. Design review required
3. Must be actionable and specific
4. No vague or subjective rules
---
## ÄNDRINGSHISTORIA
| Version | Datum | Beskrivning |
|---------|-------|-------------|
| 1.0 | 2026-07-02 | Initial 19 anti-patterns covering visual, technical, interaction, content, and AI-specific |
---
## STATUS
**LOCKED**
- Mindre revideringar: 1.x-serien
- Brytande ändringar: Kräver Architecture Review, ny major-version (2.0+)
+219 -32
View File
@@ -163,27 +163,27 @@ Level 3: Component Tokens → Component-specific (button-primary-bg-hover)
| Token | Primitive Reference | Usage |
|-------|---------------------|-------|
| `surface-primary` | `gray-0` | Main background |
| `surface-secondary` | `gray-50` | Card background |
| `surface-elevated` | `gray-0` + shadow | Modal, popover |
| `surface-overlay` | `gray-900` @ 50% | Backdrop |
| `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` | `gray-900` | Headings, body |
| `text-secondary` | `gray-600` | Captions, metadata |
| `text-muted` | `gray-400` | Placeholders |
| `text-inverse` | `gray-0` | On dark surfaces |
| `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` | `gray-200` | Dividers |
| `border-focus` | `blue-500` | Focus rings |
| `border-error` | `red-500` | Error states |
| `border-default` | `neutral-200` | Dividers |
| `border-focus` | `brand-500` | Focus rings |
| `border-error` | `semantic-red-500` | Error states |
### 1.3 Component Tokens
@@ -192,15 +192,15 @@ Level 3: Component Tokens → Component-specific (button-primary-bg-hover)
| Token | Semantic Reference | Usage |
|-------|-------------------|-------|
| `button-primary-bg` | `surface-primary` | Default background |
| `button-primary-bg-hover` | `blue-600` | Hover state |
| `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` | `gray-50` | Hover highlight |
| `table-header-bg` | `gray-100` | Header background |
| `table-row-hover` | `neutral-50` | Hover highlight |
| `table-header-bg` | `neutral-100` | Header background |
### 1.4 Export Format
@@ -235,42 +235,229 @@ See `TOKEN_PHILOSOPHY.md` §3 for full specification.
## 3. Typography
> **Status:** ⏳ Ej påbörjad
> **Status:** ✅ Specified
> **Principle:** Typography is the foundation of information hierarchy. It must be readable, scannable, and calm.
### 3.1 Font Stack
### 3.2 Type Scale
| 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 |
| `text-sm` | 14px | 20px | 400 | 0 | Body small |
| `text-base` | 16px | 24px | 400 | 0 | Body |
| `text-lg` | 18px | 28px | 400 | -0.01em | Lead paragraph |
| `text-xl` | 20px | 28px | 500 | -0.02em | Section headers |
| `text-2xl` | 24px | 32px | 500 | -0.02em | Page titles |
| `text-3xl` | 30px | 36px | 600 | -0.02em | Major headings |
| `text-4xl` | 36px | 40px | 600 | -0.03em | Hero titles |
| `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.3 Font Weights
### 3.5 Heading Hierarchy
### 3.4 Monospace (Data)
| Level | Token | Weight | Usage |
|-------|-------|--------|-------|
| H1 | `text-4xl` | 600 | Page title, top-level view |
| H2 | `text-3xl` | 600 | Section title, dashboard panel |
| H3 | `text-2xl` | 500 | Card title, modal header |
| H4 | `text-xl` | 500 | Subsection, list header |
| H5 | `text-lg` | 400 | Label, group title |
| H6 | `text-base` | 500 | Small label, filter title |
### 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:** ⏳ Ej påbörjad
> **Status:** ✅ Foundation specified, Brand & Map pending
> **Principle:** Information dominates color. Color supports, never competes.
### 4.1 Neutral Scale
### 4.1 Foundation Colors (Neutral Palette)
### 4.2 Primary Colors
**Primitive Tokens:**
### 4.3 Semantic Colors
| 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 |
### 4.4 Data Visualization Colors
**Rationale:** 12-step scale provides sufficient granularity without excess. Based on open-source neutral scales (Open Color, Tailwind) for familiarity.
### 4.5 Map Colors
### 4.2 Semantic Colors
Derived from primitives, mapped to purpose:
| 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.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 |
**Rule:** Brand colors never appear in data visualization or map layers.
### 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:
| Layer | Token | Rationale |
|-------|-------|-----------|
| Map surface | `map-surface` | Subtle, non-competing |
| Terrain | `map-terrain` | Elevation indication |
| Roads | `map-road` | Hierarchy (motorway → path) |
| Water | `map-water` | Consistent with cartographic convention |
| Buildings | `map-building` | Subtle 3D effect |
| Administrative | `map-boundary` | Dashed, muted |
| Mission markers | `map-mission` | Brand color, high visibility |
| Heatmap | `map-heatmap` | Gradient from neutral to alert |
| Selection | `map-selection` | Clear, non-intrusive |
| Overlay | `map-overlay` | Contextual information |
**Principle:** Map colors must work in all lighting conditions and never compete with data overlays.
---