@conciso/design-system 0.0.0-bootstrap.0 → 2.1.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/README.md CHANGED
@@ -41,8 +41,15 @@ Ausführlich in [docs/GETTING-STARTED.md](docs/GETTING-STARTED.md). Kurzfassung:
41
41
 
42
42
  Die Schriften (Montserrat + Libre Baskerville) liegen self-hosted unter `fonts/` und werden über `css/fonts.css` eingebunden — keine externe CDN-Anfrage. Das gebündelte `dist/conciso-ds.css` enthält die `@font-face`-Regeln bereits.
43
43
 
44
- **Variante B — als npm-Paket von npmjs.org** (der empfohlene Weg):
44
+ **Variante B — als npm-Paket aus GitHub Packages** (der empfohlene Weg):
45
45
 
46
+ Das Paket liegt privat und org-scoped in GitHub Packages. Das Konsumenten-Projekt
47
+ braucht dafür eine `.npmrc`, die den `@conciso`-Scope umleitet:
48
+
49
+ ```ini
50
+ @conciso:registry=https://npm.pkg.github.com
51
+ //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
52
+ ```
46
53
  ```bash
47
54
  npm install @conciso/design-system
48
55
  ```
@@ -56,37 +63,26 @@ import { icons } from '@conciso/design-system/icons';
56
63
  import logo from '@conciso/design-system/assets/brand/logo-conciso.svg';
