From 22be1efcd47afeb5bab68585a0452e62c29c0fdd Mon Sep 17 00:00:00 2001 From: Bernt Date: Thu, 2 Jul 2026 08:42:55 +0000 Subject: [PATCH] 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. --- docs/design/DESIGN_ANTI_PATTERNS.md | 234 ++++++++++++++++++ docs/design/LANDVEX_DESIGN_SPECIFICATION.md | 251 +++++++++++++++++--- 2 files changed, 453 insertions(+), 32 deletions(-) create mode 100644 docs/design/DESIGN_ANTI_PATTERNS.md diff --git a/docs/design/DESIGN_ANTI_PATTERNS.md b/docs/design/DESIGN_ANTI_PATTERNS.md new file mode 100644 index 000000000..7e3dfe1eb --- /dev/null +++ b/docs/design/DESIGN_ANTI_PATTERNS.md @@ -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+) diff --git a/docs/design/LANDVEX_DESIGN_SPECIFICATION.md b/docs/design/LANDVEX_DESIGN_SPECIFICATION.md index 823438378..be76745a1 100644 --- a/docs/design/LANDVEX_DESIGN_SPECIFICATION.md +++ b/docs/design/LANDVEX_DESIGN_SPECIFICATION.md @@ -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 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 | -| `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.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:** ⏳ 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 (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 | + +**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. ---