@klodd/ds 3.20.0 → 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.
- package/css/10-semantic.css +3 -1
- package/css/components/button.css +12 -0
- package/css/components/profile-panel.css +57 -0
- package/css/index.css +1 -0
- package/css/utilities.css +65 -0
- package/package.json +1 -1
- package/references/02-components.md +9 -0
- package/references/04-locked-decisions/0014-css-specificity-doctrine.md +147 -0
- package/references/04-locked-decisions/0015-panel-title-tag-doctrine.md +122 -0
- package/references/DESIGN-LANGUAGE.md +116 -0
package/css/10-semantic.css
CHANGED
|
@@ -327,7 +327,9 @@
|
|
|
327
327
|
--card-bg: var(--surface-default);
|
|
328
328
|
--card-bg-elevated: var(--surface-raised);
|
|
329
329
|
--card-border-color: var(--border-subtle);
|
|
330
|
-
--card-radius
|
|
330
|
+
/* 2026-05-13: --card-radius borttaget. Var --radius-20 (legacy) men
|
|
331
|
+
ingen komponent konsumerade tokenet. Kort-komponenter anvander
|
|
332
|
+
var(--radius-14) direkt enligt BR-skalan. */
|
|
331
333
|
--card-padding-x: var(--space-18);
|
|
332
334
|
--card-padding-y: var(--space-16);
|
|
333
335
|
--card-margin-bottom: var(--space-14);
|
|
@@ -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
|
@@ -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:
|