@klodd/ds 3.21.5 → 4.0.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.
@@ -17,8 +17,8 @@
17
17
  anvand dessa klasser eller (i komponentens CSS) primitive-tokens
18
18
  med kommentar om varfor en bundlad klass inte rackte.
19
19
 
20
- Undantag: .hero-amount (display-siffra, fw 600) - dokumenterat
21
- undantag i components/hero-roll.css.
20
+ Undantag: .hero__amount (display-siffra, fw 600) - dokumenterat
21
+ undantag i components/hero.css per ADR 0019.
22
22
  ================================================================ */
23
23
 
24
24
 
@@ -1,41 +1,41 @@
1
1
  /* ================================================================
2
2
  components/hero-roll.css
3
3
  Delad animationskomponent: kodlas-rullnings-animation pa hero-siffror.
4
- Aktiveras via <p class="hero-amount" data-animate-roll="N">N kr</p>
4
+ Aktiveras via <p class="hero__amount" data-animate-roll="N">N kr</p>
5
5
  och hero-roll.js. Ursprung: Ekonom Sprint J + J.3-J.6 (2026-04-27 ff).
6
6
 
7
- Helt app-token-fri - referar bara primitives (--lh-tight, --space-N,
8
- --fs-N, --fw-medium) och en text-color (--text-default). Inga
9
- --accent-*, --blue-*, --purple-* eller andra app-overrides. Samma
10
- styling for Jubb och Ekonom.
7
+ v4.0.0 (2026-05-14, ADR 0019): `.hero-amount`-compound raderad.
8
+ `.hero__amount` ar nu canonisk i hero.css. Digit-roller-children
9
+ ar BEM-element av separat block `.hero-roll` (anti-3-niva-nesting).
10
+
11
+ Helt app-token-fri - refererar bara primitives. Samma styling for
12
+ Jubb och Ekonom.
11
13
 
12
14
  Krav for korrekt rendering:
13
15
  - font-variant-numeric: tabular-nums (sa 0-9-glyfer ar lika breda)
14
16
  - --lh-tight definierad i primitives (anvands som rullhojd)
15
17
  - prefers-reduced-motion respekteras (hoppar direkt till slut-state)
18
+
19
+ Blocks:
20
+ .hero-roll - animation-mekanism (bara BEM-children, ingen baseregel)
21
+
22
+ Element:
23
+ .hero-roll__digit-roller - en per siffra, overflow:hidden-clipper
24
+ .hero-roll__digit-track - vertikal stack av siffer-spans
25
+ .hero-roll__static-char - mellanslag och "kr"-suffix mellan rollers
16
26
  ================================================================ */
17
27
 
18
28
 
19
29
  /* ================================================================
20
- ==== HERO-AMOUNT BAS
21
- Display-siffran. Storre an UI-text och tyngre vikt for visuell
22
- prioritet. Server renderar slutvardet som text - JS bygger
23
- digit-roller-DOM vid trigger och restoreraar tillbaka till server-
24
- text vid done.
30
+ ==== HERO__AMOUNT INLINE-FLEX VID ANIMATION
31
+ .hero__amount ar default block-flow (text-content). Nar JS bygger
32
+ roller-children-DOM aktiveras inline-flex via :has()-selector sa
33
+ rollerna staplas horizontellt. Server-text + post-animation-restore
34
+ behaller default block-flow.
25
35
  ================================================================ */
