@klodd/ds 3.20.1 → 3.21.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.
@@ -122,6 +122,18 @@
122
122
  }
123
123
  }
124
124
 
125
+ /* --logout: subtil ghost-variant for "Logga ut"-knapp. Opacity 0.7
126
+ gor knappen visuellt mindre framtradande an primar-actions men
127
+ fortfarande klickbar. Lyft fran Ekonoms .logout-btn (v3.21.0).
128
+ Anvands som modifier ovanpa .btn--ghost --sm:
129
+ <button class="btn btn--ghost btn--sm btn--logout" data-action="logout">Logga ut</button> */
130
+ .btn--logout {
131
+ opacity: 0.7;
132
+ }
133
+ @media (hover: hover) and (pointer: fine) {
134
+ .btn--logout:hover { opacity: 1; }
135
+ }
136
+
125
137
  /* --positive: transparent + positive-border. Bekraftande action
126
138
  (t.ex. "Gemensam"-flagga i review_queue). Lyft fran Ekonom v3.9.0. */
127
139
  .btn--positive {
@@ -0,0 +1,57 @@
1
+ /* ================================================================
2
+ components/profile-panel.css
3
+ Centrerad profilkort: avatar (lg) + namn + email.
4
+ Anvands pa /jag (Ekonom) och /min-sida (Jubb).
5
+
6
+ Blocks:
7
+ .profile-panel - centrerad flex-column med komposit-children
8
+
9
+ Inga BEM-element - children ar paketets atomer (.avatar, .heading,
10
+ .inline-edit, .text-caption, .text-meta). Descendant-overrides
11
+ kalibrerar margin/layout for child-positions inom kortet.
12
+
13
+ Anvandning:
14
+ <div class="panel profile-panel">
15
+ <span class="avatar avatar--lg">CE</span>
16
+ <p class="text-meta">calle@klodd.io</p>
17
+ </div>
18
+
19
+ Med inline-edit (Ekonoms /jag-mönster):
20
+ <div class="panel profile-panel" data-profile-panel>
21
+ <span class="avatar avatar--lg">CE</span>
22
+ <p class="heading inline-edit">
23
+ <span class="inline-edit__text">Calle</span>
24
+ <button class="inline-edit__btn">...</button>
25
+ </p>
26
+ <p class="text-caption">calle@klodd.io</p>
27
+ </div>
28
+
29
+ Lyft fran Ekonoms .profile-panel-centered + Jubbs .profile-panel
30
+ (v3.21.0, 2026-05-13). Single source of truth ersatter app-domain-
31
+ kopior i ekonom.css + jubb.css.
32
+ ================================================================ */
33
+ .profile-panel {
34
+ display: flex;
35
+ flex-direction: column;
36
+ align-items: center;
37
+ text-align: center;
38
+ gap: var(--space-8);
39
+ padding: var(--space-20) var(--space-16);
40
+ }
41
+
42
+ .profile-panel .avatar--lg {
43
+ margin-bottom: var(--space-4);
44
+ }
45
+
46
+ .profile-panel .inline-edit {
47
+ display: inline-flex;
48
+ align-items: center;
49
+ gap: var(--space-6);
50
+ justify-content: center;
51
+ margin: 0;
52
+ }
53
+
54
+ .profile-panel .text-caption,
55
+ .profile-panel .text-meta {
56
+ margin: 0;
57
+ }
package/css/index.css CHANGED
@@ -41,6 +41,7 @@
41
41
  /* v2.0.0 - flyttade fran app-repona */
42
42
  @import './components/banner.css';
43
43
  @import './components/panel.css';
44
+ @import './components/profile-panel.css';
44
45
  @import './components/hub-card.css';
45
46
  @import './components/stat.css';
46
47
  @import './components/form.css';
package/css/utilities.css CHANGED
@@ -113,3 +113,68 @@
113
113
  /* Text-color utilities (CSP-migration: ersatter style="color: var(--text-X)") */
114
114
  .text-subtle { color: var(--text-subtle); }
115
115
  .text-muted { color: var(--text-muted); }
116
+
117
+
118
+ /* ================================================================
119
+ Layout-utilities (v3.21.0 lyft fran Jubb-domain)
120
+ ================================================================ */
121
+
122
+ /* Logout-rad: centrerad btn-wrapper. Anvands pa /jag (Ekonom) och
123
+ /min-sida (Jubb) som container for "Logga ut"-knappen. */
124
+ .logout-row {
125
+ display: flex;
126
+ justify-content: center;
127
+ margin-top: var(--space-24);
128
+ margin-bottom: var(--space-16);
129
+ }
130
+
131
+
132
+ /* ================================================================
133
+ Text-utilities (v3.21.0 lyft fran Jubb-domain)
134
+ ================================================================ */
135
+
136
+ /* Inline-separator "·" mellan meta-text-items. Disabled-fargad
137
+ sa den fungerar som tyst avgransning utan att dra blicken. */
138
+ .dot-sep {
139
+ margin: 0 var(--space-6);
140
+ color: var(--text-disabled);
141
+ }
142
+
143
+ /* Pre-formatted code/text. Sunken bakgrund, monospace, pre-wrap
144
+ for line-break-preservering med word-wrap pa lang text. */
145
+ .code-block {
146
+ margin: 0;
147
+ padding: var(--space-12);
148
+ background: var(--surface-sunken);
149
+ border-radius: var(--radius-14);
150
+ font-family: var(--font-mono);
151
+ font-size: var(--fs-12);
152
+ color: var(--text-subtle);
153
+ white-space: pre-wrap;
154
+ overflow-wrap: break-word;
155
+ }
156
+
157
+ /* Pre-formatted long-text (job-descriptions, multi-line content).
158
+ Likt .code-block men sans-font + default-fargad text. */
159
+ .description-block {
160
+ margin: 0;
161
+ font-family: var(--font-sans);
162
+ font-size: var(--fs-13);
163
+ color: var(--text-default);
164
+ white-space: pre-wrap;
165
+ overflow-wrap: break-word;
166
+ line-height: var(--lh-base);
167
+ }
168
+
169
+ /* ul med default discs + standardspacing. Plain bullet-lista. */
170
+ .bullet-list {
171
+ margin: 0;
172
+ padding-left: var(--space-20);
173
+ }
174
+
175
+ .bullet-list > li {
176
+ margin-bottom: var(--space-4);
177
+ font-size: var(--fs-13);
178
+ color: var(--text-default);
179
+ line-height: var(--lh-base);
180
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klodd/ds",
3
- "version": "3.20.1",
3
+ "version": "3.21.0",
4
4
  "description": "Klodd shared design system - tokens, components, JS",
5
5
  "main": "css/index.css",
6
6
  "bin": {
@@ -133,6 +133,15 @@ För varje entry gäller:
133
133
  - **Modifiers:** `.panel--info`, `.panel--info-warning`, `.panel--danger`, `.panel--attention`
134
134
  - **Anvand:** Sektion med ramad styling och titel
135
135
  - **INTE:** Klickbart kort (anvand `.card--interactive`)
136
+ - **HTML-tag for `.panel__title`:** `<h3>` default. Specialfall: `<span>` inom `.panel__step-row` (compound badge+title), `<summary>` inom `<details>`-element. Se ADR 0015 (panel-title-tag-doctrine).
137
+
138
+ ### profile-panel (`profile-panel.css`) - v3.21.0
139
+ - **Blocks:** `.profile-panel`
140
+ - **Anvand:** Centrerad profilkort med avatar + namn + email/meta. Pa /jag (Ekonom) och /min-sida (Jubb).
141
+ - **INTE:** Allmant kort med titel (anvand `.panel` med `.panel__title`)
142
+ - **Tokens:** `--space-8/-16/-20`, `--space-4` (avatar margin), `--space-6` (inline-edit gap)
143
+ - **Composition:** Inga egna BEM-element. Children ar paketets atomer (`.avatar--lg`, `.heading`, `.inline-edit`, `.text-caption`, `.text-meta`). Descendant-overrides for child-positions inom kortet.
144
+ - **Lyft fran:** Ekonoms `.profile-panel-centered` + Jubbs `.profile-panel` (v3.21.0).
136
145
 
137
146
  ### hub-card (`hub-card.css`)
138
147
  - **Blocks:** `.hub-card`, `.hub-list` (sibling-wrapper for kort-lista), `.hub-category` (sibling-rubrik over hub-list)
@@ -0,0 +1,147 @@
1
+ # 0014 - CSS Specificity Doctrine
2
+
3
+ ## Status
4
+ Locked.
5
+
6
+ ## Context
7
+
8
+ Sprint 2026-05-13 avslöjade en tyst CSS-specificity-bugg i kv-list.css.
9
+ Default-regeln var skriven som:
10
+
11
+ ```css
12
+ .kv-list > li:not(.kv-list__item--budget):not(.kv-list__item--divider) {
13
+ color: var(--text-subtle);
14
+ font-size: var(--fs-13);
15
+ }
16
+ ```
17
+
18
+ Specificity blev 0,3,1 (3 klasser via .kv-list + 2x :not()-arg, plus 1
19
+ li element). Modifier-reglerna `.kv-list__item--strong` (color: text-
20
+ default + medium weight) och `.kv-list__item--sub` (font-size: fs-11)
21
+ hade specificity 0,1,0 - kunde inte vinna mot 0,3,1.
22
+
23
+ Symptom: Calle/Lisa/Totalt-rader förblev text-subtle istället för
24
+ text-default (font-weight: medium tillämpades dock - delvis vinst gav
25
+ intryck att modifier "fungerade"). Verklig kostnad förblev fs-13
26
+ istället för fs-11.
27
+
28
+ Tyst bugg eftersom font-weight på --strong och font-size på --sub
29
+ INTE konflikterade med default-regeln, så modifier-classes såg ut att
30
+ fungera. Visuell skillnad förlorades men ingen runtime-error.
31
+
32
+ Felmönstret: `:not()`-filter på default-regeln drog upp specificity
33
+ till en nivå där flat modifier-classes inte kunde override:a.
34
+
35
+ ## Decision
36
+
37
+ **Locked regel:** default/base-regler för rad-layout, list-items,
38
+ comp-bas-styling **får inte** sätta `color`, `font-size`, `font-weight`,
39
+ `background`, `border`, `text-transform`, `letter-spacing` när
40
+ modifier-classes existerar för samma property.
41
+
42
+ Tre alternativ för att undvika konflikt:
43
+
44
+ ### Alternativ 1: Inheritance från block-parent (rekommenderat)
45
+
46
+ Sätt default-properties på **block-roten** (`.X`), inte på item-rule
47
+ (`.X__item` eller `.X > li`).
48
+
49
+ ```css
50
+ /* RÄTT */
51
+ .kv-list {
52
+ color: var(--text-subtle);
53
+ font-size: var(--fs-13);
54
+ }
55
+
56
+ .kv-list > li:not(--budget):not(--divider) {
57
+ display: flex;
58
+ padding: var(--space-8) 0;
59
+ /* INGEN color/font-size */
60
+ }
61
+
62
+ .kv-list__item--strong { /* specificity 0,1,0 - vinner via cascade */
63
+ color: var(--text-default);
64
+ font-weight: var(--fw-medium);
65
+ }
66
+ ```
67
+
68
+ Alla item-rader **ärver** color/font-size från `.kv-list`. Modifier-
69
+ classes (0,1,0) override:ar via inheritance utan specificity-konflikt.
70
+
71
+ ### Alternativ 2: Höj modifier-specificity
72
+
73
+ Om Alternativ 1 inte funkar (t.ex. parent har inte naturlig
74
+ inheritance-relation), matcha modifier-specificity till default-rule:
75
+
76
+ ```css
77
+ .X > li.X--strong:not(.X--budget):not(.X--divider) { color: ...; }
78
+ ```
79
+
80
+ Brus och svårläsligt - undvik om möjligt.
81
+
82
+ ### Alternativ 3: :where() runt default-rule
83
+
84
+ ```css
85
+ :where(.X > li:not(.X--budget):not(.X--divider)) {
86
+ color: var(--text-subtle); /* specificity 0,0,0 */
87
+ }
88
+ ```
89
+
90
+ `:where()` nollställer specificity. Modifiers vinner trivialt. Modernt
91
+ CSS (alla browsers sedan 2021). Använd när inheritance inte fungerar
92
+ och Alternativ 2 är för fult.
93
+
94
+ ## Konsekvenser
95
+
96
+ **Bra:**
97
+ - Modifier-classes vinner förutsägbart utan specificity-hack
98
+ - Default-rules kan ha `:not()`-filter för layout-undantag utan att
99
+ förstöra modifier-override
100
+ - Inheritance-based design ger renare CSS (mindre upprepning)
101
+
102
+ **Trade-offs:**
103
+ - Kräver att block-parent (.X) finns och har naturlig
104
+ inheritance-relation
105
+ - Inheritance fungerar inte för layout-properties (display, padding,
106
+ gap) - dessa måste fortfarande sättas på item-rule
107
+ - Lite mer tankearbete vid komponent-design (vad är "default" och vad
108
+ är "modifier-overridable")
109
+
110
+ ## Migration: kv-list 3.19.0 → 3.19.3
111
+
112
+ 3.19.1 introducerade `:not()`-filter på default-rule (för --budget +
113
+ --divider exclusion) som gav specificity 0,3,1. Modifier-reglerna
114
+ tappade tyst. Tre patches behövdes:
115
+
116
+ - 3.19.1: layout-fix för bare LI (introducerade buggen)
117
+ - 3.19.2: fix layout för --budget (lade till :not()-filter)
118
+ - 3.19.3: flyttade color/font-size från item-rule till .kv-list-
119
+ parent (löste specificity-konflikten)
120
+
121
+ ## Audit över paketet
122
+
123
+ Sprint 2026-05-13 audit över alla 39 paket-CSS-filer hittade INGEN
124
+ liknande bugg utöver kv-list. Övriga komponenter har:
125
+ - Default-rules på 0,1,0 (.X { ... }) - matchas av modifier 0,1,0 via
126
+ cascade-order
127
+ - Context-overrides på 0,2,0 (.X--mod .X__element) - intentional för
128
+ cross-element-styling, inte konflikt mot self-modifier
129
+
130
+ Mönstret som triggade kv-list-buggen var unikt: `:not()`-filter på
131
+ en default-rule som också konkurrerade om color/font-size med
132
+ modifiers på samma block. Det mönstret ska undvikas framöver.
133
+
134
+ ## Future work
135
+
136
+ 1. **Stylelint-plugin** för att varna när default-rules sätter samma
137
+ property som modifier-rules i samma fil.
138
+ 2. **Custom selector-specificity-linting**: flagga rules med
139
+ specificity > 0,2,0 som inte är context-overrides.
140
+
141
+ ## References
142
+
143
+ - klodd-ds commit 9854004 (3.19.3 fix)
144
+ - kv-list.css JSDoc-header rad 24-35
145
+ - DESIGN-LANGUAGE.md sektion 14 (CSS-specificity-disciplin)
146
+ - ADR 0011-strikt-bem-elementsyntax.md (besläktad)
147
+ - ADR 0013-visual-coherence-doctrine.md (besläktad)
@@ -0,0 +1,122 @@
1
+ # 0015 - Panel-title-tag-doctrine
2
+
3
+ ## Status
4
+ Locked.
5
+
6
+ ## Context
7
+
8
+ Audit 2026-05-13 kvällsessionen avslöjade två problem med
9
+ `.panel__title`-användning över Klodd-ekosystemet:
10
+
11
+ **Problem 1: Inkonsekvent HTML-tagg i Ekonom.**
12
+ - 35 platser använder `<div class="panel__title">` (94%)
13
+ - 2 platser använder `<span class="panel__title">` (auto_kategorisering.html)
14
+ - 1 plats använder `<summary class="panel__title">` (bolan.html)
15
+
16
+ `<div>` saknar heading-semantik. Screen readers kan inte navigera
17
+ mellan paneler via heading-nav. Sökmotorer ser ingen rubrik-hierarki.
18
+
19
+ **Problem 2: Jubb använder `.hero__label` som panel-rubrik.**
20
+ - 25 platser har `<p class="hero__label">` som rubrik för en panel som
21
+ innehåller list/text/textarea - INTE följd av `.hero__amount`.
22
+ - Bara 1 plats är legitim hero-kontext (dashboard.html med pending_count
23
+ som hero-amount).
24
+
25
+ Felanvändningen uppstod eftersom `.hero__label` och `.panel__title`
26
+ visuellt liknar varandra (12px vs 11px, samma color/weight/letter-
27
+ spacing). Felet kostade inget visuellt, men semantiskt är klassen
28
+ "label OVAN en hero-amount" - inte en generisk paneltitel.
29
+
30
+ ## Decision
31
+
32
+ **Locked regel:** panel-rubriker använder `<h3 class="panel__title">`
33
+ som default-tagg.
34
+
35
+ ### Specialfall (två dokumenterade undantag)
36
+
37
+ **1. Inline i `.panel__step-row` eller `.panel__title-row`:**
38
+
39
+ Använd `<span class="panel__title">` när rubriken sitter inline i en
40
+ flex-rad med andra element (step-badge, meta, link). Block-element
41
+ (h3) bryter flex-layouten.
42
+
43
+ ```html
44
+ <div class="panel__step-row">
45
+ <span class="panel__step-badge">Steg 1</span>
46
+ <span class="panel__title">Bankavi-matchning</span>
47
+ </div>
48
+ ```
49
+
50
+ **2. Inom `<details>`-element:**
51
+
52
+ Använd `<summary class="panel__title">` eftersom native HTML kräver
53
+ `<summary>` som första child av `<details>`. Summary fungerar
54
+ analogt med en heading - aria-tree exponerar den som klickbar
55
+ expander.
56
+
57
+ ```html
58
+ <details class="panel">
59
+ <summary class="panel__title">Värderingshistorik (3)</summary>
60
+ <ul class="list mt-12">...</ul>
61
+ </details>
62
+ ```
63
+
64
+ ### `.hero__label` vs `.panel__title` - definition
65
+
66
+ - `<p class="hero__label">` används ENDAST om följt av `<p class="hero-amount">`
67
+ eller `<p class="hero__amount--card">`. Klassen är "labeltext OVANFÖR
68
+ en stor siffer-display".
69
+ - Allt annat (rubrik för list, table, form, text-content) ska vara
70
+ `<h3 class="panel__title">`.
71
+
72
+ Card-hero-pattern (panel som innehåller hero-mönster) är legitimt:
73
+
74
+ ```html
75
+ <div class="panel collapsible">
76
+ <p class="hero__label">Gemensamma utgifter</p>
77
+ <p class="hero__amount--card">12 500 kr</p>
78
+ </div>
79
+ ```
80
+
81
+ Här är `.hero__label` korrekt eftersom `.hero__amount--card` följer.
82
+
83
+ ## Konsekvenser
84
+
85
+ **Bra:**
86
+ - A11y-semantik korrekt: screen readers exponerar paneler som
87
+ navigerbara rubriker
88
+ - Industri-praxis (Radix UI, Material UI, Chakra renderar card-title
89
+ som h3 default)
90
+ - CSS oförändrad - `.panel__title`-stylling targetar klassen, inte
91
+ taggen
92
+ - Konsekvens över Klodd-ekosystemet (Jubb + Ekonom + framtida appar)
93
+
94
+ **Trade-offs:**
95
+ - Heading-hierarki är inte alltid h1→h2→h3 över hela sajten. Vyer utan
96
+ `<h1 class="heading-1">` får h3 som top-level (icke-ideal men inte
97
+ brott - browser-tree är OK med "skipping levels").
98
+ - Future custom stylelint-plugin kan enforce: `<h3 class="panel__title">`
99
+ default + dokumenterade specialfall. Tills dess är det human-disciplin.
100
+
101
+ ## Migration 2026-05-13
102
+
103
+ **Klodd-ds:** denna ADR + 02-components.md panel-entry uppdaterad +
104
+ DESIGN-LANGUAGE.md ny sektion 16 (HTML-tagg-konvention).
105
+
106
+ **Ekonom:** 35 `<div class="panel__title">` → `<h3 class="panel__title">`.
107
+ Specialfall (2 span + 1 summary) behålls med kommentar i template.
108
+
109
+ **Jubb:** 25 `<p class="hero__label">` (icke-hero-kontext) →
110
+ `<h3 class="panel__title">`. Legitim hero-användning (dashboard.html
111
+ rad 16) oförändrad.
112
+
113
+ Inga CSS-ändringar, ingen npm publish behövs. Bara templates +
114
+ dokumentation.
115
+
116
+ ## References
117
+
118
+ - DESIGN-LANGUAGE.md sektion 3 (hero vs page-header patterns)
119
+ - 02-components.md panel-entry
120
+ - 02-components.md hero-entry
121
+ - ADR 0011-strikt-bem-elementsyntax.md (besläktad - BEM-disciplin)
122
+ - ADR 0013-visual-coherence-doctrine.md (besläktad - visuell rytm)
@@ -376,6 +376,122 @@ universell PWA-refresh-action via tap på vänster avatar.
376
376
 
377
377
  **Etablerad 2026-05-13.** Refaktor från flex till grid samma datum.
378
378
 
379
+ ## 14. CSS Specificity-disciplin (modifier-vinst)
380
+
381
+ **Regel:** default/base-regler för komponenter får INTE sätta `color`,
382
+ `font-size`, `font-weight`, `background`, `border`, `text-transform`
383
+ eller `letter-spacing` på item-level när modifier-classes existerar
384
+ för samma property.
385
+
386
+ **Default-properties ska sättas på block-roten** (`.X`), inte på
387
+ item-rule. Item-rader ärver via cascade, modifier-classes (0,1,0)
388
+ override:ar utan specificity-konflikt.
389
+
390
+ **RÄTT (kv-list 3.19.3):**
391
+ ```css
392
+ .kv-list {
393
+ color: var(--text-subtle); /* default på block-root */
394
+ font-size: var(--fs-13);
395
+ }
396
+
397
+ .kv-list > li:not(--budget):not(--divider) {
398
+ display: flex;
399
+ /* INGEN color/font-size här */
400
+ }
401
+
402
+ .kv-list__item--strong { /* 0,1,0 vinner via cascade */
403
+ color: var(--text-default);
404
+ font-weight: var(--fw-medium);
405
+ }
406
+ ```
407
+
408
+ **FEL (kv-list 3.19.1-3.19.2 - tyst bugg):**
409
+ ```css
410
+ .kv-list > li:not(--budget):not(--divider) {
411
+ color: var(--text-subtle); /* 0,3,1 - för hög! */
412
+ font-size: var(--fs-13);
413
+ }
414
+
415
+ .kv-list__item--strong { /* 0,1,0 - vinner inte mot 0,3,1 */
416
+ color: var(--text-default); /* förlorar */
417
+ font-weight: var(--fw-medium); /* OK - ingen konflikt */
418
+ }
419
+ ```
420
+
421
+ Tyst bugg: modifier-classes vinner DELVIS (font-weight) men förlorar
422
+ på color/font-size. Visuell skillnad försvinner. Ingen runtime-error.
423
+
424
+ Se ADR 0014 för fullständig analys + alternativa lösningar (`:where()`,
425
+ modifier-specificity-boost).
426
+
427
+ **Etablerad 2026-05-13** efter kv-list-specificity-incidenten.
428
+
429
+ ## 15. Sentence-case för labels (svenska)
430
+
431
+ **Regel:** label- och header-style text använder sentence-case
432
+ ("Din dagsbudget"), inte uppercase ("DIN DAGSBUDGET"). Visuell
433
+ hierarki kommer från font-size + weight + color, inte caps.
434
+
435
+ **Sentence-case (default):**
436
+ - `.hero__label`, `.panel__title`, `.form-section__title`
437
+ - `.sheet__title`, `.hub-category`, `.sub-section-header`
438
+ - Banner-headings, empty-state titlar, card-rubriker
439
+
440
+ **Uppercase behålls (etablerad konvention):**
441
+ - `.heading-4`, `.text-tiny` (semantiska typo-klasser, dokumenterade
442
+ som "micro-tracker")
443
+ - `.table th` (tabellhuvuden)
444
+ - `.swipe-decision-overlay` (action-overlays SPARA/FÖRVISA)
445
+ - `.avatar` (initialer "CE")
446
+ - `.panel__step-badge`, `.sheet__field-label--upper` (explicit modifier)
447
+ - Styleguide-element i `/design` (visuell hierarki via caps)
448
+
449
+ **Rationale:** svensk grafisk konvention. Calle 2026-05-13: "bara
450
+ capital letter och sen gemener, som vanligt." Matchar iOS Settings,
451
+ Apple HIG, modern app-design. Caps reserveras för badges/actions/
452
+ metadata där tighet + kort längd gör det läsbart.
453
+
454
+ **Letter-spacing:** sentence-case-text använder `var(--ls-tight)`,
455
+ inte `--ls-wider` eller hårdkodad 0.04-0.12em (det är designat för
456
+ uppercase-tracking och ser sträckt ut i sentence-case).
457
+
458
+ **Etablerad 2026-05-13** efter uppercase-audit över paketet.
459
+
460
+ ## 16. HTML-tagg för `.panel__title`
461
+
462
+ **Regel:** panel-rubriker använder `<h3 class="panel__title">` som
463
+ default-tagg. Två specialfall behålls:
464
+
465
+ | Kontext | Tagg | Skäl |
466
+ |---|---|---|
467
+ | Default | `<h3>` | A11y-semantik, screen-reader-navigerbar |
468
+ | Inom `.panel__step-row` | `<span>` | Compound badge+title som en konceptuell rubrik (Steg 1: X) |
469
+ | Inom `<details>` | `<summary>` | Native HTML-krav (summary måste vara första child) |
470
+
471
+ **Definition av `.hero__label` vs `.panel__title`:**
472
+ - `<p class="hero__label">` ENDAST om följt av `<p class="hero-amount">`
473
+ eller `<p class="hero__amount--card">`. Klassen är "labeltext OVANFÖR
474
+ en stor siffer-display".
475
+ - Allt annat (rubrik för list, table, form, text-content, knapp) ska
476
+ vara `<h3 class="panel__title">`.
477
+
478
+ **Förbjudet:**
479
+ - `<div class="panel__title">` (saknar heading-semantik)
480
+ - `<p class="panel__title">` (paragraph är fel semantik för rubrik)
481
+ - `<h3 class="hero__label">` (mismatch klass/tagg)
482
+
483
+ **Rationale:** `<div>` är aria-tree-osynligt - screen readers kan inte
484
+ navigera mellan paneler via heading-shortcut. `<h3>` är industri-praxis
485
+ för card-titles (Radix UI, Material UI, Chakra). CSS oförändrad
486
+ eftersom `.panel__title`-stylling targetar klassen, inte taggen.
487
+
488
+ **Heading-hierarki:** vyer med `<h1 class="heading-1">` får h1→h3
489
+ (legitimt skip). Vyer utan h1 får h3 som top-level (icke-ideal men
490
+ inte brott - browser-tree accepterar skipping levels).
491
+
492
+ **Etablerad 2026-05-13** efter panel__title-audit över Jubb + Ekonom.
493
+ Se ADR 0015 (panel-title-tag-doctrine).
494
+
379
495
  ## 12. När ändra regler
380
496
 
381
497
  Denna fil är **locked**. Ändringar kräver: