@conciso/design-system-mcp 2.4.0 → 2.6.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.
Files changed (68) hide show
  1. package/README.md +1 -0
  2. package/package.json +1 -1
  3. package/snapshot/manifests/components.json +207 -27
  4. package/snapshot/manifests/docs.json +0 -128
  5. package/snapshot/services/addon-docs/mdx/grundlagen-farben.json +18 -0
  6. package/snapshot/services/addon-docs/mdx/grundlagen-typografie.json +18 -0
  7. package/snapshot/services/addon-docs/mdx/komponenten-buchungsformular--/303/274bersicht.json +1 -1
  8. package/snapshot/services/addon-docs/mdx/komponenten-buttons-button.json +1 -1
  9. package/snapshot/services/addon-docs/mdx/komponenten-call-to-action-cta-band.json +18 -0
  10. package/snapshot/services/addon-docs/mdx/komponenten-cards-teaser-card.json +18 -0
  11. package/snapshot/services/addon-docs/mdx/komponenten-chips-badges-pills-chip.json +18 -0
  12. package/snapshot/services/addon-docs/mdx/komponenten-code-block-code-block.json +18 -0
  13. package/snapshot/services/addon-docs/mdx/komponenten-dropdowns-custom-select.json +18 -0
  14. package/snapshot/services/addon-docs/mdx/komponenten-feedback-snackbar.json +18 -0
  15. package/snapshot/services/addon-docs/mdx/komponenten-footer-komplett.json +18 -0
  16. package/snapshot/services/addon-docs/mdx/komponenten-hero-hero-bild.json +18 -0
  17. package/snapshot/services/addon-docs/mdx/komponenten-inputs-forms-textfeld.json +18 -0
  18. package/snapshot/services/addon-docs/mdx/komponenten-navigation-topnav.json +18 -0
  19. package/snapshot/services/addon-docs/mdx/komponenten-sektion-sektion.json +18 -0
  20. package/snapshot/services/addon-docs/mdx/komponenten-slider-carousel-carousel.json +18 -0
  21. package/snapshot/services/addon-docs/mdx/komponenten-tabelle-tabelle.json +18 -0
  22. package/snapshot/services/addon-docs/mdx/komponenten-theme-umschalter-cycle-button.json +18 -0
  23. package/snapshot/services/addon-docs/mdx/komponenten-zitate-testimonials-blockquote.json +18 -0
  24. package/snapshot/services/addon-docs/mdx/marke-logo-logo.json +18 -0
  25. package/snapshot/services/core/docgen/komponenten-call-to-action-downloadcta.json +1 -1
  26. package/snapshot/services/core/docgen/komponenten-cards-teaser-feature-liste.json +1 -1
  27. package/snapshot/services/core/docgen/komponenten-cards-teaser-featured-karte.json +1 -1
  28. package/snapshot/services/core/docgen/komponenten-cards-teaser-icon-karte.json +1 -1
  29. package/snapshot/services/core/docgen/komponenten-cards-teaser-klickbare-karte.json +1 -1
  30. package/snapshot/services/core/docgen/komponenten-cards-teaser-statcard.json +1 -1
  31. package/snapshot/services/core/docgen/komponenten-cards-teaser-statstrip.json +1 -1
  32. package/snapshot/services/core/docgen/komponenten-cards-teaser-tier-trenner.json +1 -1
  33. package/snapshot/services/core/docgen/komponenten-chips-badges-pills-bereichs-badge.json +1 -1
  34. package/snapshot/services/core/docgen/komponenten-chips-badges-pills-pill.json +1 -1
  35. package/snapshot/services/core/docgen/komponenten-chips-badges-pills-status-badge.json +1 -1
  36. package/snapshot/services/core/docgen/komponenten-dropdowns-combobox.json +1 -1
  37. package/snapshot/services/core/docgen/komponenten-footer-oberer-teil.json +1 -1
  38. package/snapshot/services/core/docgen/komponenten-footer-unterer-teil.json +1 -1
  39. package/snapshot/services/core/docgen/komponenten-hero-st/303/266rer.json +1 -1
  40. package/snapshot/services/core/docgen/komponenten-inputs-forms-auswahlfeld.json +1 -1
  41. package/snapshot/services/core/docgen/komponenten-inputs-forms-checkbox.json +1 -1
  42. package/snapshot/services/core/docgen/komponenten-inputs-forms-radio.json +1 -1
  43. package/snapshot/services/core/docgen/komponenten-inputs-forms-skala.json +1 -1
  44. package/snapshot/services/core/docgen/komponenten-inputs-forms-slider.json +1 -1
  45. package/snapshot/services/core/docgen/komponenten-inputs-forms-textbereich.json +1 -1
  46. package/snapshot/services/core/docgen/komponenten-slider-carousel-logocarousel.json +1 -1
  47. package/snapshot/services/core/docgen/komponenten-tabelle-vergleichstabelle.json +1 -1
  48. package/snapshot/services/core/docgen/komponenten-theme-umschalter-dropdown.json +1 -1
  49. package/snapshot/services/core/docgen/komponenten-theme-umschalter-segment.json +1 -1
  50. package/snapshot/services/core/docgen/komponenten-zitate-testimonials-teamvoice.json +1 -1
  51. package/snapshot/services/core/docgen/komponenten-zitate-testimonials-testimonial.json +1 -1
  52. package/src/instructions.mjs +9 -1
  53. package/snapshot/services/addon-docs/mdx/komponenten-call-to-action--verwendung.json +0 -18
  54. package/snapshot/services/addon-docs/mdx/komponenten-cards-teaser--verwendung.json +0 -18
  55. package/snapshot/services/addon-docs/mdx/komponenten-chips-badges-pills--verwendung.json +0 -18
  56. package/snapshot/services/addon-docs/mdx/komponenten-code-block--verwendung.json +0 -18
  57. package/snapshot/services/addon-docs/mdx/komponenten-dropdowns--verwendung.json +0 -18
  58. package/snapshot/services/addon-docs/mdx/komponenten-feedback--verwendung.json +0 -18
  59. package/snapshot/services/addon-docs/mdx/komponenten-footer--verwendung.json +0 -18
  60. package/snapshot/services/addon-docs/mdx/komponenten-hero--/303/274bersicht.json +0 -18
  61. package/snapshot/services/addon-docs/mdx/komponenten-inputs-forms--verwendung.json +0 -18
  62. package/snapshot/services/addon-docs/mdx/komponenten-navigation--verwendung.json +0 -18
  63. package/snapshot/services/addon-docs/mdx/komponenten-sektion--/303/274bersicht.json +0 -18
  64. package/snapshot/services/addon-docs/mdx/komponenten-slider-carousel--verwendung.json +0 -18
  65. package/snapshot/services/addon-docs/mdx/komponenten-tabelle--/303/274bersicht.json +0 -18
  66. package/snapshot/services/addon-docs/mdx/komponenten-theme-umschalter--verwendung.json +0 -18
  67. package/snapshot/services/addon-docs/mdx/komponenten-zitate-testimonials--verwendung.json +0 -18
  68. package/snapshot/services/addon-docs/mdx/marke-logo--verwendung.json +0 -18
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-cards-teaser-statstrip",
5
5
  "name": "StatStripComponent",
6
6
  "path": "./src/lib/stat-strip/stat-strip.stories.ts",
7
- "description": "StatStrip — Wrapper um `.card-stat-strip` + `.card-stat-flat` aus\ncss/components.css → „Stat-Strip“. Flacher Bandstreifen (auto-fit-Grid auf\n--n-50-Grund) mit zentrierten Kennzahlen ohne Rahmen/Schatten; Wert je\nBereich getönt via [data-area]. Genau wie docs/index.html.",
7
+ "description": "StatStrip — Wrapper um `.card-stat-strip` + `.card-stat-flat` aus\ncss/components.css → „Stat-Strip“. Flacher Bandstreifen (auto-fit-Grid auf\n--n-50-Grund) mit zentrierten Kennzahlen ohne Rahmen/Schatten; Wert je\nBereich getönt via [data-area]. Genau wie docs/index.html.\n\nVerwendungsguidance dieser Gruppe: siehe Card (`komponenten-cards-teaser-card--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "rounded": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-cards-teaser-tier-trenner",
5
5
  "name": "TierComponent",
6
6
  "path": "./src/lib/tier/tier.stories.ts",
7
- "description": "Tier (`cds-tier`) — Wrapper um `.ep-tier` aus css/components.css\n(css/components.css:1381–1384): der Stufen-Trenner (Label + Haarlinie), der eine\nOffene Feature-Liste in Pakete gliedert (z. B. „In jedem Paket enthalten“ /\n„Zusätzlich mit Pro“, Doku-Sektion `docs/index.html:4880`, Beispielseiten\n`docs/index.html:11855–11857`, `11883–11885`, `12576–12578`).\n\n**Element-Selektor, kein Attribut (ADR-0008-Standardfall).** Ausgezählt: alle 4\n`.ep-tier`-Vorkommen in `docs/index.html` stehen als eigenständiger `<div>` VOR\neinem `.layout-grid` oder einer Karten-Reihe, nie als deren Kind — keines trägt\neine `col-*`-Spaltenklasse, keines liegt in einem Grid/Flex, das seine Kinder\ndehnt. Das Tag variiert ebenfalls nicht (immer `<div>`). Keines der drei\nADR-0008-Kriterien (Grid-/Flex-Kind, Ziel einer Layout-Klasse, wechselndes Tag)\ntrifft zu, der Element-Selektor bleibt deshalb der Standardfall. `.ep-tier{\ndisplay:flex}` sitzt direkt auf dem Host (`host: { class: 'ep-tier' }`), kein\ninneres Wrapper-Element darunter — anders als bei `cds-section` (ADR-0008 Fall 2)\nist hier nichts von außen auf eine bestimmte DOM-Tiefe angewiesen: kein\nNachfahren-Selektor zielt auf `.ep-tier`, keine Fläche hängt am Host.\n\n**`area` ist auf `'ki'` typisiert, nicht auf `CdsArea`.** `css/components.css:1383`\nkennt nur die eine Regel `.ep-tier-label[data-area=\"ki\"]` (Dark-Override\n`css/dark-mode.css:476`) — für `co`/`es`/`wo` existiert keine einzige\n`[data-area]`-Regel auf `.ep-tier-label`, per Grep über `css/*.css` geprüft.\nAusgezählt in `docs/index.html`: von 4 `.ep-tier-label`-Vorkommen tragen 3\n`data-area=\"ki\"` (4880, 11884, 12577), eines trägt gar kein `data-area` (11856),\nkeines der Werte `co`/`es`/`wo` kommt vor. Ein `area`-Input vom Typ `CdsArea`\nwürde für drei von vier gültigen Werten ein `data-area`-Attribut schreiben, das\nim CSS folgenlos bleibt — die Falle, die genau dann entsteht, wenn eine Eingabe\nmehr verspricht, als die Stilschicht einlöst. Der Typ ist deshalb auf den einen\nWert eingeschränkt, den das CSS tatsächlich kennt; der Compiler verhindert damit\nstrukturell, dass jemand `co`/`es`/`wo` setzt und ein wirkungsloses Attribut\nbekommt, statt es nur im JSDoc zu behaupten.",
7
+ "description": "Tier (`cds-tier`) — Wrapper um `.ep-tier` aus css/components.css\n(css/components.css:1381–1384): der Stufen-Trenner (Label + Haarlinie), der eine\nOffene Feature-Liste in Pakete gliedert (z. B. „In jedem Paket enthalten“ /\n„Zusätzlich mit Pro“, Doku-Sektion `docs/index.html:4880`, Beispielseiten\n`docs/index.html:11855–11857`, `11883–11885`, `12576–12578`).\n\n**Element-Selektor, kein Attribut (ADR-0008-Standardfall).** Ausgezählt: alle 4\n`.ep-tier`-Vorkommen in `docs/index.html` stehen als eigenständiger `<div>` VOR\neinem `.layout-grid` oder einer Karten-Reihe, nie als deren Kind — keines trägt\neine `col-*`-Spaltenklasse, keines liegt in einem Grid/Flex, das seine Kinder\ndehnt. Das Tag variiert ebenfalls nicht (immer `<div>`). Keines der drei\nADR-0008-Kriterien (Grid-/Flex-Kind, Ziel einer Layout-Klasse, wechselndes Tag)\ntrifft zu, der Element-Selektor bleibt deshalb der Standardfall. `.ep-tier{\ndisplay:flex}` sitzt direkt auf dem Host (`host: { class: 'ep-tier' }`), kein\ninneres Wrapper-Element darunter — anders als bei `cds-section` (ADR-0008 Fall 2)\nist hier nichts von außen auf eine bestimmte DOM-Tiefe angewiesen: kein\nNachfahren-Selektor zielt auf `.ep-tier`, keine Fläche hängt am Host.\n\n**`area` ist auf `'ki'` typisiert, nicht auf `CdsArea`.** `css/components.css:1383`\nkennt nur die eine Regel `.ep-tier-label[data-area=\"ki\"]` (Dark-Override\n`css/dark-mode.css:476`) — für `co`/`es`/`wo` existiert keine einzige\n`[data-area]`-Regel auf `.ep-tier-label`, per Grep über `css/*.css` geprüft.\nAusgezählt in `docs/index.html`: von 4 `.ep-tier-label`-Vorkommen tragen 3\n`data-area=\"ki\"` (4880, 11884, 12577), eines trägt gar kein `data-area` (11856),\nkeines der Werte `co`/`es`/`wo` kommt vor. Ein `area`-Input vom Typ `CdsArea`\nwürde für drei von vier gültigen Werten ein `data-area`-Attribut schreiben, das\nim CSS folgenlos bleibt — die Falle, die genau dann entsteht, wenn eine Eingabe\nmehr verspricht, als die Stilschicht einlöst. Der Typ ist deshalb auf den einen\nWert eingeschränkt, den das CSS tatsächlich kennt; der Compiler verhindert damit\nstrukturell, dass jemand `co`/`es`/`wo` setzt und ein wirkungsloses Attribut\nbekommt, statt es nur im JSDoc zu behaupten.\n\nVerwendungsguidance dieser Gruppe: siehe Card (`komponenten-cards-teaser-card--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-chips-badges-pills-bereichs-badge",
5
5
  "name": "AreaBadgeComponent",
6
6
  "path": "./src/lib/area-badge/area-badge.stories.ts",