26
- .hero-amount {
27
- /* 2026-05-13: fs-80 → fs-100 default (25% storre) for hero-display-tyngd.
28
- Apparna kan overstyra via --hero-amount-fz om mindre size behovs. */
29
- font-size: var(--hero-amount-fz, var(--fs-100));
30
- /* Undantag fran 400/500-policy: display-siffra, inte UI-text.
31
- 600 ger nodvandig visuell tyngd pa hero-storlekar. */
32
- font-weight: 600;
33
- letter-spacing: var(--ls-tightest);
34
- color: var(--text-default);
35
- line-height: var(--lh-tight);
36
- /* Tabular-nums kritisk for rullnings-animationen: alla 0-9-glyfer
37
- packas identiskt sa layout inte vibrerar nar siffran roterar. */
38
- font-variant-numeric: tabular-nums;
36
+ .hero__amount[data-animate-roll]:has(.hero-roll__digit-roller) {
37
+ display: inline-flex;
38
+ align-items: baseline;
39
39
  }
40
40
 
41
41
 
@@ -44,7 +44,7 @@
44
44
  En per siffra. Containrar en track av siffror som translateY:as
45
45
  till slutvardet. Overflow:hidden klipper allt utom synlig position.
46
46
  ================================================================ */
47
- .hero-amount__digit-roller {
47
+ .hero-roll__digit-roller {
48
48
  display: inline-block;
49
49
  height: var(--hero-digit-height, 1em);
50
50
  line-height: var(--hero-digit-height, 1em);
@@ -56,8 +56,8 @@
56
56
  /* Vignett over och under sa siffrorna fadar ut nar de rullar in/ut.
57
57
  --hero-vignette-color satts av app-konsumenten om subtle fade
58
58
  onskas mot bg, default transparent. */
59
- .hero-amount__digit-roller::before,
60
- .hero-amount__digit-roller::after {
59
+ .hero-roll__digit-roller::before,
60
+ .hero-roll__digit-roller::after {
61
61
  content: '';
62
62
  position: absolute;
63
63
  left: 0;
@@ -68,7 +68,7 @@
68
68
  background: transparent;
69
69
  }
70
70
 
71
- .hero-amount__digit-roller::before {
71
+ .hero-roll__digit-roller::before {
72
72
  top: 0;
73
73
  background: linear-gradient(
74
74
  to bottom,
@@ -77,7 +77,7 @@
77
77
  );
78
78
  }
79
79
 
80
- .hero-amount__digit-roller::after {
80
+ .hero-roll__digit-roller::after {
81
81
  bottom: 0;
82
82
  background: linear-gradient(
83
83
  to top,
@@ -91,15 +91,15 @@
91
91
  ==== DIGIT-TRACK
92
92
  Vertikal stack av siffer-spans. translateY-styrt av JS via inline
93
93
  transition + transform. tabular-nums upprepad pa span-niva som
94
- safety-net om hero-amount-arvet skulle brytas av nan parent.
94
+ safety-net om hero__amount-arvet skulle brytas av nan parent.
95
95
  ================================================================ */
96
- .hero-amount__digit-track {
96
+ .hero-roll__digit-track {
97
97
  display: flex;
98
98
  flex-direction: column;
99
99
  will-change: transform;
100
100
  }
101
101
 
102
- .hero-amount__digit-track > span {
102
+ .hero-roll__digit-track > span {
103
103
  height: var(--hero-digit-height, 1em);
104
104
  line-height: var(--hero-digit-height, 1em);
105
105
  display: block;
@@ -112,7 +112,7 @@
112
112
  Mellanslag och "kr"-suffix runt rollers. white-space: pre bevarar
113
113
  exakta blanksteg.
114
114
  ================================================================ */
115
- .hero-amount__static-char {
115
+ .hero-roll__static-char {
116
116
  display: inline-block;
117
117
  white-space: pre;
118
118
  }
@@ -125,7 +125,7 @@
125
125
  denna regel bara safety-net for befintliga inline-transitions.
126
126
  ================================================================ */
127
127
  @media (prefers-reduced-motion: reduce) {
128
- .hero-amount__digit-track {
128
+ .hero-roll__digit-track {
129
129
  transition: none !important;
130
130
  }
131
131
  }
@@ -3,21 +3,26 @@
3
3
  Stora display-rubriker med amount + meta. Används på dashboard,
4
4
  detaljvyer, primary-page-toppar.
5
5
 
6
+ v4.0.0 (2026-05-14, ADR 0019): `.hero-amount`-compound-block raderat.
7
+ `.hero__amount` är canonisk klass för alla hero-display-siffror
8
+ (animerade och statiska). Digit-roller-animationen bygger
9
+ `.hero-roll__*`-children inom `.hero__amount[data-animate-roll]` -
10
+ se components/hero-roll.css.
11
+
6
12
  Blocks:
7
- .hero - wrapper med padding och text-alignment (huvud-block)
8
- .hero-amount - sibling-block: hero-roll-animations-target
13
+ .hero - wrapper med padding och text-alignment (huvud-block)
9
14
 
10
- .hero har BEM-element (__heading/__amount/__amount-row/__label/__meta/__actions).
11
- .hero-amount är ett separat root-block av historiska skäl - hero-roll-
12
- animationen adresserar just klassen .hero-amount[data-animate-roll],
13
- inte .hero__amount. Definieras även i hero-roll.css (animation-styling).
15
+ Element:
16
+ .hero__heading, .hero__label, .hero__amount, .hero__amount-row,
17
+ .hero__meta, .hero__actions
14
18
 
15
19
  Modifiers:
16
- .hero__amount --card (40px sekundär), --fluid (clamp 40-80px)
17
20
  .hero__label --muted
21
+ .hero__amount --card (40px sekundär), --fluid (clamp 40-80px)
18
22
 
19
- Se components/hero-roll.css för digit-roller-styling när
20
- data-animate-roll triggar animationen.
23
+ .hero__amount font-weight 600 är dokumenterat undantag från
24
+ 400/500-policyn (regel 5) - display-siffer-tyngd ärvd från tidigare
25
+ `.hero-amount`-implementation per ADR 0019.
21
26
  ================================================================ */
22
27
  .hero {
23
28
  /* 2026-05-13: text-align center for hero-sektion. Hero-content
@@ -56,9 +61,15 @@
56
61
  }
57
62
 
58
63
  .hero__amount {
59
- /* 2026-05-13: fs-80 → fs-100 (25% storre) for mer display-tyngd. */
60
- font-size: var(--fs-100);
61
- font-weight: var(--fw-medium);
64
+ /* 2026-05-13: fs-80 → fs-100 (25% storre) for mer display-tyngd.
65
+ 2026-05-14 (ADR 0019): font-size konsumerar --hero-amount-fz-token
66
+ for app-override-mojlighet. */
67
+ font-size: var(--hero-amount-fz, var(--fs-100));
68
+ /* Undantag fran 400/500-policy (regel 5): display-siffra, inte
69
+ UI-text. 600 ger nodvandig visuell tyngd pa hero-storlekar.
70
+ Per ADR 0019 garlder weight 600 alla hero__amount-instances
71
+ (animerade och statiska) for konsekvens. */
72
+ font-weight: 600;
62
73
  letter-spacing: var(--ls-tightest, -0.04em);
63
74
  color: var(--text-default);
64
75
  line-height: var(--lh-tight);
package/js/hero-roll.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* Hero Roll Animation - delad komponent
2
- * Krav: .hero-amount[data-animate-roll] i HTML
2
+ * Krav: .hero__amount[data-animate-roll] i HTML
3
3
  * Krav: font-variant-numeric: tabular-nums pa elementet
4
4
  * Krav: --lh-tight definierad i CSS (anvands som rullhojd)
5
5
  * Turbo: triggar via turbo:swap-event om Turbo finns, annars fresh-session only
@@ -68,7 +68,7 @@
68
68
  let lastSeenUrl = window.location.href;
69
69
 
70
70
  function getHeroEl () {
71
- return document.querySelector( '.hero-amount[data-animate-roll]' );
71
+ return document.querySelector( '.hero__amount[data-animate-roll]' );
72
72
  }
73
73
 
74
74
  function prefersReducedMotion () {
@@ -77,10 +77,10 @@
77
77
 
78
78
  function buildRoller ( targetDigit ) {
79
79
  const roller = document.createElement( 'span' );
80
- roller.className = 'hero-amount__digit-roller';
80
+ roller.className = 'hero-roll__digit-roller';
81
81
 
82
82
  const track = document.createElement( 'span' );
83
- track.className = 'hero-amount__digit-track';
83
+ track.className = 'hero-roll__digit-track';
84
84
 
85
85
  const totalSteps = targetDigit + ( EXTRA_ROUNDS * 10 );
86
86
  for ( let i = 0; i <= totalSteps; i++ ) {
@@ -95,7 +95,7 @@
95
95
 
96
96
  function buildStaticChar ( text ) {
97
97
  const span = document.createElement( 'span' );
98
- span.className = 'hero-amount__static-char';
98
+ span.className = 'hero-roll__static-char';
99
99
  span.textContent = text;
100
100
  return span;
101
101
  }
package/js/turbo-nav.js CHANGED
@@ -256,7 +256,7 @@
256
256
  performSwap( doc );
257
257
  // Sprint J.3: dispatcha SYNKRON 'turbo:swap'-event INOM
258
258
  // swap-callback fore VT slut-snapshot tas. Subscribers (hero-
259
- // roll.js) kan modifiera nya DOM (t.ex. byta ut hero-amount
259
+ // roll.js) kan modifiera nya DOM (t.ex. byta ut hero__amount
260
260
  // till digit-rollers) sa VT slut-state inkluderar deras
261
261
  // modifikationer. Forhindrar 0.2s-flash av server-text
262
262
  // under VT-fade vid month-change.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@klodd/ds",
3
- "version": "3.21.5",
3
+ "version": "4.0.0",
4
4
  "description": "Klodd shared design system - tokens, components, JS",
5
5
  "main": "css/index.css",
6
6
  "bin": {
@@ -80,12 +80,13 @@ För varje entry gäller:
80
80
  - **Tokens:** `currentColor` - parent-element styr fargen
81
81
 
82
82
  ### hero-roll (`hero-roll.css`)
83
- - **Blocks:** `.hero-amount` (definieras aven i `hero.css`)
84
- - **Element:** `.hero-amount__digit-roller`, `.hero-amount__digit-track`, `.hero-amount__static-char`
85
- - **States:** `[data-animate-roll]` pa `.hero-amount` (JS triggar animation)
83
+ - **Blocks:** `.hero-roll` (animation-mekanism - bara BEM-children, ingen baseregel; agglomereras inom `.hero__amount[data-animate-roll]`)
84
+ - **Element:** `.hero-roll__digit-roller`, `.hero-roll__digit-track`, `.hero-roll__static-char`
85
+ - **States:** `[data-animate-roll]` pa `.hero__amount` (JS triggar animation, bygger `.hero-roll__*`-children)
86
86
  - **Anvand:** Display-siffer-animation pa hero-vyer (kodlas-rullning). `__digit-roller` ar wrapper med ::before/::after-faders, `__digit-track` ar siffran-stack som flyttas vertikalt, `__static-char` ar statiska tecken (kr-suffix, kommatecken) utanfor rullnings-mekaniken.
87
87
  - **INTE:** Vanliga numeriska varden (anvand `.hero__amount` utan data-animate-roll)
88
- - **Tokens:** `--text-default`, `--lh-tight`, `--ls-tightest`, `--fs-80`. **Undantag:** `font-weight: 600` (display-undantaget fran 400/500-policyn).
88
+ - **Tokens:** `--text-default`, `--lh-tight`, `--ls-tightest`. CSS aktiverar `display: inline-flex` pa `.hero__amount[data-animate-roll]:has(.hero-roll__digit-roller)` sa rollerna staplas horizontellt.
89
+ - **Konvention (ADR 0019, v4.0.0):** `.hero-roll` ar separat block fran `.hero__amount` for att undvika 3-niva-BEM-nesting (`.block__elem__sub` ar forbjudet per ADR 0011). JS bygger `.hero-roll__*`-children inom `.hero__amount[data-animate-roll]` vid trigger.
89
90
 
90
91
  ### divider (`divider.css`)
91
92
  - **Blocks:** `.divider`
@@ -194,11 +195,13 @@ För varje entry gäller:
194
195
  - **INTE:** Single-bar-progress (anvand `.hbar`)
195
196
 
196
197
  ### hero (`hero.css`)
197
- - **Blocks:** `.hero`, `.hero-amount` (sibling, animation-target - definieras aven i `hero-roll.css`)
198
+ - **Blocks:** `.hero`
198
199
  - **Element:** `.hero__heading`, `.hero__amount`, `.hero__amount-row`, `.hero__label`, `.hero__meta`, `.hero__actions`
199
200
  - **Modifiers:** `.hero__amount--card`, `.hero__amount--fluid`, `.hero__label--muted`
200
- - **Anvand:** Stora display-rubriker (80px-skala default, 40px card)
201
+ - **Anvand:** Stora display-rubriker. `.hero__amount` ar default 100px (via `--hero-amount-fz`-token), `--card` 40px, `--fluid` clamp(40, 12vw, 80).
201
202
  - **INTE:** Vanlig `<h1>` (anvand `.heading-1`)
203
+ - **Animation:** `.hero__amount[data-animate-roll="N"]` triggar digit-roller-animation via hero-roll.js + hero-roll.css. Se `hero-roll`-entry ovan.
204
+ - **Konvention (ADR 0019, v4.0.0):** `.hero__amount` ar canonisk klass for alla hero-display-siffror (animerade och statiska). Tidigare `.hero-amount`-compound-block raderat. `.hero__amount` har `font-weight: 600` som dokumenterat undantag fran 400/500-policyn (regel 5) - display-tyngd.
202
205
 
203
206
  ### chip (`chip.css`)
204
207
  - **Blocks:** `.chip`, `.chip-list` (sibling-wrapper for chips i rad), `.brand-pill`, `.month-pill`
@@ -0,0 +1,122 @@
1
+ # 0018 - Outline-offset: list-rows får använda -2px (anti-clipping)
2
+
3
+ ## Status
4
+ Locked.
5
+
6
+ ## Context
7
+
8
+ DESIGN-LANGUAGE.md sektion 9 (etablerad 2026-05-12 via ADR 0013)
9
+ specificerade `outline: 2px solid var(--border-focus); outline-offset: 2px`
10
+ som regel för alla interaktiva element.
11
+
12
+ Audit 2026-05-14 (Ekonom UI/UX/CSS-cykel) visade att paketet självt
13
+ använder `outline-offset: -2px` på 5 komponenter:
14
+
15
+ | Fil | Selector | Värde |
16
+ |---|---|---|
17
+ | `collapsible.css:50` | `.collapsible__header:focus-visible` | `-2px` |
18
+ | `setting-row.css:63` | `.setting-row:focus-visible` | `-2px` |
19
+ | `sheet-content.css:101` | `.sheet__item:focus-visible` | `-1px` |
20
+ | `sheet-content.css:150` | `.sheet__btn--save:focus-visible` | `-1px` |
21
+ | `dropdown.css:72` | `.dropdown__item:focus-visible` | `-2px` |
22
+
23
+ Plus i Ekonom-domain:
24
+ - `ekonom.css:162` `.cat-row__header:focus-visible` `-2px`
25
+ - `ekonom.css:229` `.cat-list-row[data-tx-id]:focus-visible` `-2px`
26
+ - `ekonom.css:319` `.sub-row:focus-visible` `-2px`
27
+
28
+ Detta är **inte** slarv. Negative offset placerar outline _innanför_
29
+ elementets borders, vilket är nödvändigt för:
30
+
31
+ 1. **List-rows utan visible border**: outline +2px hänger utanför
32
+ elementet och clip:as av parent-list-row's border eller scroll-
33
+ container's `overflow: hidden`. Result: outline syns delvis eller
34
+ inte alls vid keyboard-fokus.
35
+ 2. **Dropdown-items inom radius-14-clippad menu**: outline +2px på
36
+ sista item:t clip:as av menu-borderns BR.
37
+ 3. **Items inom collapsible/sheet/card med BR-clipping**: samma
38
+ problem.
39
+
40
+ Standalone-element (knappar, inputs, links i text) har visible borders
41
+ eller tillräcklig spacing för outline +2px.
42
+
43
+ ## Decision
44
+
45
+ **Outline-offset är context-sensitive:**
46
+
47
+ ### -2px (inom-element, "inset")
48
+
49
+ Använd för items inom radius-clippade containers eller list-rader
50
+ utan visible border:
51
+ - `.list-row:focus-visible`
52
+ - `.setting-row:focus-visible`
53
+ - `.collapsible__header:focus-visible`
54
+ - `.sheet__item:focus-visible` (`-1px` pga tightare BR)
55
+ - `.sheet__btn--save:focus-visible` (`-1px`)
56
+ - `.dropdown__item:focus-visible`
57
+ - App-domain list-rows (Ekonom: `.cat-row__header`, `.cat-list-row[data-tx-id]`,
58
+ `.sub-row`; Jubb: motsvarande list-row-typer)
59
+
60
+ ### +2px (utanför-element, "outset")
61
+
62
+ Använd för standalone-element med visible border eller tillräcklig
63
+ spacing:
64
+ - `.btn:focus-visible`
65
+ - `.input:focus-visible` (text-input-undantag - använder `:focus`
66
+ istället per ADR-konvention, men om outline används är det +2px)
67
+ - `.skip-link:focus`
68
+ - `.chip:focus-visible`
69
+ - `.month-pill a:focus-visible`
70
+ - Topbar-actions (`.btn--icon`, `.pwa-avatar`, `.avatar` med focus)
71
+ - Generic `:focus-visible`-default i app/base.css
72
+
73
+ ### Komposita BR (för list-row med inset)
74
+
75
+ `border-radius: var(--radius-4)` på outline:n så den följer en mjuk
76
+ form, inte fyrkantig 0px. Per app/base.css default `:focus-visible`-rule.
77
+
78
+ ### Outline-bredd
79
+
80
+ `2px solid var(--accent-9)` (paket) eller `var(--border-focus)` (ADR
81
+ 0013-spec). Båda är acceptabla token-konsumenter.
82
+
83
+ ## Konsekvenser
84
+
85
+ **Bra:**
86
+ - Doktrinen matchar paketets faktiska implementation
87
+ - Future-CC har klar regel för var att applicera vilken offset
88
+ - Inset-värdet är _korrekt_ för list-rows (anti-clipping är funktionell
89
+ design, inte slarv)
90
+ - Stylelint-plugin (Sprint 5) kan validera per-komponent-typ
91
+
92
+ **Trade-offs:**
93
+ - Två varianter av outline-offset i systemet (-2/-1 vs +2). Komplexitet
94
+ ökar marginellt.
95
+ - Visuell skillnad mellan inset och outset är märkbar för
96
+ keyboard-användare. Outset är mer prominent, inset är mer subtil.
97
+ Trade-off: subtilitet vs synlighet. Anti-clipping vinner.
98
+
99
+ ## Migration
100
+
101
+ **Ingen migration krävs.** Paketet och appar är redan i låst state.
102
+ ADR dokumenterar bara regeln post-hoc.
103
+
104
+ Sprint F i Ekonom-auditen 2026-05-14 skippades baserat på denna analys -
105
+ fyndet var inte ett brott utan en medveten design-pattern som doktrinen
106
+ inte hade dokumenterat.
107
+
108
+ ## Stylelint-plugin (Sprint 5, framtida)
109
+
110
+ Validera:
111
+ - `outline-offset: -1px` eller `-2px` är endast tillåtet på selectors
112
+ som matchar list-row-/dropdown-item-/sheet-item-pattern
113
+ - `outline-offset: 2px` på alla andra :focus-visible-regler
114
+ - Varning vid avvikelse från ADR-tabellen ovan
115
+
116
+ ## References
117
+
118
+ - DESIGN-LANGUAGE.md sektion 9 (uppdaterad 2026-05-14)
119
+ - ADR 0013 (visual-coherence-doctrine) - tidigare regel
120
+ - Ekonom DECISIONS 2026-05-14 (audit-cykel skip-rationale för Sprint F)
121
+ - Audit-not: paketets faktiska outline-offset-värden inventoradde
122
+ 2026-05-14 via `grep -rEn "outline-offset:\s*-" app/static/css/ds/`
@@ -0,0 +1,153 @@
1
+ # 0019 - Hero-amount: en BEM-klass + hero-roll som separat block
2
+
3
+ ## Status
4
+ Locked. Major version-bump (4.0.0) - breaking change.
5
+
6
+ ## Context
7
+
8
+ Designsystemet hade två parallella klasser för samma display-siffer-koncept:
9
+
10
+ - `.hero-amount` (compound block i `hero-roll.css`, font-weight 600,
11
+ Tier D-undantag) - target för digit-roller-animation via
12
+ `[data-animate-roll]`-attribut.
13
+ - `.hero__amount` (BEM-element av `.hero` i `hero.css`, font-weight 500
14
+ via `--fw-medium`) - statisk display-text utan animation.
15
+
16
+ Plus modifiers `.hero__amount--card` (fs-40), `.hero__amount--fluid`
17
+ (clamp), `.hero__amount-row` (flex-wrapper) - alla på `.hero__amount`-
18
+ namespacet, inte `.hero-amount`.
19
+
20
+ Detta gav templates inkonsekvent klassanvändning:
21
+
22
+ | Template | Klass | Konsekvens |
23
+ |---|---|---|
24
+ | `avstamning.html` | `.hero-amount[data-animate-roll]` | Animerad, fw-600 |
25
+ | `bolan.html:22` | `.hero-amount.hero__amount--fluid` | Modifier på fel block |
26
+ | `bolan.html:130` | `.hero-amount.hero__amount--fluid` | Samma |
27
+ | `var_bostad.html:34` | `.hero-amount` | Statisk men fw-600 |
28
+ | `dashboard.html` (Jubb) | `.hero-amount[data-animate-roll]` | Animerad, fw-600 |
29
+
30
+ Per ADR 0011 ska modifier sitta på samma block som basklassen.
31
+ `.hero__amount--fluid` på `.hero-amount` är teknisk inkorrekt CSS.
32
+
33
+ Plus: `.hero-amount__digit-roller`, `.hero-amount__digit-track`,
34
+ `.hero-amount__static-char` är BEM-children med dubbel-segment som
35
+ i praktiken bryter ADR 0011-syntax-regeln (BEM stödjer inte 3-nivå-
36
+ nesting `.block__elem__sub`).
37
+
38
+ Per Calle 2026-05-14: "Vi kör konsekvent hero__amount. Det ska vara
39
+ samma. Ingen split."
40
+
41
+ ## Decision
42
+
43
+ ### En klass: `.hero__amount`
44
+
45
+ Alla hero-display-siffror använder `.hero__amount` (BEM-element av
46
+ `.hero`). `.hero-amount`-compound-block raderas helt. Modifiers
47
+ (`--card`, `--fluid`) appliceras på `.hero__amount`.
48
+
49
+ `.hero__amount` har **font-weight 600** som dokumenterat undantag från
50
+ 400/500-policyn (per Calle: behåll display-tyngd från tidigare
51
+ `.hero-amount`-implementation). Detta ärver behovet hero-roll-display-
52
+ siffror har för visuell tyngd.
53
+
54
+ ### Digit-roller children: `.hero-roll`-block
55
+
56
+ Animation-mekanismen renderar children som JS bygger inom `.hero__amount`.
57
+ Dessa namnges som BEM-children av ett separat block `.hero-roll`:
58
+
59
+ - `.hero-roll__digit-roller` (var: `.hero-amount__digit-roller`)
60
+ - `.hero-roll__digit-track` (var: `.hero-amount__digit-track`)
61
+ - `.hero-roll__static-char` (var: `.hero-amount__static-char`)
62
+
63
+ `.hero-roll` är ett separat block (bara children, ingen egen base-rule)
64
+ för att undvika 3-nivå-BEM-nesting (`.block__elem__sub` är förbjudet
65
+ per ADR 0011-syntax-regex).
66
+
67
+ JS-modulen `hero-roll.js` adresserar `.hero__amount[data-animate-roll]`
68
+ och bygger `.hero-roll__*`-children inom det elementet.
69
+
70
+ ### Filerna efter migration
71
+
72
+ `hero.css` äger `.hero__amount` baseregeln + alla modifiers
73
+ (`--card`, `--fluid`, samt `.hero__amount-row` wrapper).
74
+
75
+ `hero-roll.css` äger bara `.hero-roll__*`-children + `:has()`-aktivering
76
+ av `display: inline-flex` på `.hero__amount[data-animate-roll]:has(.hero-roll__digit-roller)`.
77
+
78
+ ### CSS-disciplin
79
+
80
+ `.hero__amount` font-weight 600-undantaget dokumenteras i `hero.css`-
81
+ JSDoc-header och i regel 5 (font-weight 400/500-policyn).
82
+
83
+ ## Migration
84
+
85
+ ### Klodd-ds (4.0.0)
86
+
87
+ - `css/components/hero.css` - `.hero__amount` font-weight 500 → 600 +
88
+ font-size använder `var(--hero-amount-fz, var(--fs-100))` (override-
89
+ vänligt)
90
+ - `css/components/hero-roll.css`:
91
+ - Radera `.hero-amount` baseregeln
92
+ - Rename `.hero-amount__digit-roller` → `.hero-roll__digit-roller`
93
+ - Rename `.hero-amount__digit-track` → `.hero-roll__digit-track`
94
+ - Rename `.hero-amount__static-char` → `.hero-roll__static-char`
95
+ - Update `:has()`-selector
96
+ - `css/base/typography.css` - kommentar uppdateras
97
+ - `js/hero-roll.js`:
98
+ - Selector `.hero-amount[data-animate-roll]` → `.hero__amount[data-animate-roll]`
99
+ - Roller-element className → `hero-roll__digit-roller`
100
+ - Track-element className → `hero-roll__digit-track`
101
+ - Static-char-element className → `hero-roll__static-char`
102
+ - `js/turbo-nav.js` - kommentar
103
+ - `references/02-components.md` - hero-roll-entry komplett rename
104
+ - `references/DESIGN-LANGUAGE.md` sektion 3 - uppdatera Pattern A
105
+
106
+ ### Ekonom
107
+
108
+ - 5 templates: `avstamning.html`, `bolan.html` (x2), `installningar/var_bostad.html`,
109
+ `design.html`. Klass `hero-amount` → `hero__amount`.
110
+ - `ds/base.css` 2 ställen: tabular-nums-selector + user-select-text
111
+ - SW VERSION + static_version bump
112
+
113
+ ### Jubb
114
+
115
+ - 2 templates med klassanvändning: `dashboard.html`, `design.html` (line 853)
116
+ - Doc-kommentarer i 3 templates uppdateras (base.html, design.html line 859,
117
+ 1336)
118
+ - `ds/base.css` 2 ställen
119
+ - `ds/jubb.css` rad 726-727 (desktop responsive overrides)
120
+ - `pages/design.css` rad 403 (.ds-anim-demo styling)
121
+ - SW VERSION + static_version bump
122
+
123
+ ### Stylelint-regex
124
+
125
+ Oförändrad - `.hero__amount` (en `__`) + `.hero-roll__digit-roller` (en `__`)
126
+ matchar standard-BEM. Inga undantag behövs i regex.
127
+
128
+ ## Konsekvenser
129
+
130
+ **Bra:**
131
+ - En klass per koncept - templates har inte längre val mellan
132
+ `.hero-amount` och `.hero__amount`
133
+ - Modifiers `--card`/`--fluid` används korrekt (på samma block som basklassen)
134
+ - BEM-konsekvens: ingen 3-nivå-nesting (`.block__elem__sub`)
135
+ - Future-CC kan inte introducera mismatch
136
+ - Stylelint fångar nya brott via existerande regex
137
+
138
+ **Trade-offs:**
139
+ - Major version-bump (4.0.0) - alla apparna måste uppdatera templates
140
+ + lokala CSS-overrides parallellt
141
+ - Visuell paritet: `.hero__amount` får font-weight 600 (var 500). Statiska
142
+ hero-vyer (utan digit-roller) kommer rendera tjockare display-text. Per
143
+ Calle: "konsekvent hero__amount" - ingen split, weight 600 vinner.
144
+ - `.hero-roll`-namn introducerar nytt block-koncept. Dokumentera i 02-components.
145
+
146
+ ## References
147
+
148
+ - ADR 0011 (strikt-bem-elementsyntax)
149
+ - ADR 0012 (stylelint-bem-enforcement)
150
+ - DESIGN-LANGUAGE.md sektion 3 (page-toppar)
151
+ - Ekonom DECISIONS 2026-05-14 (audit-cykel skip-rationale för Sprint D)
152
+ - Calle's beslut 2026-05-14: "Vi kör konsekvent hero__amount. Det ska
153
+ vara samma. Ingen split."
@@ -82,7 +82,7 @@ För dashboards där primär-data är en STOR siffer-display.
82
82
 
83
83
  ```html
84
84
  <section class="hero">
85
- <p class="hero__label">SEKTION-LABEL</p>
85
+ <p class="hero__label">Sektion-label</p>
86
86
  <p class="hero__amount">{stort-värde}</p>
87
87
  <p class="hero__meta">{kontextuell-info}</p>
88
88
  <div class="hero__actions">
@@ -91,12 +91,19 @@ För dashboards där primär-data är en STOR siffer-display.
91
91
  </section>
92
92
  ```
93
93
 
94
- `.hero__amount` är fs-80 (siffer-display). `.hero__amount--card`
95
- (fs-40) för hero inom panel. `.hero__amount--fluid` (clamp 40-80vw)
96
- för responsiv siffer-display.
94
+ `.hero__amount` är default fs-100 (`--hero-amount-fz`-token, override-vänlig
95
+ per app). `.hero__amount--card` (fs-40) för hero inom panel.
96
+ `.hero__amount--fluid` (clamp 40-80vw) för responsiv siffer-display.
97
+ Font-weight 600 dokumenterat undantag (display-tyngd, ADR 0019).
97
98
 
98
99
  Hero har `padding: 20px 0 24px` (alignment med övriga container-element).
99
100
 
101
+ **Animation:** lägg till `data-animate-roll="N"` på `.hero__amount`
102
+ för digit-roller-animation vid fresh-session eller turbo:swap. JS i
103
+ hero-roll.js bygger `.hero-roll__*`-children inom elementet. Se
104
+ ADR 0019 (`.hero__amount` är canonisk klass - tidigare `.hero-amount`
105
+ raderat i v4.0.0).
106
+
100
107
  ### Pattern B: `.page-header` (utility-page med titel)
101
108
 
102
109
  För pages utan primär-metric, bara navigation-kontext.
@@ -289,6 +296,24 @@ egna `margin-bottom`. Välj en mekanism per kontext.
289
296
  - List-rows: `padding: 14px 0` minimum (= 50px height med text-line).
290
297
  - Icon-buttons: `width: 44px; height: 44px`.
291
298
 
299
+ ### Focus-ring (outline-offset context-sensitive)
300
+
301
+ Outline-offset är **inte** alltid `+2px`. Inom radius-clippade
302
+ containers eller list-rader utan visible border klipps `+2px` outline
303
+ av parent. Använd inset (`-2px` eller `-1px`) i dessa fall för
304
+ synlig fokus-ring.
305
+
306
+ | Kontext | offset | Komponenter |
307
+ |---|---|---|
308
+ | Standalone-element med border eller spacing | `+2px` | `.btn`, `.chip`, `.skip-link`, `.month-pill a`, topbar-actions, generic `:focus-visible` |
309
+ | List-rader utan visible border | `-2px` | `.list-row`, `.setting-row`, `.collapsible__header`, `.dropdown__item` |
310
+ | Items inom radius-clippad menu/sheet | `-1px` | `.sheet__item`, `.sheet__btn--save` (tightare BR kräver -1) |
311
+ | App-domain list-rows | `-2px` | Ekonom `.cat-row__header`/`.cat-list-row[data-tx-id]`/`.sub-row`; Jubb motsvarande |
312
+
313
+ `outline: 2px solid var(--accent-9)` (eller `var(--border-focus)`) +
314
+ `border-radius: var(--radius-4)` på outline:n så den följer en mjuk
315
+ form. Se ADR 0018 för full rationale.
316
+
292
317
  ### Mobile-first
293
318
 
294
319
  - Default-styles är mobile (375-430 viewport).