@klodd/ds 3.14.13 → 3.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,305 @@
1
+ # Klodd Design Language
2
+
3
+ Konkreta regler för **visuell koherens** över Klodd-ekosystemet. Token-
4
+ arkitekturen (`01-tokens.md`) och komponent-API (`02-components.md`)
5
+ specificerar **vad** som finns; denna fil specificerar **hur** komponenter
6
+ ska användas tillsammans för homogen design-uttryck.
7
+
8
+ **Grundprincip:** rytm > flexibilitet. Begränsade val ger visuell
9
+ koherens. Varje element i samma kategori ska kunna bytas ut mot ett
10
+ annat utan att layout-rytm bryts.
11
+
12
+ Etablerad 2026-05-12 baserat på audit av 17 vyer (se
13
+ `AUDIT-VISUAL-COHERENCE-2026-05-12.md`).
14
+
15
+ ## 1. Border-radius-skala (fem värden)
16
+
17
+ **Regel:** all border-radius i komponent-CSS ska vara EN av:
18
+
19
+ | Värde | Token | Användning |
20
+ |---|---|---|
21
+ | 4px | `--radius-4` | Thin-bars: progress, skeleton-line, split-bar-segment |
22
+ | 10px | `--radius-10` | Button, inputs, tab-bar__item, small-action-button |
23
+ | 14px | `--radius-14` | All cards/containers: card, panel, hub-card, job-card, swipe-card, banner, form-card, stat-card, list-row, setting-row, toast, dialog, sheet, collapsible, offline-wrap, sheet-content fields |
24
+ | 50% | (calculated) | Avatars, icon-circles, toggle-thumb |
25
+ | 9999px | `--radius-full` | Pills: badge, chip, status-pill, dot-separator, score-pill |
26
+
27
+ **Förbjudet:** 2px, 6px, 8px, 12px, 16px, 18px, 20px, 22px, 24px på
28
+ komponent-element. (Existerar som tokens men ska inte appliceras
29
+ direkt på BR i komponent-CSS efter denna konsolidering.)
30
+
31
+ **Rationale:** ögat skiljer på fem kategorier: thin-bar, button,
32
+ container, circle, pill. 11+ värden ger visuell brus utan
33
+ informations-värde. Calle's audit-observation "olika former" var
34
+ denna BR-spridning.
35
+
36
+ **Migration-not:** existerande paket-komponenter med BR=6/8/12/16/20/24
37
+ flyttas till närmaste av de fem. Sprint 3b 2026-05-12 genomförde
38
+ migrationen i paketet. App-domain-CSS följer samma regel.
39
+
40
+ ## 2. Shadow-policy (restriktiv)
41
+
42
+ **Regel:** shadow används i tre exakt-definierade kontexter:
43
+
44
+ | Kontext | Värde | Rationale |
45
+ |---|---|---|
46
+ | Modaler, sheets, dropdowns (overlay-elementer) | `box-shadow: none` | Dark-mode: surface-overlay + border ger djup. Shadow på mörk bg ger inverterad djupkänsla. |
47
+ | iOS-style active-state-indikatorer (toggle-thumb, active-tab-pill) | `var(--shadow-card)` | Fysisk thumb-feel. Motiverat per regel 10. |
48
+ | Allt annat | `box-shadow: none` | Default. |
49
+
50
+ **Förbjudet:**
51
+ - `--shadow-float`, `--shadow-resting`, `--shadow-raised`-tokens
52
+ utöver `--shadow-card`. (Existerar som alias - candidate för
53
+ borttagning i Sprint 3b.)
54
+ - Hardkodade `box-shadow` med oklch eller rgba
55
+ - Shadow på panel, card, hub-card, stat-card, banner, form-card
56
+ (de är inom-flow-element, hierarki via surface-tokens)
57
+ - Shadow på bottom-nav, toast (inom-flow + backdrop-filter räcker)
58
+
59
+ **Dark-mode-rationale:** ljus shadow på mörk bg ger inverterad
60
+ djupkänsla (ljust = lyft, inte sänkt). Använd surface-color-hierarki
61
+ istället: `--surface-page < default < raised < overlay`.
62
+
63
+ ## 3. Page-toppar: två separata patterns
64
+
65
+ **Regel:** två väldefinierade patterns för page-toppar - hero och
66
+ page-header. Välj baserat på purpose, inte preferens.
67
+
68
+ ### Pattern A: `.hero` (dashboard med metric)
69
+
70
+ För dashboards där primär-data är en STOR siffer-display.
71
+
72
+ ```html
73
+ <section class="hero">
74
+ <p class="hero__label">SEKTION-LABEL</p>
75
+ <p class="hero__amount">{stort-värde}</p>
76
+ <p class="hero__meta">{kontextuell-info}</p>
77
+ <div class="hero__actions">
78
+ <button class="btn btn--primary">{primär-action}</button>
79
+ </div>
80
+ </section>
81
+ ```
82
+
83
+ `.hero__amount` är fs-80 (siffer-display). `.hero__amount--card`
84
+ (fs-40) för hero inom panel. `.hero__amount--fluid` (clamp 40-80vw)
85
+ för responsiv siffer-display.
86
+
87
+ Hero har `padding: 20px 0 24px` (alignment med övriga container-element).
88
+
89
+ ### Pattern B: `.page-header` (utility-page med titel)
90
+
91
+ För pages utan primär-metric, bara navigation-kontext.
92
+
93
+ ```html
94
+ <div class="page-header">
95
+ <h1 class="page-title">{Titel}</h1>
96
+ <p class="page-subtitle">{Beskrivning}</p>
97
+ </div>
98
+ ```
99
+
100
+ `.page-title` är fs-22 (heading-size). `.page-subtitle` är fs-13
101
+ muted. Page-header har `display: flex` med space-between för
102
+ sidoplacerade actions vid behov.
103
+
104
+ ### När använda vilken
105
+
106
+ | Vy-typ | Pattern |
107
+ |---|---|
108
+ | Dashboard med primär-metric | `.hero` |
109
+ | Lista-vy med titel | `.page-header` |
110
+ | Settings-hub | `.page-header` |
111
+ | Detalj-vy med metric | `.hero` (inom panel: `.hero--card`) |
112
+ | Form-page | `.page-header` |
113
+
114
+ ### Konkret per app
115
+
116
+ - **Jubb /, /installera**: `.hero` (job-count är primär-metric)
117
+ - **Jubb /jobb, /korningar, /insikter**: `.page-header` (list-vyer)
118
+ - **Jubb /triage**: ingen page-topp (swipe-stack är huvudobjekt)
119
+ - **Ekonom /avstamning, /privat, /bolanet, /kategorier**: `.hero`
120
+ (saldo/utgifter/equity är primär-metric)
121
+ - **Ekonom /jag**: `.page-header` (profil-vy, ingen metric)
122
+ - **Ekonom /installningar, /granskning, /import**: `.page-header`
123
+ - **Ekonom /jag/abonnemang**: `.page-header`
124
+
125
+ ### Gemensam spacing-doktrin
126
+
127
+ Båda patterns följer alignment-regel sektion 8: content på `x = 14`
128
+ (main-padding-left). Ingen inner horizontal padding på top-level
129
+ container (hero, page-header).
130
+
131
+ ### Förbjudet
132
+
133
+ - Blanda `.hero` och `.page-header` i samma vy
134
+ - Använda `<div>` med ad-hoc styling istället för en av de två
135
+ patterns
136
+ - Hardkodad font-size för titel-element (använd `.hero__amount`
137
+ eller `.page-title`)
138
+
139
+ ## 4. Padding-rytm (sex värden)
140
+
141
+ **Regel:** all padding i komponent-CSS ska vara EN av:
142
+
143
+ | Värde | Token | Användning |
144
+ |---|---|---|
145
+ | 4px | `--space-4` | Mini-gaps, badge inner, tab-spacing |
146
+ | 8px | `--space-8` | Standard gap, icon-margin |
147
+ | 12px | `--space-12` | List-row vertical, button-internal |
148
+ | 16px | `--space-16` | Card internal, panel internal, hero |
149
+ | 20px | `--space-20` | Section gap, hero-internal vertical |
150
+ | 24px | `--space-24` | Major section break |
151
+
152
+ **Förbjudet i komponent-CSS:** 2, 6, 10, 14, 18, 22, 28, 32-värden
153
+ direkt. (Finns som tokens men reserverat för layout-grid och spacing
154
+ mellan section-block, inte inom komponenter.)
155
+
156
+ **Sammansatta padding (TRBL)**:
157
+ - Symmetric preferred: `padding: 16px` ✓
158
+ - Vertical-horizontal: `padding: 12px 16px` ✓
159
+ - Asymmetric only with rationale: `padding: 20px 0 24px` (hero) -
160
+ kommentar med motivering krävs
161
+
162
+ ## 5. Font-size-skala (åtta värden)
163
+
164
+ **Regel:** font-size i komponent-CSS ska vara EN av token-skalan:
165
+
166
+ | Token | Användning |
167
+ |---|---|
168
+ | --fs-11 | Meta-text, time-stamps |
169
+ | --fs-12 | Default body, list-row-text |
170
+ | --fs-13 | Card-body, secondary |
171
+ | --fs-14 | Primary body, button-text |
172
+ | --fs-17 | Subtitle, panel-title |
173
+ | --fs-22 | Heading, section-title |
174
+ | --fs-32 | Large-display, card-hero |
175
+ | --fs-80 | Page-hero amount |
176
+
177
+ **Förbjudet:** 15px, 18px, 20px, 24px, 40px, 64px på text-content.
178
+ (Token-värden finns men ska användas selektivt och inom
179
+ specifika komponenter.)
180
+
181
+ **Förbjudet i app-domain-CSS:**
182
+ - `clamp()`-baserade font-sizes som ger non-integer rendering
183
+ - `font-size: 13.3333px` (browser sub-pixel av %-baserat värde)
184
+ - Hardkodade `font-size: 14px` utan token
185
+ - `font-size: 51.6px` (Bolanet) - off-token värde
186
+
187
+ ## 6. Container-klassifikation (vilket är vad)
188
+
189
+ **Regel:** välj rätt container baserat på funktion:
190
+
191
+ | Komponent | När använda | Inte använda för |
192
+ |---|---|---|
193
+ | `.card` | Klickbar enhet med titel + body | Statisk info-panel |
194
+ | `.card--interactive` | Card med hover/press-feedback | Static-card |
195
+ | `.panel` | Ramad sektion med titel, statisk innehåll | Klickbar |
196
+ | `.hub-card` | Settings-hub navigation-target | Generic listrad |
197
+ | `.job-card` (Jubb) | Job-listing enhet | Generic card |
198
+ | `.swipe-card` | Tinder-stil swipeable card | Static info |
199
+ | `.stat-card` | Single-metric display (siffra + label) | Multi-content |
200
+ | `.banner` | Bred info-rad i flow | Action card |
201
+ | `.form-card` | Form-wrapper | Generic content |
202
+ | `.list-row` | Generic list-rad med ikon + body + amount | Settings-rad |
203
+ | `.setting-row` | Tap-to-edit settings-rad | Klickbart kort |
204
+
205
+ **Bias-toward-panel:** vid osäkerhet, använd `.panel`. Det är default-
206
+ container.
207
+
208
+ ## 7. Spacing-rytm mellan block
209
+
210
+ **Regel:** vertikalt spacing mellan distinkta block:
211
+
212
+ - Mellan topbar och första block: `margin-bottom: 16` på topbar
213
+ - Mellan section-block (panel, hero, section): `margin-bottom: 14`
214
+ - Mellan list-row (samma list): `margin: 0` (border-top för separator)
215
+ - Mellan hub-card-list-items: `margin-bottom: 12`
216
+ - Mellan section och footer-text: `margin-top: 16` på footer
217
+
218
+ **Förbjudet:** beroende på `gap`-property på parent när siblings har
219
+ egna `margin-bottom`. Välj en mekanism per kontext.
220
+
221
+ ## 8. Alignment-regler
222
+
223
+ **Regel:** alla primära block-content sitter på samma horizontal-x.
224
+
225
+ - Main har `padding: 16px 14px 84px` (top-right-bottom-left). Content
226
+ startar på `x = 14`.
227
+ - Container-block (panel, card, hero, hub-card) sitter på `x = 14`
228
+ (no extra margin).
229
+ - Inom container, text-content sitter på `x = 14 + container-inner-padding`.
230
+ - Hero ska INTE ha asymmetrisk horizontal padding (förbjudet:
231
+ `padding: 20px 4px 24px`). Tillåtet: `padding: 20px 0 24px` eller
232
+ `padding: 20px`.
233
+
234
+ ## 9. PWA-specifika konventioner
235
+
236
+ ### Tap-targets
237
+
238
+ - Alla interaktiva element MÅSTE vara minst 44x44px (WCAG 2.5.5).
239
+ - Buttons: `min-height: var(--touch-min)` (= 44).
240
+ - List-rows: `padding: 14px 0` minimum (= 50px height med text-line).
241
+ - Icon-buttons: `width: 44px; height: 44px`.
242
+
243
+ ### Mobile-first
244
+
245
+ - Default-styles är mobile (375-430 viewport).
246
+ - Tablet (768+) och desktop (1024+) är progressive enhancements.
247
+ - Test alltid på iPhone 14 Pro Max (430x932) som baseline.
248
+
249
+ ### Safe areas
250
+
251
+ - `padding-top: calc(var(--safe-top) + 16px)` på main för iOS-notch.
252
+ - `padding-bottom: var(--bottom-nav-clearance)` (= 84px) för fixed
253
+ bottom-nav.
254
+
255
+ ### iOS-specifika
256
+
257
+ - Inputs: `font-size: 17px` minimum (anti auto-zoom).
258
+ - Touch-feedback: `:active` med `transform: scale(0.97)` + spring-easing.
259
+ - Hover wrappas i `@media (hover: hover) and (pointer: fine)`.
260
+
261
+ ## 10. Färg-konvention
262
+
263
+ **Regel:** alla bakgrundsfärger via semantic surface-tokens:
264
+
265
+ ```
266
+ --surface-page (sidens bg, lägst)
267
+ --surface-default (sektioner, list-rows)
268
+ --surface-raised (kort, paneler - en steg upp)
269
+ --surface-overlay (modaler, popovers)
270
+ --surface-hover (:hover bg)
271
+ --surface-active (:active bg)
272
+ --surface-sunken (inputs - LÄGRE än page för iOS-stil)
273
+ ```
274
+
275
+ **Förbjudet i komponent-CSS:**
276
+ - Hardkodade hex/rgb-värden
277
+ - `var(--gray-N)`, `var(--blue-N)`, `var(--plum-N)` direkt (bara i
278
+ primitives + apps/-filer)
279
+ - `rgba()` med alpha - använd `color-mix(in oklch, ...)` eller
280
+ `--accent-aN`-tokens
281
+
282
+ ## 11. Enforcement-status
283
+
284
+ Mekanisk enforcement via stylelint (Sprint 10-1) fångar BEM-syntax-
285
+ brott men INTE design-rule-brott. Visuell coherence är fortfarande
286
+ human-disciplin + framtida custom plugin.
287
+
288
+ Future custom stylelint-plugin kan enforce:
289
+ - BR-value är en av {10, 14, 9999}
290
+ - Font-size är en av token-skalan
291
+ - Padding-värden begränsade till de 6 listade
292
+ - Shadow forbidden utöver `--shadow-card`
293
+
294
+ Tills sådan plugin finns: visual-coherence är CC-disciplin baserat
295
+ på denna fil.
296
+
297
+ ## 12. När ändra regler
298
+
299
+ Denna fil är **locked**. Ändringar kräver:
300
+ 1. ADR i `references/04-locked-decisions/` med rationale
301
+ 2. Audit-pass av berörda vyer
302
+ 3. Migration av befintliga komponenter till nya regeln
303
+ 4. Update av ADR 0013 (visual-coherence-doctrine)
304
+
305
+ Inga ad-hoc-ändringar utan ADR-process.