7
- "description": "Bereichs-Badge — passive Bereichs-Kennzeichnung auf Basis von `.badge` +\n`[data-area]` aus css/components.css.\n\nOrdnet ein Element einer der vier Brand Areas zu (50er-Grund, 800er-Text).\nNicht interaktiv. Für Zustände die Status-Badge, für einen redaktionellen\nAnker im Lesefluss die Pill nutzen; für interaktive Filter den Chip.",
7
+ "description": "Bereichs-Badge — passive Bereichs-Kennzeichnung auf Basis von `.badge` +\n`[data-area]` aus css/components.css.\n\nOrdnet ein Element einer der vier Brand Areas zu (50er-Grund, 800er-Text).\nNicht interaktiv. Für Zustände die Status-Badge, für einen redaktionellen\nAnker im Lesefluss die Pill nutzen; für interaktive Filter den Chip.\n\nVerwendungsguidance dieser Gruppe: siehe Chip (`komponenten-chips-badges-pills-chip--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-chips-badges-pills-pill",
5
5
  "name": "PillComponent",
6
6
  "path": "./src/lib/pill/pill.stories.ts",
7
- "description": "Pill — Wrapper um `.pill` aus css/components.css → „Badges & Chips“ (Pill).\n\nPassive, redaktionelle Bereichs-Markierung, typografisch als Eyebrow (uppercase,\nletter-spacing .09em, label-xs) — sitzt typischerweise oberhalb eines Titels und\nordnet einen Inhalt einer Brand Area zu. Abgrenzung zur Badge: die Pill ist der\nthematische „Was für ein Inhalt ist das?“-Anker im Lesefluss; die Badge die\npunktuelle Status-/Bereichs-Kennzeichnung neben Elementen. Nicht interaktiv.\n\na11y: Der reine Bereichsname klingt im Screenreader-Fluss leicht wie eine\nÜberschrift — daher trägt die Pill ein explizites `aria-label` (Default\n„Bereich <label>“, überschreibbar), genau wie in der Doku vorgegeben.",
7
+ "description": "Pill — Wrapper um `.pill` aus css/components.css → „Badges & Chips“ (Pill).\n\nPassive, redaktionelle Bereichs-Markierung, typografisch als Eyebrow (uppercase,\nletter-spacing .09em, label-xs) — sitzt typischerweise oberhalb eines Titels und\nordnet einen Inhalt einer Brand Area zu. Abgrenzung zur Badge: die Pill ist der\nthematische „Was für ein Inhalt ist das?“-Anker im Lesefluss; die Badge die\npunktuelle Status-/Bereichs-Kennzeichnung neben Elementen. Nicht interaktiv.\n\na11y: Der reine Bereichsname klingt im Screenreader-Fluss leicht wie eine\nÜberschrift — daher trägt die Pill ein explizites `aria-label` (Default\n„Bereich <label>“, überschreibbar), genau wie in der Doku vorgegeben.\n\nVerwendungsguidance dieser Gruppe: siehe Chip (`komponenten-chips-badges-pills-chip--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-chips-badges-pills-status-badge",
5
5
  "name": "StatusBadgeComponent",
6
6
  "path": "./src/lib/status-badge/status-badge.stories.ts",
7
- "description": "Status-Badge — passive Zustands-Kennzeichnung auf Basis von `.badge` +\n`.badge-{ok|warn|err|neu}` aus css/components.css.\n\nTrägt einen Zustand über semantische Farben (OK, Warnung, Fehler, Neutral) —\nz. B. „Live“, „Beta“, „Deprecated“, „Draft“. Nicht interaktiv. Für die\nZuordnung zu einer Brand Area die Bereichs-Badge, für einen redaktionellen\nAnker im Lesefluss die Pill nutzen; für interaktive Filter den Chip.",
7
+ "description": "Status-Badge — passive Zustands-Kennzeichnung auf Basis von `.badge` +\n`.badge-{ok|warn|err|neu}` aus css/components.css.\n\nTrägt einen Zustand über semantische Farben (OK, Warnung, Fehler, Neutral) —\nz. B. „Live“, „Beta“, „Deprecated“, „Draft“. Nicht interaktiv. Für die\nZuordnung zu einer Brand Area die Bereichs-Badge, für einen redaktionellen\nAnker im Lesefluss die Pill nutzen; für interaktive Filter den Chip.\n\nVerwendungsguidance dieser Gruppe: siehe Chip (`komponenten-chips-badges-pills-chip--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "label": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-dropdowns-combobox",
5
5
  "name": "ComboboxComponent",
6
6
  "path": "./src/lib/combobox/combobox.stories.ts",
7
- "description": "Combobox (cds-combobox) — Tipp-Filter über `.ep-combobox` aus css/components.css\n→ Doku „Dropdowns“. Wie der Custom Select, aber mit Substring-Filter im Feld (für\nlange Listen). Optional Multi-Select mit Chips (`multi`).\n\nVerhalten/a11y selbst getragen: Input mit role=combobox (dort ist\naria-activedescendant erlaubt), aria-expanded/-controls/-autocomplete; Listbox mit\nrole=listbox/option; ↓ öffnet/navigiert, Enter wählt, Esc schließt, Rücktaste bei\nleerem Feld entfernt im Multi-Modus den letzten Chip. Beim Schließen ohne Auswahl\nfällt die Einzelauswahl auf das gewählte Label zurück (kein loser Filtertext).\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); der Formularwert ist im Multi-Modus `string[]`, sonst `string`.\nOhne Formular gehen `[(value)]` / `[(values)]` (valueChange/valuesChange via model()).",
7
+ "description": "Combobox (cds-combobox) — Tipp-Filter über `.ep-combobox` aus css/components.css\n→ Doku „Dropdowns“. Wie der Custom Select, aber mit Substring-Filter im Feld (für\nlange Listen). Optional Multi-Select mit Chips (`multi`).\n\nVerhalten/a11y selbst getragen: Input mit role=combobox (dort ist\naria-activedescendant erlaubt), aria-expanded/-controls/-autocomplete; Listbox mit\nrole=listbox/option; ↓ öffnet/navigiert, Enter wählt, Esc schließt, Rücktaste bei\nleerem Feld entfernt im Multi-Modus den letzten Chip. Beim Schließen ohne Auswahl\nfällt die Einzelauswahl auf das gewählte Label zurück (kein loser Filtertext).\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); der Formularwert ist im Multi-Modus `string[]`, sonst `string`.\nOhne Formular gehen `[(value)]` / `[(values)]` (valueChange/valuesChange via model()).\n\nVerwendungsguidance dieser Gruppe: siehe Custom Select (`komponenten-dropdowns-custom-select--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-footer-oberer-teil",
5
5
  "name": "FooterMainComponent",
6
6
  "path": "./src/lib/footer/footer-main.stories.ts",
7
- "description": "Footer — oberer Teil (`.footer-main`): helles Band als **generisches Spalten-Layout**.\nDer Inhalt wird als beliebige Spalten projiziert (jedes Top-Level-Kind = eine\nGrid-Spalte), statt fester Adresse/Nav/Newsletter-Struktur — so eignet es sich für\nWebsite- UND App-Footer ohne Marketing-Lock-in.\n\n```html\n<cds-footer-main>\n <div>…Spalte 1…</div>\n <div>…Spalte 2…</div>\n</cds-footer-main>\n```\n\nDie Host-Klasse `footer-main` trägt Hintergrund/Padding aus css/components.css;\n`:host{display:block}` macht das Band auch standalone zum Block. Spaltenanzahl/-breiten\nüber `columns` (grid-template-columns); ohne Angabe gilt das 3-Spalten-Default.",
7
+ "description": "Footer — oberer Teil (`.footer-main`): helles Band als **generisches Spalten-Layout**.\nDer Inhalt wird als beliebige Spalten projiziert (jedes Top-Level-Kind = eine\nGrid-Spalte), statt fester Adresse/Nav/Newsletter-Struktur — so eignet es sich für\nWebsite- UND App-Footer ohne Marketing-Lock-in.\n\n```html\n<cds-footer-main>\n <div>…Spalte 1…</div>\n <div>…Spalte 2…</div>\n</cds-footer-main>\n```\n\nDie Host-Klasse `footer-main` trägt Hintergrund/Padding aus css/components.css;\n`:host{display:block}` macht das Band auch standalone zum Block. Spaltenanzahl/-breiten\nüber `columns` (grid-template-columns); ohne Angabe gilt das 3-Spalten-Default.\n\nVerwendungsguidance dieser Gruppe: siehe Footer, Komplett (`komponenten-footer-komplett--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "columns": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-footer-unterer-teil",
5
5
  "name": "FooterBottomComponent",
6
6
  "path": "./src/lib/footer/footer-bottom.stories.ts",
7
- "description": "Footer — unterer Teil (`.footer-btm`): dunkler Streifen mit Copyright, Rechts-Links\nund Social-Profilen. Die Host-Klasse `footer-btm` trägt Hintergrund/Flex-Layout aus\ncss/components.css. Social-Glyphen sind schlanke Inline-SVGs in Weiß; verifizierte\nBuilt-in-Icons (linkedin, youtube) via `platform`, beliebige weitere via `iconPath`.",
7
+ "description": "Footer — unterer Teil (`.footer-btm`): dunkler Streifen mit Copyright, Rechts-Links\nund Social-Profilen. Die Host-Klasse `footer-btm` trägt Hintergrund/Flex-Layout aus\ncss/components.css. Social-Glyphen sind schlanke Inline-SVGs in Weiß; verifizierte\nBuilt-in-Icons (linkedin, youtube) via `platform`, beliebige weitere via `iconPath`.\n\nVerwendungsguidance dieser Gruppe: siehe Footer, Komplett (`komponenten-footer-komplett--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "copyright": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-hero-störer",
5
5
  "name": "StoererSetComponent",
6
6
  "path": "./src/lib/stoerer/stoerer.stories.ts",
7
- "description": "StoererSet (cds-stoerer-set) — Wrapper um `.stoerer-set` / `.stoerer-list` aus\ncss/components.css (css/components.css:926–974): das Set aus ein bis drei\n`<cds-stoerer>`-Kacheln, das auf der Startseite oben rechts über dem Hero-Bild\nliegt. Der Positionsrahmen `.stoerer-hero` (umschließt Hero-Bild UND Set,\n`container-type:inline-size` für die Container-Query-Schwelle) ist bewusst NICHT\nTeil dieser Komponente, sondern bleibt beim Konsumenten (siehe\n`.scratch/angular-seitenbausteine/issues/03-stoerer.md`): er umschließt Hero UND\nSet gemeinsam, das könnte diese Komponente als internes Detail nicht leisten, ohne\ndas Hero-Bild selbst zu kennen.\n\n**Entscheidung — `<li>` ohne strukturelles Wrapper-Element.** `.stoerer-list` ist\nein `<ul>`; nach HTML-AAM bekommt ein `<li>` die implizite Rolle `listitem` nur als\ndirektes Kind eines `<ul>`/`<ol>`/`<menu>` — Screenreader kündigen die Liste sonst\nnicht mit Anzahl an. Ein einfaches `<ng-content>` hätte `<cds-stoerer>` selbst\nzwischen `<ul>` und `<li>` geschoben (kein direktes Kind mehr), und ein\n`display:contents`-Wrapper verbietet sich als neues CSS (ADR-0001). Gelöst über\ndasselbe Muster, das `cds-area-tabs`/`cds-area-tab` bereits für „projizierte\nKind-Komponente, deren Markup an einer selbst bestimmten Stelle im eigenen Template\nlandet“ etabliert (`area-tabs/area-tabs.component.ts`): `cds-stoerer` rendert nicht\nin sich selbst, sondern in ein `<ng-template>` und liefert es als `TemplateRef`\n(`stoerer.component.ts`). Diese Komponente liest die projizierten `<cds-stoerer>`\nüber `contentChildren()` und setzt ihr Template per `ngTemplateOutlet` direkt in\nein selbst gerendertes `<li>` ein. Im laufenden Storybook geprüft (`Komponenten/Hero/\nStörer` → Story „Interaktiv“, DOM live im Browser per `querySelector` abgefragt,\nzusätzlich in der Play-Funktion der Story gepinnt): `<ul class=\"stoerer-list\">`\nhat ausschließlich `<li>` als direkte Kinder (`ul.stoerer-list > *` → `[\"LI\",\"LI\"]`),\n`<cds-stoerer>` selbst taucht im gerenderten DOM nirgends auf — Angular hängt\nunprojizierten Content ohne passendes `<ng-content>`-Ziel gar nicht erst ein, exakt\nwie bei `<cds-area-tab>` innerhalb von `<cds-area-tabs>`. Ein `items`-Array (die im\nTicket vermerkte Alternative) hätte denselben DOM-Baum ergeben, aber den\nKonsumenten gezwungen, das projizierte Icon jeder Kachel in ein Datenobjekt\numzuziehen; mit dieser Lösung bleibt die deklarative, Content-projizierende API\nerhalten.",
7
+ "description": "StoererSet (cds-stoerer-set) — Wrapper um `.stoerer-set` / `.stoerer-list` aus\ncss/components.css (css/components.css:926–974): das Set aus ein bis drei\n`<cds-stoerer>`-Kacheln, das auf der Startseite oben rechts über dem Hero-Bild\nliegt. Der Positionsrahmen `.stoerer-hero` (umschließt Hero-Bild UND Set,\n`container-type:inline-size` für die Container-Query-Schwelle) ist bewusst NICHT\nTeil dieser Komponente, sondern bleibt beim Konsumenten (siehe\n`.scratch/angular-seitenbausteine/issues/03-stoerer.md`): er umschließt Hero UND\nSet gemeinsam, das könnte diese Komponente als internes Detail nicht leisten, ohne\ndas Hero-Bild selbst zu kennen.\n\n**Entscheidung — `<li>` ohne strukturelles Wrapper-Element.** `.stoerer-list` ist\nein `<ul>`; nach HTML-AAM bekommt ein `<li>` die implizite Rolle `listitem` nur als\ndirektes Kind eines `<ul>`/`<ol>`/`<menu>` — Screenreader kündigen die Liste sonst\nnicht mit Anzahl an. Ein einfaches `<ng-content>` hätte `<cds-stoerer>` selbst\nzwischen `<ul>` und `<li>` geschoben (kein direktes Kind mehr), und ein\n`display:contents`-Wrapper verbietet sich als neues CSS (ADR-0001). Gelöst über\ndasselbe Muster, das `cds-area-tabs`/`cds-area-tab` bereits für „projizierte\nKind-Komponente, deren Markup an einer selbst bestimmten Stelle im eigenen Template\nlandet“ etabliert (`area-tabs/area-tabs.component.ts`): `cds-stoerer` rendert nicht\nin sich selbst, sondern in ein `<ng-template>` und liefert es als `TemplateRef`\n(`stoerer.component.ts`). Diese Komponente liest die projizierten `<cds-stoerer>`\nüber `contentChildren()` und setzt ihr Template per `ngTemplateOutlet` direkt in\nein selbst gerendertes `<li>` ein. Im laufenden Storybook geprüft (`Komponenten/Hero/\nStörer` → Story „Interaktiv“, DOM live im Browser per `querySelector` abgefragt,\nzusätzlich in der Play-Funktion der Story gepinnt): `<ul class=\"stoerer-list\">`\nhat ausschließlich `<li>` als direkte Kinder (`ul.stoerer-list > *` → `[\"LI\",\"LI\"]`),\n`<cds-stoerer>` selbst taucht im gerenderten DOM nirgends auf — Angular hängt\nunprojizierten Content ohne passendes `<ng-content>`-Ziel gar nicht erst ein, exakt\nwie bei `<cds-area-tab>` innerhalb von `<cds-area-tabs>`. Ein `items`-Array (die im\nTicket vermerkte Alternative) hätte denselben DOM-Baum ergeben, aber den\nKonsumenten gezwungen, das projizierte Icon jeder Kachel in ein Datenobjekt\numzuziehen; mit dieser Lösung bleibt die deklarative, Content-projizierende API\nerhalten.\n\nVerwendungsguidance dieser Gruppe: siehe Hero-Bild (`komponenten-hero-hero-bild--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "label": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-auswahlfeld",
5
5
  "name": "SelectFieldComponent",
