@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,133 @@
1
+ # 0011 - Strikt BEM-elementsyntax för inre struktur av compound-blocks
2
+
3
+ ## Status
4
+ Locked.
5
+
6
+ ## Context
7
+
8
+ Regel 11 i `03-quality-bar.md` (compound blocks i samma fil) öppnade
9
+ för flat-hyphen-klasser via sibling-relation-undantaget. Den nuvarande
10
+ formuleringen säger:
11
+
12
+ > Ett block som logiskt kunde varit BEM-element av ett annat - i så
13
+ > fall ska det vara `.X__Y`, inte `.X-Y` som separat block.
14
+
15
+ Detta var stipulerat men inte konsekvent verkställt i app-domain-CSS.
16
+ Jubbs `jubb.css` och `pages/triage.css` ackumulerade ~28 flat-hyphen-
17
+ klasser som logiskt var inre struktur av compound-blocks men namngivna
18
+ utan `__`-syntax (`.score-dim-row` istället för `.score-breakdown__dim-row`,
19
+ `.triage-source` istället för `.triage-card__source` etc).
20
+
21
+ Ekonoms domain-CSS (`ekonom.css`) har också compound-block-undantag
22
+ men dessa är dokumenterade som Sprint G Tier D-undantag (2026-05-09)
23
+ med specifik rationale (visuell paritet, etablerade namn, lyft-värda
24
+ till paketet).
25
+
26
+ Skärpning behövdes för att:
27
+ 1. Förtydliga vad "kunde varit BEM-element" betyder (test-baserat)
28
+ 2. Stänga gapet där LLM-sessioner skapade flat-hyphen-inner-element
29
+ med felklassificering som "sibling"
30
+ 3. Etablera dokumenterad Tier D-katalog som hindrar nya odokumenterade
31
+ undantag
32
+
33
+ ## Decision
34
+
35
+ Compound-blocks i samma fil är OK ENDAST när alla följande gäller:
36
+
37
+ 1. **JSDoc-header med `Blocks:`-sektion** (oförändrat krav från regel 11)
38
+ 2. **Listade i `02-components.md`** (oförändrat krav)
39
+ 3. **Inre struktur av compound-block MÅSTE använda BEM-element-syntax
40
+ (`__element`).** Bara root-level sibling-blocks (genuint fristående
41
+ koncept) får vara flat-hyphen.
42
+
43
+ ### Test (compound-sibling vs BEM-element)
44
+
45
+ > "Skulle detta block fungera om jag tar bort dess parent-block?"
46
+ > - Ja, det är ett fristående koncept → sibling-block (flat-hyphen OK)
47
+ > - Nej, det är inre struktur av parent → BEM-element (`__`-syntax krav)
48
+
49
+ ### Exempel
50
+
51
+ Rätt (siblings, kan användas separat):
52
+ - `.hub-card` + `.hub-list` + `.hub-category` (paketets hub-card.css)
53
+ - `.swipe-stack` + `.swipe-card` + `.swipe-actions` + ... (paketets swipe-stack.css)
54
+ - `.form-card` + `.form-section` + `.form-group` (paketets form.css)
55
+
56
+ Rätt (BEM-element, inre struktur):
57
+ - `.hub-card__icon` (inom .hub-card)
58
+ - `.swipe-card__title` (inom .swipe-card)
59
+ - `.score-breakdown__dim-row` (inom .score-breakdown)
60
+ - `.triage-card__source` (inom .triage-card)
61
+
62
+ Fel (flat-hyphen för inre struktur):
63
+ - `.score-dim-row` (skulle varit `.score-breakdown__dim-row`)
64
+ - `.triage-source` (skulle varit `.triage-card__source`)
65
+ - `.source-numbers` (skulle varit `.source-stats__numbers`)
66
+
67
+ ## Migration genomförd 2026-05-12
68
+
69
+ Sprint BEM-2 + BEM-3 i Jubb migrerade 18 flat-hyphen-klasser till
70
+ strikt BEM via `scripts/migrate_bem.py`:
71
+
72
+ **BEM-2 (Jubb commit `21840ec`):**
73
+ - `.score-dim-row/-label/-value` → `.score-breakdown__dim-row/-label/-value`
74
+ - `.source-row/-numbers/-int/-dis` → `.source-stats__row/-numbers/-int/-dis`
75
+
76
+ **BEM-3 (Jubb commit `c371f56`):**
77
+ - `.triage-source/-title/-meta-row/-why/-detail-link` → `.triage-card__*`
78
+ - `.triage-dismiss/-save/-interest` → `.triage-btn--*`
79
+ - `.banner-triage*` → `.triage-banner` + `__text/__cta`
80
+
81
+ Verifiering via `migrate_bem.py verify` (0 träffar gamla namn).
82
+ Pytest 429 pass varje sprint. Class-maps committade som
83
+ `scripts/class_map_bem2.yaml` + `scripts/class_map_bem3.yaml` för
84
+ spårbarhet.
85
+
86
+ ## Tier D-undantagskatalog (dokumenterade flat-hyphen-block-familjer)
87
+
88
+ Se `references/02-components.md` "Tier D-undantagskatalog"-sektionen
89
+ för komplett lista. Två kategorier:
90
+
91
+ ### Paketets dokumenterade undantag
92
+ - `.tooltip-wrapper` (compound block parent till `.tooltip`)
93
+ - `.offline-wrap/-icon/-title/-text` (compound, alla 4 används tillsammans)
94
+ - `.kv-budget-header/-body` (compound, lyfta från Ekonom utan rename
95
+ för template-kompatibilitet)
96
+
97
+ ### Ekonom Tier D (Sprint G 2026-05-09)
98
+ - `.cat-bar-*` (7 klasser)
99
+ - `.equity-bar-*` (6 klasser)
100
+ - `.budget-bar-*` (5 klasser)
101
+ - `.cat-tx-*` (6 klasser)
102
+
103
+ Total: 7 paket-undantag + 24 Ekonom Tier D = 31 dokumenterade undantag.
104
+
105
+ **Inga nya Tier D-poster utan ADR-beslut.**
106
+
107
+ ## Consequences
108
+
109
+ **Bra:**
110
+ - LLM-sessioner kan applicera regel 11 entydigt via test:en
111
+ - Future flat-hyphen-inner-element fångas som regelbrott
112
+ - Tier D-katalog är frusen lista, inte växande
113
+ - Tooling (`scripts/migrate_bem.py`) kan användas igen för app-domain-
114
+ klasser som ackumuleras över tid
115
+
116
+ **Trade-off:**
117
+ - Existerande Ekonom Tier D-klasser förblir flat-hyphen. Migrera dem
118
+ retroaktivt skulle ge ingen visuell vinst men kostar template-byten
119
+ och risk för regression. Sprint G-rationale (2026-05-09) håller.
120
+ - Jubbs `jubb.css` har fortfarande sibling-block-familjer (hour-heatmap,
121
+ radar-indicator, mode-toggle, signal-badge, job-list/job-card) som
122
+ passerar testen som genuint fristående siblings. Dokumentation pass
123
+ i BEM-6 listar dessa explicit i `02-components.md`.
124
+
125
+ ## References
126
+
127
+ - Jubb commit `21840ec` (BEM-2: score-breakdown + source-stats)
128
+ - Jubb commit `c371f56` (BEM-3: triage.css)
129
+ - klodd-ds commit (denna ADR)
130
+ - `references/03-quality-bar.md` regel 11
131
+ - `references/02-components.md` Tier D-undantagskatalog
132
+ - ADR `0009-no-flat-components-css.md` (besläktad, paket-vs-app-domain-separation)
133
+ - ADR `0010-collapsible-block-rename.md` (besläktad, BEM-konvertering i paketet)
@@ -0,0 +1,117 @@
1
+ # 0012 - Stylelint BEM-enforcement via CI
2
+
3
+ ## Status
4
+ Locked.
5
+
6
+ ## Context
7
+
8
+ Regel 11 + ADR 0011 etablerade strikt BEM-element-syntax för inre
9
+ struktur av compound-blocks. Enforcement var dock enbart mänsklig
10
+ disciplin - inget automatiserat verktyg fångade regel-brott innan
11
+ commit. Future-CC kunde introducera flat-hyphen-inner-class utan
12
+ att CI flaggade det.
13
+
14
+ Sprint BEM-2/3/6 (2026-05-12) migrerade 23 klasser i Jubb manuellt.
15
+ Utan CI-enforcement skulle motsvarande drift kunna återinföras i
16
+ nästa sprint utan att fångas.
17
+
18
+ ## Decision
19
+
20
+ Stylelint configurerad i alla repos (klodd-ds + Jubb + Ekonom) med
21
+ `selector-class-pattern`-regel som enforce BEM-syntax mekaniskt.
22
+
23
+ ### Regex-pattern
24
+
25
+ ```
26
+ ^[a-z][a-z0-9]*(-[a-z0-9]+)*(__[a-z0-9]+(-[a-z0-9]+)*)?(--[a-z0-9]+(-[a-z0-9]+)*)?$
27
+ ```
28
+
29
+ Matchar:
30
+ - `.block` (lowercase, kebab-case)
31
+ - `.block-with-dashes` (compound block-namn)
32
+ - `.block__element`
33
+ - `.block--modifier`
34
+ - `.block__element--modifier`
35
+ - `.block-name__element-name--modifier-name` (compound på alla nivåer)
36
+
37
+ Fångar (block):
38
+ - PascalCase / camelCase (`.BadCapital`)
39
+ - snake_case (`.block_with_underscores`)
40
+ - Numerisk start (`.123-numeric`)
41
+ - Dubbel-`__` (`.block__elem__nested`)
42
+ - Dubbel-`--` (`.block--mod1--mod2`)
43
+ - Trailing dash / underscore
44
+
45
+ ### CI-integration
46
+
47
+ GitHub Actions workflow (`.github/workflows/stylelint.yml`) i alla
48
+ tre repos kör `npm run lint:css` på push + PR mot main. Misslyckad
49
+ lint blockerar merge / deploy.
50
+
51
+ ### Tier D-undantag
52
+
53
+ Eftersom regex tillåter compound-block-namn (`.cat-bar-row`,
54
+ `.tooltip-wrapper`) kräver dokumenterade Tier D-undantag inga
55
+ `/* stylelint-disable */`-kommentarer. Regex matchar dem som
56
+ "compound block". Begränsning: stylelint kan inte mekaniskt skilja
57
+ på "dokumenterat Tier D" vs "nytt brott av samma typ".
58
+
59
+ För strikt enforcement av Tier D-katalogen krävs custom plugin
60
+ (framtida arbete) som korsreferrerar 02-components.md. Sprint 10-1
61
+ levererar BEM-SYNTAX-enforcement, inte semantisk-Tier-D-enforcement.
62
+
63
+ ## Konfigurations-detaljer
64
+
65
+ **Stäng av** (irrelevanta code-style-regler från stylelint-config-standard):
66
+ - `lightness-notation`, `color-function-notation`, `alpha-value-notation`
67
+ - `declaration-block-single-line-max-declarations`
68
+ - `declaration-block-no-shorthand-property-overrides` (override-intent
69
+ i overlay.css)
70
+ - Diverse `*-empty-line-before`-regler
71
+
72
+ **Behåll**:
73
+ - `selector-class-pattern` (BEM-regex) - huvudregel
74
+ - `color-no-invalid-hex`
75
+ - `no-duplicate-at-import-rules`
76
+ - `comment-no-empty`
77
+ - `no-invalid-double-slash-comments`
78
+
79
+ ## Consequences
80
+
81
+ **Bra:**
82
+ - Future-CC får CI-error vid BEM-syntax-brott
83
+ - Regression-prevention för BEM-2/3/6-migrationen
84
+ - Mekanisk enforcement minskar dependence på mänsklig review
85
+
86
+ **Trade-off:**
87
+ - Tier D vs nytt-brott skillnaden är inte mekaniskt fångad. Kräver
88
+ fortfarande mänsklig kontroll mot 02-components.md Tier D-katalog.
89
+ - Stylelint-config replikeras i tre repos (klodd-ds + Jubb + Ekonom).
90
+ Migration till shared `@klodd/ds/stylelint-config` möjlig framöver
91
+ om underhåll blir issue.
92
+ - Code-style-regler från stylelint-config-standard avstängda för att
93
+ inte blockera på icke-BEM-violations.
94
+
95
+ ## Setup-resultat 2026-05-12
96
+
97
+ Audit-resultat efter installation:
98
+ - **klodd-ds**: 0 BEM-violations (alla 37 komponentfiler + base/
99
+ + utilities passerar)
100
+ - **Jubb**: 0 BEM-violations efter BEM-2/3/6-migrationen
101
+ - **Ekonom**: 0 BEM-violations (Tier D-klasser tillåtna som compound)
102
+
103
+ Test av regelns enforcement med medvetna brott:
104
+ - `.BadCapital` → fångad
105
+ - `.block_with_underscores` → fångad
106
+ - `.123-numeric` → fångad
107
+ - `.block__elem__nested` → fångad
108
+ - `.block--mod1--mod2` → fångad
109
+
110
+ ## References
111
+
112
+ - ADR 0011 (strikt BEM-elementsyntax) - regel 11-skärpning
113
+ - `references/03-quality-bar.md` regel 11
114
+ - `references/02-components.md` Tier D-undantagskatalog
115
+ - `.stylelintrc.json` i alla tre repos
116
+ - `.github/workflows/stylelint.yml` i alla tre repos
117
+ - Jubb commits 21840ec, c371f56, 0bd1f97 (BEM-2/3/6-migration)
@@ -0,0 +1,216 @@
1
+ # Visual Coherence Audit - 2026-05-12
2
+
3
+ Full systemaudit av Jubb (jubb.klodd.io) och Ekonom (ekonom.klodd.io)
4
+ mot målet "homogent designuttryck, slaviskt följt". 17 vyer
5
+ auditerade via Chrome MCP javascript_tool layout-extraction.
6
+
7
+ iPhone 14 Pro Max viewport (430x932).
8
+
9
+ ## Auditerade vyer (17)
10
+
11
+ **Jubb (7):** /, /jobb, /triage, /insikter, /installera, /korningar
12
+ **Ekonom (10):** /avstamning, /privat, /bolanet, /jag, /jag/abonnemang,
13
+ /import, /granskning, /kategorier, /installningar, /installningar/{vart-hushall,
14
+ var-bostad, auto-kategorisering, data}
15
+
16
+ ## Sammanställning: 5 kritiska brott
17
+
18
+ ### 1. Border-radius-kaos (11+ distinkta värden)
19
+
20
+ Systemet använder **11+ olika BR-värden**:
21
+
22
+ | Värde | Använt på |
23
+ |---|---|
24
+ | 2px | split-bar-segments |
25
+ | 4px | mini-progress-bars |
26
+ | 6px | small-badges |
27
+ | 8px | tab-bar__item |
28
+ | 10px | button (.btn) |
29
+ | 12px | stat-card, tab-bar, setting-row |
30
+ | 14px | job-card, hub-card |
31
+ | 16px | banner, swipe-card |
32
+ | 20px | panel, form-card |
33
+ | 50% | icon-circles, avatars |
34
+ | 9999px | pills (chip, badge--neutral) |
35
+
36
+ **Inkonsekvenser inom samma "card-typ"**:
37
+ - panel BR=20, form-card BR=20 ✓ matchar
38
+ - job-card BR=14, hub-card BR=14 ✓ matchar
39
+ - stat-card BR=12, swipe-card BR=16, banner BR=16 - varför olika?
40
+ - tab-bar BR=12, tab-bar__item BR=8 - inkonsekvent inom samma komponent!
41
+
42
+ **Ögat fångar detta som "olika former"** även när varje val är token-driven.
43
+
44
+ ### 2. Shadow-användning bryter regel 10
45
+
46
+ Regel 10 (quality-bar): "ENDAST `var(--shadow-card)` i hela systemet.
47
+ Aldrig hierarkisk skugg-skala."
48
+
49
+ **Brott funna på 4 vyer**:
50
+ - Jubb /jobb (sheet/dialog rendered i DOM)
51
+ - Jubb /triage (sheet)
52
+ - Ekonom /jag (sheet)
53
+ - Ekonom /import (sheet)
54
+
55
+ Shadow-värde: `oklch(0.949679 0.0026593 none / 0.08) 0px 8px 16px 0px`
56
+
57
+ Detta är `--shadow-float` (overlay-shadow). På dark-mode ger ljus
58
+ shadow inverterad djupkänsla (ljust på mörkt = lyft, inte sänkt).
59
+
60
+ **Calle's observation "märklig ljus skugga på mörk bakgrund" är detta**.
61
+
62
+ ### 3. Hero-padding ger 4px alignment-drift
63
+
64
+ Paketets `hero.css` har `padding: 20px 4px 24px`. Detta 4px horizontal
65
+ shift sätter hero-content på x=18 (i 430-viewport). Andra element
66
+ (setting-list, panels) sitter på x=14.
67
+
68
+ **Resultat**: hero-content och andra block är på olika vertikala
69
+ linjer. Calle's "alignment-problem" exakt fångat.
70
+
71
+ ### 4. Font-size-spread varierar dramatiskt
72
+
73
+ Per-vy distinkta font-sizes:
74
+
75
+ | Vy | Antal sizes | Spread |
76
+ |---|---|---|
77
+ | Jubb /korningar | 3 | 13/14/17 (clean) |
78
+ | Ekonom /granskning | 4 | 12/14/15/22 (clean) |
79
+ | Jubb /jobb | 5 | 11/12/13/14/17 |
80
+ | Jubb /insikter | 7 | 10-22 |
81
+ | Ekonom /jag | 9 | 10-24 |
82
+ | Ekonom /bolanet | 9 | 10-51.6 (!) |
83
+
84
+ **Anomalier**:
85
+ - `51.6px` på Bolanet - INTE i token-skala (--fs-N är heltal-pixlar)
86
+ - `13.3333px` på 6 Ekonom-vyer - browser sub-pixel-rendering av %-baserad fs
87
+
88
+ ### 5. Hero-pattern är inkonsekvent
89
+
90
+ - **Jubb /, /installera**: hero med siffer-display (fs-80 hero_amount)
91
+ - **Jubb /jobb, /insikter, /korningar**: ingen hero, börjar direkt med panel/list
92
+ - **Ekonom /avstamning, /privat, /bolanet, /kategorier**: hero med fs-22-32-headings
93
+ - **Ekonom /jag**: ingen hero, börjar med profil-panel
94
+ - **Ekonom /granskning**: minimal hero
95
+
96
+ Ingen kanonisk hero-pattern. Varje vy uppfinner sin egen.
97
+
98
+ ## Sekundära observationer
99
+
100
+ ### Padding-rytm är spridd
101
+
102
+ Distinkta padding-värden funna:
103
+ `0/2/4/6/8/10/12/14/16/18/20/24` plus combinations (20/4/24, 16/18, ...).
104
+
105
+ 12 distinkta värden i en enda design-system. För många.
106
+
107
+ ### Container-klasser används parallellt
108
+
109
+ Bag av "card-like" containers över systemet:
110
+ - .card (paketet)
111
+ - .panel (paketet)
112
+ - .job-card (Jubb)
113
+ - .swipe-card (paketet)
114
+ - .stat-card (paketet)
115
+ - .hub-card (paketet)
116
+ - .form-card (paketet)
117
+ - .banner (paketet)
118
+
119
+ 8 olika container-typer. Varje har egen BR/bg/padding.
120
+
121
+ ### Bolanet är värst för konsekvens
122
+
123
+ Ekonom /bolanet har:
124
+ - 9 distinkta font-sizes (inkl 51.6 som är off-token)
125
+ - 7 distinkta border-radius-värden
126
+ - 9 distinkta padding-värden
127
+ - Banner med OKLCH bg (positive-tint) som avviker från andra paneler
128
+
129
+ Värst-i-klass. Förmodligen hot-spot för Calle's "olika storlekar".
130
+
131
+ ## Fix-strategi (Sprint 2-4)
132
+
133
+ Fyra fix-kategorier prioriterade efter ROI:
134
+
135
+ ### Quick-wins (Sprint 2)
136
+
137
+ 1. **Ta bort shadow på sheet/dialog**: paket-fix i overlay.css.
138
+ Använd surface-overlay-token istället för shadow för djup.
139
+ Estimat: 30 min + npm bump + 2 appar.
140
+
141
+ 2. **Fixa hero-padding alignment**: paket-fix i hero.css. Byt
142
+ `padding: 20px 4px 24px` till `padding: 20px 0 24px`.
143
+ Estimat: 15 min + bump.
144
+
145
+ 3. **Fixa Bolanet fs-51.6**: Ekonom-domain. Förmodligen
146
+ `font-size: clamp(...)` med fluid sizing som ger non-integer.
147
+ Estimat: 30 min audit + fix.
148
+
149
+ 4. **Lägg till spacing-rule på setting-list/footer-text**: 16px gap.
150
+ Paket-fix på .muted-footer-text. Estimat: 15 min + bump.
151
+
152
+ ### Medium-fixes (Sprint 3)
153
+
154
+ 5. **Konsolidera BR-skala till 4 värden**: 10/14/20 + 9999.
155
+ - Button = 10
156
+ - Stat-card/tab-bar/setting-row = 14 (lyfta från 12)
157
+ - Job-card/hub-card/swipe-card/banner/panel/form-card = 14 (lyfta
158
+ från 14/16/20 till en värde)
159
+ - Pills/avatars = 9999/50%
160
+
161
+ Faktiskt sänka radikalt: 10 + 14 + 9999 = bara 3 värden.
162
+
163
+ Estimat: 2-3h paket-fix + 1h re-audit visuellt.
164
+
165
+ 6. **Konsolidera padding-rytm till 5 värden**: 4/8/12/16/20.
166
+ Eliminera 6/10/14/18/24 från komponent-CSS.
167
+ Plus app-domain audit.
168
+
169
+ Estimat: 3-4h paket-fix + audit.
170
+
171
+ ### Kanonisering (Sprint 4)
172
+
173
+ 7. **Hero-doktrin**: en kanonisk hero-struktur med modifier-klasser
174
+ för varianter (.hero, .hero--amount, .hero--minimal).
175
+ Alla dashboards använder hero (eller medvetet skippa det).
176
+
177
+ Estimat: 2-3h doc + paket-update + app-migration.
178
+
179
+ 8. **Container-klassifikation**: matrix för när använda card vs
180
+ panel vs *-card. Etablera doktrin "panel = sektion-container,
181
+ card = klickbar enhet, hub-card = navigation-target".
182
+
183
+ Estimat: 1-2h doc.
184
+
185
+ ### Locked decisions (Sprint 5)
186
+
187
+ 9. **ADR 0013-visual-coherence-doctrine.md** locked.
188
+ 10. **DESIGN-LANGUAGE.md** i klodd-ds.
189
+ 11. **SKILL.md update** med 10/10 visuell + mekanisk status.
190
+
191
+ ## Datapunkter (för transparens)
192
+
193
+ Räknat över alla 17 vyer:
194
+
195
+ - **Unique BR-values**: 11
196
+ - **Unique font-sizes**: 13 (inkl rounding)
197
+ - **Unique padding-values**: 18 (kombinationer)
198
+ - **Unique container-classes**: 8
199
+ - **Vyer med shadow**: 4 av 17 (24%)
200
+ - **Vyer med hero**: 8 av 17 (47%)
201
+
202
+ Mätbar mål för 10/10 efter Sprint 2-4:
203
+ - BR-values: 11 → 4
204
+ - Font-sizes: 13 → 8 (matchande --fs-N-tokens)
205
+ - Padding-values: 18 → 6
206
+ - Vyer med shadow: 4 → 0 (regel 10 strikt)
207
+ - Vyer med hero: standardiserat per dashboard-doktrin
208
+
209
+ ## Begränsningar
210
+
211
+ - Endast mobile-viewport (430x932)
212
+ - Endast dashboard-vyer, inte modal/sheet-interna views
213
+ - Sheets/dialogs auditerade i DOM-state, inte open-state
214
+ - Animation/transition inte auditerade
215
+ - Tap-target visuellt verifierat på job-card (44x44) men inte
216
+ systematiskt över hela systemet