57
64
  ```
58
65
 
59
- Keine `.npmrc` nötig — das Paket liegt auf der öffentlichen npm-Registry, `npm install`
60
- funktioniert ohne weitere Einrichtung. Siehe [ADR-0011](docs/adr/0011-veroeffentlichung-auf-npmjs.md).
61
- Gilt ab dem ersten echten Release nach dem Merge dieser Änderung; bis dahin liegt auf
62
- npmjs nur eine Bootstrap-Platzhalterversion (siehe ADR-0011).
63
-
64
66
  Die Wortmarke liegt als SVG unter [`assets/brand/`](assets/brand/README.md) (Default, Light, Dark). Größen, Schutzraum und Verwendung stehen in der Doku unter **Marke → Logo**.
65
67
 
66
68
  > Das Paket steht unter der [MIT-Lizenz](LICENSE) (Ausnahmen — Brand-Assets, Schriften,
67
- > Icons — siehe [NOTICE](NOTICE)).
68
- >
69
- > **Alternative — GitHub Packages** (weiterhin verfügbar, unverändert, z. B. für
70
- > Consumer innerhalb der GitHub-Organisation `conciso`): eine `.npmrc`, die den
71
- > `@conciso`-Scope umleitet, plus ein Token mit Scope `read:packages` auch fürs Lesen
72
- > (in GitHub Actions genügt `secrets.GITHUB_TOKEN`):
73
- > ```ini
74
- > @conciso:registry=https://npm.pkg.github.com
75
- > //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
76
- > ```
77
- > GitHub Packages verlangt diese Auth wegen der **Registry**, nicht wegen der Lizenz.
78
- > Details in [Getting Started](docs/GETTING-STARTED.md#1-einbinden), Begründung in
79
- > [ADR-0004](docs/adr/0004-verteilung-und-versionierung.md). Ohne npm bleibt Variante A
80
- > (Vendoren von `dist/conciso-ds.css` + `fonts/`) der schlankeste Weg.
69
+ > Icons — siehe [NOTICE](NOTICE)), liegt aber weiterhin in GitHub Packages statt der
70
+ > öffentlichen npm-Registry — GitHub Packages verlangt daher Auth auch fürs Lesen (lokal
71
+ > ein Token mit Scope `read:packages` als `GITHUB_TOKEN`, in GitHub Actions genügt
72
+ > `secrets.GITHUB_TOKEN`). Details in [Getting Started](docs/GETTING-STARTED.md#1-einbinden),
73
+ > Begründung in [ADR-0004](docs/adr/0004-verteilung-und-versionierung.md). Ohne npm bleibt
74
+ > Variante A (Vendoren von `dist/conciso-ds.css` + `fonts/`) der schlankeste Weg.
81
75
  >
82
- > Die **Doku** (Storybook, die Komponenten-Referenz der Angular-Lib) ist öffentlich
83
- > einsehbar unter <https://conciso.github.io/conciso-design-system/> — ohne Auth, aber
84
- > `noindex` (nicht für Suchmaschinen bestimmt). Details und Abwägung in
76
+ > Der Lese-Auth-Zwang gilt damit nur wegen der **Registry**, nicht wegen der Lizenz, und
77
+ > betrifft nur das **Paket** selbst. Die **Doku** (Storybook, die Komponenten-Referenz der
78
+ > Angular-Lib) ist dagegen öffentlich einsehbar unter
79
+ > <https://conciso.github.io/conciso-design-system/> — ohne Auth, aber `noindex` (nicht für
80
+ > Suchmaschinen bestimmt). Details und Abwägung in
85
81
  > [ADR-0009](docs/adr/0009-storybook-oeffentlich-auf-github-pages.md).
86
82
 
87
83
  **Angular:** Für Angular gibt es Komponenten statt nur CSS-Klassen —
88
- `@conciso/design-system-angular` aus denselben beiden Registries, im Lockstep auf
89
- derselben Version. Siehe [README der Lib](angular-lib/projects/design-system-angular/README.md).
84
+ `@conciso/design-system-angular` aus derselben Registry, im Lockstep auf derselben Version.
85
+ Siehe [README der Lib](angular-lib/projects/design-system-angular/README.md).
90
86
 
91
87
  **Dark Mode:** `data-theme="dark"` am `<html>` setzen. Siehe [Getting Started](docs/GETTING-STARTED.md#3-dark-mode) für das Anti-Flash-Snippet.
92
88
 
@@ -127,7 +123,7 @@ npm run check:contrast # Kontrast der gerenderten Doku in Light UND Dark
127
123
 
128
124
  ## Versionierung
129
125
 
130
- [SemVer](https://semver.org/lang/de/). Die Version steht **nicht** im Repo, sondern im jeweiligen Git-Tag `vX.Y.Z`; Änderungen dazu stehen im zugehörigen GitHub-Release. Releases entstehen automatisch aus Conventional Commits auf `main` ([ADR-0010](docs/adr/0010-release-ausloesung-und-versionsquelle.md)) und werden nach npmjs.org **und** GitHub Packages veröffentlicht ([ADR-0011](docs/adr/0011-veroeffentlichung-auf-npmjs.md)). Der handgeschriebene [CHANGELOG](CHANGELOG.md) ist mit Version 2.0.0 eingefroren. `@conciso/design-system` und `@conciso/design-system-angular` tragen dabei im **Lockstep** immer dieselbe Version, damit die peerDependency der Angular-Lib auf die CSS-Schicht eng gepinnt auflöst ([ADR-0004](docs/adr/0004-verteilung-und-versionierung.md)).
126
+ [SemVer](https://semver.org/lang/de/). Die Version steht **nicht** im Repo, sondern im jeweiligen Git-Tag `vX.Y.Z`; Änderungen dazu stehen im zugehörigen GitHub-Release. Releases entstehen automatisch aus Conventional Commits auf `main` ([ADR-0010](docs/adr/0010-release-ausloesung-und-versionsquelle.md)) und werden nach GitHub Packages veröffentlicht. Der handgeschriebene [CHANGELOG](CHANGELOG.md) ist mit Version 2.0.0 eingefroren. `@conciso/design-system` und `@conciso/design-system-angular` tragen dabei im **Lockstep** immer dieselbe Version, damit die peerDependency der Angular-Lib auf die CSS-Schicht eng gepinnt auflöst ([ADR-0004](docs/adr/0004-verteilung-und-versionierung.md)).
131
127
 
132
128
  ## Lizenz & Kontakt
133
129
 
@@ -151,6 +151,17 @@
151
151
  Interaktion liegt dann in den Buttons; so eine Karte ruht flach mit dem --bd-Rahmen aus .card.
152
152
  Deshalb hängt die ganze Variante an a.*: eine <article>/<div>-Karte bekommt den Schatten auch
153
153
  dann nicht, wenn die Klasse gesetzt ist. Das ist der Riegel, nicht nur eine Empfehlung. */
154
+ /* Ohne data-area erbt eine <article>/<div>-Karte die Seiten-Textfarbe automatisch, weil Eyebrow
155
+ und Media-Icon keine eigene Farbe setzen. Ein <a> bringt aber die UA-Linkfarbe UND -Unterstreichung
156
+ mit: ohne dieses Reset läuft die Unterstreichung durch alle Block-Kinder (Eyebrow, Titel, Text,
157
+ Meta), weil text-decoration nicht vererbt, sondern über in-flow-Nachfahren PROPAGIERT wird — ein
158
+ text-decoration:none auf dem Kind allein stoppt das nicht, nur der Reset am <a> selbst.
159
+ color:inherit + text-decoration:none gleichen beides an: Link-Card ohne Bereich = Card ohne
160
+ Bereich, Bereichs-Regeln (oben) bleiben unberührt, weil sie spezifischer sind (Befund 01).
161
+ .card-cta-link bleibt unberührt: als <span> im Card-Footer hatte es nie UA-Unterstreichung, als
162
+ eigenständiges a.card-cta-link (css/components.css ~1377) sitzt es nie verschachtelt in a.card
163
+ (ungültiges HTML, siehe LinkCardComponent-Klassendoku) und behält seinen eigenen Hover-Unterstrich. */
164
+ a.card{color:inherit;text-decoration:none}
154
165
  a.card-elevated{box-shadow:var(--e1);border:none;background:var(--bg-surface)}
155
166
  a.card-elevated:hover{box-shadow:var(--e2);transform:translateY(-2px)}
156
167
 
@@ -594,8 +605,11 @@ a.card-elevated:hover{box-shadow:var(--e2);transform:translateY(-2px)}
594
605
  /* ── Snackbar ── */
595
606
  .snack{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s5);border-radius:var(--r-md);font:var(--ty-body-md);max-width:480px;box-shadow:var(--e3);margin-bottom:var(--s3);min-height:48px}
596
607
  .snack-def{background:var(--n-700);color:var(--n-0)}
597
- .snack-ok{background:#0d5e39;color:#d6f5e8}
598
- .snack-err{background:#7a1515;color:#fde8e8}
608
+ /* Tokens statt Hardcodes (Befund 04): Werte und Kontraste stehen bei --c-success-strong/
609
+ --c-error-strong in tokens.css. Die Fläche flippt im Dark über den Token, kein eigenes
610
+ Dark-Overwrite hier nötig. */
611
+ .snack-ok{background:var(--c-success-strong);color:var(--c-success-on-strong)}
612
+ .snack-err{background:var(--c-error-strong);color:var(--c-error-on-strong)}
599
613
  .snack-act{margin-left:auto;background:none;border:none;color:inherit;opacity:.8;font:var(--ty-label-sm);cursor:pointer;text-transform:uppercase;letter-spacing:.04em;padding:0}
600
614
 
601
615
  /* ── Footer ──
@@ -1603,7 +1617,10 @@ thead th[aria-sort="descending"] .tbl-sort svg{opacity:1;color:var(--co-600)}
1603
1617
  .article-callout[data-area="ki"]{background:var(--ki-50);border-left-color:var(--ki-500)}
1604
1618
  .article-callout[data-area="es"]{background:var(--es-50);border-left-color:var(--es-500)}
1605
1619
  .article-callout[data-area="wo"]{background:var(--wo-50);border-left-color:var(--wo-500)}
1606
- .article-callout-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin:0 0 var(--s1)}
1620
+ /* Direktkind-Selektor statt reiner Klasse: die Eyebrow ist selbst ein <p>, also schlägt
1621
+ .article-callout > p (0,1,1) unten sonst diese Regel (0,1,0). Mit
1622
+ .article-callout > .article-callout-eyebrow (0,2,0) gewinnt die Eyebrow (Befund 02). */
1623
+ .article-callout > .article-callout-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin:0 0 var(--s1)}
1607
1624
  .article-callout[data-area="ki"] .article-callout-eyebrow{color:var(--ki-800)}
1608
1625
  .article-callout[data-area="es"] .article-callout-eyebrow{color:var(--es-700)}
1609
1626
  .article-callout[data-area="wo"] .article-callout-eyebrow{color:var(--wo-700)}
package/css/dark-mode.css CHANGED
@@ -78,6 +78,12 @@
78
78
  --c-error:#FFA5A5; /* auf bg-page: 9.32:1 ✓ AAA · auf bg-surface: 6.93:1 ✓ AAA. Angehoben von
79
79
  #FF8E8E, das nur gegen bg-page geprüft war und auf bg-surface 4.0:1
80
80
  erreichte. Inline-Fehlertext sitzt aber fast immer auf bg-surface. */
81
+ /* Dark-only: Snackbar-Fläche (Befund 04) flippt auf die bereits vorhandenen --c-*-bg-Tints, der
82
+ helle Text auf --c-success-on-strong wird angehoben (--c-error-on-strong und beide -icon-Tokens
83
+ bleiben in Light UND Dark gleich, deshalb hier bewusst kein Override). Kontraste siehe
84
+ tokens.css. (Light: #0d5e39 / #d6f5e8.) */
85
+ --c-success-strong:var(--c-success-bg); --c-success-on-strong:#b0f0d0;
86
+ --c-error-strong:var(--c-error-bg);
81
87
  /* Brand tints (Dark), getrennt nach den zwei Jobs, die --XX-50 im Light in einem Wert erledigt.
82
88
  Der Grund: Ein Band muss DUNKLER bleiben als die Karten darauf, eine Badge- oder Kachel-Füllung
83
89
  muss HELLER sein als ihr Grund, sonst liest sie nicht als Fläche. Bei einer Basis von 17,51:1
@@ -249,18 +255,17 @@
249
255
  [data-theme="dark"] .logo-carousel-pause:hover { color: var(--n-200) }
250
256
  [data-theme="dark"] .ai-warning { color:var(--ki-300) }
251
257
  [data-theme="dark"] .pal-note { background:var(--c-warning-bg);color:#f0d080;border-color:#806000 }
252
- /* Dark-only: Die Flächen standen hier als hartkodierte Kopien von --c-success-bg und --c-error-bg
253
- (#052415 / #220808). Als die Status-Tints angehoben wurden, blieben die Kopien zurück und trugen
254
- nur noch ❌ 1,06:1 bzw. 1,08:1 gegen die Seite, die Snackbar war als Fläche praktisch weg.
255
- Jetzt über die Token ✓ 1,78:1 und 1,79:1; Text darauf 7,60:1 und 8,34:1. */
256
- [data-theme="dark"] .snack-ok { background:var(--c-success-bg); color:#b0f0d0 }
257
- [data-theme="dark"] .snack-err { background:var(--c-error-bg); color:#fde8e8 }
258
- /* Dieselbe Familie wie die Snackbar darüber: die Kreisflächen standen als hartkodierte Kopien von
259
- --c-success-bg und --c-error-bg (#052415 / #220808) und blieben beim Anheben der Status-Tints
260
- zurück. Gegen die neue Seite trugen sie nur ❌ 1,06:1 bzw. 1,08:1, der Kreis war keine Fläche
261
- mehr, nur noch ein farbiger Glyph. Jetzt über die Token ✓ 1,78:1 und 1,79:1 zur Seite, 1,32 und
262
- 1,33:1 zur Card. Der Fehler-Glyph geht mit: #F08080 trägt auf der aufgehellten Füllung nur
263
- ❌ 3,78:1, --c-error (#FFA5A5) ✓ 5,21:1. Analog --c-success (#5CE8A0) auf Grün 6,33:1.
258
+ /* Snackbar-Fläche/-Text (.snack-ok/.snack-err) brauchten hier früher ein eigenes Dark-Overwrite,
259
+ weil die Farben in components.css als Hex standen und im Dark nicht mitliefen. Seit Befund 04
260
+ stehen sie über --c-success-strong/--c-error-strong (tokens.css, Dark-Werte oben im Token-Block),
261
+ die Fläche flippt jetzt über den Token selbst — kein Overwrite mehr nötig, siehe .snack-ok/
262
+ .snack-err in components.css. */
263
+ /* Die Kreisflächen hier standen als hartkodierte Kopien von --c-success-bg und --c-error-bg
264
+ (#052415 / #220808) und blieben beim Anheben der Status-Tints zurück. Gegen die neue Seite
265
+ trugen sie nur ❌ 1,06:1 bzw. 1,08:1, der Kreis war keine Fläche mehr, nur noch ein farbiger
266
+ Glyph. Jetzt über die Token ✓ 1,78:1 und 1,79:1 zur Seite, 1,32 und 1,33:1 zur Card. Der
267
+ Fehler-Glyph geht mit: #F08080 trägt auf der aufgehellten Füllung nur ❌ 3,78:1, --c-error
268
+ (#FFA5A5) ✓ 5,21:1. Analog --c-success (#5CE8A0) auf Grün 6,33:1.
264
269
  (Light: helle Tints #E6F9F1 / #FDEAEA mit dunklem Glyph, kein Fix nötig.) */
265
270
  [data-theme="dark"] .a11y-ok .a11y-rule-icon { background:var(--c-success-bg); color:var(--c-success) }
266
271
  [data-theme="dark"] .a11y-fail .a11y-rule-icon { background:var(--c-error-bg); color:var(--c-error) }
@@ -482,7 +487,13 @@
482
487
  /* In-Article-Callout-Eyebrow: 700er-/800er-Ton → dunkel-auf-dunkel auf der getönten -50-Fläche
483
488
  (1,6–2,5:1). Auf die hellen Bereichs-Tints heben (8–10:1), wie bei .t-Utilities und Badges. Body-Text ist
484
489
  tx-primary und flippt ohnehin. */
485
- [data-theme="dark"] .article-callout-eyebrow { color: var(--co-200) }
490
+ /* .article-callout > vorangestellt (Befund 02, Spezifitäts-Fix in components.css): ohne den
491
+ Eltern-Qualifier lag diese Regel bei 0,2,0, exakt gleichauf mit der neuen Light-Basisregel
492
+ .article-callout > .article-callout-eyebrow — bei Gleichstand gewinnt components.css, weil es
493
+ nach dark-mode.css gebündelt wird (bundle-css.mjs), der Ton fiel im Dark auf co-700 zurück
494
+ (1,77:1 statt 4,5:1, von check:contrast gefangen). 0,3,0 hält den Vorsprung, wie bei den
495
+ Bereichs-Varianten darunter. */
496
+ [data-theme="dark"] .article-callout > .article-callout-eyebrow { color: var(--co-200) }
486
497
  [data-theme="dark"] .article-callout[data-area="ki"] .article-callout-eyebrow { color: var(--ki-200) }
487
498
  [data-theme="dark"] .article-callout[data-area="es"] .article-callout-eyebrow { color: var(--es-100) }
488
499
  [data-theme="dark"] .article-callout[data-area="wo"] .article-callout-eyebrow { color: var(--wo-200) }
package/css/tokens.css CHANGED
@@ -78,6 +78,17 @@
78
78
  --c-warning:#785008; --c-warning-bg:#F5D08C; /* Text auf #fff 7,12:1, auf dem eigenen Tint 4,84:1 (vorher #8A5E0A: 5,70 bzw. nur 3,87:1) */
79
79
  --c-error:#9B2020; --c-error-bg:#F5BFBF; /* Text auf #fff 8,01:1, auf dem eigenen Tint 4,99:1 (vorher #B22020: 6,73 bzw. nur 4,19:1) */
80
80
 
81
+ /* --c-*-strong sind die satte Snackbar-Fläche (.snack-ok/.snack-err) plus Text-/Icon-Farbe darauf
82
+ (Befund 04): eigene Tokens statt --c-success/-error, weil das dort der Tint-Text ist, hier aber
83
+ eine volle Fläche. Werte = bisheriger hartkodierter Render, keine optische Änderung. Dark-Werte
84
+ in dark-mode.css (Fläche flippt auf --c-success-bg/--c-error-bg, Icon/Text meist unverändert).
85
+ Kontrast Text/Fläche und Icon/Fläche gemessen (Formel wie scripts/check-contrast.mjs):
86
+ Light: ok Text 6,76:1, ok Icon 5,72:1 · err Text 9,19:1, err Icon 5,75:1
87
+ Dark: ok Text 6,53:1, ok Icon 6,16:1 · err Text 7,57:1, err Icon 4,74:1
88
+ (Soll ≥ 4,5:1 Text, ≥ 3:1 Icon — alle acht Paare ✓) */
89
+ --c-success-strong:#0d5e39; --c-success-on-strong:#d6f5e8; --c-success-strong-icon:#88f0c4;
90
+ --c-error-strong:#7a1515; --c-error-on-strong:#fde8e8; --c-error-strong-icon:#f9a8a8;
91
+
81
92
  /* ── Component color tokens (theme-overridable) ── */
82
93
  --badge-ok-text:var(--c-success); --badge-warn-text:var(--c-warning); --badge-err-text:var(--c-error); /* dieselben Töne wie die semantischen Textfarben: sie stehen auf denselben Tints, zwei Werte dafür wären zwei Quellen der Wahrheit */
83
94
  --badge-neu-bg:var(--n-200); --badge-neu-text:var(--n-600); /* n-200 statt n-100: als Füllung trug n-100 nur 1,18:1 gegen Weiß und 1,10:1 gegen n-50, n-200 gibt 1,53 / 1,42:1. Text darauf 6,69:1 */
@@ -102,6 +102,17 @@
102
102
  --c-warning:#785008; --c-warning-bg:#F5D08C; /* Text auf #fff 7,12:1, auf dem eigenen Tint 4,84:1 (vorher #8A5E0A: 5,70 bzw. nur 3,87:1) */
103
103
  --c-error:#9B2020; --c-error-bg:#F5BFBF; /* Text auf #fff 8,01:1, auf dem eigenen Tint 4,99:1 (vorher #B22020: 6,73 bzw. nur 4,19:1) */
104
104
 
105
+ /* --c-*-strong sind die satte Snackbar-Fläche (.snack-ok/.snack-err) plus Text-/Icon-Farbe darauf
106
+ (Befund 04): eigene Tokens statt --c-success/-error, weil das dort der Tint-Text ist, hier aber
107
+ eine volle Fläche. Werte = bisheriger hartkodierter Render, keine optische Änderung. Dark-Werte
108
+ in dark-mode.css (Fläche flippt auf --c-success-bg/--c-error-bg, Icon/Text meist unverändert).
109
+ Kontrast Text/Fläche und Icon/Fläche gemessen (Formel wie scripts/check-contrast.mjs):
110
+ Light: ok Text 6,76:1, ok Icon 5,72:1 · err Text 9,19:1, err Icon 5,75:1
111
+ Dark: ok Text 6,53:1, ok Icon 6,16:1 · err Text 7,57:1, err Icon 4,74:1
112
+ (Soll ≥ 4,5:1 Text, ≥ 3:1 Icon — alle acht Paare ✓) */
113
+ --c-success-strong:#0d5e39; --c-success-on-strong:#d6f5e8; --c-success-strong-icon:#88f0c4;
114
+ --c-error-strong:#7a1515; --c-error-on-strong:#fde8e8; --c-error-strong-icon:#f9a8a8;
115
+
105
116
  /* ── Component color tokens (theme-overridable) ── */
106
117
  --badge-ok-text:var(--c-success); --badge-warn-text:var(--c-warning); --badge-err-text:var(--c-error); /* dieselben Töne wie die semantischen Textfarben: sie stehen auf denselben Tints, zwei Werte dafür wären zwei Quellen der Wahrheit */
107
118
  --badge-neu-bg:var(--n-200); --badge-neu-text:var(--n-600); /* n-200 statt n-100: als Füllung trug n-100 nur 1,18:1 gegen Weiß und 1,10:1 gegen n-50, n-200 gibt 1,53 / 1,42:1. Text darauf 6,69:1 */
@@ -313,6 +324,12 @@
313
324
  --c-error:#FFA5A5; /* auf bg-page: 9.32:1 ✓ AAA · auf bg-surface: 6.93:1 ✓ AAA. Angehoben von
314
325
  #FF8E8E, das nur gegen bg-page geprüft war und auf bg-surface 4.0:1
315
326
  erreichte. Inline-Fehlertext sitzt aber fast immer auf bg-surface. */
327
+ /* Dark-only: Snackbar-Fläche (Befund 04) flippt auf die bereits vorhandenen --c-*-bg-Tints, der
328
+ helle Text auf --c-success-on-strong wird angehoben (--c-error-on-strong und beide -icon-Tokens
329
+ bleiben in Light UND Dark gleich, deshalb hier bewusst kein Override). Kontraste siehe
330
+ tokens.css. (Light: #0d5e39 / #d6f5e8.) */
331
+ --c-success-strong:var(--c-success-bg); --c-success-on-strong:#b0f0d0;
332
+ --c-error-strong:var(--c-error-bg);
316
333
  /* Brand tints (Dark), getrennt nach den zwei Jobs, die --XX-50 im Light in einem Wert erledigt.
317
334
  Der Grund: Ein Band muss DUNKLER bleiben als die Karten darauf, eine Badge- oder Kachel-Füllung
318
335
  muss HELLER sein als ihr Grund, sonst liest sie nicht als Fläche. Bei einer Basis von 17,51:1
@@ -484,18 +501,17 @@
484
501
  [data-theme="dark"] .logo-carousel-pause:hover { color: var(--n-200) }
485
502
  [data-theme="dark"] .ai-warning { color:var(--ki-300) }
486
503
  [data-theme="dark"] .pal-note { background:var(--c-warning-bg);color:#f0d080;border-color:#806000 }
487
- /* Dark-only: Die Flächen standen hier als hartkodierte Kopien von --c-success-bg und --c-error-bg
488
- (#052415 / #220808). Als die Status-Tints angehoben wurden, blieben die Kopien zurück und trugen
489
- nur noch ❌ 1,06:1 bzw. 1,08:1 gegen die Seite, die Snackbar war als Fläche praktisch weg.
490
- Jetzt über die Token ✓ 1,78:1 und 1,79:1; Text darauf 7,60:1 und 8,34:1. */
491
- [data-theme="dark"] .snack-ok { background:var(--c-success-bg); color:#b0f0d0 }
492
- [data-theme="dark"] .snack-err { background:var(--c-error-bg); color:#fde8e8 }
493
- /* Dieselbe Familie wie die Snackbar darüber: die Kreisflächen standen als hartkodierte Kopien von
494
- --c-success-bg und --c-error-bg (#052415 / #220808) und blieben beim Anheben der Status-Tints
495
- zurück. Gegen die neue Seite trugen sie nur ❌ 1,06:1 bzw. 1,08:1, der Kreis war keine Fläche
496
- mehr, nur noch ein farbiger Glyph. Jetzt über die Token ✓ 1,78:1 und 1,79:1 zur Seite, 1,32 und
497
- 1,33:1 zur Card. Der Fehler-Glyph geht mit: #F08080 trägt auf der aufgehellten Füllung nur
498
- ❌ 3,78:1, --c-error (#FFA5A5) ✓ 5,21:1. Analog --c-success (#5CE8A0) auf Grün 6,33:1.
504
+ /* Snackbar-Fläche/-Text (.snack-ok/.snack-err) brauchten hier früher ein eigenes Dark-Overwrite,
505
+ weil die Farben in components.css als Hex standen und im Dark nicht mitliefen. Seit Befund 04
506
+ stehen sie über --c-success-strong/--c-error-strong (tokens.css, Dark-Werte oben im Token-Block),
507
+ die Fläche flippt jetzt über den Token selbst — kein Overwrite mehr nötig, siehe .snack-ok/
508
+ .snack-err in components.css. */
509
+ /* Die Kreisflächen hier standen als hartkodierte Kopien von --c-success-bg und --c-error-bg
510
+ (#052415 / #220808) und blieben beim Anheben der Status-Tints zurück. Gegen die neue Seite
511
+ trugen sie nur ❌ 1,06:1 bzw. 1,08:1, der Kreis war keine Fläche mehr, nur noch ein farbiger
512
+ Glyph. Jetzt über die Token ✓ 1,78:1 und 1,79:1 zur Seite, 1,32 und 1,33:1 zur Card. Der
513
+ Fehler-Glyph geht mit: #F08080 trägt auf der aufgehellten Füllung nur ❌ 3,78:1, --c-error
514
+ (#FFA5A5) ✓ 5,21:1. Analog --c-success (#5CE8A0) auf Grün 6,33:1.
499
515
  (Light: helle Tints #E6F9F1 / #FDEAEA mit dunklem Glyph, kein Fix nötig.) */
500
516
  [data-theme="dark"] .a11y-ok .a11y-rule-icon { background:var(--c-success-bg); color:var(--c-success) }
501
517
  [data-theme="dark"] .a11y-fail .a11y-rule-icon { background:var(--c-error-bg); color:var(--c-error) }
@@ -717,7 +733,13 @@
717
733
  /* In-Article-Callout-Eyebrow: 700er-/800er-Ton → dunkel-auf-dunkel auf der getönten -50-Fläche
718
734
  (1,6–2,5:1). Auf die hellen Bereichs-Tints heben (8–10:1), wie bei .t-Utilities und Badges. Body-Text ist
719
735
  tx-primary und flippt ohnehin. */
720
- [data-theme="dark"] .article-callout-eyebrow { color: var(--co-200) }
736
+ /* .article-callout > vorangestellt (Befund 02, Spezifitäts-Fix in components.css): ohne den
737
+ Eltern-Qualifier lag diese Regel bei 0,2,0, exakt gleichauf mit der neuen Light-Basisregel
738
+ .article-callout > .article-callout-eyebrow — bei Gleichstand gewinnt components.css, weil es
739
+ nach dark-mode.css gebündelt wird (bundle-css.mjs), der Ton fiel im Dark auf co-700 zurück
740
+ (1,77:1 statt 4,5:1, von check:contrast gefangen). 0,3,0 hält den Vorsprung, wie bei den
741
+ Bereichs-Varianten darunter. */
742
+ [data-theme="dark"] .article-callout > .article-callout-eyebrow { color: var(--co-200) }
721
743
  [data-theme="dark"] .article-callout[data-area="ki"] .article-callout-eyebrow { color: var(--ki-200) }
722
744
  [data-theme="dark"] .article-callout[data-area="es"] .article-callout-eyebrow { color: var(--es-100) }
723
745
  [data-theme="dark"] .article-callout[data-area="wo"] .article-callout-eyebrow { color: var(--wo-200) }
@@ -1409,6 +1431,17 @@ body{font-family:var(--font);font-size:1rem;line-height:1.7;color:var(--tx-prima
1409
1431
  Interaktion liegt dann in den Buttons; so eine Karte ruht flach mit dem --bd-Rahmen aus .card.
1410
1432
  Deshalb hängt die ganze Variante an a.*: eine <article>/<div>-Karte bekommt den Schatten auch
1411
1433
  dann nicht, wenn die Klasse gesetzt ist. Das ist der Riegel, nicht nur eine Empfehlung. */
1434
+ /* Ohne data-area erbt eine <article>/<div>-Karte die Seiten-Textfarbe automatisch, weil Eyebrow
1435
+ und Media-Icon keine eigene Farbe setzen. Ein <a> bringt aber die UA-Linkfarbe UND -Unterstreichung
1436
+ mit: ohne dieses Reset läuft die Unterstreichung durch alle Block-Kinder (Eyebrow, Titel, Text,
1437
+ Meta), weil text-decoration nicht vererbt, sondern über in-flow-Nachfahren PROPAGIERT wird — ein
1438
+ text-decoration:none auf dem Kind allein stoppt das nicht, nur der Reset am <a> selbst.
1439
+ color:inherit + text-decoration:none gleichen beides an: Link-Card ohne Bereich = Card ohne
1440
+ Bereich, Bereichs-Regeln (oben) bleiben unberührt, weil sie spezifischer sind (Befund 01).
1441
+ .card-cta-link bleibt unberührt: als <span> im Card-Footer hatte es nie UA-Unterstreichung, als
1442
+ eigenständiges a.card-cta-link (css/components.css ~1377) sitzt es nie verschachtelt in a.card
1443
+ (ungültiges HTML, siehe LinkCardComponent-Klassendoku) und behält seinen eigenen Hover-Unterstrich. */
1444
+ a.card{color:inherit;text-decoration:none}
1412
1445
  a.card-elevated{box-shadow:var(--e1);border:none;background:var(--bg-surface)}
1413
1446
  a.card-elevated:hover{box-shadow:var(--e2);transform:translateY(-2px)}
1414
1447
 
@@ -1852,8 +1885,11 @@ a.card-elevated:hover{box-shadow:var(--e2);transform:translateY(-2px)}
1852
1885
  /* ── Snackbar ── */
1853
1886
  .snack{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s5);border-radius:var(--r-md);font:var(--ty-body-md);max-width:480px;box-shadow:var(--e3);margin-bottom:var(--s3);min-height:48px}
1854
1887
  .snack-def{background:var(--n-700);color:var(--n-0)}
1855
- .snack-ok{background:#0d5e39;color:#d6f5e8}
1856
- .snack-err{background:#7a1515;color:#fde8e8}
1888
+ /* Tokens statt Hardcodes (Befund 04): Werte und Kontraste stehen bei --c-success-strong/
1889
+ --c-error-strong in tokens.css. Die Fläche flippt im Dark über den Token, kein eigenes
1890
+ Dark-Overwrite hier nötig. */
1891
+ .snack-ok{background:var(--c-success-strong);color:var(--c-success-on-strong)}
1892
+ .snack-err{background:var(--c-error-strong);color:var(--c-error-on-strong)}
1857
1893
  .snack-act{margin-left:auto;background:none;border:none;color:inherit;opacity:.8;font:var(--ty-label-sm);cursor:pointer;text-transform:uppercase;letter-spacing:.04em;padding:0}
1858
1894
 
1859
1895
  /* ── Footer ──
@@ -2861,7 +2897,10 @@ thead th[aria-sort="descending"] .tbl-sort svg{opacity:1;color:var(--co-600)}
2861
2897
  .article-callout[data-area="ki"]{background:var(--ki-50);border-left-color:var(--ki-500)}
2862
2898
  .article-callout[data-area="es"]{background:var(--es-50);border-left-color:var(--es-500)}
2863
2899
  .article-callout[data-area="wo"]{background:var(--wo-50);border-left-color:var(--wo-500)}
2864
- .article-callout-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin:0 0 var(--s1)}
2900
+ /* Direktkind-Selektor statt reiner Klasse: die Eyebrow ist selbst ein <p>, also schlägt
2901
+ .article-callout > p (0,1,1) unten sonst diese Regel (0,1,0). Mit
2902
+ .article-callout > .article-callout-eyebrow (0,2,0) gewinnt die Eyebrow (Befund 02). */
2903
+ .article-callout > .article-callout-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin:0 0 var(--s1)}
2865
2904
  .article-callout[data-area="ki"] .article-callout-eyebrow{color:var(--ki-800)}
2866
2905
  .article-callout[data-area="es"] .article-callout-eyebrow{color:var(--es-700)}
2867
2906
  .article-callout[data-area="wo"] .article-callout-eyebrow{color:var(--wo-700)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conciso/design-system",
3
- "version": "0.0.0-bootstrap.0",
3
+ "version": "2.1.0",
4
4
  "description": "Conciso Design System — Design Tokens, CSS-Komponenten und Light/Dark-Mode, framework-agnostisch und WCAG-AA-konform.",
5
5
  "license": "MIT",
6
6
  "repository": {
package/tokens/tokens.js CHANGED
@@ -79,6 +79,12 @@ export const tokens = {
79
79
  "c-warning-bg": "#F5D08C",
80
80
  "c-error": "#9B2020",
81
81
  "c-error-bg": "#F5BFBF",
82
+ "c-success-strong": "#0d5e39",
83
+ "c-success-on-strong": "#d6f5e8",
84
+ "c-success-strong-icon": "#88f0c4",
85
+ "c-error-strong": "#7a1515",
86
+ "c-error-on-strong": "#fde8e8",
87
+ "c-error-strong-icon": "#f9a8a8",
82
88
  "badge-ok-text": "#0E6644",
83
89
  "badge-warn-text": "#785008",
84
90
  "badge-err-text": "#9B2020",
@@ -196,6 +202,9 @@ export const darkTokens = {
196
202
  "c-success": "#5CE8A0",
197
203
  "c-warning": "#F0C060",
198
204
  "c-error": "#FFA5A5",
205
+ "c-success-strong": "#1F573B",
206
+ "c-success-on-strong": "#b0f0d0",
207
+ "c-error-strong": "#882725",
199
208
  "co-50": "#134C47",
200
209
  "ki-50": "#384912",
201
210
  "wo-50": "#144E1F",
@@ -79,6 +79,12 @@
79
79
  "c-warning-bg": "#F5D08C",
80
80
  "c-error": "#9B2020",
81
81
  "c-error-bg": "#F5BFBF",
82
+ "c-success-strong": "#0d5e39",
83
+ "c-success-on-strong": "#d6f5e8",
84
+ "c-success-strong-icon": "#88f0c4",
85
+ "c-error-strong": "#7a1515",
86
+ "c-error-on-strong": "#fde8e8",
87
+ "c-error-strong-icon": "#f9a8a8",
82
88
  "badge-ok-text": "#0E6644",
83
89
  "badge-warn-text": "#785008",
84
90
  "badge-err-text": "#9B2020",
@@ -195,6 +201,9 @@
195
201
  "c-success": "#5CE8A0",
196
202
  "c-warning": "#F0C060",
197
203
  "c-error": "#FFA5A5",
204
+ "c-success-strong": "#1F573B",
205
+ "c-success-on-strong": "#b0f0d0",
206
+ "c-error-strong": "#882725",
198
207
  "co-50": "#134C47",
199
208
  "ki-50": "#384912",
200
209
  "wo-50": "#144E1F",
@@ -80,6 +80,12 @@ $c-warning: #785008;
80
80
  $c-warning-bg: #F5D08C;
81
81
  $c-error: #9B2020;
82
82
  $c-error-bg: #F5BFBF;
83
+ $c-success-strong: #0d5e39;
84
+ $c-success-on-strong: #d6f5e8;
85
+ $c-success-strong-icon: #88f0c4;
86
+ $c-error-strong: #7a1515;
87
+ $c-error-on-strong: #fde8e8;
88
+ $c-error-strong-icon: #f9a8a8;
83
89
  $badge-ok-text: #0E6644;
84
90
  $badge-warn-text: #785008;
85
91
  $badge-err-text: #9B2020;
@@ -197,6 +203,9 @@ $conciso-dark: (
197
203
  "c-success": #5CE8A0,
198
204
  "c-warning": #F0C060,
199
205
  "c-error": #FFA5A5,
206
+ "c-success-strong": #1F573B,
207
+ "c-success-on-strong": #b0f0d0,
208
+ "c-error-strong": #882725,
200
209
  "co-50": #134C47,
201
210
  "ki-50": #384912,
202
211
  "wo-50": #144E1F,