6
6
  "path": "./src/lib/field/select-field.stories.ts",
7
- "description": "Auswahlfeld — `<select>` im `.field`-Gerüst. Die Optionen kommen über `options`;\na11y-Verdrahtung wie beim Textfeld (aria-required/-invalid/-describedby).\n\nAls `ControlValueAccessor` (siehe FieldBase) direkt an Angular-Formulare\nanbindbar (`[(ngModel)]`, `formControlName`) bzw. ohne Formular per `[(value)]`.",
7
+ "description": "Auswahlfeld — `<select>` im `.field`-Gerüst. Die Optionen kommen über `options`;\na11y-Verdrahtung wie beim Textfeld (aria-required/-invalid/-describedby).\n\nAls `ControlValueAccessor` (siehe FieldBase) direkt an Angular-Formulare\nanbindbar (`[(ngModel)]`, `formControlName`) bzw. ohne Formular per `[(value)]`.\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "disabled": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-checkbox",
5
5
  "name": "CheckboxComponent",
6
6
  "path": "./src/lib/checkbox/checkbox.stories.ts",
7
- "description": "Checkbox — Einwilligungs-/Consent-Feld nach docs/index.html („Forms“).\n\nBewusst KEIN nachgebautes Kästchen: ein natives `<input type=\"checkbox\">` mit\n`accent-color` in der Bereichsfarbe (genau wie die Doku), umschlossen von einem\n`<label>` mit dem Einwilligungstext und optional verlinktem Datenschutzhinweis.\nDokumentierte Verwendung: Newsletter-/DSGVO-Einwilligung, i. d. R. `required`.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(checked)]` (checkedChange via model()).",
7
+ "description": "Checkbox — Einwilligungs-/Consent-Feld nach docs/index.html („Forms“).\n\nBewusst KEIN nachgebautes Kästchen: ein natives `<input type=\"checkbox\">` mit\n`accent-color` in der Bereichsfarbe (genau wie die Doku), umschlossen von einem\n`<label>` mit dem Einwilligungstext und optional verlinktem Datenschutzhinweis.\nDokumentierte Verwendung: Newsletter-/DSGVO-Einwilligung, i. d. R. `required`.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(checked)]` (checkedChange via model()).\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-radio",
5
5
  "name": "RadioGroupComponent",
6
6
  "path": "./src/lib/radio-group/radio-group.stories.ts",
7
- "description": "Radio-Gruppe (Optionsfelder) nach docs/index.html („Forms“).\n\nFür 2–6 sich gegenseitig ausschließende Optionen (mehr → Select). Bewusst KEIN\nnachgebauter Kreis: native `<input type=\"radio\">` mit `accent-color` in der\nBereichsfarbe, gruppiert in `<fieldset>`/`<legend>` (Gruppen-Label wie ein\nFeld-Label), alle Optionen teilen denselben `name`.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(value)]` (valueChange via model()).",
7
+ "description": "Radio-Gruppe (Optionsfelder) nach docs/index.html („Forms“).\n\nFür 2–6 sich gegenseitig ausschließende Optionen (mehr → Select). Bewusst KEIN\nnachgebauter Kreis: native `<input type=\"radio\">` mit `accent-color` in der\nBereichsfarbe, gruppiert in `<fieldset>`/`<legend>` (Gruppen-Label wie ein\nFeld-Label), alle Optionen teilen denselben `name`.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(value)]` (valueChange via model()).\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-skala",
5
5
  "name": "ScaleComponent",
6
6
  "path": "./src/lib/scale/scale.stories.ts",
7
- "description": "Skala (cds-scale) — Slider für GEORDNETE (ordinale) Kategorien, deren Labels die\nWerte SIND (z. B. Niedrig < Mittel < Hoch, nie < selten < oft < immer).\n\nBasiert auf dem nativen <input type=\"range\">; min=0, max=labels.length-1, step=1\nwerden intern abgeleitet und NICHT exponiert. Der aktuelle Wert erscheint als\nLABEL im <output> und wird Screenreadern über `aria-valuetext` als Text gemeldet\n(nicht als Zahl) — das anerkannte APG-Muster für ordinale Slider. Die Skalenpunkte\nzeigen alle Labels, exakt auf ihre Position ausgerichtet und bewusst OHNE\nReduktion (jedes Label ist eine wählbare Stufe).\n\nNUR für geordnete Kategorien. Ungeordnete/gleichrangige Optionen (ohne natürliche\nReihenfolge) gehören NICHT auf einen Slider → cds-radio-group oder cds-area-tabs.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); der Formularwert ist der Stufen-INDEX. Ohne Formular geht\n`[(value)]` (valueChange via model()).",
7
+ "description": "Skala (cds-scale) — Slider für GEORDNETE (ordinale) Kategorien, deren Labels die\nWerte SIND (z. B. Niedrig < Mittel < Hoch, nie < selten < oft < immer).\n\nBasiert auf dem nativen <input type=\"range\">; min=0, max=labels.length-1, step=1\nwerden intern abgeleitet und NICHT exponiert. Der aktuelle Wert erscheint als\nLABEL im <output> und wird Screenreadern über `aria-valuetext` als Text gemeldet\n(nicht als Zahl) — das anerkannte APG-Muster für ordinale Slider. Die Skalenpunkte\nzeigen alle Labels, exakt auf ihre Position ausgerichtet und bewusst OHNE\nReduktion (jedes Label ist eine wählbare Stufe).\n\nNUR für geordnete Kategorien. Ungeordnete/gleichrangige Optionen (ohne natürliche\nReihenfolge) gehören NICHT auf einen Slider → cds-radio-group oder cds-area-tabs.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); der Formularwert ist der Stufen-INDEX. Ohne Formular geht\n`[(value)]` (valueChange via model()).\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-slider",
5
5
  "name": "SliderComponent",
6
6
  "path": "./src/lib/slider/slider.stories.ts",
7
- "description": "Slider — Wrapper um `.field-slider` / `.slider` aus css/components.css → „Slider“.\n\nRange-Eingabe mit Label + Live-Ausgabe, bereichsgefärbtem Thumb/Output\n(.slider-<area> setzt --sl-color), automatisch berechneten Ticks und Helper-Text.\n\nTicks: Es wird nur eine gewünschte ANZAHL (`tickCount`) angegeben; die Positionen/\nLabels werden gleichmäßig aus [min, max] berechnet (space-between wie das CSS-\nLayout). Wird der Slider zu schmal, reduziert die Komponente die Tick-Zahl reaktiv\n(ResizeObserver), sodass die Labels nicht überlappen — Endpunkte bleiben erhalten.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(value)]` (valueChange via model()).",
7
+ "description": "Slider — Wrapper um `.field-slider` / `.slider` aus css/components.css → „Slider“.\n\nRange-Eingabe mit Label + Live-Ausgabe, bereichsgefärbtem Thumb/Output\n(.slider-<area> setzt --sl-color), automatisch berechneten Ticks und Helper-Text.\n\nTicks: Es wird nur eine gewünschte ANZAHL (`tickCount`) angegeben; die Positionen/\nLabels werden gleichmäßig aus [min, max] berechnet (space-between wie das CSS-\nLayout). Wird der Slider zu schmal, reduziert die Komponente die Tick-Zahl reaktiv\n(ResizeObserver), sodass die Labels nicht überlappen — Endpunkte bleiben erhalten.\n\nAls `ControlValueAccessor` direkt an Angular-Formulare anbindbar (`[(ngModel)]`,\n`formControlName`); ohne Formular geht `[(value)]` (valueChange via model()).\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-inputs-forms-textbereich",
5
5
  "name": "TextareaFieldComponent",
6
6
  "path": "./src/lib/field/textarea-field.stories.ts",
7
- "description": "Textbereich — mehrzeiliges `<textarea>` im `.field`-Gerüst. Gleiche a11y-\nVerdrahtung wie das Textfeld (aria-required/-invalid/-describedby).\n\nAls `ControlValueAccessor` (siehe FieldBase) direkt an Angular-Formulare\nanbindbar (`[(ngModel)]`, `formControlName`) bzw. ohne Formular per `[(value)]`.",
7
+ "description": "Textbereich — mehrzeiliges `<textarea>` im `.field`-Gerüst. Gleiche a11y-\nVerdrahtung wie das Textfeld (aria-required/-invalid/-describedby).\n\nAls `ControlValueAccessor` (siehe FieldBase) direkt an Angular-Formulare\nanbindbar (`[(ngModel)]`, `formControlName`) bzw. ohne Formular per `[(value)]`.\n\nVerwendungsguidance dieser Gruppe: siehe Textfeld (`komponenten-inputs-forms-textfeld--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "disabled": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-slider-carousel-logocarousel",
5
5
  "name": "LogoCarouselComponent",
6
6
  "path": "./src/lib/logo-carousel/logo-carousel.stories.ts",
7
- "description": "LogoCarousel — Wrapper um `.logo-carousel` aus css/components.css → „Logo-Carousel“.\n\nDiskrete Sets von je fünf Logos, die automatisch per Crossfade wechseln\n(`[aria-hidden]` je Slide). Das Autoplay pausiert bei Maus-Hover und Tastatur-Fokus\n(damit Nutzer in Ruhe lesen/bedienen können), zusätzlich dauerhaft über den\nPause-Button (.logo-carousel-pause, sichtbar bei Hover/Fokus bzw. im .paused-Zustand);\nDots wählen ein Set direkt. Autoplay respektiert prefers-reduced-motion.\n\nDer Timer wird zentral über ein `effect` gesteuert: er läuft nur, wenn NICHT\npausiert, NICHT gehovert, NICHT fokussiert und reduzierte Bewegung nicht gewünscht\nist. Eine Änderung des `interval` startet ihn automatisch neu.\n\nJede Kachel ist ein `cds-logo`: bevorzugt ein Bild (`src`), sonst der Text als\nPlatzhalter/Fallback. Standardmäßig sind reine Text-Platzhalter gesetzt – reale\nAnwendungen übergeben ihre Kundenlogos als Bilder.",
7
+ "description": "LogoCarousel — Wrapper um `.logo-carousel` aus css/components.css → „Logo-Carousel“.\n\nDiskrete Sets von je fünf Logos, die automatisch per Crossfade wechseln\n(`[aria-hidden]` je Slide). Das Autoplay pausiert bei Maus-Hover und Tastatur-Fokus\n(damit Nutzer in Ruhe lesen/bedienen können), zusätzlich dauerhaft über den\nPause-Button (.logo-carousel-pause, sichtbar bei Hover/Fokus bzw. im .paused-Zustand);\nDots wählen ein Set direkt. Autoplay respektiert prefers-reduced-motion.\n\nDer Timer wird zentral über ein `effect` gesteuert: er läuft nur, wenn NICHT\npausiert, NICHT gehovert, NICHT fokussiert und reduzierte Bewegung nicht gewünscht\nist. Eine Änderung des `interval` startet ihn automatisch neu.\n\nJede Kachel ist ein `cds-logo`: bevorzugt ein Bild (`src`), sonst der Text als\nPlatzhalter/Fallback. Standardmäßig sind reine Text-Platzhalter gesetzt – reale\nAnwendungen übergeben ihre Kundenlogos als Bilder.\n\nVerwendungsguidance dieser Gruppe: siehe Carousel (`komponenten-slider-carousel-carousel--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "active": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-tabelle-vergleichstabelle",
5
5
  "name": "CompareComponent",
6
6
  "path": "./src/lib/compare/compare.stories.ts",
7
- "description": "Compare (`cds-compare`) — Wrapper um `.ep-compare*` aus css/components.css\n(css/components.css:1275–1294): die aufklappbare Vergleichstabelle für den zeilenweisen\nDirektvergleich mehrerer Pakete/Tarife (Doku-Site `sec-table`, Nav-Eintrag\n„Vergleichstabelle (aufklappbar)“, `docs/index.html:5182–5204`). Zehntes Ticket der\nSeitenbausteine-Serie, nach `cds-table` (Ticket 09).\n\n**Mit Daten-Input, anders als `cds-table`.** `cds-table` projiziert `<thead>`/`<tbody>`\nunverändert per `<ng-content>`, weil seine Zellen Badges, Links und `data-num` tragen können\n(siehe dessen Klassendoku). Hier ist der Zellinhalt strukturell auf Ja/Nein oder eine kurze\nAngabe begrenzt — ausgezählt: alle 22 Datenzellen des einzigen realen Vorkommens\n(`docs/index.html:11970–12038`, 11 Zeilen × 2 Spalten, ohne die Zeilenüberschriften) sind\nentweder ein `.ep-compare-yes`/`-no`-Marker (18×, davon 14× „Ja“, 4× „Nein“) oder ein kurzer\nText wie „bis 70 Mrd. Param.“ bzw. „30 Min.“ (4×) — nie ein Badge, Link oder anderes Markup.\nWeil Spaltenzahl, `pro`-Spalte und Zellinhalt damit vollständig aus zwei Arrays (`columns`,\n`rows`) hervorgehen, würde `<ng-content>` beim Konsumenten nur denselben `@for`-Code\nduplizieren, ohne eine Freiheit zu gewinnen, die die Zell-Typisierung (`boolean | string`)\nohnehin ausschließt.\n\n**Ja/Nein-Zellen tragen einen Screenreader-Text, übernommen statt erfunden.** Im einzigen\nrealen Vorkommen steht hinter jeder Glyphe ein `.sr-only`-Text, ausnahmslos:\n`<span class=\"ep-compare-yes\" aria-hidden=\"true\">✓</span><span class=\"sr-only\">Enthalten</span>`\n(14×) bzw. `<span class=\"ep-compare-no\" aria-hidden=\"true\">−</span><span class=\"sr-only\">Nicht\nenthalten</span>` (4×, „−“ ist U+2212 Minus, kein Bindestrich). Genau diese Zeichen und dieser\nWortlaut, keine eigene Formulierung — Farbe und Glyphe allein tragen keine Bedeutung\n(WCAG 1.4.1), der `.sr-only`-Text ist deshalb kein optionaler Zusatz, sondern fest verdrahtet,\nnicht per Input überschreibbar.\n\n**`caption` ist Pflicht (`input.required<string>()`), abweichend von der Ticket-Skizze (dort\nkein Input dafür vorgesehen) — dieselbe Begründung wie bei `cds-table`.** Die eigene Doku\n(`storybook-angular/src/docs/komponenten/tabelle.mdx:91`) nennt `<caption class=\"sr-only\">`\nausdrücklich als Teil des Bauteils, und das einzige reale Vorkommen hat eine. Anders als bei\n`cds-table` ist sie hier `.sr-only`, nicht sichtbar: der Klartext steht schon im `<summary>`\n(`summary`-Input), die `<caption>` wiederholt ihn nur für Screenreader, die nach dem Aufklappen\ndirekt in die Tabelle springen, ohne den Summary-Text erneut vorgelesen zu bekommen.\n\n**`rowsLabel` (erste Kopfzelle, `<th scope=\"col\">Funktion</th>` im Mockup) ist dagegen Beiwerk,\noptional mit Default `''`.** Auch dafür sieht die Ticket-Skizze keinen Input vor. Den Text fest\nim Template zu verdrahten hieße, AI.Box-Copy in einen wiederverwendbaren Wrapper zu backen\n(ADR-0007 §2); ihn ganz wegzulassen wich ohne CSS-Befund vom einzigen Beleg ab, ohne dass die\nDoku das verlangt. Anders als `caption` ist die Kopfzelle nicht barrierefreiheitsrelevant\nPflicht: ein leeres `<th scope=\"col\">` bleibt eine gültige, in Vergleichsmatrizen verbreitete\nEcke ohne eigenen Namen. Deshalb Beiwerk, kein Inhalt — das Beispielwort „Funktion“ steht in\nder Story, nicht in der Klasse.\n\n**Natives `<details>`/`<summary>` bleibt erhalten, kein nachgebautes Disclosure** (Ticket-\nVorgabe, analog `cds-faq`): Tastaturbedienung und Toggle-Verhalten kommen vom Browser, das CSS\nhängt direkt an `[open]` (`.ep-compare[open] .ep-compare-caret`). `<details class=\"ep-compare\">`\nsitzt deshalb im TEMPLATE, nicht am Host — derselbe Grund wie bei `cds-table`s\n`.tbl-wrap`/`.tbl`: ein `<cds-compare>`-Host ist ein unbekanntes Custom Element, kein echtes\n`<details>`, und kann dessen native Disclosure-Semantik nicht annehmen.\n\n**Element-Selektor (ADR-0008-Standardfall).** `.ep-compare` sitzt im einzigen realen Vorkommen\nals gewöhnlicher Block-Nachfahre in `.ep-section` (`docs/index.html:11969`) — kein Grid-/\nFlex-Kind, keine `col-*`-Klasse vom Konsumenten, kein Tag-Wechsel (immer `<details>`). Keines\nder drei ADR-0008-Kriterien greift, ein Attributselektor brächte hier nichts.\n\n**`open` ist ein reiner Anfangszustand, keine Zwei-Wege-Bindung.** Gebunden über\n`[attr.open]=\"open() ? '' : null\"`: Angular schreibt das Attribut nur, wenn sich der GEPRÜFTE\nAusdruckswert seit dem letzten Change-Detection-Lauf ändert. `open()` bleibt nach dem ersten\nRendern konstant (die Komponente schreibt nie in dieses Signal zurück), ein nachfolgender\nnativer Toggle wird deshalb nicht rückgängig gemacht — geprüft in der Story „Interaktiv“\n(Play-Funktion: Klick öffnet, `toggled` feuert `true`, ein zweiter, vom Toggle unabhängiger\nInteraktionsschritt lässt die Tabelle weiterhin offen).",
7
+ "description": "Compare (`cds-compare`) — Wrapper um `.ep-compare*` aus css/components.css\n(css/components.css:1275–1294): die aufklappbare Vergleichstabelle für den zeilenweisen\nDirektvergleich mehrerer Pakete/Tarife (Doku-Site `sec-table`, Nav-Eintrag\n„Vergleichstabelle (aufklappbar)“, `docs/index.html:5182–5204`). Zehntes Ticket der\nSeitenbausteine-Serie, nach `cds-table` (Ticket 09).\n\n**Mit Daten-Input, anders als `cds-table`.** `cds-table` projiziert `<thead>`/`<tbody>`\nunverändert per `<ng-content>`, weil seine Zellen Badges, Links und `data-num` tragen können\n(siehe dessen Klassendoku). Hier ist der Zellinhalt strukturell auf Ja/Nein oder eine kurze\nAngabe begrenzt — ausgezählt: alle 22 Datenzellen des einzigen realen Vorkommens\n(`docs/index.html:11970–12038`, 11 Zeilen × 2 Spalten, ohne die Zeilenüberschriften) sind\nentweder ein `.ep-compare-yes`/`-no`-Marker (18×, davon 14× „Ja“, 4× „Nein“) oder ein kurzer\nText wie „bis 70 Mrd. Param.“ bzw. „30 Min.“ (4×) — nie ein Badge, Link oder anderes Markup.\nWeil Spaltenzahl, `pro`-Spalte und Zellinhalt damit vollständig aus zwei Arrays (`columns`,\n`rows`) hervorgehen, würde `<ng-content>` beim Konsumenten nur denselben `@for`-Code\nduplizieren, ohne eine Freiheit zu gewinnen, die die Zell-Typisierung (`boolean | string`)\nohnehin ausschließt.\n\n**Ja/Nein-Zellen tragen einen Screenreader-Text, übernommen statt erfunden.** Im einzigen\nrealen Vorkommen steht hinter jeder Glyphe ein `.sr-only`-Text, ausnahmslos:\n`<span class=\"ep-compare-yes\" aria-hidden=\"true\">✓</span><span class=\"sr-only\">Enthalten</span>`\n(14×) bzw. `<span class=\"ep-compare-no\" aria-hidden=\"true\">−</span><span class=\"sr-only\">Nicht\nenthalten</span>` (4×, „−“ ist U+2212 Minus, kein Bindestrich). Genau diese Zeichen und dieser\nWortlaut, keine eigene Formulierung — Farbe und Glyphe allein tragen keine Bedeutung\n(WCAG 1.4.1), der `.sr-only`-Text ist deshalb kein optionaler Zusatz, sondern fest verdrahtet,\nnicht per Input überschreibbar.\n\n**`caption` ist Pflicht (`input.required<string>()`), abweichend von der Ticket-Skizze (dort\nkein Input dafür vorgesehen) — dieselbe Begründung wie bei `cds-table`.** Die eigene Doku\n(`storybook-angular/src/docs/komponenten/tabelle.mdx:91`) nennt `<caption class=\"sr-only\">`\nausdrücklich als Teil des Bauteils, und das einzige reale Vorkommen hat eine. Anders als bei\n`cds-table` ist sie hier `.sr-only`, nicht sichtbar: der Klartext steht schon im `<summary>`\n(`summary`-Input), die `<caption>` wiederholt ihn nur für Screenreader, die nach dem Aufklappen\ndirekt in die Tabelle springen, ohne den Summary-Text erneut vorgelesen zu bekommen.\n\n**`rowsLabel` (erste Kopfzelle, `<th scope=\"col\">Funktion</th>` im Mockup) ist dagegen Beiwerk,\noptional mit Default `''`.** Auch dafür sieht die Ticket-Skizze keinen Input vor. Den Text fest\nim Template zu verdrahten hieße, AI.Box-Copy in einen wiederverwendbaren Wrapper zu backen\n(ADR-0007 §2); ihn ganz wegzulassen wich ohne CSS-Befund vom einzigen Beleg ab, ohne dass die\nDoku das verlangt. Anders als `caption` ist die Kopfzelle nicht barrierefreiheitsrelevant\nPflicht: ein leeres `<th scope=\"col\">` bleibt eine gültige, in Vergleichsmatrizen verbreitete\nEcke ohne eigenen Namen. Deshalb Beiwerk, kein Inhalt — das Beispielwort „Funktion“ steht in\nder Story, nicht in der Klasse.\n\n**Natives `<details>`/`<summary>` bleibt erhalten, kein nachgebautes Disclosure** (Ticket-\nVorgabe, analog `cds-faq`): Tastaturbedienung und Toggle-Verhalten kommen vom Browser, das CSS\nhängt direkt an `[open]` (`.ep-compare[open] .ep-compare-caret`). `<details class=\"ep-compare\">`\nsitzt deshalb im TEMPLATE, nicht am Host — derselbe Grund wie bei `cds-table`s\n`.tbl-wrap`/`.tbl`: ein `<cds-compare>`-Host ist ein unbekanntes Custom Element, kein echtes\n`<details>`, und kann dessen native Disclosure-Semantik nicht annehmen.\n\n**Element-Selektor (ADR-0008-Standardfall).** `.ep-compare` sitzt im einzigen realen Vorkommen\nals gewöhnlicher Block-Nachfahre in `.ep-section` (`docs/index.html:11969`) — kein Grid-/\nFlex-Kind, keine `col-*`-Klasse vom Konsumenten, kein Tag-Wechsel (immer `<details>`). Keines\nder drei ADR-0008-Kriterien greift, ein Attributselektor brächte hier nichts.\n\n**`open` ist ein reiner Anfangszustand, keine Zwei-Wege-Bindung.** Gebunden über\n`[attr.open]=\"open() ? '' : null\"`: Angular schreibt das Attribut nur, wenn sich der GEPRÜFTE\nAusdruckswert seit dem letzten Change-Detection-Lauf ändert. `open()` bleibt nach dem ersten\nRendern konstant (die Komponente schreibt nie in dieses Signal zurück), ein nachfolgender\nnativer Toggle wird deshalb nicht rückgängig gemacht — geprüft in der Story „Interaktiv“\n(Play-Funktion: Klick öffnet, `toggled` feuert `true`, ein zweiter, vom Toggle unabhängiger\nInteraktionsschritt lässt die Tabelle weiterhin offen).\n\nVerwendungsguidance dieser Gruppe: siehe Tabelle (`komponenten-tabelle-tabelle--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "caption": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-theme-umschalter-dropdown",
5
5
  "name": "ThemeSelectComponent",
6
6
  "path": "./src/lib/theme-switch/select.stories.ts",
7
- "description": "Theme-Dropdown — Theme-Umschalter auf Basis unseres Custom Select (cds-select):\ngestylte Einzelauswahl mit Listbox-Popup und Häkchen. Vorgesehener Einsatz: nur in\nden Einstellungen (Settings), NICHT als persistentes Element auf allen Seiten.\n\n`showSystem` schaltet zwischen Hell/Dunkel/System und binär Hell/Dunkel.",
7
+ "description": "Theme-Dropdown — Theme-Umschalter auf Basis unseres Custom Select (cds-select):\ngestylte Einzelauswahl mit Listbox-Popup und Häkchen. Vorgesehener Einsatz: nur in\nden Einstellungen (Settings), NICHT als persistentes Element auf allen Seiten.\n\n`showSystem` schaltet zwischen Hell/Dunkel/System und binär Hell/Dunkel.\n\nVerwendungsguidance dieser Gruppe: siehe Cycle-Button (`komponenten-theme-umschalter-cycle-button--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "showSystem": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-theme-umschalter-segment",
5
5
  "name": "ThemeSegmentComponent",
6
6
  "path": "./src/lib/theme-switch/segment-tri.stories.ts",
7
- "description": "Theme-Segment — Segment-Switch für das Farbthema. Vorgesehener Einsatz: als\neigenständiges Element zum Hovern. Ist daher IMMER responsiv (unter 640px\nIcon-only) und IMMER animiert (Aktiv-Markierung gleitet als Thumb) — beides\nfest, nicht konfigurierbar. Icon + Textlabel stehen immer nebeneinander.\n\nEinzige Konfiguration: `showSystem` (tri Hell/Dunkel/System vs. binär Hell/Dunkel).\n\nBaut auf den CSS-Kern-Klassen `.theme-bar`/`.tbtn` auf. Jeder Button trägt ein\n`aria-label`, ist also auch im Icon-only-Modus benannt. Der Thumb wird per\ngetBoundingClientRect an die aktive Zelle gesetzt (ResizeObserver misst bei\nBreakpoint-/Font-Änderungen nach).",
7
+ "description": "Theme-Segment — Segment-Switch für das Farbthema. Vorgesehener Einsatz: als\neigenständiges Element zum Hovern. Ist daher IMMER responsiv (unter 640px\nIcon-only) und IMMER animiert (Aktiv-Markierung gleitet als Thumb) — beides\nfest, nicht konfigurierbar. Icon + Textlabel stehen immer nebeneinander.\n\nEinzige Konfiguration: `showSystem` (tri Hell/Dunkel/System vs. binär Hell/Dunkel).\n\nBaut auf den CSS-Kern-Klassen `.theme-bar`/`.tbtn` auf. Jeder Button trägt ein\n`aria-label`, ist also auch im Icon-only-Modus benannt. Der Thumb wird per\ngetBoundingClientRect an die aktive Zelle gesetzt (ResizeObserver misst bei\nBreakpoint-/Font-Änderungen nach).\n\nVerwendungsguidance dieser Gruppe: siehe Cycle-Button (`komponenten-theme-umschalter-cycle-button--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "showSystem": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-zitate-testimonials-teamvoice",
5
5
  "name": "TeamVoiceComponent",
6
6
  "path": "./src/lib/team-voice/team-voice.stories.ts",
7
- "description": "TeamVoice — Wrapper um `.team-voice` aus css/components.css → „Team-Stimmen“.\n\nEditoriale Zitat-Reihe mit seitlichem Foto (im Grid abwechselnd links/rechts,\ngesteuert per :nth-child innerhalb von `.team-voices`), bereichsgefärbtem\nAkzent (data-area), Quote-Icon (ui-quote), Zitat und Name/Rolle. Mehrere\nKomponenten in einen `<div class=\"team-voices\">` legen, damit das alternierende\nLayout greift (siehe Story).",
7
+ "description": "TeamVoice — Wrapper um `.team-voice` aus css/components.css → „Team-Stimmen“.\n\nEditoriale Zitat-Reihe mit seitlichem Foto (im Grid abwechselnd links/rechts,\ngesteuert per :nth-child innerhalb von `.team-voices`), bereichsgefärbtem\nAkzent (data-area), Quote-Icon (ui-quote), Zitat und Name/Rolle. Mehrere\nKomponenten in einen `<div class=\"team-voices\">` legen, damit das alternierende\nLayout greift (siehe Story).\n\nVerwendungsguidance dieser Gruppe: siehe Blockquote (`komponenten-zitate-testimonials-blockquote--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -4,7 +4,7 @@
4
4
  "id": "komponenten-zitate-testimonials-testimonial",
5
5
  "name": "TestimonialComponent",
6
6
  "path": "./src/lib/testimonial/testimonial.stories.ts",
7
- "description": "Testimonial — Wrapper um `.testimonial` aus css/components.css → „Testimonial Card“.\n\nStatische Zitat-Karte mit bereichsgefärbtem Top-Akzent (data-area), Quote-Icon\n(.testimonial-icon, fill:currentColor), Zitat (blockquote) und Footer mit Name/Rolle.\nNur bestehende Klassen — kein eigenes CSS.",
7
+ "description": "Testimonial — Wrapper um `.testimonial` aus css/components.css → „Testimonial Card“.\n\nStatische Zitat-Karte mit bereichsgefärbtem Top-Akzent (data-area), Quote-Icon\n(.testimonial-icon, fill:currentColor), Zitat (blockquote) und Footer mit Name/Rolle.\nNur bestehende Klassen — kein eigenes CSS.\n\nVerwendungsguidance dieser Gruppe: siehe Blockquote (`komponenten-zitate-testimonials-blockquote--verwendung`).",
8
8
  "jsDocTags": {},
9
9
  "argTypes": {
10
10
  "area": {
@@ -20,7 +20,15 @@ Feste Regeln für die Angular-Lib „@conciso/design-system-angular“:
20
20
  1. CSS-Schicht und Fonts global einbinden, nicht pro Komponente. Ohne diesen Schritt bleiben die Wrapper-Komponenten ungestylt.
21
21
  2. Kein eigenes CSS für DS-Komponenten schreiben und keine CSS-Klassen erfinden.
22
22
  3. Nur Inputs und Outputs verwenden, die docs-show für die jeweilige Komponente liefert. Vorher nachsehen, nie raten.
23
- 4. Bei Fragen zur Einrichtung docs-show mit der ID „${EINRICHTUNG_DOC_ID}“ aufrufen (Storybook-Seite „Einrichtung“).`;
23
+ 4. Bei Fragen zur Einrichtung docs-show mit der ID „${EINRICHTUNG_DOC_ID}“ aufrufen (Storybook-Seite „Einrichtung“).
24
+ 5. Für Auswahl- und Gestaltungsfragen (welche Komponente, welche Variante, wo platzieren) zusätzlich die Verwendungsguidance heranziehen: Sie steht, wenn vorhanden, in der docs-show-Antwort der Komponente im Abschnitt „Docs“. Fehlt dieser Abschnitt, über docs-list nach einer Seite „Verwendung“ der Komponentengruppe suchen und sie mit docs-show laden.`;
25
+
26
+ /**
27
+ * Anzahl der oben nummerierten Regeln in OWN_INSTRUCTIONS. Exportiert, damit ein Test sie gegen
28
+ * die Regel-Liste in der Paket-README (mcp-server/README.md, Abschnitt „Was er kann“) absichern
29
+ * kann, ohne die Regeln selbst dafür zu duplizieren.
30
+ */
31
+ export const OWN_RULE_COUNT = (OWN_INSTRUCTIONS.match(/^\d+\.\s/gm) ?? []).length;
24
32
 
25
33
  /**
26
34
  * Baut den vollständigen `instructions`-Text: eigene Regeln, optional die Versions-Notiz aus
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-call-to-action--verwendung": {
4
- "id": "komponenten-call-to-action--verwendung",
5
- "name": "komponenten-call-to-action--verwendung",
6
- "docs": {
7
- "komponenten-call-to-action--verwendung": {
8
- "id": "komponenten-call-to-action--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/cta-verwendung.mdx",
11
- "title": "Komponenten/Call to Action",
12
- "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Call to Action\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nCall to Action deckt zwei Pattern-Familien ab: das Page-End-CTA-Band als letzte, konkrete\nEinladung am Ende jeder Customer-Page, und vier Download-CTA-Varianten für\nRessourcen-Downloads. Ergänzend dokumentiert diese Seite den Editorial Split als\nsekundäre Konversionsfläche neben dem primären Page-End-CTA. Das Page-End-CTA-Band hat\nseit Ticket 07 der Seitenbausteine-Serie ein eigenes Bauteil (`CtaBand`, Attributselektor\n`[cdsCtaBand]`), ebenso die vier Download-Varianten (`DownloadCta`); der Editorial Split\nbleibt ein CSS-Rezept ohne Angular-Komponente.\n\n## Wann welche Variante\n\n| Variante | Bauteil | Wann einsetzen |\n|---|---|---|\n| Page-End-CTA-Band | `CtaBand` (`[cdsCtaBand]`) | Letzte Einladung am Ende jeder Customer-Page, direkt vor dem Footer, eine Aktion auf der Bereichsfarbe als Hintergrund |\n| Editorial Split | bauteillos (CSS-Rezept `.ep-section` + `.layout-grid`) | Sekundäre oder tertiäre Konversionsfläche neben dem primären Page-End-CTA (zum Beispiel ein Karriere-Block auf der Landing), ohne Card-Chrome |\n| Download · Hero | `DownloadCta` | Hauptressource einer Seite, Landing Pages, Ressourcenseiten, Kampagnen, maximal einmal pro Seite |\n| Download · Mit Vorschaubild | `DownloadCta` | Whitepapers und Reports, deren Deckblatt als Vorschau den Inhalt sofort greifbar macht |\n| Download · Kompakt | `DownloadCta` | Ressourcenlisten mit mehreren Downloads (zum Beispiel eine Mediathek) |\n| Download · Minimal | `DownloadCta` | Quellenangaben, Fließtext-Links oder Nebenbereiche (Footer, Blog, Dokumentation) |\n\n### Page-End-CTA-Band (`CtaBand`)\n\nAttributselektor `[cdsCtaBand]` statt eigenem Element: die Bandfläche ist im Mockup\nausnahmslos ein Inline-Style direkt am Element (`.ep-cta-band`, Padding\n`var(--s12) var(--s8)`, zentriert) — ein eigenes Element würde denselben „Fläche am\nHost“-Fehler reproduzieren, den `docs/adr/0008` für `cds-section` gemessen hat. Der\nKonsument setzt Hintergrund und Schrift deshalb\nweiterhin selbst, auf demselben `<div cdsCtaBand>`, das die Komponente trägt:\nBereichsfarbe (`--co-700` / `--ki-800` / `--es-700` / `--wo-700`), Schrift `color:#fff`.\nAuf der dunklen Fläche wird der Filled-Button über die zusammengesetzte Modifier-Klasse\n`.btn-on-band` invertiert (weißer Hintergrund, Text in der Bereichsfarbe) — die\nKomponente setzt diese Klassen direkt (`cds-button` kennt zwar den Modifier, kann aber\nkeinen `<a>` rendern, siehe `cta-band.component.ts`). Die Aktion führt in der\nRegel auf die adaptive Kontaktseite (`data-ep=\"kontakt\"`), nie auf ein Overlay oder\nModal. Bewusst nur EINE Aktion, kein `secondaryLabel`: keines der 22\nMockup-Vorkommen zeigt eine zweite, und `.btn-on-band` lässt sich mit den\nvorhandenen CSS-Klassen ohnehin nicht in einer zurückhaltenderen zweiten Variante\nbauen (jede Nicht-`filled`-Variante würde Text in Bandfarbe auf Bandfarbe zeigen —\nfestgehalten in\n`.scratch/angular-seitenbausteine/issues/16-css-luecke-zweite-aktion-auf-band.md`).\n\n```html\n<div cdsCtaBand\n heading=\"Erstgespräch, 30 Minuten, kostenfrei.\"\n sub=\"Du schilderst Deine Situation, wir geben eine erste Einschätzung.\"\n primaryLabel=\"Termin buchen\"\n primaryHref=\"/kontakt\"\n style=\"background:var(--co-700);color:#fff\">\n</div>\n```\n\n### Editorial Split (bauteillos)\n\nRuhige 2-Spalten-Aufteilung in einer normalen `.ep-section`: links ein Foto im\n4:3-Format mit `--r-md`, rechts Eyebrow, H2, Lead und Button. Kein Card-Container, kein\nSchatten, keine Border. Bühne entsteht über die Hintergrundfarbe der Sektion\n(typischerweise `--co-50` oder `--n-50`) und über das Foto links, nicht über\nCard-Chrome, das dem Markenwert „Ruhig“ widerspräche.\n\n```html\n<div class=\"ep-section\" style=\"background:var(--co-50)\">\n <div class=\"layout-grid\" style=\"align-items:center\">\n <div class=\"col-6\">\n <img src=\"bild.jpg\" alt=\"Beschreibend\"\n style=\"width:100%;aspect-ratio:4/3;object-fit:cover;border-radius:var(--r-md)\">\n </div>\n <div class=\"col-6\">\n <div class=\"ep-section-label t-co\">Karriere</div>\n <h2 class=\"ep-section-h2\">Dein Fußabdruck bei Conciso.</h2>\n <p class=\"ep-section-sub\">Projekte mit Wirkung, ein Team, das füreinander einsteht.</p>\n <button class=\"btn btn-filled btn-co\">Stellen entdecken</button>\n </div>\n </div>\n</div>\n```\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Button-Label | `aria-label` mit Dateiname und Format auf dem Download-Button setzen (zum Beispiel „Figma-Bibliothek herunterladen (Figma, 48 MB)“), der Text „Herunterladen“ allein nennt kein Ziel |\n| Format- und Größenangabe | Dateiformat und Dateigröße immer sichtbar im Markup, nicht nur im Button-Label |\n| Brand Area | Bereichsfarbe des zugehörigen Dokuments nutzen, keine bereichsfremde Farbe |\n| Kontrast auf Bereichsfläche | Der Filled-Button wird auf der farbigen Fläche des Page-End-CTA-Band über `.btn-on-band` invertiert (weißer Hintergrund, Text in Bereichsfarbe); ohne Inversion würde der Button auf der eigenen Bereichsfarbe stehen und Kontrast verlieren |\n\n## Dos & Don'ts\n\n**Tun**\n\n- Dateiformat und -größe immer angeben, Nutzer sollen vor dem Download wissen, was sie erhalten\n- Brand-Area-Farbe des zugehörigen Dokuments verwenden, stärkt die visuelle Zugehörigkeit\n- `aria-label` auf dem Button setzen, zum Beispiel „Figma-Bibliothek herunterladen (Figma, 48 MB)“\n- Pro Seite maximal einen Hero-CTA, mehrere Hero-Blöcke erzeugen visuelle Konkurrenz\n\n**Nicht tun**\n\n- Download-Button ohne Format und Größe, erhöht die kognitive Last und bricht Vertrauen\n- Hero-Variante für unwichtige Sekundär-Downloads, die Größe signalisiert Wichtigkeit\n- Generisches „Herunterladen“ ohne Dateinamen, schlecht für Screenreader und Kontext\n- Bereichsfremde Farbe für ein Dokument verwenden, bricht den thematischen Zusammenhang\n\n## Verwandte Seiten\n\n- Komponenten/Call to Action/CTA-Band (Story, deckt `CtaBand` ab)\n- Komponenten/Call to Action/DownloadCta (Story, deckt alle vier Download-Varianten ab)\n- Doku-Sektion: `docs/index.html#gt-cta-band` (Page-End-CTA-Band)\n- Doku-Sektion: `docs/index.html#gt-cta-editorial` (Editorial Split)\n",
13
- "summary": "# Verwendung Call to Action deckt zwei Pattern-Familien ab: das Page-End-CTA-Band als letz..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-cards-teaser--verwendung": {
4
- "id": "komponenten-cards-teaser--verwendung",
5
- "name": "komponenten-cards-teaser--verwendung",
6
- "docs": {
7
- "komponenten-cards-teaser--verwendung": {
8
- "id": "komponenten-cards-teaser--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/cards-verwendung.mdx",
11
- "title": "Komponenten/Cards & Teaser",
12
- "content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Cards & Teaser\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nGenerische Karten (statisch, Link-Karte) und Inhaltskarten (Stat), alle Brand Areas, barrierefrei. Der Abschnitt deckt mehr ab, als es eigene Bauteile gibt: die editoriale Kennzahl-Zeile ist ein reines CSS-Rezept ohne eigene Komponente. Klickbare Karte, Featured-Karte, Icon-Karte, offene Feature-Liste und Tier-Trenner haben jeweils ein eigenes Angular-Bauteil (siehe „Verwandte Seiten“).\n\n## Anatomie\n\nDie folgende Anatomie zeigt die fünf Bausteine einer generischen Karte: Media-Bereich, Eyebrow, Title, Text und Footer. Die Ziffern korrespondieren mit den Begriffen, die in den übrigen Abschnitten dieser Seite verwendet werden.\n\n<Unstyled>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 60,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n borderBottom: 'var(--bd)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n ① Media, Bereichsfarbe <code className=\"token\">-50</code>\n </span>\n </div>\n <div style={{ padding: 'var(--s4)' }}>\n <div\n className=\"t-co\"\n style={{\n font: '500 12px/16px var(--font)',\n letterSpacing: '.08em',\n textTransform: 'uppercase',\n marginBottom: 'var(--s1)',\n }}\n >\n ② Eyebrow, Bereichsname\n </div>\n <div\n style={{\n font: '500 16px/24px var(--font)',\n color: 'var(--tx-primary)',\n marginBottom: 'var(--s1)',\n }}\n >\n ③ Title, Kernaussage\n </div>\n <div style={{ font: 'var(--ty-body-md)', color: 'var(--tx-secondary)', marginBottom: 'var(--s4)' }}>\n ④ Text, max. 2 Sätze, konkret\n </div>\n <div\n style={{\n display: 'flex',\n justifyContent: 'flex-end',\n gap: 'var(--s2)',\n borderTop: 'var(--bd)',\n paddingTop: 'var(--s3)',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-muted)' }}>\n ⑤ Footer, max. 2 Aktionen\n </span>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Wann welche Variante\n\n| Variante | Klasse | Wann einsetzen | Elevation |\n|---|---|---|---|\n| Statisch | `.card` | Der Standard, Karten deren Aktionen in Footer-Buttons liegen, dazu Listen- und Tabellen-Kontexte ohne visuelle Schwere | `--e0` + Rahmen |\n| Link-Karte | `a.card.card-elevated` | Wenn die ganze Karte zu einem Ziel führt: Listing-Teaser, Beitrags-, Job- und Veranstaltungs-Karten | `--e1`, Hover `--e2` + Lift |\n\n**Klickbare Karte als Modus.** Wenn die ganze Karte zu einem Ziel führen soll, gibt es zwei Patterns, je nach Karten-Typ und Inhaltsdichte:\n\n| Pattern | Wrapping | Wann einsetzen |\n|---|---|---|\n| `.ep-card.ep-card-link` | `<a class=\"ep-card ep-card-link\">` | Kompakte Teaser-Kacheln mit Icon, Eyebrow, Titel, kurzem Text und CTA-Pfeil-Zeile, ohne Card-Footer-Buttons |\n| `a.card.card-elevated` | `<a class=\"card card-elevated\">` | Textreiche Listing-Cards mit Card-Media, Card-Body (Pill, Titel, Text, Meta-Zeile) und implizitem „Beitrag lesen →“-Anker am Ende |\n| `a.card.card-elevated.card-featured` | `<a class=\"card card-elevated card-featured\">` | Horizontale Großkarte für genau einen hervorgehobenen Beitrag oder Termin, Bild links im 16:9, Content rechts |\n\nIn Angular deckt jedes der drei Patterns ein eigenes Bauteil ab: `<a cdsIconCard>` (Icon-Karte), `cds-link-card` (Klickbare Karte) und `cds-featured-card` (Featured-Karte).\n\n**Weitere CSS-Rezepte ohne eigenes Bauteil**, sinnvoll dort, wo ein weiteres Karten-Grid die Seite überladen würde:\n\n| Muster | Rolle | Wann statt Karte |\n|---|---|---|\n| Stat-Karte (`.card-stat`) | Eigenständige KPI-Kachel mit Rahmen | Kennzahlen auf Landingpages, Jahresberichten, Dashboards |\n| Bandstreifen (`.card-stat-strip` / `.card-stat-flat`) | Flache Variante ohne Rahmen und Schatten | Kompakte KPI-Bänder, Footer-Stats, Hero-Anschluss-Sektionen |\n| Editoriale Kennzahl-Zeile | Redaktioneller Fließinhalt, nur durch Haarlinien getrennt, kein Karten-Chrome | Case-, Projekt- und Leistungslisten, wenn auf der Seite bereits Karten-Grids stehen |\n| Offene Feature-Liste (`.ep-feature`, in Angular `<div cdsFeature>`) | Icon-geführte Aufzählung ohne Rahmen, Schatten oder Media-Fläche | Vollständiger Funktionsumfang, wenn ein weiteres Karten-Grid überladen würde |\n\nKarten sind für Angebots-Menüs und Teaser da: Lösungs- und Leistungskacheln, Artikel-Vorschauen, Elemente, die zu einem Ziel führen und als abgeschlossene, klickbare Einheit funktionieren. Für Stimmen, Funktions- und Case-Listen ist meist eine offene, redaktionelle Darstellung die bessere Wahl: direkt auf der Fläche, durch Haarlinien getrennt. Das hält inhaltsdichte Abschnitte luftig und vermeidet den Eindruck einer Kachelwand, wenn mehrere Karten-Grids aufeinanderfolgen.\n\n**Testimonial-Karte**: wohnt unter `Komponenten/Zitate & Testimonials/Testimonial`, hier nur der Querverweis. Zitat mit Quellenangabe, farbiger Top-Border signalisiert die Brand Area, Auszeichnung über `<figure>` + `<blockquote>` für korrekte Semantik.\n\n<Unstyled>\n <div className=\"layout-grid\">\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Mit Media-Bereich → keine Linie\n </div>\n <div style={{ border: 'var(--bd-strong)', borderRadius: 'var(--r-lg)', overflow: 'hidden' }}>\n <div\n style={{\n height: 40,\n background: 'var(--co-50)',\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n }}\n >\n <span style={{ font: '400 12px/16px var(--font)', color: 'var(--tx-secondary)' }}>\n Media\n </span>\n </div>\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n <div className=\"col-4\">\n <div\n style={{\n font: '500 12px/16px var(--font)',\n color: 'var(--tx-muted)',\n marginBottom: 'var(--s2)',\n }}\n >\n Ohne Media-Bereich → Linie oben\n </div>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderTop: '4px solid var(--co-500)',\n borderRadius: 'var(--r-lg)',\n overflow: 'hidden',\n }}\n >\n <div style={{ padding: 'var(--s3) var(--s4)' }}>\n <div\n style={{\n height: 6,\n borderRadius: 3,\n background: 'var(--n-200)',\n marginBottom: 6,\n width: '55%',\n }}\n />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', marginBottom: 4 }} />\n <div style={{ height: 8, borderRadius: 3, background: 'var(--n-100)', width: '80%' }} />\n </div>\n </div>\n </div>\n </div>\n</Unstyled>\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Semantik | `<article>` für eigenständige Cards, Screenreader listen Artikel als navigierbare Landmark, Überschriften-Hierarchie einhalten (Card-Titel als `h3` unter einer Section-`h2`) |\n| Klickbereich | Wenn die ganze Karte zu einem Ziel führt: das umschließende Element auf `<a>` oder `<button>` umstellen, nie `<div>` mit `onclick`. Pfeil-Suffix in `<span aria-hidden=\"true\">` hüllen, Focus-Ring sichtbar lassen. Trägt die Karte nur passive Information, gehören Interaktionselemente ausschließlich in den Card-Footer |\n| Bilder & Icons | Card-Media-Bilder mit beschreibendem `alt`-Text versehen, dekorative SVGs mit `aria-hidden=\"true\"` + `focusable=\"false\"` ausblenden |\n\n**Bildslots sind 16/9 und kommen aus `.card-media`.** Listing-Grid und Featured-Card teilen sich das Verhältnis, damit Redaktion pro Beitrag ein Bild in einem Zuschnitt pflegt statt einen je Slot. Den Bildausschnitt setzt `object-position` am `<img>`, nicht `background-position` an einem Container, sonst gilt der Zuschnitt nur in einem Slot. Eigene Verhältnisse haben nur Hero und Slider (21/9) sowie Avatare (1/1). Reicht die Höhe nicht, wird Text gekappt, nicht das Verhältnis gedehnt.\n\n**Der Abstand gehört dem Container, nicht dem Kind.** `.card-body` ist eine Flex-Spalte mit `gap: var(--s3)`, das ist der einzige vertikale Rhythmus der Karte. `.card-eyebrow`, `.card-cta-link` und die Pill setzen im Card-Body keine eigene Marge, sonst addiert sie sich zum `gap`, statt zu kollabieren, denn im Flex-Layout kollabieren Margen nicht. Braucht eine Karte mehr Luft, wird nur der `gap` überschrieben, nicht eine Marge nachgeschoben.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Eyebrow und Media konsequent in der Bereichsfarbe halten, die Karte ist immer einem Bereich zugehörig.\n- Schatten nur auf Link-Karten (`a.card.card-elevated`), Karten mit Aktionen im Footer ruhen flach mit Rahmen.\n- Max. 2 Aktionen im Card-Footer: Text-Button (sekundär) plus Filled-Button (primär).\n- Card-Text auf max. 2 Sätze begrenzen, prägnant und scanbar, kein Fließtext.\n- Gleichartige Karten in einem Grid konsistent halten, gleiche Variante, gleiche Breite.\n\n**Nicht tun**\n\n- Statische und Link-Karten in derselben Reihe mischen, der Schatten liest sich dann als Zufall statt als Klick-Angebot.\n- Mehr als 2 Filled Buttons im Footer, die Hierarchie wird unklar, eine Hauptaktion reicht.\n- Bereichsfarben einer Karte und ihrer Nachbarkarte mischen, jede Karte gehört zu einem Bereich.\n- Eine Karte erhöhen, deren Fläche nirgendwohin führt, das verspricht Klickbarkeit, die es nicht gibt.\n- Langen Fließtext in Card-Body, stattdessen einen Teaser formulieren und auf eine Detailseite verlinken.\n\n## Verwandte Seiten\n\n- Card (`Komponenten/Cards & Teaser/Card`)\n- Klickbare Karte (`Komponenten/Cards & Teaser/Klickbare Karte`), `cds-link-card`\n- Featured-Karte (`Komponenten/Cards & Teaser/Featured-Karte`), `cds-featured-card`\n- Icon-Karte (`Komponenten/Cards & Teaser/Icon-Karte`), `[cdsIconCard]`\n- Feature-Liste (`Komponenten/Cards & Teaser/Feature-Liste`), `[cdsFeature]`\n- Tier-Trenner (`Komponenten/Cards & Teaser/Tier-Trenner`), `cds-tier`\n- StatCard (`Komponenten/Cards & Teaser/StatCard`)\n- StatStrip (`Komponenten/Cards & Teaser/StatStrip`)\n- Testimonial (`Komponenten/Zitate & Testimonials/Testimonial`), Zitat-Karte mit Quellenangabe, hier nur verlinkt\n",
13
- "summary": "# Verwendung Generische Karten (statisch, Link-Karte) und Inhaltskarten (Stat), alle Brand..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-chips-badges-pills--verwendung": {
4
- "id": "komponenten-chips-badges-pills--verwendung",
5
- "name": "komponenten-chips-badges-pills--verwendung",
6
- "docs": {
7
- "komponenten-chips-badges-pills--verwendung": {
8
- "id": "komponenten-chips-badges-pills--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/chips-verwendung.mdx",
11
- "title": "Komponenten/Chips, Badges & Pills",
12
- "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Chips, Badges & Pills\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nDrei Formen, die leicht verwechselt werden: interaktive Filter-Chips (Toggle), passive Status- und Bereichs-Badges und redaktionelle Pills, alle je Brand Area farblich codiert (Bereichsreihenfolge co · ki · es · wo).\n\n## Wann welche Variante\n\n| Form | Interaktion | Rolle | Label |\n|---|---|---|---|\n| Chip | Interaktiv, Toggle über `aria-pressed=\"true/false\"` | Aktive Filter- und Auswahlkomponente | Max. 3 Wörter, prägnante Kategorie- oder Filterbegriffe |\n| Badge | Passiv, kein Klickverhalten | Status- oder Bereichskennzeichnung neben einem Element | 1 bis 2 Wörter, kein Verb |\n| Pill | Passiv, kein Klickverhalten | Redaktioneller Eyebrow vor einem Titel, ordnet einen Inhalt einer Brand Area zu | 1 bis 3 Wörter, ausschließlich der Bereichsname |\n\n**Abgrenzung Pill gegen Bereichs-Badge**: beide nutzen den 50er-Hintergrund und den 700er- beziehungsweise 800er-Text der Brand Area, beide haben die abgerundete Form.\n\n| Aspekt | Pill | Bereichs-Badge |\n|---|---|---|\n| Rolle | Redaktionelle Meta-Markierung, ordnet einen Inhalt einer Brand Area zu, oft als Eyebrow vor Titeln | Status- oder Bereichs-Kennzeichnung neben Inhalts-Elementen (z. B. neben einem Modulnamen) |\n| Typografie | label-xs, uppercase, `letter-spacing: .09em` | label-xs, gemischte Schreibweise, `letter-spacing: .04em` |\n| Position | Im Lesefluss, vor dem Titel, bringt einen ruhigen visuellen Anker | Inline mit Listen-/Tabellenelementen oder neben Karten-Titeln |\n| Wahl-Indiz | „Was für eine Art Inhalt ist das?“, kategorisch und thematisch | „In welchem Zustand, welchem Bereich ist dieses Element?“, punktuell |\n\nDer spürbare Unterschied entsteht durch Großschreibung und Letter-Spacing: Die Pill wirkt feierlicher, die Badge alltäglicher. Faustregel: Steht unter der Markierung ein Titel oder Beitrag, den sie einordnet, dann Pill. Sitzt die Markierung neben einem Element wie Modulname oder Tabellenzelle, dann Badge. Status (Live, Beta, Deprecated, Draft) ist immer Badge, die Pill hat keine Status-Variante.\n\n**Die Eyebrow-Form ist voll belegt, keine fünfte Bedeutung darauf.** `--ty-label-xs` plus `uppercase`, `letter-spacing:.09em` und `--co-ink` ist pixelgleich in vier Rollen im Einsatz: `.ep-hero-eyebrow` (Haltung, „Verbunden gedacht“), `.ep-section-label` (Sektions-Thema, „Was wir tun“), `.ep-card-eyebrow` (Brand Area, in Bereichsfarbe) und `.stoerer-topic` (Inhaltstyp, „Nächste Veranstaltung“). Aufgelöst wird das nur durch die Position (in einer Kachel, über einer Sektion), nicht durch die Form. Eine neue Komponente, die eine fünfte Bedeutung auf dieselbe Form legt, macht die kleinste Label-Ebene beliebig. Wer eine fünfte Rolle braucht, gibt ihr ein eigenes Unterscheidungsmerkmal (Glyph vor dem Label, neutrale statt farbiger Schrift) oder benutzt eine vorhandene Rolle.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Interaktivität | Klickbare Chips als `<button>` oder `<a>` implementieren, nie als `<div>` mit `onClick`, nur native Elemente sind per Tastatur und Screenreader korrekt bedienbar |\n| Auswahl-Zustand | Toggle-Chips mit `aria-pressed=\"true/false\"` versehen, der visuelle Auswahl-Stil allein ist für Screenreader nicht erkennbar |\n| Kontrast | Chip-, Badge- und Pill-Text auf dem jeweiligen Hintergrund mindestens 4,5 zu 1 prüfen, besonders bei markierten oder aktiven Chips, da sich Hintergrund und Textfarbe ändern |\n| Pill-`aria-label` | Pflicht bei Pills mit Trennzeichen (`·`), Screenreader verschlucken das Punktzeichen oder lesen es als „Punkt“. `aria-label` mit ausgeschriebener Form (z. B. „Bereich Effektive Software, Format Meet-Up“) schreibt die Aussprache vor. Bei Pills ohne Trennzeichen kann das `aria-label` entfallen, der sichtbare Text reicht |\n\n## Dos & Don'ts\n\n**Tun**\n\n- Chips für aktive Filterauswahl, die Nutzerin steuert selbst, was sichtbar ist.\n- Badge für reinen Status, „Live“, „Beta“, „Deprecated“, „Draft“, immer ohne Klick-Handler.\n- Pill als redaktionellen Eyebrow vor einem Titel einsetzen, ordnet den Beitrag thematisch ein und stiftet Erwartung.\n- Bereichsfarbe konsequent einhalten, aktiver Chip einer Brand Area nutzt nur deren Farbtoken.\n- Chip-Labels auf max. 3 Wörter begrenzen, klare, scanbare Begriffe.\n- Semantische Statusfarben bei Badges einhalten, Grün für positiv, Gelb für Warnung, Rot für Fehler.\n- Pills mit Trennzeichen (`·`) immer mit einem `aria-label` in ausgeschriebener Form versehen.\n\n**Nicht tun**\n\n- Chips rein dekorativ einsetzen ohne Toggle-Funktion, verwirrt Nutzerinnen über Interaktivität.\n- Badges klickbar machen ohne visuelles Feedback, Badges sind keine Buttons.\n- Pills für Status verwenden, dafür gibt es Status-Badges, Pill ist redaktioneller Eyebrow, nicht Statusmarker.\n- Bereichsfarben im selben Kontext mischen, `data-area=\"co\"` und `data-area=\"ki\"` Chips nicht gemeinsam in einer Filterleiste.\n- Chip-Labels als vollständige Sätze, zu lang, passt nicht zur kompakten Form.\n- Mehr als 7 Chips in einer Gruppe, lieber kategorisieren oder eine Auswahlliste verwenden.\n- Mehrere Pills nebeneinander an demselben Inhalt, eine Pill pro Beitrag reicht.\n\n## Verwandte Seiten\n\n- Chip (`Komponenten/Chips, Badges & Pills/Chip`)\n- Status-Badge (`Komponenten/Chips, Badges & Pills/Status-Badge`)\n- Bereichs-Badge (`Komponenten/Chips, Badges & Pills/Bereichs-Badge`)\n- Pill (`Komponenten/Chips, Badges & Pills/Pill`)\n",
13
- "summary": "# Verwendung Drei Formen, die leicht verwechselt werden: interaktive Filter-Chips (Toggle)..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-code-block--verwendung": {
4
- "id": "komponenten-code-block--verwendung",
5
- "name": "komponenten-code-block--verwendung",
6
- "docs": {
7
- "komponenten-code-block--verwendung": {
8
- "id": "komponenten-code-block--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/code-block-verwendung.mdx",
11
- "title": "Komponenten/Code-Block",
12
- "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Code-Block\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nCode-Block stellt Quellcode und Terminal-Ausgaben für Wissens- und Technikbeiträge dar:\nStandard, mit Zeilennummern, Terminal und Inline-Code. Alle vier sind Varianten\nderselben Story `Komponenten/Code-Block/Code-Block` (gesteuert über die Property `terminal` sowie\ndie Klassen `.cb-numbered` und `.cb-prose`), kein eigenes Bauteil je Variante.\n\n## Wann welche Variante\n\n| Variante | Wann einsetzen | Nicht geeignet für |\n|---|---|---|\n| Standard | Einzelne Funktionen, Konfigurationen, kurze Snippets | Shell-Befehle, langen Fließtext-Kontext |\n| Mit Zeilennummern | Wenn im Begleittext auf bestimmte Zeilen verwiesen wird (ab etwa 10 Zeilen) | Snippets unter 5 Zeilen, Terminal-Ausgaben |\n| Terminal | Installations- und Setup-Befehle, CLI-Workflows | Programm-Code mit Syntax-Highlighting |\n| Inline-Code | Bezeichner, Tokens, Klassen im Fließtext, maximal eine Zeile | Mehrzeilige Snippets, vollständige Statements |\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Semantik | `<pre><code>` als Grundgerüst, Screenreader kündigen den Inhalt als „Code“ an; `<pre>` allein reicht nicht |\n| Scrollbarkeit | Scrollbare `<pre>`-Blöcke mit `tabindex=\"0\"` versehen, sonst per Tastatur nicht erreichbar |\n| Copy-Button | `aria-label=\"Code kopieren\"` auf dem Copy-Button, der Text „Kopieren“ allein nennt kein Ziel. Das Label bleibt nach dem Kopieren **stabil** — ein Bedienelement trägt den Namen seiner Funktion, nicht den seines letzten Ereignisses. Die Erfolgsmeldung läuft stattdessen über eine eigene, von Anfang an im DOM stehende Live-Region (`role=\"status\"`, `.sr-only`) neben dem Button; eine Region, die erst beim Klick entsteht, kündigt bei vielen Screenreadern nichts an |\n\n## Dos & Don'ts\n\n**Tun**\n\n- Sprache beziehungsweise Programmiersprache immer sichtbar im Header angeben, erleichtert das Lesen und ermöglicht Syntax-Highlighting\n- Zeilennummern nur ab etwa 10 Zeilen beziehungsweise wenn der Begleittext explizit auf Zeilen verweist (zum Beispiel „Zeile 8 setzt den Radius“)\n- Terminal-Variante für alle Shell-Befehle und Ausgaben, der grüne Prompt signalisiert sofort: hier wird etwas ausgeführt\n- Copy-Button immer einbauen mit `aria-label`, Leser kopieren Code häufiger als sie ihn abtippen\n- `<pre><code>` als semantisches Grundgerüst verwenden\n- Code-Block immer mit einer kurzen Einleitung im Fließtext versehen, Kontext vor dem Block, nicht danach\n\n**Nicht tun**\n\n- Inline-Code für mehrzeilige Snippets oder Beispiele, ab 2 Zeilen gehört der Inhalt in einen Block\n- Screenshots von Code statt echtem Text, nicht kopierbar und nicht zugänglich für Screenreader\n- Highlight-Klassen (`.k`, `.s` …) für rein dekorative Farben zweckentfremden, sie tragen Bedeutung und sollten semantisch korrekt eingesetzt werden\n- Terminal und Code-Block mischen, Shell-Befehle und Programm-Code gehören in getrennte Blöcke\n- Eigene Hintergrundfarben außerhalb der Token setzen, bricht Konsistenz und Dark-Mode-Kompatibilität\n- Code ohne Sprachkennzeichnung ausliefern, Syntax-Highlighting und Screenreader-Kontext fehlen dann\n- Zu lange Zeilen ohne Umbruch oder Block-Code direkt im Fließtext ohne visuellen Abstand\n\n## Verwandte Seiten\n\n- Komponenten/Code-Block/Code-Block (Story, alle vier Varianten)\n",
13
- "summary": "# Verwendung Code-Block stellt Quellcode und Terminal-Ausgaben für Wissens- und Technikbei..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-dropdowns--verwendung": {
4
- "id": "komponenten-dropdowns--verwendung",
5
- "name": "komponenten-dropdowns--verwendung",
6
- "docs": {
7
- "komponenten-dropdowns--verwendung": {
8
- "id": "komponenten-dropdowns--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/dropdowns-verwendung.mdx",
11
- "title": "Komponenten/Dropdowns",
12
- "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Dropdowns\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nAuswahl-Komponenten über das native `<select>` hinaus: Custom Select (gestylte Einzelauswahl mit Listbox-Popup, Häkchen und Bereichs-Akzent) und Combobox (Tipp-Filter über langen Listen, optional Multi-Select mit Chips). Beide sind markup-getrieben, semantisches HTML genügt, das Skript ergänzt IDs, ARIA-Zustände und Tastatur. Durchgängig WCAG AA: `role=\"listbox\"`/`role=\"option\"`, `aria-expanded`, `aria-activedescendant`, Fokusring in beiden Modi.\n\n## Wann welche Variante\n\n| Form | Wann einsetzen |\n|---|---|\n| Natives `<select>` | Standard für kurze Listen (bis 8 Optionen) in Formularen, siehe Inputs & Forms |\n| Custom Select | Wenn die Auswahl optisch zum Bereich gehören soll (Häkchen, Tönung) oder das native Popup nicht ausreicht |\n| Combobox | Ab ca. 10 Optionen, wo Tippen schneller ist als Scrollen |\n| Multi-Select | Nur für echte Mehrfachauswahl (Tags, Filter). Kein eigenes Bauteil: Multi-Select ist der Modifier `.is-multi` auf der Combobox, keine separate Komponente |\n\n| Baustein | Zweck |\n|---|---|\n| `.ep-select` | Gestylte Einzelauswahl, `data-area` setzt den Bereichs-Akzent, `data-name` erzeugt ein verstecktes Feld für den Submit |\n| `.ep-combobox` | Tipp-Filter über langen Listen, `data-empty-text` setzt den Leerzustand |\n| `.is-multi` | Modifier am `.ep-combobox` für Mehrfachauswahl mit Chips |\n| `.ep-combobox-clear` | Lösch-Button (per Skript injiziert), erscheint bei Texteingabe und leert das Feld, Multi behält die Chips |\n| `data-value` | Maschinenwert je Option, sichtbarer Text ist das Label (oder `data-label`) |\n| `ep:change` | Custom-Ereignis bei Auswahl (`detail.value`, `detail.selected`) zum Anbinden eigener Logik |\n\nDas Popup schwebt über fremdem Inhalt und kann sich dort nicht auf den Schatten verlassen, der Rand übernimmt deshalb im Dark Mode `--bd-strong-c` statt `--bd-c`. Gilt für jedes schwebende Panel, auch das Topnav-Untermenü und das Suchpanel.\n\n## Barrierefreiheit\n\n| Attribut / Verhalten | Zweck |\n|---|---|\n| `role=\"listbox\"` / `option` | Popup und Einträge als Auswahlliste ausgewiesen, vom Skript gesetzt beziehungsweise ergänzt |\n| `aria-expanded` | Offen-Zustand am Trigger beziehungsweise am Combobox-Input |\n| `aria-activedescendant` | Tastaturcursor ohne Fokusverlust, der hervorgehobene Eintrag wird vorgelesen |\n| Tastatur | Pfeiltasten, Pos1/Ende, Type-ahead (Select), Enter wählt, Esc/Tab schließt |\n| Fokusring | Neutral-Teal `--focus-ring` in beiden Modi, mindestens 3 zu 1 Rahmenkontrast |\n\nBeim Schließen ohne Auswahl bleibt kein loser Filtertext stehen: die Einzelauswahl fällt auf das Label der gewählten Option zurück (beziehungsweise leert), getippter Text bleibt nie im Feld hängen.\n\n## Dos & Don'ts\n\n**Tun**\n\n- Natives `<select>` für kurze Listen behalten, Custom Select erst, wenn Bereichs-Akzent oder Popup-Styling gebraucht wird.\n- Combobox ab ca. 10 Optionen einsetzen, wo Tippen schneller filtert als Scrollen.\n- Jedes Dropdown mit sichtbarem `.ep-select-label` versehen, Placeholder ist kein Label.\n- Den Bereichs-Akzent zur Brand Area der Seite passend wählen (Corporate, Angewandte KI, Effektive Software, Wirksame Organisationen).\n\n**Nicht tun**\n\n- Custom Select für eine Ja/Nein- oder Zwei-Optionen-Wahl, dafür sind Radios oder ein nativer Select besser.\n- Den Fokusrahmen pro Bereich einfärben, der Akzent gehört in den gewählten Eintrag, nicht in den Fokus.\n- Multi-Select als Notlösung für eine Einzelauswahl, das verwirrt die Erwartung an die Eingabe.\n- Mehrere Bereichs-Akzente in einem Formular mischen, ein Formular gehört zu genau einer Brand Area.\n\n## Verwandte Seiten\n\n- Custom Select (`Komponenten/Dropdowns/Custom Select`)\n- Combobox (`Komponenten/Dropdowns/Combobox`), Multi-Select ist der Modus `.is-multi` derselben Story\n",
13
- "summary": "# Verwendung Auswahl-Komponenten über das native `` hinaus: Custom Select (gestylte Einzel..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-feedback--verwendung": {
4
- "id": "komponenten-feedback--verwendung",
5
- "name": "komponenten-feedback--verwendung",
6
- "docs": {
7
- "komponenten-feedback--verwendung": {
8
- "id": "komponenten-feedback--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/feedback-verwendung.mdx",
11
- "title": "Komponenten/Feedback",
12
- "content": "import { Meta } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Feedback\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nDrei Snackbar-Varianten (Default, OK, Fehler) für Kontaktformular, Newsletter-Anmeldung und Validierungsfehler auf Landingpages.\n\n## Wann welche Variante\n\n| Variante | Wann einsetzen | ARIA |\n|---|---|---|\n| Default | Neutrale Statusmeldung mit optionaler Aktion, Formular zwischengespeichert, Cookie-Einwilligung bestätigt | `role=\"status\"` `aria-live=\"polite\"` |\n| OK / Erfolg | Abgeschlossene Landingpage-Aktion, Kontaktformular gesendet, Newsletter-Anmeldung bestätigt | `role=\"status\"` `aria-live=\"polite\"` |\n| Fehler | Versand- oder Serverfehler nach Submit, bleibt sichtbar bis die Nutzerin aktiv reagiert | `role=\"alert\"` `aria-live=\"assertive\"` |\n\n| Eigenschaft | Regel |\n|---|---|\n| Auto-Dismiss | Default und OK nach 4 bis 6 Sekunden, Fehler-Snackbar bleibt offen |\n| Position | Unten links oder zentriert, nie über primären Aktionsschaltflächen |\n| Menge | Max. 1 Snackbar gleichzeitig, neue verdrängt die vorherige |\n| Aktion | Max. 1 Aktion pro Snackbar, kurzes Verb, max. 2 Wörter |\n\nFeldfehler gehören immer inline unter das betroffene Feld, nicht als Snackbar: die Snackbar transportiert nur den globalen Submit-Fehler, sonst verliert die Nutzerin den Bezug zum Feld.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Default & OK | `role=\"status\"`, `aria-live=\"polite\"` |\n| Fehler | `role=\"alert\"`, `aria-live=\"assertive\"`, bleibt offen bis aktive Reaktion |\n| Dark Mode | Die Snackbar schwebt über beliebigem Inhalt und kommt im Light ohne Rahmen aus. Im Dark liegt sie sehr nah am Grund, deshalb bekommt sie dort zusätzlich `--bd-strong-c` als Rand, dieselbe Regel wie bei Menüs und Popover |\n| Status-Flächen | Farbe aus `--c-success-bg` und `--c-error-bg`, nicht aus eigenen Hexwerten, sonst bleiben sie bei einer Token-Änderung zurück |\n\n## Dos & Don'ts\n\n**Tun**\n\n- OK-Snackbar nach erfolgreichem Formularversand, die Nutzerin bekommt klare Rückmeldung ohne Seitenwechsel.\n- Feldfehler inline direkt unter dem Eingabefeld zeigen, Snackbar nur für globale Submit-Fehler.\n- Fehler-Snackbar offen lassen, bis die Nutzerin aktiv reagiert, kein Auto-Dismiss bei kritischen Meldungen.\n- Aktions-Label als konkretes Verb, „Erneut versuchen“, „Jetzt senden“, „Schließen“.\n- `role=\"alert\"` nur für Versand- oder Serverfehler, nicht für Bestätigungen und Hinweise.\n\n**Nicht tun**\n\n- Feldfehler als Snackbar, die Nutzerin verliert den Bezug zum betroffenen Feld.\n- OK-Snackbar auto-dismissen, bevor die Nutzerin sie gelesen hat, bei langen Erfolgstexten den Timer auf 6 Sekunden setzen.\n- Snackbar für nächste Schritte nutzen, nach Formularversand lieber per E-Mail oder Folgeseite bestätigen.\n- Mehrere Snackbars gleichzeitig anzeigen, eine neue Meldung verdrängt immer die vorherige.\n- Fehler-Snackbar als einzige Validierung verwenden, Pflichtfelder müssen schon vor dem Submit markiert sein.\n\n## Verwandte Seiten\n\n- Snackbar (`Komponenten/Feedback/Snackbar`)\n",
13
- "summary": "# Verwendung Drei Snackbar-Varianten (Default, OK, Fehler) für Kontaktformular, Newsletter..."
14
- }
15
- }
16
- }
17
- }
18
- }
@@ -1,18 +0,0 @@
1
- {
2
- "components": {
3
- "komponenten-footer--verwendung": {
4
- "id": "komponenten-footer--verwendung",
5
- "name": "komponenten-footer--verwendung",
6
- "docs": {
7
- "komponenten-footer--verwendung": {
8
- "id": "komponenten-footer--verwendung",
9
- "name": "Verwendung",
10
- "path": "./src/docs/komponenten/footer-verwendung.mdx",
11
- "title": "Komponenten/Footer",
12
- "content": "import { Meta, Unstyled } from '@storybook/addon-docs/blocks';\n\n<Meta title=\"Komponenten/Footer\" name=\"Verwendung\" tags={['angular']} />\n\n# Verwendung\n\nFooter ist ein Zwei-Band-Layout: heller Main-Bereich mit Spalten-Grid (Brand & Kontakt ·\nWichtige Inhalte · Contentletter abonnieren) und dunkler Bottom-Streifen für Copyright,\nPflichtangaben und Social-Icons. Drei Stories bilden das ab: `Footer/Komplett` (die volle Demo),\n`Footer/Oberer Teil` (das Main-Band) und `Footer/Unterer Teil` (der Bottom-Streifen).\n`cds-footer-main` ist dabei ein generisches Spalten-Layout: Jedes Top-Level-Kind wird\neine eigene Grid-Spalte, die Spaltenzahl ist nicht fest auf drei begrenzt.\n\n## Anatomie\n\nDas folgende Schema zeigt die fünf nummerierten Zonen des Footers, von der\nBrand-Spalte links bis zu den Social-Icons rechts im dunklen Bottom-Streifen. Es\nergänzt die Spalten-Struktur unten um die räumliche Anordnung.\n\n<Unstyled>\n <div\n style={{\n border: 'var(--bd-strong)',\n borderRadius: 'var(--r-lg)',\n overflow: 'hidden',\n font: '400 12px/16px var(--font)',\n }}\n >\n <div\n style={{\n display: 'grid',\n gridTemplateColumns: '1.2fr 1fr 1.3fr',\n gap: 0,\n borderBottom: 'var(--bd)',\n background: 'var(--n-50)',\n }}\n >\n <div style={{ padding: 'var(--s4)', borderRight: 'var(--bd)' }}>\n <div className=\"t-co\" style={{ fontWeight: 700, marginBottom: '4px' }}>\n ① Brand & Kontakt\n </div>\n <div style={{ color: 'var(--tx-muted)' }}>Wortmarke + Adresse + Karten + Telefon/E-Mail</div>\n </div>\n <div style={{ padding: 'var(--s4)', borderRight: 'var(--bd)' }}>\n <div style={{ fontWeight: 600, color: 'var(--tx-primary)', marginBottom: '4px' }}>\n ② Wichtige Inhalte\n </div>\n <div style={{ color: 'var(--tx-muted)' }}>\n Sechs Top-Level-Links\n <br />\n (Bereiche · Beiträge · Jobs · Kontakt)\n </div>\n </div>\n <div style={{ padding: 'var(--s4)' }}>\n <div className=\"t-co\" style={{ fontWeight: 700, marginBottom: '4px' }}>\n ③ Contentletter abonnieren\n </div>\n <div style={{ color: 'var(--tx-muted)' }}>Lead + Name-Feld + E-Mail-Feld + Consent + Pill-Button</div>\n </div>\n </div>\n <div\n style={{\n padding: 'var(--s3) var(--s4)',\n background: 'var(--n-700)',\n color: 'var(--n-300)',\n display: 'flex',\n alignItems: 'center',\n gap: 'var(--s4)',\n }}\n >\n <span>④ © Jahr Firma · Standort · Datenschutz · Impressum</span>\n <span style={{ marginLeft: 'auto' }}>⑤ LinkedIn · YouTube</span>\n </div>\n </div>\n</Unstyled>\n\n## Spalten-Struktur\n\n| Spalte | Inhalt | Hinweis |\n|---|---|---|\n| 1, Brand & Kontakt | Wort-Marke „Conciso GmbH“ (`.footer-brand`) plus Postadresse, Karten-Links (Google Maps, OpenStreetMap, Apple Karten), Telefon, Fax, E-Mail, als `<address class=\"footer-address\">` semantisch markiert | Breitere Spalte (1.2fr). Kein Logo-Bild, weil die sticky Topnav das Logo bereits trägt |\n| 2, Wichtige Inhalte | Eine flache Liste mit sechs Top-Level-Zielen: Angewandte KI · Effektive Software · Wirksame Organisationen · Beiträge · Jobs · Kontakt | Bewusst konsolidiert statt nach Themen aufgeteilt, der Footer ist Wiederfindungs-Anker, keine zweite Hauptnavigation |\n| 3, Contentletter abonnieren | Gestapelte Form: Lead → Name-Feld → E-Mail-Feld → Datenschutz-Consent → Anmelden-Button (Pill, natürliche Breite) | Consent steht vor dem Submit, damit Tab- und Klickpfad keine Anmeldung ohne gelesene Datenschutzinfo erlauben (DSGVO und Trust) |\n| Bottom-Zeile | Dunkler Streifen: Copyright plus Pflichtangaben (Datenschutz, Impressum) linksbündig, Social-Icons (LinkedIn, YouTube) rechtsbündig via `margin-left:auto` | Pflichtangaben links, der sticky Back-to-Top-Button rechts unten würde rechts platzierte Links sonst überlagern |\n\n## Typografie: ruhige Utility-Zone\n\n`.footer-brand` und `.footer-htitle` nutzen `--ty-title-sm` (Sans 500, 18/26 px),\nbewusst ohne Uppercase und ohne Letter-Spacing. Der Footer ist eine\nWiederfindungs- und Pflichtangaben-Zone, keine editoriale Bühne: Familie (Sans statt\nSerif), Größe (18 px statt 28 px Headline-md) und Gewicht (500 statt 400 Serif) rücken\ndie Headlines gegenüber Section-H2 bewusst in den Hintergrund. Caps und Letter-Spacing\nwürden ein zweites Konversions-Signal neben dem Page-End-CTA-Band darüber erzeugen,\nReibung statt Ruhe.\n\n| Klasse | Token | Rolle |\n|---|---|---|\n| `.footer-brand` | `--ty-title-sm` | Wortmarke „Conciso GmbH“ in Spalte 1 |\n| `.footer-htitle` | `--ty-title-sm` | Spalten-Titel („Wichtige Inhalte“, „Contentletter abonnieren“) |\n| `.footer-subtitle` | Label-Größe (12 px) | Optionale Zwischen-Überschrift bei Sub-Area-Aufgliederung |\n\n## Contentletter-Form\n\nEine bewusst leisere Variante der Form-Komponente: Felder sind kompakter (14 px Body\nstatt 16 px) und die Border ist 1 px statt 2 px, passend zur Utility-Zone. Labels sind\nidentisch mit `.field label` (Uppercase, `--ty-label-sm`, letter-spacing .06em,\n`--tx-secondary`), damit die Form-Sprache zonenübergreifend gleich liest.\n\n| Klasse | Rolle | Hinweis |\n|---|---|---|\n| `.footer-newsletter-form` | Form-Container | Submit-Button via `align-self:flex-start` auf natürliche Pill-Breite |\n| `.footer-field` | Feld-Wrapper (`<label>`) | Implizite Label-Input-Verknüpfung, keine `for`/`id`-Paare nötig |\n| `.footer-field-label` | Sichtbarer Label-Text | `--ty-label-sm`, Uppercase, letter-spacing .06em |\n| `.footer-field.has-error` | Inline-Validierungs-State | Border kippt auf `--c-error`, Fehlertext via `.error-msg` |\n| `.footer-newsletter-consent` | DSGVO-Checkbox-Zeile | Sitzt zwingend vor dem Submit |\n\nDer Rechtstext in der Einwilligung ist ein echtes `<a class=\"body-link\">`, nie ein\n`<span>` mit `cursor:pointer` (CONTRIBUTING § 8): Ein Span ist per Tab nicht erreichbar\nund für Screenreader kein Link, obwohl genau dieser Text die Grundlage der Einwilligung\nist. Im `<label for>` ist der Anker unkritisch, die Label-Aktivierung läuft bei\ninteraktiven Nachfahren nicht, ein Klick auf den Link setzt kein Häkchen.\n\n## Sub-Hierarchie\n\nAktuell nutzt keine Footer-Spalte eine Sub-Hierarchie. Soll eine Spalte künftig in\nSub-Areas mit eigenen Listen aufgegliedert werden, steht dafür `.footer-subtitle`\nbereit: eine Zwischen-Überschrift auf Label-Größe, eine Stufe unter `.footer-htitle`,\ndie eine zweite konkurrierende Headline-Ebene innerhalb einer Spalte vermeidet.\n\n## Barrierefreiheit\n\n| Aspekt | Regel |\n|---|---|\n| Landmark | `<footer>` mit `aria-label=\"Seitenfuß\"`; jede eingebettete `<nav>` braucht ein eigenes `aria-label` (zum Beispiel „Wichtige Inhalte“, „Rechtliche Hinweise“, „Soziale Netzwerke“), damit Screenreader Haupt- und Footer-Navigation unterscheiden |\n| Adresse | Postanschrift und Kontaktdaten als `<address>` semantisch markiert |\n| Karten-Links | Externe Ziele (`target=\"_blank\"`) tragen `rel=\"noopener\"` und ein `aria-label`, das Ziel und „neues Tab“ nennt |\n| Social-Icons | Bild-Links ohne sichtbaren Text brauchen ein `aria-label` auf dem `<a>` (das Icon-Bild selbst mit leerem `alt=\"\"`) |\n| Consent-Link | Der Rechtstext in der Contentletter-Einwilligung ist ein echtes `<a class=\"body-link\">`, nie ein `<span>` mit `cursor:pointer` (CONTRIBUTING § 8) |\n| Reihenfolge im Formular | Die Consent-Checkbox steht vor dem Submit-Button, Tab- und Klickpfad können ohne die Einwilligung nicht abschließen |\n\n## Dos & Don'ts\n\n**Tun**\n\n- Wortmarke „Conciso GmbH“ als Brand-Anker im Main-Band verwenden, die sticky Topnav trägt das Logo schon, ein Logo-Bild hier wäre Doppelung\n- Navigation als konsolidierte Spalte „Wichtige Inhalte“ mit maximal 6 bis 8 Top-Level-Zielen führen, der Footer ist Wiederfindungs-Anker, keine zweite Hauptnavigation\n- Jede `<nav>` mit eindeutigem `aria-label` versehen (Wichtige Inhalte · Rechtliche Hinweise · Soziale Netzwerke)\n- Datenschutz und Impressum linksbündig in der Bottom-Bar setzen, verhindert Kollision mit dem sticky Back-to-Top-Button rechts unten\n- Consent vor Submit in der Contentletter-Form platzieren, Tab- und Klickpfad führt durch die Einwilligung, bevor abgesendet wird (DSGVO und Trust)\n- Spalten-Headlines (`.footer-brand`, `.footer-htitle`) in Title-sm halten, Mixed Case, Sans 500, 18 px, der Footer ist Wiederfindungs-Zone, keine Headline-Bühne\n\n**Nicht tun**\n\n- Logo-Bild im Brand-Bereich zeigen, redundant zur sticky Topnav, die die Marke bereits trägt\n- Spalten-Headlines auf Headline-Serifen-Token oder Uppercase plus Letter-Spacing setzen, sie würden mit dem Erstgespräch-CTA-Band darüber um Aufmerksamkeit konkurrieren\n- Footer als primäre Navigation verwenden, er ist eine Ergänzung, kein Ersatz für die Topnav\n- Mehr als etwa 8 Items in der Wichtige-Inhalte-Liste führen, der Footer würde zur Mini-Sitemap, tiefere Inhalte gehören auf den jeweiligen Bereichs-Hub\n- Datenschutz und Impressum rechts in der Bottom-Bar oder in der Wichtige-Inhalte-Spalte platzieren, sie gehören in den dunklen Bottom-Streifen linksbündig\n- Footer ohne Copyright-Jahr und Firmennamen ausliefern, beide sind rechtlich relevant und müssen aktuell sein\n\n## Verwandte Seiten\n\n- Komponenten/Footer/Komplett\n- Komponenten/Footer/Oberer Teil\n- Komponenten/Footer/Unterer Teil\n",
13
- "summary": "# Verwendung Footer ist ein Zwei-Band-Layout: heller Main-Bereich mit Spalten-Grid (Brand ..."
14
- }
15
- }
16
- }
17
- }
18
- }