@conciso/design-system 0.0.0-bootstrap.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 (141) hide show
  1. package/CHANGELOG.md +1786 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +15 -0
  4. package/README.md +134 -0
  5. package/assets/brand/LICENSE +11 -0
  6. package/assets/brand/README.md +45 -0
  7. package/assets/brand/logo-conciso-dark.svg +4 -0
  8. package/assets/brand/logo-conciso-light.svg +4 -0
  9. package/assets/brand/logo-conciso.svg +4 -0
  10. package/css/base.css +303 -0
  11. package/css/components.css +1633 -0
  12. package/css/dark-mode.css +716 -0
  13. package/css/fonts.css +20 -0
  14. package/css/tokens.css +209 -0
  15. package/dist/conciso-ds.css +2891 -0
  16. package/fonts/LibreBaskerville-OFL.txt +93 -0
  17. package/fonts/Montserrat-OFL.txt +93 -0
  18. package/fonts/libre-baskerville-400-latin-ext.woff2 +0 -0
  19. package/fonts/libre-baskerville-400-latin.woff2 +0 -0
  20. package/fonts/libre-baskerville-400i-latin-ext.woff2 +0 -0
  21. package/fonts/libre-baskerville-400i-latin.woff2 +0 -0
  22. package/fonts/libre-baskerville-700-latin-ext.woff2 +0 -0
  23. package/fonts/libre-baskerville-700-latin.woff2 +0 -0
  24. package/fonts/montserrat-300-latin-ext.woff2 +0 -0
  25. package/fonts/montserrat-300-latin.woff2 +0 -0
  26. package/fonts/montserrat-400-latin-ext.woff2 +0 -0
  27. package/fonts/montserrat-400-latin.woff2 +0 -0
  28. package/fonts/montserrat-400i-latin-ext.woff2 +0 -0
  29. package/fonts/montserrat-400i-latin.woff2 +0 -0
  30. package/fonts/montserrat-500-latin-ext.woff2 +0 -0
  31. package/fonts/montserrat-500-latin.woff2 +0 -0
  32. package/fonts/montserrat-700-latin-ext.woff2 +0 -0
  33. package/fonts/montserrat-700-latin.woff2 +0 -0
  34. package/icons/LICENSE-heroicons +21 -0
  35. package/icons/README.md +186 -0
  36. package/icons/icons.js +1156 -0
  37. package/icons/icons.json +1152 -0
  38. package/icons/manifest.json +595 -0
  39. package/icons/source/co-building.svg +1 -0
  40. package/icons/source/co-mark.svg +1 -0
  41. package/icons/source/es-window-check.svg +1 -0
  42. package/icons/source/ki-bot.svg +1 -0
  43. package/icons/source/ui-academic-cap.svg +1 -0
  44. package/icons/source/ui-adjustments-horizontal.svg +1 -0
  45. package/icons/source/ui-arrow-down-tray-2.svg +1 -0
  46. package/icons/source/ui-arrow-down-tray.svg +1 -0
  47. package/icons/source/ui-arrow-path.svg +1 -0
  48. package/icons/source/ui-arrow-trending-up.svg +1 -0
  49. package/icons/source/ui-banknotes.svg +1 -0
  50. package/icons/source/ui-bars-3-center-left.svg +1 -0
  51. package/icons/source/ui-bars-3.svg +1 -0
  52. package/icons/source/ui-bolt-2.svg +1 -0
  53. package/icons/source/ui-bolt.svg +1 -0
  54. package/icons/source/ui-book-open.svg +1 -0
  55. package/icons/source/ui-briefcase-2.svg +1 -0
  56. package/icons/source/ui-briefcase.svg +1 -0
  57. package/icons/source/ui-building-office.svg +1 -0
  58. package/icons/source/ui-calendar-days.svg +1 -0
  59. package/icons/source/ui-calendar.svg +1 -0
  60. package/icons/source/ui-caret-down.svg +1 -0
  61. package/icons/source/ui-chart-bar.svg +1 -0
  62. package/icons/source/ui-chat-bubble-left-right.svg +1 -0
  63. package/icons/source/ui-chat-bubble-oval-left-ellipsis.svg +1 -0
  64. package/icons/source/ui-chat-bubble-oval.svg +1 -0
  65. package/icons/source/ui-check-badge.svg +1 -0
  66. package/icons/source/ui-check-circle-2.svg +1 -0
  67. package/icons/source/ui-check-circle.svg +1 -0
  68. package/icons/source/ui-check.svg +1 -0
  69. package/icons/source/ui-chevron-down.svg +1 -0
  70. package/icons/source/ui-chevron-up-down.svg +1 -0
  71. package/icons/source/ui-circle-stack.svg +1 -0
  72. package/icons/source/ui-clock.svg +1 -0
  73. package/icons/source/ui-code-bracket-2.svg +1 -0
  74. package/icons/source/ui-code-bracket-square.svg +1 -0
  75. package/icons/source/ui-code-bracket.svg +1 -0
  76. package/icons/source/ui-cog-6tooth.svg +1 -0
  77. package/icons/source/ui-cog.svg +1 -0
  78. package/icons/source/ui-computer-desktop.svg +1 -0
  79. package/icons/source/ui-cpu-chip-2.svg +1 -0
  80. package/icons/source/ui-cpu-chip.svg +1 -0
  81. package/icons/source/ui-cube-2.svg +1 -0
  82. package/icons/source/ui-cube-transparent.svg +1 -0
  83. package/icons/source/ui-cube.svg +1 -0
  84. package/icons/source/ui-currency-euro.svg +1 -0
  85. package/icons/source/ui-cursor-arrow-rays.svg +1 -0
  86. package/icons/source/ui-device-phone-mobile.svg +1 -0
  87. package/icons/source/ui-document-text.svg +1 -0
  88. package/icons/source/ui-face-smile.svg +1 -0
  89. package/icons/source/ui-flag.svg +1 -0
  90. package/icons/source/ui-folder.svg +1 -0
  91. package/icons/source/ui-hand-raised.svg +1 -0
  92. package/icons/source/ui-heart.svg +1 -0
  93. package/icons/source/ui-information-circle.svg +1 -0
  94. package/icons/source/ui-language.svg +1 -0
  95. package/icons/source/ui-link.svg +1 -0
  96. package/icons/source/ui-list-bullet.svg +1 -0
  97. package/icons/source/ui-lock-closed-2.svg +1 -0
  98. package/icons/source/ui-lock-closed.svg +1 -0
  99. package/icons/source/ui-magnifying-glass.svg +1 -0
  100. package/icons/source/ui-map-pin-2.svg +1 -0
  101. package/icons/source/ui-map-pin.svg +1 -0
  102. package/icons/source/ui-megaphone.svg +1 -0
  103. package/icons/source/ui-newspaper-2.svg +1 -0
  104. package/icons/source/ui-newspaper.svg +1 -0
  105. package/icons/source/ui-pause.svg +1 -0
  106. package/icons/source/ui-pencil-square.svg +1 -0
  107. package/icons/source/ui-photo.svg +1 -0
  108. package/icons/source/ui-play.svg +1 -0
  109. package/icons/source/ui-puzzle-piece.svg +1 -0
  110. package/icons/source/ui-quote.svg +1 -0
  111. package/icons/source/ui-rectangle-stack.svg +1 -0
  112. package/icons/source/ui-rocket-launch.svg +1 -0
  113. package/icons/source/ui-shield-check-2.svg +1 -0
  114. package/icons/source/ui-shield-check.svg +1 -0
  115. package/icons/source/ui-sparkles-2.svg +1 -0
  116. package/icons/source/ui-sparkles-3.svg +1 -0
  117. package/icons/source/ui-sparkles-4.svg +1 -0
  118. package/icons/source/ui-sparkles.svg +1 -0
  119. package/icons/source/ui-square-2-stack.svg +1 -0
  120. package/icons/source/ui-squares-2x2.svg +1 -0
  121. package/icons/source/ui-squares-plus.svg +1 -0
  122. package/icons/source/ui-star-2.svg +1 -0
  123. package/icons/source/ui-star.svg +1 -0
  124. package/icons/source/ui-sun.svg +1 -0
  125. package/icons/source/ui-swatch.svg +1 -0
  126. package/icons/source/ui-table-cells.svg +1 -0
  127. package/icons/source/ui-tag.svg +1 -0
  128. package/icons/source/ui-trophy-2.svg +1 -0
  129. package/icons/source/ui-trophy.svg +1 -0
  130. package/icons/source/ui-user-group-2.svg +1 -0
  131. package/icons/source/ui-user-group.svg +1 -0
  132. package/icons/source/ui-users-2.svg +1 -0
  133. package/icons/source/ui-users.svg +1 -0
  134. package/icons/source/ui-viewfinder-circle.svg +1 -0
  135. package/icons/source/ui-window.svg +1 -0
  136. package/icons/source/ui-wrench-screwdriver.svg +1 -0
  137. package/icons/source/wo-network.svg +1 -0
  138. package/package.json +87 -0
  139. package/tokens/tokens.js +229 -0
  140. package/tokens/tokens.json +227 -0
  141. package/tokens/tokens.scss +228 -0
@@ -0,0 +1,1633 @@
1
+ /* ── Components ── */
2
+
3
+ /* ── Brand Wheel ── */
4
+ .bw-wrap{display:flex;justify-content:center;padding:var(--s8) 0}
5
+ .bw-svg{width:100%;max-width:480px;display:block}
6
+ .bw-outer{fill:var(--co-50)}
7
+ .bw-middle{fill:var(--co-200)}
8
+ /* #fff on co-400 (#26C2C2) = 2.19:1 ❌. co-800 (#004F4F) = 9.42:1 ✓ AAA in beiden Modi.
9
+ Inhaltlich getrieben (GELASSENHEIT muss lesbar sein); visuell wird das Rad damit dunkler im Zentrum. */
10
+ .bw-inner{fill:var(--co-800)}
11
+ .bw-divider{stroke:#fff;stroke-width:2;fill:none}
12
+ .bw-ring-outline{fill:none;stroke:#fff;stroke-width:2}
13
+ /* SVG-Text bleibt in px (Ausnahme von der rem-Konvention): skaliert über das viewBox
14
+ der SVG mit, rem in SVG ist Browser-abhängig unzuverlässig. */
15
+ .bw-label-core{fill:#fff;font-family:var(--font);font-size:17px;font-weight:700;letter-spacing:2px}
16
+ .bw-label-segment{fill:var(--co-800);font-family:var(--font);font-size:13px;font-weight:700;letter-spacing:1px}
17
+ .bw-label-attr{fill:var(--co-700);font-family:var(--font);font-size:12px;font-weight:600;letter-spacing:.8px}
18
+ .bw-pillar-card{flex:1;min-width:180px;padding:var(--s5);border-radius:var(--r-lg);background:var(--n-0);border:var(--bd-strong)}
19
+ .bw-pillar-title{font-size:0.875rem;font-weight:700;letter-spacing:.08em;text-transform:uppercase;margin-bottom:var(--s2);color:var(--co-700)}
20
+ .bw-pillar-attrs{font-size:0.875rem;color:var(--tx-secondary);line-height:1.6}
21
+
22
+ /* ── Buttons ── */
23
+ .btn{display:inline-flex;align-items:center;gap:var(--s2);font:var(--ty-label-md);letter-spacing:.05em;text-transform:uppercase;padding:10px 24px;border-radius:var(--r-full);border:none;cursor:pointer;transition:box-shadow var(--m-fast),transform var(--m-fast),filter var(--m-fast);min-height:44px;text-decoration:none}
24
+ .btn:hover,.btn:focus,.btn:active{text-decoration:none}
25
+ .btn:focus-visible{outline:none;box-shadow:var(--focus-ring)}
26
+ .btn:active{transform:scale(.97)}
27
+ .btn[disabled]{opacity:.38;cursor:not-allowed;pointer-events:none}
28
+ .btn-sm{padding:6px 16px;font-size:0.75rem;line-height:1rem;min-height:36px}
29
+ .btn-lg{padding:14px 32px;font-size:1rem;line-height:1.5rem;min-height:52px}
30
+ .btn-filled{background:var(--c500);color:#fff;box-shadow:var(--e1)}
31
+ .btn-filled:hover{filter:brightness(.92);box-shadow:var(--e2)}
32
+ .btn-tonal{background:var(--c50);color:var(--c500);border:1.5px solid rgba(0,0,0,.12)}
33
+ .btn-tonal:hover{filter:brightness(.96);box-shadow:var(--e1)}
34
+ .btn-elevated{background:var(--bg-surface);color:var(--c500);box-shadow:var(--e1)}
35
+ .btn-elevated:hover{box-shadow:var(--e2)}
36
+ .btn-outlined{background:transparent;color:var(--c500);border:2px solid var(--c500)}
37
+ .btn-outlined:hover{background:var(--c50)}
38
+ .btn-text{background:transparent;color:var(--c500);padding:10px 12px}
39
+ .btn-text:hover{background:var(--c50)}
40
+
41
+ /* ── Button brand-area color variants ── */
42
+ .btn-co {--c500:var(--co-700);--c50:var(--co-50)}
43
+ .btn-ki {--c500:var(--ki-800);--c50:var(--ki-50)}
44
+ .btn-es {--c500:var(--es-700);--c50:var(--es-50)}
45
+ .btn-wo {--c500:var(--wo-700);--c50:var(--wo-50)}
46
+ /* Modifier: invertiert auf dunklem Bereichs-Band (z. B. .ep-cta-band) — kombiniert mit .btn-co/.btn-ki/.btn-es/.btn-wo. Background wird weiß, Text trägt die Bereichsfarbe. */
47
+ .btn-on-band{--c500:#fff;--c50:rgba(255,255,255,.1)}
48
+ .btn-co.btn-on-band{color:var(--co-700)}
49
+ .btn-ki.btn-on-band{color:var(--ki-800)}
50
+ .btn-es.btn-on-band{color:var(--es-700)}
51
+ .btn-wo.btn-on-band{color:var(--wo-700)}
52
+ /* Full-width centered submit button */
53
+ .btn-full {width:100%;justify-content:center}
54
+
55
+ /* ── Showcase containers ── */
56
+ .ds-card {border:var(--bd-strong);border-radius:var(--r-lg);overflow:hidden;display:flex;flex-direction:column;flex:1}
57
+ .ds-surface{border:var(--bd-strong);border-radius:var(--r-lg);padding:var(--s6);background:var(--bg-surface)}
58
+ .ds-inner {padding:var(--s6);background:var(--bg-surface);flex:1}
59
+ /* Formular-Karten in gleich hohen Grid-Spalten: das Textarea-Feld füllt den Leerraum, damit der
60
+ Submit-Button unten bündig zur Nachbar-Karte sitzt. flex-basis:auto (natürliche Höhe) + grow,
61
+ kein Schrumpfen unter die natürliche Größe; min-height als Boden. Nur .field mit Textarea wächst. */
62
+ .ds-inner-fill{display:flex;flex-direction:column}
63
+ .ds-inner-fill .field:has(textarea){flex:1 1 auto;display:flex;flex-direction:column}
64
+ .ds-inner-fill .field:has(textarea) textarea{flex:1 1 auto;min-height:96px}
65
+ .clip-card {border-radius:var(--r-md);overflow:hidden;border:var(--bd-strong)}
66
+
67
+ /* ── Badges & Chips ── */
68
+ .badge{display:inline-flex;align-items:center;gap:var(--s1);padding:3px 10px;border-radius:var(--r-full);font:var(--ty-label-xs);letter-spacing:.04em}
69
+ .badge-ok{background:var(--c-success-bg);color:var(--badge-ok-text)}
70
+ .badge-warn{background:var(--c-warning-bg);color:var(--badge-warn-text)}
71
+ .badge-err{background:var(--c-error-bg);color:var(--badge-err-text)}
72
+ .badge-neu{background:var(--badge-neu-bg);color:var(--badge-neu-text)}
73
+ /* Bereichs-Badges: --XX-50-Grund + --XX-800-Text. Dark-Overrides (dark-mode.css) heben den Text auf -200/-100, Grund bleibt die dunkle -50-Kachel. */
74
+ /* Füllung über --XX-fill, nicht --XX-50: die Füllung muss als Fläche lesen (1,3:1 gegen jeden
75
+ Grund), --XX-50 trug im Light nur 1,06 bis 1,14:1. Siehe Token-Kommentar in tokens.css. */
76
+ .badge[data-area="co"]{background:var(--co-fill);color:var(--co-800)}
77
+ .badge[data-area="ki"]{background:var(--ki-fill);color:var(--ki-800)}
78
+ .badge[data-area="es"]{background:var(--es-fill);color:var(--es-800)}
79
+ .badge[data-area="wo"]{background:var(--wo-fill);color:var(--wo-800)}
80
+ /* text-decoration:none, damit der Chip auch als <a> trägt (Tag-Link, Sprungmarke, externer Verweis)
81
+ und nicht unterstrichen rendert. Auf <button> ohne Wirkung. */
82
+ .chip{display:inline-flex;align-items:center;gap:var(--s1);padding:6px var(--s4);border-radius:var(--r-sm);font:var(--ty-label-md);border:1.5px solid var(--n-200);cursor:pointer;background:var(--bg-surface);color:var(--tx-primary);min-height:32px;text-decoration:none;transition:background var(--m-fast),border-color var(--m-fast),color var(--m-fast)}
83
+ .chip:hover{background:var(--bg-overlay);border-color:var(--n-400)}
84
+ .chip:focus-visible{outline:none;box-shadow:var(--focus-aa)}
85
+ .chip[aria-pressed="true"]{background:var(--n-700);border-color:var(--n-700);color:#fff}
86
+ .chip[aria-pressed="true"]:hover{background:var(--n-800);border-color:var(--n-800)}
87
+ /* Area-aware Chips: Outline + Bereichs-Textfarbe (inaktiv) für ruhige Filter-Leiste, dezenter Tonal-Hint beim Hover, gefüllte dunklere Variante mit weißer Schrift (aktiv, AA-konform) */
88
+ /* Rahmen = hellerer Ton als Text (Nicht-Text 3:1 vs. Text 4,5:1) — bei co jedoch co-600 statt co-500,
89
+ da co-500 #00BEBE nur 2,3:1 auf Weiß erreicht (WCAG 1.4.11); co-600 #009E9E = 3,28:1, bleibt < co-700-Text */
90
+ .chip[data-area="co"]{border-color:var(--co-600);color:var(--co-700)}
91
+ .chip[data-area="ki"]{border-color:var(--ki-700);color:var(--ki-800)}
92
+ .chip[data-area="es"]{border-color:var(--es-500);color:var(--es-700)}
93
+ .chip[data-area="wo"]{border-color:var(--wo-500);color:var(--wo-700)}
94
+ .chip[data-area="co"]:hover{background:var(--co-50);border-color:var(--co-600)}
95
+ .chip[data-area="ki"]:hover{background:var(--ki-50);border-color:var(--ki-700)}
96
+ .chip[data-area="es"]:hover{background:var(--es-50);border-color:var(--es-500)}
97
+ .chip[data-area="wo"]:hover{background:var(--wo-50);border-color:var(--wo-500)}
98
+ .chip[data-area="co"][aria-pressed="true"]{background:var(--co-700);border-color:var(--co-700);color:#fff}
99
+ .chip[data-area="ki"][aria-pressed="true"]{background:var(--ki-800);border-color:var(--ki-800);color:#fff}
100
+ .chip[data-area="es"][aria-pressed="true"]{background:var(--es-700);border-color:var(--es-700);color:#fff}
101
+ .chip[data-area="wo"][aria-pressed="true"]{background:var(--wo-700);border-color:var(--wo-700);color:#fff}
102
+ .chip[data-area][aria-pressed="true"]:hover{filter:brightness(.92)}
103
+
104
+ /* ── Segmented Control ──
105
+ Native <input type="radio"> als verbundene Button-Gruppe (2–4 kurze Optionen).
106
+ Der :checked-Zustand ist nur per Selektor stylbar (nicht inline), daher als echte
107
+ Komponente. Das native Input bleibt fokussierbar (visuell versteckt), Auswahl per
108
+ Klick aufs Label und per Pfeiltasten. Aktives Segment = solide Bereichsfüllung
109
+ (Light co-700/weiß, Dark co-300/co-900) — AA in beiden Modi. overflow:hidden
110
+ clippt die Füllung sauber zur Rundung; der Fokusring liegt daher per :has() auf
111
+ dem Container (dessen eigener outset-Schatten wird vom overflow NICHT geclippt). */
112
+ /* Bereichs-Varianten wie bei .btn: Default ist Corporate, .seg-ki/-es/-wo überschreiben die
113
+ Füllung des gewählten Segments. Ohne diese Varianten trägt ein Bereichsformular mitten in
114
+ seinen Feldern einen Corporate-Akzent, was der Regel „ein Formular, eine Brand Area“
115
+ widerspricht. Der Fokusring bleibt bewusst Corporate (siehe Don'ts unter Dropdowns). */
116
+ /* Rahmen über --field-border: n-200 trug als Bedienelement-Grenze nur 1,53:1 und verfehlte die
117
+ 3:1-Schwelle aus WCAG 1.4.11. --field-border ist genau dafür da (Light n-400, 3,92:1). */
118
+ .seg{display:inline-flex;border:1.5px solid var(--field-border);border-radius:var(--r-sm);overflow:hidden;background:var(--bg-surface);--seg-fill:var(--co-700);--seg-on:#fff}
119
+ .seg-ki{--seg-fill:var(--ki-800)}
120
+ .seg-es{--seg-fill:var(--es-700)}
121
+ .seg-wo{--seg-fill:var(--wo-700)}
122
+ .seg:has(input:focus-visible){box-shadow:var(--focus-aa)}
123
+ .seg-option:not(:last-child){border-right:1.5px solid var(--n-200)}
124
+ .seg-option input{position:absolute;width:1px;height:1px;opacity:0}
125
+ .seg-option label{display:flex;align-items:center;min-height:40px;padding:var(--s2) var(--s5);font:var(--ty-label-md);color:var(--tx-secondary);white-space:nowrap;cursor:pointer;transition:background var(--m-fast),color var(--m-fast)}
126
+ .seg-option label:hover{background:var(--bg-overlay);color:var(--tx-primary)}
127
+ .seg-option input:checked + label{background:var(--seg-fill);color:var(--seg-on)}
128
+
129
+ /* ── Area Tabs ── */
130
+ .area-tabs{display:flex;gap:2px;border-bottom:var(--bd);margin-bottom:var(--s6)}
131
+ .atab{padding:var(--s2) var(--s4);font:var(--ty-label-md);cursor:pointer;border-bottom:3px solid transparent;margin-bottom:-1px;color:var(--tx-secondary);transition:color var(--m-fast),border-color var(--m-fast);min-height:40px;display:flex;align-items:center;gap:var(--s2);background:none;border-top:none;border-left:none;border-right:none}
132
+ .atab:hover{color:var(--tx-primary)}
133
+ .atab:focus-visible{outline:none;box-shadow:var(--focus-aa)}
134
+ .atab.active{color:var(--atab-color);border-bottom-color:var(--atab-color)}
135
+ .atab-content{display:none}
136
+ .atab-content.visible{display:block}
137
+
138
+ /* ── Cards ── */
139
+ /* Die Karte ist eine vertikale Spalte: Bild, Body, optionaler Footer. Das steht hier und nicht im
140
+ style-Attribut, weil das dokumentierte Rezept es voraussetzt: .card-body{flex:1} kann die
141
+ Resthöhe nur in einem Flex-Container einnehmen, und ohne diese Resthöhe hat
142
+ .card-cta-link--pinned kein margin-top:auto, an dem es sich ausrichten könnte. Die Karten in
143
+ einem .layout-grid werden von außen auf gleiche Höhe gezogen; der Body nimmt den Überschuss
144
+ auf, damit die CTA-Zeilen nebeneinanderliegender Karten auf einer Linie sitzen.
145
+ .card-featured bleibt display:block (weiter unten, spätere Regel gewinnt): dort liegt der Body
146
+ absolut, eine Flex-Spalte hätte da nichts zu verteilen. */
147
+ .card{background:var(--bg-surface);border-radius:var(--r-lg);border:var(--bd-strong);overflow:hidden;display:flex;flex-direction:column;transition:box-shadow var(--m-std),transform var(--m-std)}
148
+ /* Card-Varianten */
149
+ /* Elevation = Interaktivität, und zwar an der FLÄCHE: Schatten trägt eine Karte nur, wenn die Karte
150
+ selbst der klickbare Bereich ist. Buttons im .card-footer machen die Fläche nicht klickbar, die
151
+ Interaktion liegt dann in den Buttons; so eine Karte ruht flach mit dem --bd-Rahmen aus .card.
152
+ Deshalb hängt die ganze Variante an a.*: eine <article>/<div>-Karte bekommt den Schatten auch
153
+ dann nicht, wenn die Klasse gesetzt ist. Das ist der Riegel, nicht nur eine Empfehlung. */
154
+ a.card-elevated{box-shadow:var(--e1);border:none;background:var(--bg-surface)}
155
+ a.card-elevated:hover{box-shadow:var(--e2);transform:translateY(-2px)}
156
+
157
+ .card-media{width:100%;aspect-ratio:16/9;display:flex;align-items:center;justify-content:center}
158
+ /* Der Body ordnet seine Kinder, also gehört ihm auch der Abstand zwischen ihnen: eine Flex-Spalte
159
+ mit gap:var(--s3) als einziger vertikaler Rhythmus der Karte. Vorher trug jedes Kind seine
160
+ eigene Außenmarge, und wer den Body flexte, bekam Marge PLUS Gap (im Flex-Layout kollabieren
161
+ sie nicht). Darum haben .card-eyebrow und .card-cta-link hier keine Marge mehr, und die Pill
162
+ bekommt ihre unten zurückgenommen.
163
+ flex:1 lässt den Body die Resthöhe der Karte einnehmen. Nötig für .card-cta-link--pinned
164
+ (margin-top:auto braucht freien Raum im Container) und für gleich hohe Karten im Grid: ohne das
165
+ sammelt sich der Überschuss unter dem Body, statt in ihm. Auf einer nicht-flexen Karte ist die
166
+ Deklaration wirkungslos, nicht schädlich. */
167
+ .card-body{padding:var(--s5);display:flex;flex-direction:column;gap:var(--s3);flex:1}
168
+ .card-eyebrow{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase}
169
+ /* Area-branded card media + eyebrow (token-driven, dark-mode overridable) */
170
+ .card[data-area="co"] .card-media{background:var(--co-50);color:var(--co-700)}
171
+ .card[data-area="ki"] .card-media{background:var(--ki-50);color:var(--ki-700)}
172
+ .card[data-area="es"] .card-media{background:var(--es-50);color:var(--es-600)}
173
+ .card[data-area="wo"] .card-media{background:var(--wo-50);color:var(--wo-700)}
174
+ .card[data-area="co"] .card-eyebrow{color:var(--co-700)}
175
+ .card[data-area="ki"] .card-eyebrow{color:var(--ki-800)}
176
+ .card[data-area="es"] .card-eyebrow{color:var(--es-700)}
177
+ .card[data-area="wo"] .card-eyebrow{color:var(--wo-700)}
178
+ /* card-title und card-text: line-clamp + min-height halten Karten in Grids visuell ausgerichtet,
179
+ unabhängig davon ob Titel/Anreißer im aktuellen CMS-Stand 1, 2 oder 3 Zeilen lang sind.
180
+ line-clamp kappt zu lange Inhalte; min-height (in lh-Units, skaliert mit Typografie-Tokens)
181
+ reserviert die Maximum-Höhe, damit Karten in einer Row nicht durch Längen-Varianz „springen“.
182
+ Trade-Off: bei aktuell kurzem Content sieht das wie ein Hohlraum aus, ist aber gewollt — das Layout
183
+ muss morgen mit einer 2-zeiligen Headline umgehen, ohne dass jemand CSS-Klassen umtauschen muss. */
184
+ /* Äußerer Container: reserviert min. 2-Zeilen-Höhe und zentriert den Inhalt vertikal mittig.
185
+ Inneres <span> trägt das Line-Clamping (kappt zu lange Titel auf 2 Zeilen). */
186
+ /* Title Small (18px Sans 500) gibt eine klare Hierarchie-Stufe zur Section-H2 (Headline-md, 28px Serif)
187
+ und vermeidet, dass die Card-Titel mit den Sektion-Überschriften um Aufmerksamkeit konkurrieren. */
188
+ .card-title{font:var(--ty-title-sm);color:var(--tx-primary);min-height:2lh;display:grid;align-content:center}
189
+ .card-title>*{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
190
+ /* Hero-Variante: Editorial-Treatment für Featured-Cards (genau ein Termin oder ein Beitrag hervorgehoben).
191
+ Headline-Sm (24px Serif) als Mid-Tier zwischen Section-H2 (28px) und Standard-Card-Title (20px Sans),
192
+ saubere 4-px-Treppe in der Hierarchie. Kein min-height (kein Nachbar zum Abgleichen). */
193
+ .card-title-hero{font:var(--ty-headline-sm);color:var(--tx-primary);margin:0;text-wrap:balance}
194
+ .card-text{font:var(--ty-body-md);color:var(--tx-secondary);display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden;min-height:3lh}
195
+ /* Mobile (≤ 768px): .layout-grid wird einspaltig, die Cards stehen ohne Nachbarn full-width.
196
+ Dann sind die min-height-Reservierungen (Titel 2lh, Text 3lh) — die nur die Gleichhöhe
197
+ nebeneinanderstehender Cards sichern — leerer Raum und erzeugen große Lücken. Aufheben.
198
+ Das line-clamp (Titel 2, Text 3 Zeilen) bleibt, lange Inhalte kürzen also weiterhin.
199
+ .ep-cards (auto-fit) bleibt bewusst unberührt: dort stehen Cards auch mobil noch mehrspaltig. */
200
+ @media(max-width:768px){
201
+ .layout-grid .card-title,.layout-grid .card-text{min-height:0}
202
+ }
203
+ /* Wie im Featured-Body: die Eigenmarge der Pill (--s5, gedacht für den normalen Fluss) würde sich
204
+ zum gap des Bodys addieren, statt zu kollabieren. Der Abstand kommt aus dem Container. Nur
205
+ direkte Kinder, eine Pill tiefer im Body steht in einem eigenen Layout. */
206
+ .card-body>.pill{margin-bottom:0}
207
+ /* Kompakter Meta-Block (Datum + Ort) — kleinerer Gap zwischen den Zeilen, damit das Paar als eine Einheit gelesen wird,
208
+ nicht als zwei unabhängige Items. Sitzt selbst im Card-Body und nutzt dessen Gap (--s3) zur Pill darüber und zum Titel darunter. */
209
+ .card-meta{display:flex;flex-direction:column;gap:var(--s1)}
210
+ .card-footer{padding:var(--s3) var(--s5);border-top:var(--bd);display:flex;align-items:center;justify-content:flex-end;gap:var(--s2)}
211
+
212
+ /* ── Featured-Card: horizontale Großkarte ──
213
+ Genau ein Beitrag oder Termin auf der Bühne: Bild links, Content rechts.
214
+ Die Bildspalte trägt .card-media und damit dasselbe aspect-ratio:16/9 wie die Cards im
215
+ Listing-Grid. Das ist der Zweck der Klasse: Redaktion pflegt EIN Bild in EINEM Zuschnitt
216
+ für Featured UND Grid, statt je Slot einen eigenen.
217
+
218
+ Das BILD bestimmt die Kartenhöhe, nicht der Text. Darum liegt .card-featured-body absolut:
219
+ als normale Spalte zieht seine Inhaltshöhe die Zeile auf und streckt das Bild mit — genau
220
+ daran driftete das Verhältnis vorher auf 1,62. Ein aspect-ratio auf der Karte genügt dafür
221
+ nicht, es ist eine Wunschgröße und verliert gegen die Inhaltshöhe (gemessen 1,50). Absolut
222
+ positioniert trägt der Body nichts zur Höhe bei, das 16/9 gilt unabhängig von der Textlänge.
223
+
224
+ Zu viel Text wird gekappt, statt das Verhältnis zu brechen: .card-text bringt sein
225
+ line-clamp mit, und als schrumpfendes Flex-Item gibt der Lead nach, bevor Pill, Meta,
226
+ Titel oder CTA wegfallen. 60/40 statt 50/50, weil ein 16/9-Bild auf halber Kartenbreite
227
+ zu flach für den Content-Block ist: bei 60 % bleiben rund 26 px Reserve und drei
228
+ Lead-Zeilen, bei 50 % schrumpft der Lead auf null. Beide Prozentwerte gehören zusammen
229
+ und müssen 100 % ergeben, sonst klafft eine Lücke. */
230
+ .card-featured{display:block;position:relative;overflow:hidden;container-type:inline-size}
231
+ .card-featured>.card-media{width:60%}
232
+ .card-featured>.card-media>img{width:100%;height:100%;object-fit:cover}
233
+ .card-featured-body{position:absolute;top:0;right:0;bottom:0;width:40%;padding:var(--s6) var(--s8);display:flex;flex-direction:column;justify-content:center;gap:var(--s4);overflow:hidden}
234
+ /* Die Pill bringt eine Eigenmarge von --s5 mit, gedacht für den normalen Fluss (Pill über der H1
235
+ im Article-Header). Hier trägt der Body den Abstand als gap:var(--s4), und beide addieren sich:
236
+ im Flex-Layout kollabieren Marge und Gap nicht. Ergebnis wären 36 px unter der Pill statt 16 px,
237
+ und der Meta-Block löst sich vom Bereichs-Signal, mit dem er als Meta-Header zusammengehört. Der
238
+ Abstand gehört dem Container, nicht der Pill, also wird ihre Marge hier zurückgenommen. Nur für
239
+ direkte Kinder: eine Pill tiefer im Body (etwa in einer Zeile neben einem Titel) steht in einem
240
+ eigenen Layout und regelt ihren Abstand dort selbst. */
241
+ .card-featured-body>.pill{margin-bottom:0}
242
+ /* min-height:3lh reserviert im Grid Platz für den Gleichhöhen-Abgleich. Die Featured-Card
243
+ steht allein, hat keinen Nachbarn, und der reservierte Platz ginge zulasten des Bildes. */
244
+ .card-featured-body>.card-text{min-height:0}
245
+ /* Auch der Titel braucht einen Riegel, sonst frisst ein langer Titel die Höhe, die der Lead
246
+ braucht, und danach die von Pill und CTA (gemessen mit einem 18-Wort-Titel: Lead auf null
247
+ Zeilen, Pill und CTA aus der Karte geschoben). Drei Zeilen sind für eine Hero-Card reichlich.
248
+ Nur hier, nicht global: .card-title-hero bleibt außerhalb der Featured-Card unbeschnitten. */
249
+ .card-featured-body>.card-title-hero{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:3;line-clamp:3;overflow:hidden}
250
+ /* Drei Stufen, alle an der KARTENBREITE per @container, nicht am Viewport: die Kartenbreite
251
+ hängt am Platz im Layout (Sidebar, Section-Padding, Spaltenbreite). Im Doku-Mockup ist die
252
+ Karte bei 1180 px Viewport nur 814 px breit, bei 1024 px dagegen 958 px — eine
253
+ Viewport-Regel träfe dort das Falsche.
254
+
255
+ Die Stufen greifen über die Reihenfolge: die 1000er-Regel gilt ab hier abwärts, die
256
+ 900er-Regel überschreibt sie darunter wieder. Gleiche Spezifität, die spätere gewinnt.
257
+
258
+ 1000 px abwärts (Tablet-Landscape): nebeneinander BLEIBEN, aber verdichtet. Das Bild auf
259
+ 65 % statt 60 %, denn breiteres Bild heißt bei 16/9 auch höheres Bild und damit mehr Platz
260
+ für den Content-Block; dazu kleineres Padding. Ohne das schrumpft der Lead hier auf eine
261
+ oder null Zeilen. Gemessen bei 958 px Kartenbreite: Karte 350 px hoch, drei Lead-Zeilen,
262
+ rund 22 px Reserve (Veranstaltungs-Karte mit dreizeiligem Meta-Strip: 30 px). */
263
+ @container (max-width:1000px){
264
+ .card-featured>.card-media{width:65%}
265
+ .card-featured-body{width:35%;padding:var(--s4) var(--s6)}
266
+ /* Lead auf zwei Zeilen: drei passen hier nicht mehr vollständig, und ein Lead, der als
267
+ Flex-Item unter seine line-clamp-Höhe gedrückt wird, endet mitten in der Zeile statt mit
268
+ Auslassungspunkten. Mit zwei Zeilen bleibt die Kante bei üblichen Titellängen sauber.
269
+ Rest-Fall: bei einem Titel, der den 3-Zeilen-Riegel voll ausschöpft, wird auch die zweite
270
+ Lead-Zeile angeschnitten. Das ist bewusst so gelassen — irgendetwas muss dann nachgeben,
271
+ und eine halbe Lead-Zeile ist der geringste Schaden. Titel kürzen behebt es an der
272
+ Quelle. Die Karte bleibt in jedem Fall geschlossen: Pill und CTA werden nicht mehr
273
+ hinausgeschoben, dafür sorgt der Titel-Riegel. */
274
+ .card-featured-body>.card-text{-webkit-line-clamp:2;line-clamp:2}
275
+ }
276
+ /* 900 px abwärts (Portrait, Smartphone, schmale Container): gestapelt wie die Grid-Cards.
277
+ Bild full-width im 16/9 obenauf, Body zurück in den Fluss, nichts mehr zu kappen. Tiefer
278
+ als 900 px nebeneinander zu bleiben lohnt nicht: die Textspalte wäre unter 250 px breit,
279
+ rund 30 Zeichen pro Zeile. */
280
+ @container (max-width:900px){
281
+ .card-featured>.card-media{width:100%}
282
+ .card-featured-body{position:static;width:auto;padding:var(--s6)}
283
+ /* Lead zurück auf drei Zeilen: das Kürzen auf zwei gilt nur der knappen Höhe der
284
+ Tablet-Stufe. Gestapelt gibt es keine feste Höhe zu halten, also auch keinen Grund,
285
+ eine Zeile zu opfern. Ohne diese Rücknahme wirkt die 1000er-Regel bis aufs Handy durch. */
286
+ .card-featured-body>.card-text{-webkit-line-clamp:3;line-clamp:3}
287
+ }
288
+
289
+ /* ── Blockquote ── */
290
+ .bq{padding:var(--s5) var(--s6);border-left:4px solid var(--bq-accent,var(--co-500));background:var(--bq-bg,var(--co-50));border-radius:var(--r-md);margin:0}
291
+ .bq[data-area="co"]{--bq-accent:var(--co-500);--bq-bg:var(--co-50)}
292
+ .bq[data-area="ki"]{--bq-accent:var(--ki-500);--bq-bg:var(--ki-50)}
293
+ .bq[data-area="es"]{--bq-accent:var(--es-500);--bq-bg:var(--es-50)}
294
+ .bq[data-area="wo"]{--bq-accent:var(--wo-500);--bq-bg:var(--wo-50)}
295
+ /* fill:currentColor ist nötig, damit color (Bereichsakzent) den Glyph färbt — sonst SVG-Default schwarz. */
296
+ .bq-icon{display:block;width:20px;height:20px;color:var(--bq-accent,var(--co-500));fill:currentColor;opacity:.35;margin-bottom:var(--s3)}
297
+ .bq blockquote{font:var(--ty-serif-lg);color:var(--tx-primary);margin:0 0 var(--s3);quotes:none}
298
+ .bq-caption{display:flex;flex-direction:column;gap:2px}
299
+ .bq-name{font:var(--ty-name);color:var(--tx-primary)}
300
+ .bq-role{font:var(--ty-body-xs);color:var(--tx-secondary);font-style:normal}
301
+
302
+ /* ── Testimonial Card ── */
303
+ /* Statisch (Konvention „Elevation = Interaktivität“): flach mit --bd-strong-Rahmen + Top-Akzent, kein Schatten. */
304
+ .testimonial{background:var(--bg-surface);border:var(--bd-strong);border-top:4px solid var(--t-accent,var(--co-500));border-radius:var(--r-lg);padding:var(--s6);margin:0;display:flex;flex-direction:column;gap:var(--s4)}
305
+ .testimonial[data-area="co"]{--t-accent:var(--co-500)}
306
+ .testimonial[data-area="ki"]{--t-accent:var(--ki-500)}
307
+ .testimonial[data-area="es"]{--t-accent:var(--es-500)}
308
+ .testimonial[data-area="wo"]{--t-accent:var(--wo-500)}
309
+ .testimonial-icon{width:32px;height:32px;color:var(--t-accent,var(--co-500));fill:currentColor;opacity:.2;flex-shrink:0}
310
+ .testimonial blockquote{font:var(--ty-serif-sm);color:var(--tx-primary);margin:0;quotes:none;flex:1}
311
+ .testimonial-footer{display:flex;align-items:center;gap:var(--s3);padding-top:var(--s4);border-top:var(--bd);margin-top:auto}.testimonial-name{font:var(--ty-name);color:var(--tx-primary);margin:0}
312
+ .testimonial-role{font:var(--ty-body-xs);color:var(--tx-secondary);margin:0;font-style:normal}
313
+ /* Team-Stimmen: editoriale Reihen, Foto seitlich (abwechselnd L/R), fotostark für Repräsentation. Eigene Variante, lässt .testimonial unberührt. */
314
+ .team-voices{display:flex;flex-direction:column;gap:var(--s6)}
315
+ .team-voice{display:grid;grid-template-columns:minmax(0,5fr) minmax(0,7fr);align-items:stretch;background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-lg);overflow:hidden}
316
+ /* Bereichs-Rahmen: dieselben Stufen wie beim Bereichs-Chip, weil sie dort schon auf die
317
+ 3:1-Schwelle für grafische Objekte ausgelegt sind. Vorher -200 für alle vier, das trug auf Weiß
318
+ nur 1,27:1 (ki) bis 2,03:1 (es), der Rahmen war als Bereichssignal nicht wahrnehmbar. Jetzt
319
+ 3,29:1 (co) bis 5,66:1 (es). Das Quote-Icon bleibt dekorativ (opacity .25), der Rahmen ist damit
320
+ das tragende Farbsignal. Dark-Werte in dark-mode.css. */
321
+ .team-voice[data-area="co"]{--t-accent:var(--co-500);border-color:var(--co-600)}
322
+ .team-voice[data-area="ki"]{--t-accent:var(--ki-500);border-color:var(--ki-700)}
323
+ .team-voice[data-area="es"]{--t-accent:var(--es-500);border-color:var(--es-500)}
324
+ .team-voice[data-area="wo"]{--t-accent:var(--wo-500);border-color:var(--wo-500)}
325
+ .team-voice-media{margin:0}
326
+ .team-voice-media img{display:block;width:100%;height:100%;min-height:300px;object-fit:cover}
327
+ .team-voice-body{padding:var(--s8);display:flex;flex-direction:column;gap:var(--s5);justify-content:center}
328
+ .team-voice-icon{width:36px;height:36px;color:var(--t-accent,var(--co-500));fill:currentColor;opacity:.25;flex-shrink:0}
329
+ .team-voice-quote{font:var(--ty-serif-md);color:var(--tx-primary);margin:0;quotes:none}
330
+ .team-voice-footer{display:flex;flex-direction:column;gap:var(--s1)}
331
+ .team-voice-name{font:var(--ty-name);color:var(--tx-primary);margin:0}
332
+ .team-voice-role{font:var(--ty-body-sm);color:var(--tx-secondary);margin:0}
333
+ .team-voice:nth-child(even){grid-template-columns:minmax(0,7fr) minmax(0,5fr)}
334
+ .team-voice:nth-child(even) .team-voice-media{grid-column:2;grid-row:1}
335
+ .team-voice:nth-child(even) .team-voice-body{grid-column:1;grid-row:1}
336
+ @media(max-width:768px){
337
+ .team-voice,.team-voice:nth-child(even){grid-template-columns:1fr}
338
+ .team-voice:nth-child(even) .team-voice-media{grid-column:1;grid-row:1}
339
+ .team-voice:nth-child(even) .team-voice-body{grid-column:1;grid-row:2}
340
+ /* Gestapelt verbraucht das Quote-Icon eine eigene Zeile + Gaps und frisst viel Höhe.
341
+ Stattdessen Pull-Quote-Stil: 2-Spalten-Grid mit Icon im schmalen linken Gutter, Zitat
342
+ und Footer rechts daneben/darunter ausgerichtet. Icon kleiner, Body-Padding reduziert. */
343
+ .team-voice-body{display:grid;grid-template-columns:auto 1fr;align-items:start;column-gap:var(--s2);row-gap:var(--s3);padding:var(--s6)}
344
+ .team-voice-icon{width:26px;height:26px;grid-column:1;grid-row:1;margin-top:2px}
345
+ .team-voice-quote{grid-column:2;grid-row:1}
346
+ .team-voice-footer{grid-column:2;grid-row:2}
347
+ }
348
+ /* Stat Card */
349
+ /* Statisch (Konvention „Elevation = Interaktivität“): flach mit --bd-strong-Rahmen + Top-Akzent, kein Schatten. */
350
+ .card-stat{background:var(--bg-surface);border:var(--bd-strong);border-top:4px solid var(--st-accent,var(--co-500));border-radius:var(--r-lg);padding:var(--s5) var(--s6);display:flex;flex-direction:column;gap:var(--s2)}
351
+ .card-stat[data-area="co"]{--st-accent:var(--co-500)}
352
+ .card-stat[data-area="ki"]{--st-accent:var(--ki-500)}
353
+ .card-stat[data-area="es"]{--st-accent:var(--es-500)}
354
+ .card-stat[data-area="wo"]{--st-accent:var(--wo-500)}
355
+ .card-stat-value{font:var(--ty-display-md);color:var(--tx-primary);margin:0}
356
+ .card-stat[data-area="co"] .card-stat-value{color:var(--co-700)}
357
+ .card-stat[data-area="ki"] .card-stat-value{color:var(--ki-700)}
358
+ .card-stat[data-area="es"] .card-stat-value{color:var(--es-700)}
359
+ .card-stat[data-area="wo"] .card-stat-value{color:var(--wo-700)}
360
+ .card-stat-label{font:var(--ty-body-md);color:var(--tx-secondary);margin:0}
361
+ .card-stat-trend{display:inline-flex;align-items:center;gap:var(--s1);font:600 0.75rem/1rem var(--font);border-radius:var(--r-full);padding:2px var(--s2);margin-top:var(--s1)}
362
+ .card-stat-trend.up{background:var(--c-success-bg);color:var(--badge-ok-text)}
363
+ .card-stat-trend.down{background:var(--c-error-bg);color:var(--badge-err-text)}
364
+ /* Stat-Strip — flache Bandstreifen-Variante (ohne Border, ohne Shadow) */
365
+ .card-stat-strip{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--s6);padding:var(--s10) var(--s8);background:var(--n-50);text-align:center}
366
+ .card-stat-flat{display:flex;flex-direction:column;gap:var(--s1);align-items:center}
367
+ .card-stat-flat-value{font:var(--ty-display-sm);color:var(--tx-primary);margin:0}
368
+ .card-stat-flat[data-area="co"] .card-stat-flat-value{color:var(--co-700)}
369
+ .card-stat-flat[data-area="ki"] .card-stat-flat-value{color:var(--ki-700)}
370
+ .card-stat-flat[data-area="es"] .card-stat-flat-value{color:var(--es-700)}
371
+ .card-stat-flat[data-area="wo"] .card-stat-flat-value{color:var(--wo-700)}
372
+ .card-stat-flat-label{font:var(--ty-body-xs);color:var(--tx-secondary);margin:0}
373
+
374
+ /* ── Forms ── */
375
+ .field{margin-bottom:var(--s6)}
376
+ .field label{display:flex;align-items:center;gap:var(--s2);font:var(--ty-label-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary);margin-bottom:var(--s2)}
377
+ .req{color:var(--c-error);font-size:0.875rem}
378
+ .field input,.field textarea,.field select{width:100%;padding:var(--s3) var(--s4);font:var(--ty-body-md);color:var(--tx-primary);background:var(--bg-surface);border:2px solid var(--field-border);border-radius:var(--r-md);outline:none;transition:border-color var(--m-fast),box-shadow var(--m-fast);min-height:44px}
379
+ .field select{appearance:none;-webkit-appearance:none;height:52px;background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%234A6565' stroke-width='1.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M19.5 8.25l-7.5 7.5-7.5-7.5'/%3E%3C/svg%3E");background-repeat:no-repeat;background-position:right var(--s4) center;padding-right:var(--s10)}
380
+ .field input:focus,.field select:focus,.field textarea:focus{border-color:var(--co-500);box-shadow:var(--focus-ring)}
381
+ .field textarea{resize:vertical;max-width:100%}
382
+ /* Placeholder explizit auf tx-secondary statt UA-Default. Chrome zeichnet Placeholder sonst mit
383
+ rgb(117,117,117): im Dark sind das auf der Feldfüllung 2,8:1 und damit ein AA-Verstoß, im Light
384
+ 4,6:1 und damit knapp bestanden, aber ohne Reserve und vom Browser abhängig. Suchfeld,
385
+ Footer-Newsletter, Combobox und Nav-Suche setzten das bereits, die Standard-Felder waren der
386
+ Ausreißer. tx-secondary ist theme-aware und gemessen: Light 6,3:1, Dark 7,1:1. */
387
+ .field input::placeholder,.field textarea::placeholder,
388
+ [role="search"] input::placeholder{color:var(--tx-secondary)}
389
+ .field.has-error input,.field.has-error select,.field.has-error textarea{border-color:var(--c-error)}
390
+ /* Hilfetext unter einem Feld. --tx-secondary statt --tx-muted: Helper sitzt immer auf
391
+ --bg-surface, dort erreicht --tx-muted im Dark Mode nur 4,1:1 und verfehlt AA für Kleintext
392
+ (siehe Kontrast-Tabelle in der Doku). --tx-secondary liegt bei 6,3:1 Light / 4,9:1 Dark. */
393
+ .helper{font:var(--ty-body-xs);color:var(--tx-secondary);margin-top:var(--s1)}
394
+ .error-msg{font:var(--ty-label-sm);color:var(--c-error);margin-top:var(--s1);display:flex;align-items:center;gap:var(--s1)}
395
+
396
+ /* ── Buchungsformular ──
397
+ Komposition aus .field-Feldern für verbindliche Buchungen (Seminartermin, Platzkontingent).
398
+ Neu gegenüber der Standard-Form: Fieldset-Gliederung, bedingte Blöcke (hidden-Attribut, kein
399
+ disabled), ein Teilnehmenden-Repeater und eine Live-Preiszeile. Bereichsfarbe kommt von außen
400
+ (.btn-wo, accent-color), die Klassen selbst bleiben bereichsneutral. */
401
+ .bk-fieldset{border:0;padding:0;margin:0 0 var(--s8);min-inline-size:0}
402
+ /* Trennlinie nur zwischen den Gruppen oberster Ebene, nicht vor der ersten. Der Kindselektor ist
403
+ wichtig: Untergruppen liegen innerhalb einer Gruppe und dürfen keine Linie bekommen, sonst
404
+ trennt sie die Linie von der Entscheidung, zu der sie gehören. */
405
+ [data-booking] > .bk-fieldset + .bk-fieldset{border-top:var(--bd);padding-top:var(--s8)}
406
+ /* Untergruppe: gliedert innerhalb einer Gruppe (Radio-Gruppe, bedingter Block) und trägt deshalb
407
+ ein Label auf Feldebene statt einer Überschrift. Kein Rahmen, keine Linie, nur Abstand. */
408
+ .bk-subgroup{border:0;padding:0;margin:0 0 var(--s6);min-inline-size:0}
409
+ .bk-subgroup[hidden]{display:none}
410
+ .bk-subgroup:last-child{margin-bottom:0}
411
+ /* Mittlere Stufe: 14 px halbfett, gemischte Schreibweise, --tx-primary. Damit sind drei Ebenen
412
+ unterscheidbar (20 px Gruppe / 14 px Untergruppe / 12 px Versal-Feldlabel). Dieselben Versalien
413
+ wie beim Feldlabel zu nehmen wäre derselbe Fehler wie vorher, nur eine Ebene tiefer. */
414
+ .bk-sublegend{display:block;font:var(--ty-name);color:var(--tx-primary);padding:0;margin-bottom:var(--s3)}
415
+ .bk-fieldset::after{content:"";display:block;clear:both}
416
+ /* Gruppenüberschrift eine echte Stufe über dem Feldlabel: 20 px, gemischte Schreibweise,
417
+ --tx-primary gegen 12 px Versalien in --tx-secondary. Vorher waren beide typografisch
418
+ identisch, dadurch war die Fieldset-Gliederung semantisch da, aber optisch unsichtbar.
419
+ float statt display:block, weil ein gefloatetes <legend> nicht mehr in die obere Rahmenkante
420
+ gerendert wird und die Trennlinie deshalb durchgehend bleibt. */
421
+ .bk-legend{float:left;width:100%;font:var(--ty-title-sm);color:var(--tx-primary);margin-bottom:var(--s4);padding:0}
422
+ /* Ohne clear würde das erste Element der Gruppe neben dem 100 % breiten Float landen und sein
423
+ Label auf null Breite gequetscht. Alle Geschwister, nicht nur das erste: der absolut positionierte Entfernen-Button steht
424
+ dazwischen und nimmt kein clear an. */
425
+ .bk-legend ~ *{clear:both}
426
+ .bk-intro{font:var(--ty-body-sm);color:var(--tx-secondary);margin:calc(-1 * var(--s2)) 0 var(--s4)}
427
+ /* Zweispalter, die auf Mobile einspaltig werden (der Inline-Zweispalter älterer Formulare tut das nicht). */
428
+ .bk-grid-2{display:grid;grid-template-columns:1fr 1fr;gap:0 var(--s4)}
429
+ .bk-grid-plz{display:grid;grid-template-columns:minmax(96px,1fr) 2fr;gap:0 var(--s4)}
430
+ /* Nur das Eingabefeld ist schmal, nicht der ganze .field-Wrapper: sonst würde die
431
+ Fehlermeldung darunter in eine 140-px-Spalte gequetscht. */
432
+ .bk-count input{max-width:140px}
433
+ /* Teilnehmenden-Block: <fieldset> mit <legend>, damit Screenreader beim Betreten „Teilnehmende 3“
434
+ ansagen und „Vorname“ nicht dreimal gleich klingt. Nur Rahmen, bewusst ohne eigene Fläche,
435
+ sonst entsteht im Dark Mode eine dritte Flächenstufe über .bg-page < .bg-surface. */
436
+ .bk-person{position:relative;border:var(--bd-strong);border-radius:var(--r-md);padding:var(--s5);margin-bottom:var(--s4);min-inline-size:0}
437
+ .bk-person > .field:last-of-type{margin-bottom:0}
438
+ .bk-person::after{content:"";display:block;clear:both}
439
+ /* Wie .bk-legend gefloatet, damit die Legende in den Innenabstand rutscht statt in die
440
+ Rahmenkante. Nur so liegt der Entfernen-Button auf einer Linie mit „Teilnehmende N“ und
441
+ nicht neben dem ersten Feldlabel, wo er wie dessen Aktion aussieht. */
442
+ .bk-person-title{float:left;width:100%;font:var(--ty-label-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary);padding:0;margin-bottom:var(--s4)}
443
+ .bk-person-title ~ *{clear:both}
444
+ /* Absolut positioniert, weil <legend> das erste Kind des Fieldsets bleiben muss und sich
445
+ deshalb nicht mit dem Button in eine Flex-Zeile setzen lässt.
446
+ Achtung: jede Autorenregel mit display schlägt das hidden-Attribut (hier .btn{display:inline-flex}),
447
+ deshalb muss [hidden] explizit zurückgenommen werden. Gilt genauso für .bk-person-hint und
448
+ .bk-success. Wer im DS mit hidden arbeitet, braucht diese Zeile. */
449
+ .bk-person-remove{position:absolute;top:var(--s3);right:var(--s4)}
450
+ .bk-person-remove[hidden]{display:none}
451
+ .bk-person-hint{display:block;margin:0 0 var(--s4)}
452
+ .bk-person-hint[hidden]{display:none}
453
+ /* Fehlerübersicht am Formularkopf: Sprungliste statt einer Salve gleichzeitiger Alerts. */
454
+ .bk-errors{border:2px solid var(--c-error);border-radius:var(--r-md);padding:var(--s5);margin-bottom:var(--s6)}
455
+ .bk-errors[hidden]{display:none}
456
+ .bk-errors:focus-visible{outline:none;box-shadow:var(--focus-ring)}
457
+ .bk-errors-title{font:var(--ty-title-sm);color:var(--c-error);margin:0 0 var(--s3)}
458
+ .bk-errors ul{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:var(--s2)}
459
+ .bk-errors a{font:var(--ty-body-md);color:var(--c-error);text-decoration:underline}
460
+ .bk-errors a:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-xs)}
461
+ .bk-summary{display:flex;flex-wrap:wrap;align-items:baseline;justify-content:space-between;gap:var(--s2);background:var(--bg-overlay);border-radius:var(--r-md);padding:var(--s4);margin-bottom:var(--s5);font:var(--ty-body-md);color:var(--tx-secondary)}
462
+ .bk-summary-total{font:var(--ty-title-sm);color:var(--tx-primary)}
463
+ /* Bestellübersicht unmittelbar vor dem zahlungspflichtigen Button: was gebucht wird, für wen,
464
+ wie viele Plätze, Gesamtbetrag. Der bloße Betrag reicht hier nicht, die gebuchte Leistung steht
465
+ sonst über tausend Pixel weiter oben verstreut. */
466
+ /* Oben --s8: die Übersicht ist ein eigener Block und darf nicht am letzten Häkchen kleben.
467
+ Das Bestätigungs-Häkchen darüber gibt nur --s4 mit, das reicht als Abstand nicht. */
468
+ .bk-order{border:var(--bd-strong);border-radius:var(--r-md);background:var(--bg-overlay);padding:var(--s5);margin:var(--s8) 0 var(--s5)}
469
+ .bk-order-title{font:var(--ty-name);color:var(--tx-primary);margin:0 0 var(--s4)}
470
+ .bk-order-list{margin:0;display:flex;flex-direction:column;gap:var(--s2)}
471
+ .bk-order-list > div{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:baseline;gap:var(--s2)}
472
+ .bk-order-list dt{font:var(--ty-body-sm);color:var(--tx-secondary)}
473
+ .bk-order-list dd{margin:0;font:var(--ty-body-md);color:var(--tx-primary);text-align:right}
474
+ /* Noch nicht ausgefüllte Zeile bleibt lesbar, tritt aber zurück. */
475
+ .bk-order-list dd[data-empty]{color:var(--tx-secondary)}
476
+ .bk-order-total{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s2);margin-top:var(--s4);padding-top:var(--s4);border-top:var(--bd)}
477
+ .bk-order-total-label{font:var(--ty-body-md);color:var(--tx-secondary)}
478
+ .bk-order-total-value{font:var(--ty-title-sm);color:var(--tx-primary)}
479
+ .bk-order-note{font:var(--ty-body-xs);color:var(--tx-secondary);margin:var(--s1) 0 0;text-align:right}
480
+ .bk-consent{display:flex;align-items:flex-start;gap:var(--s3);margin-bottom:var(--s4)}
481
+ .bk-consent label{font:var(--ty-body-md);color:var(--tx-secondary);cursor:pointer}
482
+ /* Freiwilliges Opt-in vom rechtlich erforderlichen Teil absetzen. Gleiche Optik direkt unter
483
+ zwei Pflicht-Häkchen liest sich sonst wie ein Dark Pattern, auch wenn keines gemeint ist. */
484
+ .bk-consent-optional{border-top:var(--bd);padding-top:var(--s4);margin-top:var(--s5)}
485
+ .bk-success{display:flex;align-items:flex-start;gap:var(--s3);background:var(--c-success-bg);color:var(--c-success);border-radius:var(--r-md);padding:var(--s5)}
486
+ /* display:flex würde das hidden-Attribut aushebeln, deshalb explizit zurücknehmen. */
487
+ .bk-success[hidden]{display:none}
488
+ .bk-success:focus-visible{outline:none;box-shadow:var(--focus-ring)}
489
+ @media (max-width:768px){
490
+ .bk-grid-2,.bk-grid-plz{grid-template-columns:1fr}
491
+ }
492
+
493
+ /* ── Dropdowns: Custom Select & Combobox ──
494
+ Zwei Auswahl-Komponenten über das native <select> hinaus:
495
+ .ep-select — gestylte Einzelauswahl mit Listbox-Popup, Häkchen, Bereichs-Akzent.
496
+ .ep-combobox — Tipp-Filter über langen Listen; .is-multi ergänzt entfernbare Chips.
497
+ Trigger spiegelt .field select (52 px, 2 px --field-border, --r-md); Popup spiegelt .ep-nav-sub
498
+ (bg-surface, --e3, --bd, --r-md). Bereichs-Akzent über --sel-500/--sel-50 (Default = Corporate),
499
+ per [data-area] auf ki/es/wo umschaltbar — wie Buttons/Chips. Der Akzent erscheint NUR im
500
+ gewählten Eintrag (Häkchen + Tönung); Fokusring/Fokusrahmen bleiben neutral-Teal wie bei .field. */
501
+ .ep-select,.ep-combobox{position:relative;margin-bottom:var(--s6);--sel-500:var(--co-700);--sel-50:var(--co-50)}
502
+ .ep-select[data-area="ki"],.ep-combobox[data-area="ki"]{--sel-500:var(--ki-800);--sel-50:var(--ki-50)}
503
+ .ep-select[data-area="es"],.ep-combobox[data-area="es"]{--sel-500:var(--es-700);--sel-50:var(--es-50)}
504
+ .ep-select[data-area="wo"],.ep-combobox[data-area="wo"]{--sel-500:var(--wo-700);--sel-50:var(--wo-50)}
505
+
506
+ /* Label — identische Metriken wie .field label */
507
+ .ep-select-label{display:flex;align-items:center;gap:var(--s2);font:var(--ty-label-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary);margin-bottom:var(--s2)}
508
+
509
+ /* Trigger (Select) / Control (Combobox) — spiegeln .field select */
510
+ .ep-select-trigger,.ep-combobox-control{display:flex;align-items:center;gap:var(--s2);width:100%;min-height:52px;padding:var(--s3) var(--s4);font:var(--ty-body-md);color:var(--tx-primary);background:var(--bg-surface);border:2px solid var(--field-border);border-radius:var(--r-md);transition:border-color var(--m-fast),box-shadow var(--m-fast);text-align:left}
511
+ .ep-select-trigger{justify-content:space-between;cursor:pointer}
512
+ .ep-select-value{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
513
+ /* Platzhalter (noch keine Auswahl): gedämpft wie .field-Placeholder, AA in beiden Modi */
514
+ .ep-select-trigger.is-placeholder .ep-select-value{color:var(--tx-secondary)}
515
+ .ep-select-caret{flex-shrink:0;width:24px;height:24px;color:var(--n-500);stroke:var(--n-500);transition:transform var(--m-fast)}
516
+ .ep-select.is-open .ep-select-caret,.ep-combobox.is-open .ep-select-caret{transform:rotate(180deg)}
517
+
518
+ /* Combobox: textbares Feld im Control, ohne eigenen Rahmen. Chevron + Lösch-Button sind absolut
519
+ und vertikal zentriert (s. u.), daher Platz rechts reservieren (--cb-pad-r). Bei Multi-Select
520
+ umbricht das Control mehrzeilig — die absolute Position hält Chevron/Button trotzdem mittig. */
521
+ .ep-combobox-control{position:relative;cursor:text;padding-right:var(--cb-pad-r,var(--s10))}
522
+ .ep-combobox-control.has-clear{--cb-pad-r:calc(var(--s10) + var(--s8))} /* zusätzlich Platz für den Lösch-Button */
523
+ .ep-combobox-input{flex:1;min-width:0;border:none;outline:none;background:none;font:var(--ty-body-md);color:var(--tx-primary);padding:0}
524
+ .ep-combobox-input::placeholder{color:var(--tx-secondary)}
525
+ /* Chevron absolut, vertikal zentriert über die volle Control-Höhe (Multi umbricht mehrzeilig) */
526
+ .ep-combobox .ep-select-caret{position:absolute;right:var(--s4);top:50%;margin:0;transform:translateY(-50%);cursor:pointer}
527
+ .ep-combobox.is-open .ep-select-caret{transform:translateY(-50%) rotate(180deg)}
528
+ /* Lösch-Button: erscheint (per JS, [hidden] entfernt) sobald Text im Feld steht, leert es mit einem Klick.
529
+ Ebenfalls absolut + vertikal zentriert, links vom Chevron. display:inline-flex (Autor-Regel) schlägt
530
+ das UA-[hidden] → Ausblenden explizit wiederherstellen. */
531
+ .ep-combobox-clear{position:absolute;right:var(--s10);top:50%;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border:none;background:none;color:var(--tx-secondary);border-radius:var(--r-full);cursor:pointer;transition:background var(--m-fast),color var(--m-fast)}
532
+ .ep-combobox-clear:hover{background:var(--bg-overlay);color:var(--tx-primary)}
533
+ .ep-combobox-clear:focus-visible{outline:none;box-shadow:var(--focus-aa)}
534
+ .ep-combobox-clear[hidden]{display:none}
535
+
536
+ /* Fokus — neutral-Teal wie .field (Bereichsfarbe trägt nur der gewählte Eintrag) */
537
+ .ep-select-trigger:focus-visible{outline:none;border-color:var(--co-500);box-shadow:var(--focus-ring)}
538
+ .ep-combobox-control:focus-within{outline:none;border-color:var(--co-500);box-shadow:var(--focus-ring)}
539
+
540
+ /* Popup — gemeinsame Fläche für beide Komponenten, spiegelt .ep-nav-sub */
541
+ .ep-select-menu,.ep-combobox-menu{position:absolute;top:calc(100% + var(--s1));left:0;right:0;z-index:20;display:none;flex-direction:column;gap:2px;max-height:288px;overflow-y:auto;margin:0;padding:var(--s2);list-style:none;background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-md);box-shadow:var(--e3)}
542
+ .ep-select.is-open .ep-select-menu,.ep-combobox.is-open .ep-combobox-menu{display:flex}
543
+ .ep-select-menu:focus,.ep-combobox-menu:focus{outline:none}
544
+
545
+ /* Option — Hover/Tastaturcursor + gewählter Zustand tragen den Bereichs-Akzent (wie .ep-nav-sub-btn) */
546
+ .ep-select-option{display:flex;align-items:center;gap:var(--s2);padding:var(--s2) var(--s3);border-radius:var(--r-sm);font:var(--ty-body-md);color:var(--tx-primary);cursor:pointer;white-space:nowrap;transition:background var(--m-fast),color var(--m-fast)}
547
+ /* display:flex (Autor-Regel) schlägt das UA-[hidden]{display:none} — daher das Ausblenden gefilterter
548
+ bzw. bereits gewählter Optionen explizit wiederherstellen (Attribut-Selektor, höhere Spezifität). */
549
+ .ep-select-option[hidden]{display:none}
550
+ .ep-select-option:hover,.ep-select-option.is-active{background:var(--sel-50);color:var(--sel-500)}
551
+ .ep-select-option[aria-selected="true"]{background:var(--sel-50);color:var(--sel-500);font-weight:600}
552
+ /* Häkchen hält immer seinen Platz (Textbündigkeit), sichtbar nur im gewählten Eintrag */
553
+ .ep-select-check{flex-shrink:0;width:20px;height:20px;color:var(--sel-500);stroke:var(--sel-500);opacity:0}
554
+ .ep-select-option[aria-selected="true"] .ep-select-check{opacity:1}
555
+ .ep-combobox-empty{padding:var(--s2) var(--s3);font:var(--ty-body-sm);color:var(--tx-muted)}
556
+
557
+ /* Multi-Select: gewählte Werte als entfernbare Chips im Control */
558
+ .ep-combobox.is-multi .ep-combobox-control{flex-wrap:wrap;gap:var(--s1);padding:6px var(--cb-pad-r,var(--s10)) 6px var(--s3)}
559
+ .ep-combobox.is-multi .ep-combobox-input{flex:1 0 80px;min-height:28px}
560
+ .ep-combobox-token{display:inline-flex;align-items:center;gap:2px;padding:2px 2px 2px 10px;border-radius:var(--r-full);background:var(--sel-50);color:var(--sel-500);font:var(--ty-label-sm);max-width:100%}
561
+ .ep-combobox-token-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
562
+ .ep-combobox-token-remove{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;flex-shrink:0;border:none;background:none;color:inherit;border-radius:var(--r-full);cursor:pointer;transition:background var(--m-fast)}
563
+ .ep-combobox-token-remove:hover{background:color-mix(in srgb,var(--sel-500) 22%,transparent)}
564
+ .ep-combobox-token-remove:focus-visible{outline:none;box-shadow:var(--focus-aa)}
565
+
566
+ /* Disabled */
567
+ .ep-select.is-disabled .ep-select-trigger,.ep-combobox.is-disabled .ep-combobox-control{opacity:.5;cursor:not-allowed;pointer-events:none}
568
+
569
+ /* ── Typography specimens ── */
570
+ .type-row{display:flex;align-items:baseline;gap:var(--s6);padding:var(--s4) 0;border-bottom:var(--bd)}
571
+ .type-row:last-child{border-bottom:none}
572
+ .type-meta{width:200px;flex-shrink:0;display:flex;flex-direction:column;gap:3px}
573
+ .type-name{font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.07em;color:var(--tx-muted)}
574
+ .type-spec{font:var(--ty-label-xs);color:var(--tx-muted);margin-top:2px}
575
+ /* --co-ink statt co-600: co-600 trug auf Weiß nur 3,29:1 (Normaltext braucht 4,5:1). Das Ink-Token
576
+ flippt mit dem Theme (Light co-700 5,52:1, Dark co-200 11,19:1); ein festes co-700 wäre im Dark
577
+ mit 3,17:1 dunkel-auf-dunkel. */
578
+ .type-rem{font:var(--ty-body-xs);color:var(--co-ink);margin-top:1px}
579
+ .type-token{font:400 0.75rem/1rem var(--font-mono);color:var(--tx-muted);margin-top:2px;letter-spacing:-.01em}
580
+ .type-sample{flex:1;color:var(--tx-primary)}
581
+
582
+ /* ── Spacing ── */
583
+ .sp-item{display:flex;align-items:center;gap:var(--s4);padding:var(--s2) 0}
584
+ .sp-bar{height:20px;background:var(--co-50);border:1px solid var(--co-500);border-radius:2px;flex-shrink:0}
585
+
586
+ /* ── Elevation ── */
587
+ .el-card{background:var(--bg-surface);border-radius:var(--r-lg);padding:var(--s6);width:100%;text-align:center;font:var(--ty-body-md);color:var(--tx-secondary)}
588
+ .el-lbl{font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.07em;color:var(--tx-muted);margin-bottom:var(--s2);display:block}
589
+
590
+ /* ── Nav demo ── */
591
+ .nav-demo{background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--e1)}
592
+ .doc-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin-bottom:var(--s3)}
593
+
594
+ /* ── Snackbar ── */
595
+ .snack{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) var(--s5);border-radius:var(--r-md);font:var(--ty-body-md);max-width:480px;box-shadow:var(--e3);margin-bottom:var(--s3);min-height:48px}
596
+ .snack-def{background:var(--n-700);color:var(--n-0)}
597
+ .snack-ok{background:#0d5e39;color:#d6f5e8}
598
+ .snack-err{background:#7a1515;color:#fde8e8}
599
+ .snack-act{margin-left:auto;background:none;border:none;color:inherit;opacity:.8;font:var(--ty-label-sm);cursor:pointer;text-transform:uppercase;letter-spacing:.04em;padding:0}
600
+
601
+ /* ── Footer ──
602
+ Zwei-Band-Layout: heller Main-Bereich (.footer-main) + dunkler Bottom-Streifen (.footer-btm).
603
+ Beide Bänder voll-breit; Inhalt jeweils auf 1280 px gedeckelt + zentriert
604
+ (analog zum oberen Inhaltsbereich in .ep-page, components.css:454). */
605
+ .footer{display:flex;flex-direction:column}
606
+
607
+ /* Main-Band: neutrales Hellgrau mit dunklem Text. --n-50 #F5F7F7 grenzt sich subtil von der weißen Page-bg ab. */
608
+ .footer-main{background:var(--n-50);color:var(--tx-primary);padding-block:var(--s10);padding-inline:max(var(--s8), calc(50% - 640px))}
609
+
610
+ /* 3-Spalten-Grid: Brand+Kontakt | Wichtige Inhalte | Contentletter (etwas breiter für das Formular) */
611
+ .footer-grid{display:grid;grid-template-columns:1.2fr 1fr 1.3fr;gap:var(--s10)}
612
+
613
+ /* Section-Headlines im Display-Serif. Gleicher Style für Brand, Nav-Header und Contentletter-Header. */
614
+ /* Footer-Headlines auf Title Medium (sans 500, 18/26 px) — der Footer rückt damit visuell in den Hintergrund:
615
+ keine editoriale Serifen-Prominenz mehr, sondern eine ruhige Utility-Typografie. */
616
+ .footer-brand{font:var(--ty-title-sm);color:var(--tx-primary);margin:0 0 var(--s4)}
617
+ .footer-htitle{font:var(--ty-title-sm);color:var(--tx-primary);margin:0 0 var(--s4);text-transform:none;letter-spacing:0}
618
+
619
+ .footer-nav-list{list-style:none;padding:0;margin:0}
620
+ /* Inline-Links auf hellem Footer-bg. --tx-primary auf --n-50 ≈ 9.8:1 ✓ AAA. */
621
+ .footer-link{font:var(--ty-body-md);color:var(--tx-primary);text-decoration:underline;text-underline-offset:3px;padding:0}
622
+ .footer-link:hover{color:var(--co-700)}
623
+ .footer-link:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:2px}
624
+ /* In Nav-Listen: Block-Layout + vertikale Tap-Area. padding 6px 0 ≈ 32 px Tap-Area. */
625
+ .footer-nav-list .footer-link{display:block;padding:6px 0}
626
+
627
+ /* Address-Block: semantisch <address>, Stack aus Adresse / Maps-Links / Telefon-Block. */
628
+ .footer-address{font-style:normal;color:var(--tx-primary);margin:0}
629
+ .footer-address p{font:var(--ty-body-md);margin:0 0 var(--s3)}
630
+ .footer-address-maps{font:var(--ty-body-sm)}
631
+
632
+ /* Body-Link: Inline-Link im Fließtext (Querverweise zwischen Doku-Abschnitten).
633
+ Light: --co-700 #007575 auf #fff = 5.53:1 ✓ AA. Dark-Override in dark-mode.css → --co-200. */
634
+ .body-link{color:var(--co-700);text-decoration:underline;text-underline-offset:2px}
635
+ .body-link:hover{color:var(--co-800)}
636
+ .body-link:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:2px}
637
+ /* Utility: Corporate-Brand-Text mit Dark-Override. */
638
+ .t-co{color:var(--co-700)}
639
+ /* Bereichs-Text-Utilities analog .t-co (Eyebrows, Labels, inline-Akzenttext); ki nutzt -800 (700 verfehlt AA). Dark-Overrides in dark-mode.css heben auf -200/-100. */
640
+ .t-ki{color:var(--ki-800)}
641
+ .t-es{color:var(--es-700)}
642
+ .t-wo{color:var(--wo-700)}
643
+ /* Bereichsgebundene Seiten und Blöcke können den co-Default-Akzent (.t-co an Icons, Bullets, Eyebrows)
644
+ auf ihre Bereichsfarbe umstellen: data-accent am Seiten- oder Bereichs-Container. Nicht an .ep-page
645
+ gebunden, damit auch ein einzelner Block (z.B. ein Buchungsformular in einer Sektion) den Scope
646
+ aufspannen kann. ki nutzt -800 (700 verfehlt AA). */
647
+ [data-accent="ki"] .t-co{color:var(--ki-800)}
648
+ [data-accent="es"] .t-co{color:var(--es-700)}
649
+ [data-accent="wo"] .t-co{color:var(--wo-700)}
650
+ [data-accent="ki"] .body-link{color:var(--ki-800)}
651
+ [data-accent="es"] .body-link{color:var(--es-700)}
652
+ [data-accent="wo"] .body-link{color:var(--wo-700)}
653
+ [data-accent="ki"] .body-link:hover{color:var(--ki-800)}
654
+ [data-accent="es"] .body-link:hover{color:var(--es-800)}
655
+ [data-accent="wo"] .body-link:hover{color:var(--wo-800)}
656
+ /* Footer + Topnav bleiben Chrome (co), auch auf area-getönten Seiten: data-accent tönt nur den
657
+ Seiteninhalt um, nicht die Navigation. Sonst wäre die aktive Sektion (.t-co am Nav-Toggle) z.B. auf
658
+ einer wo-Seite grün statt Petrol — inkonsistent zur Nav aller anderen Seiten.
659
+ Gleiche Spezifität wie die Akzent-Regeln darüber, gewinnen per Quellreihenfolge. */
660
+ [data-accent] .footer .body-link{color:var(--co-700)}
661
+ [data-accent] .footer .body-link:hover{color:var(--co-800)}
662
+ [data-accent] .ep-topnav .t-co{color:var(--co-700)}
663
+
664
+ /* Bottom-Band: dunkler Streifen mit Copyright + Legal links und Social rechts. */
665
+ .footer-btm{background:var(--n-700);color:var(--n-300);padding-block:var(--s4);padding-inline:max(var(--s8), calc(50% - 640px));display:flex;align-items:center;font:var(--ty-body-xs);flex-wrap:wrap;gap:var(--s2) var(--s5)}
666
+ .footer-btm-link{color:var(--n-300);text-decoration:none;padding:6px 0}
667
+ .footer-btm-link:hover{color:var(--n-200);text-decoration:underline}
668
+ .footer-btm-link:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:2px}
669
+
670
+ /* Social-Icons rechtsbündig in der Bottom-Bar. Klick-Target 40x40 (WCAG 2.5.8 AAA), Icon 22x22 px. */
671
+ .footer-social{display:flex;align-items:center;gap:var(--s2)}
672
+ .footer-btm .footer-social{margin-left:auto}
673
+ .footer-social a{display:inline-flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:var(--r-sm);transition:background var(--m-fast)}
674
+ .footer-social a:hover{background:rgba(255,255,255,.08)}
675
+ .footer-social a:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-sm)}
676
+ .footer-social img{max-width:22px;max-height:22px;object-fit:contain;display:block}
677
+
678
+ /* Contentletter-Form (3. Spalte). Sichtbare Labels über jedem Input (Ihr Name / Ihre E-Mail-Adresse).
679
+ Consent vor Submit (DSGVO). Inputs auf weißem Background für ruhigen Kontrast im hellen Main-Band. */
680
+ .footer-newsletter-desc{font:var(--ty-body-md);color:var(--tx-secondary);margin:0 0 var(--s5)}
681
+ .footer-newsletter-form{display:flex;flex-direction:column}
682
+ /* In flex-direction:column streckt der Default align-items:stretch jeden Block auf die volle Spaltenbreite.
683
+ Inputs sollen das (width:100%), aber der Submit-Button soll auf seine natürliche Pill-Breite zurückfallen. */
684
+ .footer-newsletter-form button[type="submit"]{align-self:flex-start}
685
+ .footer-field{display:block;margin-bottom:var(--s4)}
686
+ /* Label folgt der Form-Komponente: uppercase + letter-spacing, --ty-label-sm, --tx-secondary.
687
+ So liest der Footer-Form identisch zu den Kontaktformularen (.field label) und unterscheidet
688
+ sich klar von den Mixed-Case-Headlines (.footer-htitle), die in Title-sm sitzen. */
689
+ .footer-field-label{display:block;font:var(--ty-label-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary);margin-bottom:var(--s2)}
690
+ .footer-newsletter-form input[type="text"],
691
+ .footer-newsletter-form input[type="email"]{display:block;width:100%;border:1px solid var(--field-border);background:var(--bg-surface);padding:0 var(--s3);height:44px;border-radius:var(--r-md);font:var(--ty-body-md);color:var(--tx-primary)}
692
+ /* tx-secondary auf bg-surface = 6,28:1 ✓ AA (Light). tx-muted wäre 3,92:1, knapp unter AA. */
693
+ .footer-newsletter-form input::placeholder{color:var(--tx-secondary)}
694
+ /* Focus-Ring auf Token: var(--focus-ring) ist Dual-Shadow (--co-50 außen, --co-500 innen) und
695
+ AA-konsistent mit allen anderen Form-Komponenten (.field, .footer-link, .footer-btm-link). */
696
+ .footer-newsletter-form input:focus{outline:none;border-color:var(--co-500);box-shadow:var(--focus-ring)}
697
+ /* Error-State, analog zu .field.has-error: --c-error-Border + Inline-Fehlertext mit Icon. */
698
+ .footer-field.has-error input{border-color:var(--c-error)}
699
+ .footer-field .error-msg{display:flex;gap:var(--s2);align-items:center;font:var(--ty-body-sm);color:var(--c-error);margin-top:var(--s2)}
700
+ /* Consent als <label> mit Checkbox + Text — implizite Verknüpfung, keine IDs nötig (Footer in 10 Tabpanels). */
701
+ .footer-newsletter-consent{display:flex;align-items:flex-start;gap:var(--s2);font:var(--ty-body-sm);color:var(--tx-secondary);cursor:pointer;margin-bottom:var(--s4)}
702
+ .footer-newsletter-consent input[type="checkbox"]{width:16px;height:16px;margin-top:2px;accent-color:var(--co-500);flex-shrink:0;cursor:pointer}
703
+ /* Konsistenter Focus-Ring (Cutout-Effekt) statt Browser-Default — passt zu Footer-Links und Submit-Button. */
704
+ .footer-newsletter-consent input[type="checkbox"]:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:2px}
705
+
706
+ /* Mobile (< 768px): Footer-Grid stapelt einspaltig, Bottom-Bar bleibt Flex-Wrap.
707
+ Padding-block etwas reduziert für kompakte Höhe auf Mobile. */
708
+ @media (max-width: 768px) {
709
+ .footer-grid{grid-template-columns:1fr;gap:var(--s8)}
710
+ .footer-main{padding-block:var(--s8)}
711
+ .footer-btm .footer-social{margin-left:0}
712
+ }
713
+ /* Tablet (769–1024px): Zwischenstufe für fix-spaltige Layouts, damit sie nicht direkt
714
+ von voller Desktop-Breite auf 1-spaltig springen. Die auto-fit-Grids (.ep-cards,
715
+ .a11y-grid, .card-stat-strip, .ep-tabs) regeln diesen Bereich bereits selbst — daher
716
+ hier nur der 3-spaltige Footer auf 2 Spalten. */
717
+ @media (min-width: 769px) and (max-width: 1024px) {
718
+ .footer-grid{grid-template-columns:1fr 1fr;gap:var(--s8) var(--s10)}
719
+ }
720
+
721
+ /* ── A11y ── */
722
+ .a11y-card{background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-lg);padding:var(--s5);margin-bottom:var(--s4)}
723
+ .a11y-card h3{font:var(--ty-title-sm);margin-bottom:var(--s2)}
724
+ .a11y-card p{font:var(--ty-body-md);color:var(--tx-secondary);margin-bottom:var(--s3)}
725
+ .a11y-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:var(--s4);margin-bottom:var(--s4)}
726
+ .a11y-grid .a11y-card{margin-bottom:0}
727
+ .a11y-kbd{display:inline-block;background:var(--n-100);border:1px solid var(--n-300);border-radius:4px;padding:2px 7px;font-family:var(--font-mono);font-size:0.75rem;color:var(--tx-primary);box-shadow:0 1px 0 var(--n-300)}
728
+ .a11y-table{width:100%;border-collapse:collapse;font:var(--ty-body-md);margin:var(--s3) 0}
729
+ .a11y-table th{text-align:left;padding:var(--s2) var(--s3);background:var(--n-50);border-bottom:2px solid var(--n-200);font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary)}
730
+ .a11y-table td{padding:var(--s2) var(--s3);border-bottom:var(--bd);vertical-align:top;line-height:1.5}
731
+ .a11y-table tr:last-child td{border-bottom:none}
732
+ .a11y-rule{display:flex;gap:var(--s3);align-items:flex-start;padding:var(--s3) 0;border-bottom:var(--bd)}
733
+ .a11y-rule:last-child{border-bottom:none}
734
+ .a11y-rule-icon{width:24px;height:24px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-size:0.875rem;font-weight:700;flex-shrink:0;margin-top:1px}
735
+ .a11y-ok .a11y-rule-icon{background:#E6F9F1;color:#0a5c38}
736
+ .a11y-fail .a11y-rule-icon{background:#FDEAEA;color:#9b2020}
737
+ .code-block{background:var(--bg-code);color:#c4e8b8;border-radius:var(--r-md);padding:var(--s4);font-family:var(--font-mono);font-size:0.8125rem;line-height:1.6;overflow-x:auto;margin:var(--s3) 0}
738
+ .code-block .k{color:#79b8ff}.code-block .v{color:#00BEBE}.code-block .s{color:#f0c070}.code-block .c{color:#739373}/* Kommentarfarbe: #6a8a6a trug auf --bg-code nur 4,43:1 und verfehlte AA knapp. Farbton und Saettigung bleiben, nur heller: Light 4,99:1, Dark 5,84:1. */
739
+ /* ── Code-Block Komponente (Wissensbeitrag) ── */
740
+ .cb-wrap{border-radius:var(--r-sm);overflow:hidden;border:1px solid var(--n-200);margin:var(--s3) 0}
741
+ .cb-header{display:flex;align-items:center;justify-content:space-between;padding:var(--s2) var(--s5);background:var(--n-100);border-bottom:1px solid var(--n-200)}
742
+ .cb-lang{font:var(--ty-label-xs-strong);text-transform:uppercase;letter-spacing:.08em;color:var(--co-700)}
743
+ .cb-copy{background:none;border:1px solid var(--n-200);border-radius:var(--r-xs);color:var(--n-500);font:var(--ty-label-xs);font-family:var(--font);padding:3px 10px;cursor:pointer;transition:background var(--m-fast),color var(--m-fast)}
744
+ .cb-copy:hover{background:var(--n-200);color:var(--n-600)}
745
+ .cb-copy:focus-visible{outline:none;box-shadow:var(--focus-aa)}
746
+ .cb-body{background:var(--n-50);padding:var(--s5) var(--s6);overflow-x:auto;font-family:var(--font-mono);font-size:0.8125rem;line-height:1.7;color:var(--n-700);margin:0;white-space:pre}
747
+ /* Semantisches <code> im <pre> (a11y): der Browser-Default (code{font-family:monospace})
748
+ würde sonst eine andere Schrift als der Rest des Blocks zeigen, obwohl .cb-body die
749
+ Schrift schon per var(--font-mono) setzt. font:inherit gleicht das exakt an. */
750
+ .cb-body code{font:inherit}
751
+ /* .cb-body ist jetzt per tabindex="0" fokussierbar (horizontales Scrollen per Tastatur).
752
+ Der Ring sitzt auf .cb-wrap statt auf .cb-body selbst: .cb-wrap clippt per overflow:hidden
753
+ die Ecken, ein box-shadow-Ring direkt auf .cb-body würde dort abgeschnitten. Gleiches
754
+ :has()-Muster wie bei .seg weiter oben in dieser Datei. */
755
+ .cb-body:focus-visible{outline:none}
756
+ .cb-wrap:has(.cb-body:focus-visible){box-shadow:var(--focus-ring)}
757
+ /* .c = Kommentar. Vorher n-400 (#6E8585), das auf dem n-50-Grund der Blöcke nur 3,65:1 trug.
758
+ --tx-muted ist theme-aware und semantisch die gedämpfte Stufe: Light 4,51:1, Dark 8,9:1.
759
+ Wer --tx-muted oder --n-50 anfasst, prüft diesen Wert mit, die Reserve ist knapp. */
760
+ .cb-body .k{color:var(--es-600)}.cb-body .v{color:var(--co-700)}.cb-body .s{color:var(--wo-600)}.cb-body .c{color:var(--tx-muted)}.cb-body .fn{color:var(--ro-600)}
761
+ /* Zeilennummern */
762
+ .cb-body.cb-numbered{line-height:0}
763
+ .cb-numbered .cb-ln{display:flex;gap:var(--s3);line-height:1.6}
764
+ .cb-numbered .cb-ln::before{content:attr(data-n);color:var(--n-300);font-size:0.75rem;min-width:20px;text-align:right;flex-shrink:0;user-select:none}
765
+ /* Terminal */
766
+ .cb-terminal .cb-header{background:#080f08}
767
+ .cb-terminal .cb-lang{color:#5CE8A0}
768
+ .cb-terminal .cb-body{background:#0b110b;color:#b8d8b8}
769
+ /* Die Terminal-Variante hat einen fest dunklen Grund in BEIDEN Modi. Der theme-aware --tx-muted
770
+ der Standard-Blöcke liegt hier im Light bei 3,94:1 und verfehlt AA. Deshalb der nicht flippende
771
+ n-400 (4,87:1 in beiden Modi). Heute steht in keinem Terminal-Block ein Kommentar, die Regel
772
+ verhindert, dass die Kombination später still durchfällt. */
773
+ .cb-terminal .cb-body .c{color:var(--n-400)}
774
+ .cb-terminal .cb-prompt{color:#5CE8A0;user-select:none}
775
+ /* Deckkraft .65, nicht .55: auf dem Terminal-Grund trug .55 nur 4,20:1, .65 gibt 5,07:1.
776
+ Die Ausgabe bleibt damit sichtbar gedämpft gegenüber dem Prompt, erfüllt aber AA. */
777
+ .cb-terminal .cb-out{color:rgba(180,210,180,.65)}
778
+ /* Kopier-Button im Terminal: der neutrale n-500 der hellen Variante trägt auf dem dunklen
779
+ Terminal-Header nur 3,09:1. n-200 gibt 12,70:1 und passt zur hellen Schrift daneben. */
780
+ .cb-terminal .cb-copy{color:var(--n-200)}
781
+ /* Inline code in Fließtext */
782
+ .cb-prose code{font-family:var(--font-mono);font-size:.875em;background:var(--co-50);color:var(--co-700);padding:2px 6px;border-radius:var(--r-xs);border:1px solid var(--co-100)}
783
+ .contrast-row{display:flex;align-items:center;gap:var(--s3);padding:var(--s3) 0;border-bottom:var(--bd);flex-wrap:wrap}
784
+ .contrast-row:last-child{border-bottom:none}
785
+ /* Keine Doppellinie: folgt direkt eine Gruppen-Überschrift (mit eigenem border-top als Trenner),
786
+ lässt die letzte Zeile ihre Unterlinie weg — sonst stehen zwei parallele Linien untereinander. */
787
+ .contrast-row:has(+ .group-title){border-bottom:none}
788
+ .cswatch{width:48px;height:48px;border-radius:var(--r-md);flex-shrink:0;display:flex;align-items:center;justify-content:center;font-weight:700;font-size:0.875rem}
789
+ .cinfo{flex:1;min-width:160px}
790
+ .cname{font:var(--ty-label-md)}
791
+ .cratio{font-size:0.8125rem;color:var(--tx-secondary);font-family:var(--font-mono)}
792
+ .cbadge{display:inline-flex;align-items:center;padding:3px var(--s2);border-radius:var(--r-full);font:var(--ty-label-xs)}
793
+ .c-aa{background:var(--cbadge-aa-bg);color:var(--cbadge-aa-text)}
794
+ .c-aaa{background:var(--cbadge-aaa-bg);color:var(--cbadge-aaa-text)}
795
+ .c-fail-badge{background:var(--cbadge-fail-bg);color:var(--cbadge-fail-text)}
796
+ /* Modus-Pill für Kontrast-Zeilen. Macht explizit, ob ein Kontrast-Wert sich auf Light, Dark oder beide Themes bezieht.
797
+ Neutral gestaltet (Border statt Fill), damit das WCAG-Badge daneben optisch dominiert. */
798
+ .a11y-mode{display:inline-flex;align-items:center;padding:1px 7px;border-radius:var(--r-full);font:var(--ty-label-xs);letter-spacing:.04em;border:var(--bd);background:transparent;color:var(--tx-secondary);margin-right:var(--s2);vertical-align:middle;white-space:nowrap}
799
+
800
+ /* ── Slider ── */
801
+ .field-slider{display:flex;flex-direction:column;gap:var(--s2);--sl-thumb:22px}
802
+ .field-slider-header{display:flex;justify-content:space-between;align-items:baseline;gap:var(--s2)}
803
+ .field-slider-label{font:var(--ty-label-sm);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary)}
804
+ .field-slider-output{font:600 0.875rem/1.25rem var(--font);color:var(--sl-text,var(--co-700));min-width:56px;text-align:right}
805
+ /* Ticks exakt auf die Thumb-Position ausgerichtet: der Thumb-Mittelpunkt läuft von
806
+ --sl-thumb/2 bis (Breite − --sl-thumb/2). Jeder Tick trägt --tick-p (0..1) als
807
+ Bruchteil des Wertebereichs und wird über seiner Mitte zentriert. (Früher
808
+ justify-content:space-between → Label-Mitten trafen die Positionen nicht.) */
809
+ .field-slider-ticks{position:relative;height:16px;font:var(--ty-caption);color:var(--tx-muted)}
810
+ .field-slider-ticks>*{position:absolute;transform:translateX(-50%);white-space:nowrap;left:calc(var(--sl-thumb) / 2 + var(--tick-p, 0) * (100% - var(--sl-thumb)))}
811
+ .slider{-webkit-appearance:none;appearance:none;width:100%;height:4px;border-radius:var(--r-full);background:var(--n-200);outline:none;cursor:pointer;display:block;margin:var(--s3) 0 var(--s1)}
812
+ .slider::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;width:var(--sl-thumb);height:var(--sl-thumb);border-radius:50%;background:var(--sl-color,var(--co-500));border:3px solid var(--bg-surface);box-shadow:var(--e2);cursor:pointer;transition:transform var(--m-fast),box-shadow var(--m-fast)}
813
+ .slider::-moz-range-thumb{width:var(--sl-thumb);height:var(--sl-thumb);border-radius:50%;background:var(--sl-color,var(--co-500));border:3px solid var(--bg-surface);box-shadow:var(--e2);cursor:pointer;transition:transform var(--m-fast),box-shadow var(--m-fast);box-sizing:border-box}
814
+ .slider:hover:not(:disabled)::-webkit-slider-thumb{transform:scale(1.2);box-shadow:var(--e3)}
815
+ .slider:hover:not(:disabled)::-moz-range-thumb{transform:scale(1.2);box-shadow:var(--e3)}
816
+ .slider:focus-visible{outline:none;box-shadow:var(--focus-ring)}
817
+ .slider:disabled{opacity:.38;cursor:not-allowed}
818
+ /* --sl-color = Thumb (helle Markenfarbe, grafisch: 3:1 genügt) · --sl-text = Wert-Anzeige
819
+ (Normaltext 14px/600 → 4,5:1 nötig, daher dunklere Töne; -500 fiel bis 2,3:1 durch, WCAG 1.4.3) */
820
+ .slider-co{--sl-color:var(--co-500);--sl-text:var(--co-700)} /* co-700 #007575 = 5,5:1 */
821
+ .slider-ki{--sl-color:var(--ki-700);--sl-text:var(--ki-800)} /* ki-800 #475705 = 8,0:1 (ki-700 nur 4,35:1) */
822
+ .slider-es{--sl-color:var(--es-500);--sl-text:var(--es-700)} /* es-700 #1B3D9A = 9,6:1 */
823
+ .slider-wo{--sl-color:var(--wo-500);--sl-text:var(--wo-700)} /* wo-700 #285E1A = 7,8:1 (wo-500 nur 3,3:1) */
824
+
825
+ /* ── Bild-Slider (Carousel) ── */
826
+ /* Basis: Crossfade — alle Slides als Grid-Items in derselben Zelle übereinander gestapelt; aktive Slide trägt .active und ist sichtbar */
827
+ .img-slider{position:relative;border-radius:var(--r-lg);overflow:hidden;user-select:none}
828
+ .img-slider-track{display:grid;grid-template-columns:1fr;grid-template-rows:1fr}
829
+ .img-slide{grid-column:1/-1;grid-row:1/-1;opacity:0;transition:opacity 600ms ease;pointer-events:none}
830
+ .img-slide.active{opacity:1;pointer-events:auto}
831
+ .img-slide-media{width:100%;aspect-ratio:16/9;display:flex;align-items:center;justify-content:center;overflow:hidden;background:var(--n-100)}
832
+ .img-slide-media img{width:100%;height:100%;object-fit:cover;display:block}
833
+ .img-slide-caption{padding:var(--s4) var(--s6);background:var(--bg-surface);border-top:var(--bd);min-height:112px;overflow:hidden}
834
+ .img-slide-caption-title{font:var(--ty-serif-md);color:var(--tx-primary);margin:0 0 var(--s1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
835
+ .img-slide-caption-text{font:var(--ty-body-md);color:var(--tx-secondary);margin:0;display:-webkit-box;-webkit-line-clamp:2;line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
836
+ .img-slider-btn{position:absolute;top:calc(50% - 28px);transform:translateY(-50%);width:44px;height:44px;border-radius:50%;background:rgba(255,255,255,.9);backdrop-filter:blur(4px);border:none;box-shadow:var(--e2);display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:2;transition:background var(--m-fast),box-shadow var(--m-fast);color:#333E48}/* Kreis ist in beiden Modi fest weiß → Chevron fest dunkel (nicht tx-primary, das im Dark auf hell flippt → hell-auf-weiß) */
837
+ .img-slider-btn:hover{background:#fff;box-shadow:var(--e3)}
838
+ .img-slider-btn:focus-visible{outline:none;box-shadow:var(--focus-ring)}
839
+ .img-slider-prev{left:var(--s4)}
840
+ .img-slider-next{right:var(--s4)}
841
+ .img-slider-dots{display:flex;justify-content:center;padding:var(--s4) 0;background:var(--bg-surface);position:relative;z-index:2}
842
+ /* Dot-Pattern: 24×24 Hit-Area (WCAG 2.5.5 AA) + 12×12 sichtbarer Punkt via ::before, gap:0 */
843
+ .img-dot{width:24px;height:24px;border-radius:50%;border:none;background:transparent;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center}
844
+ .img-dot::before{content:'';width:12px;height:12px;border-radius:50%;background:var(--n-200);transition:background var(--m-fast),transform var(--m-fast)}
845
+ .img-dot:hover::before{background:var(--n-400)}
846
+ .img-dot.active::before{background:var(--co-500);transform:scale(1.25)}
847
+ .img-dot:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:50%}
848
+ /* Hero-Variante — vollflächig, 21:9-Format, Caption als Overlay über dem Bild */
849
+ .img-slider-hero{border-radius:0}
850
+ .img-slider-hero .img-slider-track{aspect-ratio:21/9;min-height:300px;max-height:clamp(480px,75vh,900px)}
851
+ .img-slider-hero .img-slide-media{height:100%;aspect-ratio:auto;min-height:0}
852
+ .img-slider-hero .img-slide-caption{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(to top,rgba(0,0,0,.72) 0%,transparent 100%);border-top:none;padding:var(--s10) var(--s8) var(--s10);height:auto;overflow:visible}
853
+ .img-slider-hero .img-slide-caption-title{color:#fff;font-size:clamp(1.25rem, 0.943rem + 1.36vw, 2rem);line-height:1.25}
854
+ .img-slider-hero .img-slide-caption-text{color:rgba(255,255,255,.8);height:auto;overflow:visible}
855
+ .img-slider-hero .img-slider-btn{top:50%}
856
+ .img-slider-hero .img-slider-dots{position:absolute;bottom:var(--s4);left:0;right:0;background:none;border:none;padding:0}
857
+ .img-slider-hero .img-dot::before{background:rgba(255,255,255,.35)}
858
+ .img-slider-hero .img-dot.active::before{background:#fff}
859
+
860
+ /* ── Hero-Image (statische Variante der Slider-Hero, ohne Track/Buttons/Dots) ── */
861
+ .hero-image{position:relative;overflow:hidden;margin:0}
862
+ .hero-image-media{width:100%;aspect-ratio:21/9;min-height:300px;max-height:clamp(480px,75vh,900px);overflow:hidden;background:var(--n-100);display:flex;align-items:center;justify-content:center}
863
+ .hero-image-media img{width:100%;height:100%;object-fit:cover;display:block}
864
+ /* Scrim über dem Hero-Foto. Zwei Anforderungen, die sich gegenseitig begrenzen:
865
+
866
+ (1) KONTRAST. Der Eyebrow ist das erste Kind und sitzt damit im obersten, schwächsten Abschnitt
867
+ des Verlaufs. Mit dem früheren Verlauf (.85 / .65 bei 50% / transparent) stand er dort auf Alpha
868
+ 0,30: über einer ausgebrannt hellen Bildstelle sind das 1,90:1, gemessen lagen bis zu 63% der
869
+ Eyebrow-Fläche unter 4,5:1. Der text-shadow hilft optisch, zählt für WCAG nicht.
870
+
871
+ (2) KEINE SICHTBARE KANTE. Ein Verlauf wird nicht dort auffällig, wo er steil ist, sondern dort,
872
+ wo seine Steilheit springt. Entscheidend ist die Rate, mit der die Deckkraft an der OBERKANTE
873
+ einsetzt. Gemessen am gerenderten Bild (zweite Ableitung der Zeilenhelligkeit, über die Breite
874
+ gemittelt): früherer Verlauf 7,9. Ein Zwischenstand, der die Deckkraft auf kurzer Strecke aufbaute,
875
+ kam auf 21 bis 25 und zeichnete eine sichtbare Linie quer durchs Bild, unabhängig davon, wie viele
876
+ Stützstellen er hatte. Mehr Stops helfen also nicht.
877
+
878
+ Was hilft, ist eine längere Auslaufstrecke: die Deckkraft muss über genügend Pixel von 0 auf ihren
879
+ Wert kommen. Der Text endet 132px über der Unterkante; mit 96px Polsterung darüber ist der Kasten
880
+ 228px hoch, der Eyebrow sitzt bei 58%, und der Auslauf läuft mit 0,0066 pro Pixel, also etwas
881
+ sanfter als beim früheren Verlauf (0,0076). Gemessene Kantigkeit 9,2 gegenüber 7,9. Deckkraft am
882
+ Eyebrow 0,63 statt 0,30.
883
+
884
+ Die Polsterung ist fluide, weil 96px auf einem 300px hohen Mobil-Hero zu viel wären. */
885
+ .hero-image-caption{position:absolute;bottom:0;left:0;right:0;background:linear-gradient(to top,rgba(0,0,0,.85) 0%,rgba(0,0,0,.63) 58%,transparent 100%);padding:clamp(var(--s10), 6.7vw, calc(var(--s16) + var(--s8))) var(--s8) var(--s10);margin:0}
886
+ .hero-image-caption-eyebrow{font:var(--ty-label-xs);letter-spacing:.12em;text-transform:uppercase;color:rgba(255,255,255,.85);margin:0 0 var(--s2);text-shadow:0 1px 2px rgba(0,0,0,.5)}
887
+ .hero-image-caption-title{font:var(--ty-serif-md);color:#fff;font-size:clamp(1.25rem, 0.943rem + 1.36vw, 2rem);line-height:1.25;margin:0 0 var(--s1);text-shadow:0 1px 3px rgba(0,0,0,.4)}
888
+ .hero-image-caption-text{font:var(--ty-body-md);color:rgba(255,255,255,.92);margin:0;text-shadow:0 1px 2px rgba(0,0,0,.5)}
889
+
890
+ /* ── Störer (Hero-Overlay, Startseite) ──
891
+ Kompakte Verweiskacheln auf je einen aktuellen Inhalt: nächste Veranstaltung, neuer
892
+ Wissensbeitrag, Pressemitteilung, Info (neue Seminar-Landingpage, neues Produkt). Ein bis
893
+ drei Kacheln als Set oben rechts über dem Hero-Bild, Default sind zwei. Der Wrapper
894
+ .stoerer-hero umschließt Hero + Set und spannt den Positionsrahmen auf; .hero-image bleibt
895
+ unangetastet und funktioniert weiter ohne Störer.
896
+
897
+ VIER ENTSCHEIDUNGEN, DIE ABSICHT SIND
898
+
899
+ (1) EINE FARBE FÜR ALLE VIER TYPEN. Der Inhaltstyp steht im Label und im Icon, nicht in der
900
+ Fläche. Vier Bereichsfarben nebeneinander würden gegeneinander und gegen die Hero-Headline
901
+ arbeiten; die Kacheln sind ein Set und müssen als eines lesen. Der Akzent ist deshalb
902
+ durchgehend Corporate (--co-ink), wie bei der Topnav: der Störer ist Chrome über dem Bild,
903
+ kein Bereichsinhalt. Aus demselben Grund gibt es hier kein data-area.
904
+
905
+ (2) DECKENDE FLÄCHE, KEIN GLAS. Über einem Foto ist der Grund unbekannt: eine
906
+ halbtransparente Kachel trägt je nach Bildstelle 2:1 oder 12:1, und keine Regel kann das
907
+ absichern (der Grund steht nicht in der Elternkette, `npm run check:contrast` zählt solchen
908
+ Text nur, statt ihn zu werten). Auf --bg-surface steht der Text dagegen auf einer bekannten
909
+ Fläche: Light 5,52 bis 10,90:1, Dark 8,32 bis 10,48:1. Das Bild bleibt sichtbar, weil die
910
+ Kacheln klein sind, nicht weil sie durchscheinen.
911
+
912
+ (3) RAHMEN IN BEIDEN MODI. Karten im DS verlassen sich im Light auf --e1 und bekommen erst
913
+ im Dark einen Rahmen (CONTRIBUTING §5). Hier liegt die Kachel aber auf einem Foto statt auf
914
+ einer bekannten Fläche: auf einer ausgebrannt hellen Bildstelle trägt der schwarze Schatten
915
+ nichts mehr, und die weiße Kachel hat dort keine Kante. Deshalb --bd-strong schon im Light.
916
+
917
+ (4) OVERLAY NACH HERO-BREITE, NICHT NACH VIEWPORT-BREITE. Bei 21:9 gilt Hero-Höhe = Breite
918
+ × 9/21 (der max-height-Deckel liegt bei mindestens 480px und greift hier nie). Eine Kachel ist
919
+ 126px hoch (12px Polsterung, 100px Inhalt, 1px Rand je Seite), drei Kacheln plus zwei Abstände
920
+ und 24px Rand oben brauchen 426px Hero-Höhe, also 994px Hero-Breite. Ob die vorhanden ist, sagt
921
+ die Breite des Heros und nicht die des Fensters: mit einer Media Query auf 1025px ragte ein
922
+ Dreier-Set in der Doku-Vorschau (Hero 898px im 1200px-Fenster) 41px in die Sub-Sektion. Die
923
+ Entscheidung hängt deshalb an einer Container-Query auf .stoerer-hero. Darunter steht das Set
924
+ als normaler Block unter dem Hero; eine Kachel, die halb in die Sub-Sektion ragt, ist kein
925
+ Overlay mehr, sondern ein Unfall. Die Schwelle liegt bei 1025px, dem Desktop-Tier der
926
+ Responsive-Strategie, und damit über dem Rechenwert von 994px. Ohne Container-Query-Support
927
+ greift die Regel nicht und das Set bleibt in jeder Breite ein Block unter dem Hero, also der
928
+ funktionierende Fall.
929
+
930
+ MASSE IN REM, NICHT PX (WCAG 1.4.4). Die Schwelle stand zuerst als 1025px da und skalierte damit
931
+ nicht mit der Browser-Standardschriftgröße: bei 200% Textgröße wuchs die Kachel von 126 auf 290px,
932
+ das Overlay blieb aber an und ragte gemessen 96px in die Sub-Sektion. In rem (64,0625rem = 1025px
933
+ bei Default-Wurzel) wandert die Schwelle mit: bei 200% verlangt sie 2050px Hero-Breite, das Set
934
+ fällt also in den Block-Zweig, statt kaputt zu überlappen. Dieselbe Rechnung gilt für die
935
+ Kachelbreite (22,5rem) und das Grid-Minimum (16,25rem). */
936
+ .stoerer-hero{position:relative;container-type:inline-size;--stoerer-w:22.5rem}
937
+ .stoerer-set{padding:var(--s8)}
938
+ .ep-page .stoerer-set{padding-inline:max(var(--s8),calc(50% - 640px))}
939
+ /* Mobil derselbe Innenabstand wie .ep-section: 32 → 24px. Im Block-Zweig steht das Set in der
940
+ Sektionslogik der Seite, nicht mehr als Overlay, und folgt deshalb deren Rhythmus. */
941
+ @media(max-width:768px){
942
+ .stoerer-set,.ep-page .stoerer-set{padding-inline:var(--s6)}
943
+ }
944
+ /* min(16.25rem,100%) statt 16.25rem als Boden: bei 320px Viewport (WCAG 1.4.10 Reflow) ist der
945
+ Grund nur 256px breit, ein starrer 260px-Boden ragte dort in die Polsterung. Mit min() weicht die
946
+ Spalte auf 100% aus, statt den Grund zu sprengen. */
947
+ .stoerer-list{list-style:none;display:grid;grid-template-columns:repeat(auto-fit,minmax(min(16.25rem,100%),1fr));gap:var(--s3)}
948
+ /* Die Kachel IST der klickbare Bereich, trägt also Elevation (CONTRIBUTING §4). Eine Spalte:
949
+ Thema, Titel, Meta. Das Typ-Glyph sitzt IM Thema-Label, nicht in einer eigenen Spalte rechts.
950
+
951
+ WARUM NICHT RECHTS, MIT TRENNER
952
+ Material trennt die Slots einer Listenzeile nach Aufgabe: das Leading-Element „represents the
953
+ item's subject or category“, das Trailing-Element trägt „secondary information, actions, or status
954
+ indicators“. Unser Glyph ist ein reiner Typ-Marker, also eine Kategorie, und gehört damit nach
955
+ vorn. Rechts hinter einer Trennlinie stand es im Slot für Aktionen und Status, auf einer
956
+ vollständig klickbaren Kachel also doppeldeutig: es kann als Button lesen.
957
+ NN/g ergänzt die andere Richtung: „a text label must be present alongside an icon to clarify its
958
+ meaning“. Die Bedeutung trägt das Label, das Glyph ist Wiedererkennungshilfe, und die wirkt am
959
+ besten direkt neben dem Wort, das sie doppelt.
960
+ Messbarer Nebengewinn: ohne Icon-Spalte (24px Glyph + 16px Polsterung + 1px Trenner + 16px
961
+ Spaltenabstand = 57px) wächst die Textspalte von 269 auf 326px, also um 21%. Damit klammern die
962
+ realistischen Titel der Startseite nicht mehr. Die Kachelhöhe bleibt bei 126px, weil das 16px-Glyph
963
+ in die 16px hohe Label-Zeile passt.
964
+ Preis: das Glyph wird stiller (16px statt 24px, Stroke micro statt sm). Das ist vertretbar, weil es
965
+ aria-hidden ist und nichts trägt, was das Label nicht schon sagt. Wer einen kräftigen Typ-Marker
966
+ braucht, setzt ihn ins Leading, oben auf Label-Höhe, nicht zurück nach rechts. */
967
+ .stoerer{display:flex;flex-direction:column;gap:var(--s1);padding:var(--s3) var(--s4);border-radius:var(--r-md);background:var(--bg-surface);border:var(--bd-strong);box-shadow:var(--e1);text-decoration:none;color:inherit;transition:box-shadow var(--m-fast),transform var(--m-fast),background var(--m-fast)}
968
+ .stoerer:hover{background:var(--bg-surface-hover);box-shadow:var(--e3);transform:translateY(-2px)}
969
+ /* Zweites Hover-Signal, das nicht an Farbe oder Schatten hängt: über einem Foto ist der
970
+ Schatten-Zuwachs je nach Bildstelle kaum zu sehen, die Unterstreichung immer. */
971
+ .stoerer:hover .stoerer-title>*{text-decoration:underline;text-underline-offset:2px}
972
+ .stoerer:focus-visible{outline:none;box-shadow:var(--focus-ring),var(--e3)}
973
+ /* Thema-Zeile trägt das Glyph als Leading-Element. align-items:center stimmt optisch, solange das
974
+ Label einzeilig bleibt, und das ist die Regel (ein bis drei Wörter). */
975
+ .stoerer-topic{display:flex;align-items:center;gap:var(--s2);font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--co-ink)}
976
+ /* Zwei Zeilen fest: min-height reserviert die Höhe, das innere Element kappt längere Titel per
977
+ line-clamp mit Auslassungszeichen. Beides zusammen hält alle Kacheln eines Sets auf gleicher
978
+ Höhe, unabhängig von der Titellänge im CMS (dieselbe Mechanik wie .card-title). */
979
+ .stoerer-title{font:var(--ty-title-sm);color:var(--tx-primary);min-height:2lh}
980
+ .stoerer-title>*{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;line-clamp:2;overflow:hidden}
981
+ .stoerer-meta{font:var(--ty-body-sm);color:var(--tx-secondary)}
982
+ /* 16px = Micro auf der Icon-Skala, dort gehört Stroke 1 dazu (24px trüge 1.25). Farbe erbt das
983
+ Glyph vom Thema-Label über currentColor, es braucht keine eigene. */
984
+ .stoerer-icon{width:16px;height:16px;flex-shrink:0;stroke-width:var(--icon-stroke-micro)}
985
+
986
+ @container (min-width:64.0625rem){
987
+ /* Overlay oben rechts: die Caption liegt unten links, die Sub-Sektion darunter, oben rechts
988
+ ist die freie Zone. Der Abstand liegt in top/right statt im Padding, sonst wächst die
989
+ absolut positionierte Box über die Kachelbreite hinaus. */
990
+ .stoerer-set,.ep-page .stoerer-set{position:absolute;top:var(--s6);right:var(--s8);padding:0}
991
+ .ep-page .stoerer-set{right:max(var(--s8),calc(50% - 640px))}
992
+ .stoerer-list{display:flex;flex-direction:column;width:var(--stoerer-w)}
993
+ /* Die Caption-Spalte endet vor den Kacheln, sonst läuft eine lange Headline darunter.
994
+ max-width auf die Kinder, nicht Padding auf die Caption: der Gradient bleibt vollbreit.
995
+ Der .stoerer-hero-Präfix bleibt stehen, obwohl derzeit nur .stoerer-hero ein Container ist:
996
+ sonst greift die Regel auf jeden Hero, sobald irgendein Vorfahre ein Container wird. */
997
+ .stoerer-hero .hero-image-caption>*{max-width:calc(100% - var(--stoerer-w) - var(--s6))}
998
+ }
999
+
1000
+ @media(prefers-reduced-motion:reduce){.img-slide{transition:none}}
1001
+
1002
+ /* ── Logo-Tiles (geteilt vom Logo-Karussell) ── */
1003
+ /* Logos sitzen randlos auf der weißen Platte (.logo-carousel) — keine Einzel-Box, kein Hover-Lift:
1004
+ Logos sind nicht klickbar, ein Lift wäre falsche Interaktions-Andeutung („Elevation = Interaktivität“).
1005
+ Einheitliche, großzügige Logo-Höhe (100px) statt der alten 72px-Kachel mit nur ~48px nutzbarer Höhe. */
1006
+ .logo-tile{flex-shrink:0;display:flex;align-items:center;justify-content:center;padding:var(--s2) var(--s4)}
1007
+ .logo-tile img{max-height:100px;max-width:100%;width:auto;height:auto;object-fit:contain}
1008
+ .logo-placeholder{font:700 1rem/1.2 var(--font);letter-spacing:.04em;color:var(--n-500);text-align:center;user-select:none}
1009
+
1010
+ /* ── Logo-Carousel: diskrete Sets von 5 Logos, automatischer Crossfade, pausierbar ── */
1011
+ /* Helle Platte in BEIDEN Modi: Kundenlogos liegen oft farbig oder dunkel vor und haben keine
1012
+ Dark-Variante, auf theme-reaktivem Grund würden sie im Dark unsichtbar. Die Platte bleibt also
1013
+ hell, wird im Dark aber über --bg-plate gedämpft (#E8EDED statt #FFFFFF): eine reinweiße Fläche
1014
+ dieser Größe stünde mit 17,51:1 gegen die Seite und blendet. Dunkle Logos darauf 14,73:1. */
1015
+ .logo-carousel{position:relative;background:var(--bg-plate);border:var(--bd-strong);border-radius:var(--r-lg);padding:var(--s8) var(--s6)}
1016
+ .logo-carousel-track{position:relative;display:grid;align-items:center;min-height:124px}
1017
+ .logo-carousel-slide{grid-row:1;grid-column:1;display:grid;grid-template-columns:repeat(5,1fr);gap:var(--s5);opacity:0;transition:opacity .5s ease;pointer-events:none}
1018
+ .logo-carousel-slide[aria-hidden="false"]{opacity:1;pointer-events:auto}
1019
+ .logo-carousel .logo-tile{width:auto;min-width:0}
1020
+ .logo-carousel-dots{display:flex;justify-content:center;margin-top:var(--s5)}
1021
+ /* Identischer Pattern wie .img-dot: 24×24 Hit-Area + 12×12 sichtbarer Punkt, gap:0 */
1022
+ .logo-carousel-dot{width:24px;height:24px;border-radius:50%;border:none;background:transparent;cursor:pointer;padding:0;display:flex;align-items:center;justify-content:center}
1023
+ .logo-carousel-dot::before{content:'';width:12px;height:12px;border-radius:50%;background:var(--n-200);transition:background var(--m-fast),transform var(--m-fast)}
1024
+ .logo-carousel-dot:hover::before{background:var(--n-400)}
1025
+ .logo-carousel-dot[aria-selected="true"]::before{background:var(--co-500);transform:scale(1.25)}
1026
+ .logo-carousel-dot:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:50%}
1027
+ .logo-carousel-pause{position:absolute;top:var(--s2);right:var(--s2);z-index:2;background:var(--bg-surface);border:var(--bd);border-radius:var(--r-full);width:32px;height:32px;display:flex;align-items:center;justify-content:center;cursor:pointer;box-shadow:var(--e1);transition:box-shadow var(--m-fast),opacity var(--m-fast);opacity:0;color:var(--n-500)}
1028
+ .logo-carousel:hover .logo-carousel-pause,.logo-carousel:focus-within .logo-carousel-pause{opacity:1}
1029
+ .logo-carousel.paused .logo-carousel-pause{opacity:1}
1030
+ .logo-carousel-pause:hover{color:var(--n-700);box-shadow:var(--e2)}
1031
+ .logo-carousel-pause:focus-visible{outline:none;box-shadow:var(--focus-ring);opacity:1}
1032
+ .logo-carousel-pause .icon-play{display:none}
1033
+ .logo-carousel.paused .logo-carousel-pause .icon-pause{display:none}
1034
+ .logo-carousel.paused .logo-carousel-pause .icon-play{display:block}
1035
+ /* Reduced Motion: Transition aus, Autoplay wird per JS deaktiviert */
1036
+ @media(prefers-reduced-motion:reduce){.logo-carousel-slide{transition:none}}
1037
+
1038
+ /* ── Grid ── */
1039
+ .grid-vis{border:var(--bd-strong);border-radius:var(--r-md);overflow:hidden}
1040
+ .grid-12{display:grid;grid-template-columns:repeat(12,1fr);gap:var(--s3);padding:var(--s3);background:var(--bg-overlay)}
1041
+ .gcol{border-radius:var(--r-xs);padding:var(--s3);background:var(--co-50);border:1px solid var(--co-500);font:var(--ty-label-xs);color:var(--co-700);text-align:center}
1042
+
1043
+ /* ── Token ── */
1044
+ /* Die Token-Blöcke tragen ihre Überschrift als .group-title wie jede andere Doku-Sektion,
1045
+ damit sie in der Sub-Navigation erscheinen und die Heading-Ebene nicht überspringen. */
1046
+ .token-section{margin-bottom:var(--s8)}
1047
+ .ico-48{width:48px;height:48px}
1048
+
1049
+ /* ── Example Pages ── */
1050
+ /* Beispielseiten-Auswahl: nach IA gruppiert (Allgemein/Leistungen/Wissen/Unternehmen/Veranstaltungen),
1051
+ je Gruppe eine dezente Label-Zeile über den Pills. Gekürzte Pill-Labels (voller Name via aria-label). */
1052
+ /* Alle Gruppen als Spalten nebeneinander (füllt die Breite, hält die Leiste flach);
1053
+ klappt auf schmalen Screens automatisch auf weniger Spalten um. */
1054
+ .ep-tabs{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--s6) var(--s8);align-items:start;margin-bottom:var(--s8)}
1055
+ .ep-tab-group{display:flex;flex-direction:column;gap:var(--s3)}
1056
+ .ep-tab-group-label{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--tx-secondary)}
1057
+ .ep-tab-group-row{display:flex;gap:var(--s2);flex-wrap:wrap}
1058
+ /* min-height 44px = Touch-Target AAA (WCAG 2.5.5), analog zu .btn; border via --field-border
1059
+ (modusabhängig, ≥ 3:1 für die Bedienelement-Kontur nach WCAG 1.4.11: light #6E8585 = 3,9:1,
1060
+ dark #C9D3D3 = 5,8:1 — das feste --n-200 fiel im Light-Mode auf 1,5:1 durch). */
1061
+ .ep-tab{display:inline-flex;align-items:center;justify-content:center;min-height:44px;padding:7px var(--s4);border-radius:var(--r-full);border:1px solid var(--field-border);font:var(--ty-label-sm);cursor:pointer;background:var(--bg-surface);color:var(--tx-secondary);transition:all var(--m-fast)}
1062
+ .ep-tab:hover{background:var(--bg-overlay);color:var(--tx-primary);border-color:var(--field-border)}
1063
+ .ep-tab:focus-visible{outline:none;box-shadow:var(--focus-ring)}
1064
+ /* Aktiv: gefüllt mit co-700 (nicht co-500), damit weißer Text AA erreicht (#fff auf
1065
+ co-700 = 5,52:1; auf dem hellen co-500 wären es nur 2,3:1). Spiegelt .btn-filled/.btn-co. */
1066
+ .ep-tab.active{background:var(--co-700);color:#fff;border-color:var(--co-700);box-shadow:var(--e1)}
1067
+ .ep-tab.active:hover{background:var(--co-700);color:#fff;border-color:var(--co-700)}
1068
+ /* Hierarchie in einer Gruppe (Leistungen, Unternehmen): Oberpunkte stapeln untereinander,
1069
+ Unterpunkte eingerückt mit dezenter Leitlinie (wie ein Nav-Baum). */
1070
+ .ep-tab-group-row.is-tree{flex-direction:column;align-items:flex-start}
1071
+ .ep-tab-node{display:flex;flex-direction:column;align-items:flex-start;gap:var(--s2)}
1072
+ .ep-tab-parent{display:flex;align-items:center;gap:var(--s2)}
1073
+ .ep-tab-toggle{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;flex-shrink:0;border-radius:var(--r-full);border:1px solid var(--field-border);background:var(--bg-surface);color:var(--tx-secondary);cursor:pointer;padding:0;transition:all var(--m-fast)}
1074
+ .ep-tab-toggle:hover{background:var(--bg-overlay);color:var(--tx-primary);border-color:var(--field-border)}
1075
+ .ep-tab-toggle:focus-visible{outline:none;box-shadow:var(--focus-ring)}
1076
+ .ep-tab-toggle-caret{width:14px;height:14px;transition:transform var(--m-fast)}
1077
+ .ep-tab-node.is-open .ep-tab-toggle-caret{transform:rotate(180deg)}
1078
+ /* Unterpunkte standardmäßig eingeklappt, per Toggle (.is-open) aufklappbar */
1079
+ .ep-tab-children{display:none;flex-wrap:wrap;gap:var(--s2);margin-left:var(--s4);padding-left:var(--s4);border-left:1px solid var(--n-200)}
1080
+ .ep-tab-node.is-open > .ep-tab-children{display:flex}
1081
+ /* position:relative, damit .skip-link (position:absolute) sich am ep-Page-Frame orientiert
1082
+ und nicht außerhalb der Preview-Karte erscheint. overflow:hidden clipped die negative
1083
+ top-Position im Default — Skip-Link ist also unsichtbar bis Focus, dann poppt er rein. */
1084
+ .ep-page{display:none;border-radius:var(--r-lg);overflow:hidden;box-shadow:var(--e3);border:var(--bd-strong);position:relative}
1085
+ .ep-page.visible{display:block}
1086
+ /* Beispielseiten nutzen die volle verfügbare Breite bis zum rechten Fensterrand (kein 1280/1500-Deckel):
1087
+ .ds-content ist flex:1 und füllt Fensterbreite − Sidebar. Der Karten-Rahmen (.ep-page: Radius/Schatten)
1088
+ und der Außenabstand (.ds-content padding --s6) bleiben; der Seiteninhalt bleibt über das Content-Gutter
1089
+ (padding-inline: max(--s8, calc(50% − 640px)), s.u.) in einer zentrierten 1280-Lesespalte, Hero/Bänder
1090
+ laufen full-bleed über die Kartenbreite. */
1091
+ /* Breite an data-section (vom Inline-Head-Script vor dem Paint gesetzt) — verhindert den Layout-Sprung,
1092
+ den :has() allein verursacht (greift erst, wenn JS die Sektion nach dem Paint sichtbar macht).
1093
+ :has bleibt als Laufzeit-Backup für Wechsel, die nicht über activateSection laufen. */
1094
+ html[data-section="examples"] .ds-content,
1095
+ .ds-content:has(#sec-examples.visible){max-width:none}
1096
+ /* Inhalt der Sektionen folgt aber dem 1280px-Spec — Hintergründe bleiben volle Panel-Breite,
1097
+ Content wird über fluides Inline-Padding zentriert (kein zusätzlicher Wrapper nötig). */
1098
+ .ep-page .ep-topnav,
1099
+ .ep-page .ep-section,
1100
+ .ep-page .card-stat-strip,
1101
+ .ep-page .ep-cta-band,
1102
+ .ep-page .ep-media-band,
1103
+ .ep-page .hero-image-caption{padding-inline:max(var(--s8), calc(50% - 640px))}
1104
+ /* Akzent-Bänder: gerundete Ecken wie Karten & übrige Bilder (r-lg). Radius aufs <img>, da das
1105
+ <figure> durch das Content-Gutter-Padding breiter ist als das sichtbare Bild. */
1106
+ .ep-page .ep-media-band img{border-radius:var(--r-lg)}
1107
+ /* .footer hat eigene Bänder (.footer-main/.footer-btm) mit eigenem padding-inline.
1108
+ Auf .footer hier kein Padding setzen — sonst doppelte Einrückung und der Background-Streifen
1109
+ reicht nicht bis zur .ep-page-Kante. */
1110
+ .ep-topnav{display:flex;align-items:center;padding:var(--s4) var(--s8);background:var(--bg-surface);border-bottom:var(--bd);gap:var(--s8);flex-wrap:wrap}
1111
+ /* Kontakt-Button (letztes Direct-Child) wird nach rechts gedrückt; Nav hängt direkt am Logo */
1112
+ .ep-topnav > :last-child{margin-left:auto}
1113
+ .ep-logo{font:500 1.5rem/2rem var(--font);letter-spacing:.03em;flex-shrink:0;display:flex;align-items:center;color:inherit;text-decoration:none;border-radius:var(--r-xs)}
1114
+ a.ep-logo{cursor:pointer}
1115
+ a.ep-logo:focus-visible{outline:none;box-shadow:var(--focus-ring)}
1116
+ .ep-logo img{display:block;height:24px;width:auto}
1117
+ /* Theme-aware logo swap: default für hellen, light für dunklen Hintergrund.
1118
+ img.-Präfix (Element+Klasse, 0,1,1) ist nötig: .ep-logo img{display:block} (0,1,1) schlägt sonst
1119
+ die reine .logo-themed-light-Klasse (0,1,0) → im Light bliebe das WEISSE Logo sichtbar (weiß-auf-weiß
1120
+ unsichtbar, belegte aber ~Logobreite und schob .ep-nav-links nach rechts). Dark-Regeln (0,2,1) gewinnen. */
1121
+ img.logo-themed-light{display:none}
1122
+ [data-theme="dark"] img.logo-themed-default{display:none}
1123
+ [data-theme="dark"] img.logo-themed-light{display:block}
1124
+ .ep-nav-links{display:flex;gap:var(--s6);font:var(--ty-label-md);align-items:center}
1125
+ /* Top-Level-Links: Akzent-Unterstrich bei Hover/aktiv (statt Opacity-Fade). Der aktive Zustand
1126
+ ist nicht nur farbig (co-700), sondern zusätzlich durch den Unterstrich markiert (kein
1127
+ reiner Farb-Indikator → WCAG 1.4.1). */
1128
+ .ep-nav-btn{position:relative;background:none;border:none;cursor:pointer;font:inherit;color:inherit;padding:0;text-decoration:none;transition:color var(--m-fast)}
1129
+ .ep-nav-btn:link,.ep-nav-btn:visited{color:inherit;text-decoration:none}
1130
+ /* Aktiv-Unterstrich: co-700 statt co-500 → 5,52:1 auf weiß (WCAG 1.4.11 ≥3:1; co-500 lag bei 2,31:1).
1131
+ Dark-Override auf co-200 in dark-mode.css. Farbe spiegelt die Aktiv-Textfarbe. */
1132
+ .ep-nav-btn::after{content:"";position:absolute;left:0;right:0;bottom:-6px;height:2px;border-radius:1px;background:var(--co-700);opacity:0;transition:opacity var(--m-fast)}
1133
+ /* Unterstrich (::after) = ausschließlich Aktiv-Indikator (aria-current). Hover/Öffnen markieren nur
1134
+ über Petrol-Farbe (+ Caret-Dreh beim Toggle), damit das Aufklapp-Menü nicht an der Linie klebt. */
1135
+ .ep-nav-btn:hover{color:var(--co-700)}
1136
+ .ep-nav-btn:focus-visible{outline:none;box-shadow:var(--focus-aa);border-radius:2px}
1137
+ .ep-nav-btn[aria-current="page"]{color:var(--co-700)}
1138
+ .ep-nav-btn[aria-current="page"]::after{opacity:1}
1139
+ /* Aktive Sektion: trägt das Submenü die aktive Seite, bekommt der Parent-LINK denselben Unterstrich —
1140
+ nicht-farblicher Indikator (WCAG 1.4.1), damit die aktive Sektion nicht nur über Petrol-Farbe hängt.
1141
+ (Der Unterstrich sitzt am .ep-nav-btn-Link, nicht am Caret-Button — dieser hat kein ::after.) */
1142
+ .ep-nav-has-sub:has(.ep-nav-sub-btn[aria-current="page"]) .ep-nav-btn::after{opacity:1}
1143
+ /* Submenü unter "Leistungen"/"Unternehmen" — Hover/Focus-Within zeigt die Einträge */
1144
+ .ep-nav-item{position:relative;display:inline-flex;align-items:center;gap:var(--s1)}
1145
+ /* Caret-Disclosure-Button: nur der Pfeil (das Label ist der separate .ep-nav-btn-Link daneben).
1146
+ Eigene Hit-Area ≥24×24 (WCAG 2.5.8) + eigener Fokus-Ring, da nicht mehr Teil des Link-Buttons. */
1147
+ .ep-nav-item-toggle{font:inherit;color:inherit;background:none;border:none;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;min-width:24px;min-height:24px;padding:0 4px;border-radius:var(--r-sm);line-height:1}
1148
+ .ep-nav-item-toggle:focus-visible{outline:none;box-shadow:var(--focus-aa)}
1149
+ .ep-nav-item-caret{width:10px;height:10px;display:inline-block;color:currentColor;opacity:.6;transition:transform var(--m-fast)}
1150
+ /* Disclosure-Menü (.is-open ↔ aria-expanded, via main.js): Öffnen schließt offene Geschwister
1151
+ (closeAllNavItems), Escape/Außenklick schließen. Reveal keift ausschließlich an .is-open (nie an
1152
+ reinem CSS-:hover), damit aria-expanded mitläuft und nie zwei Menüs gleichzeitig offen sind.
1153
+ Geöffnet wird per Klick/Tap, Tastatur ODER — nur auf pointer:fine — per Hover (JS-gesteuert, mit
1154
+ Intent-Delay). Beim Öffnen färbt sich der Toggle Petrol und der Caret dreht; Hover gibt schon vorab
1155
+ die Petrol-Färbung als Affordanz. KEIN Unterstrich (bleibt der aktiven Seite vorbehalten). */
1156
+ .ep-nav-has-sub:hover .ep-nav-item-toggle,.ep-nav-has-sub.is-open .ep-nav-item-toggle{color:var(--co-700)}
1157
+ .ep-nav-has-sub.is-open .ep-nav-item-caret{transform:rotate(180deg)}
1158
+ .ep-nav-sub{display:none;position:absolute;top:calc(100% + var(--s4));left:0;background:var(--bg-surface);box-shadow:var(--e3);border:var(--bd-strong);border-radius:var(--r-md);padding:var(--s2);min-width:240px;flex-direction:column;gap:2px;z-index:10}
1159
+ .ep-nav-has-sub.is-open .ep-nav-sub{display:flex}
1160
+ /* Unsichtbare Hover-Brücke über den Gap (top:100% + s4): hält den Zeiger beim Weg vom Caret ins
1161
+ Flyout im Item, damit mouseleave nicht zu früh feuert (WCAG 1.4.13 „hoverable“). Nur pointer:fine
1162
+ und nur solange offen — mobil ist .ep-nav-sub statisch, dort keine Brücke. */
1163
+ @media (hover:hover) and (pointer:fine){
1164
+ .ep-nav-has-sub.is-open .ep-nav-sub::before{content:"";position:absolute;left:0;right:0;top:calc(-1*var(--s4));height:var(--s4)}
1165
+ }
1166
+ /* Sub-Items: gleiche Größe wie Top-Level (label-md), kein Umbruch, markenfarbiger Hover.
1167
+ Aktiver Eintrag mit Tönungsfläche + co-700 + Fettung (Fläche/Fettung = nicht-farbige Indikatoren). */
1168
+ .ep-nav-sub-btn{padding:var(--s2) var(--s4);border-radius:var(--r-sm);text-decoration:none;color:var(--tx-primary);font:var(--ty-label-md);white-space:nowrap;transition:background var(--m-fast),color var(--m-fast)}
1169
+ .ep-nav-sub-btn:hover{background:var(--co-50);color:var(--co-700)}
1170
+ .ep-nav-sub-btn:focus-visible{outline:none;box-shadow:var(--focus-aa)}
1171
+ .ep-nav-sub-btn[aria-current="page"]{background:var(--co-50);color:var(--co-700);font-weight:600}
1172
+ /* Hamburger (per JS injiziert) — nur unter dem Mobile-Breakpoint sichtbar */
1173
+ .ep-nav-burger{display:none;align-items:center;justify-content:center;width:48px;height:48px;flex-shrink:0;border:1px solid var(--n-200);border-radius:var(--r-sm);background:var(--bg-surface);color:var(--tx-primary);cursor:pointer;padding:0}
1174
+ .ep-nav-burger:focus-visible{outline:none;box-shadow:var(--focus-ring)}
1175
+ .ep-nav-burger .icon-close{display:none}
1176
+ .ep-topnav.nav-open .ep-nav-burger .icon-menu{display:none}
1177
+ .ep-topnav.nav-open .ep-nav-burger .icon-close{display:inline}
1178
+
1179
+ /* ── Topnav-Aktionen: Suche + Theme-Umschalter ──
1180
+ Per JS in jede .ep-topnav injiziert (wie der Hamburger). Rechts gebündelt, direkt vor dem CTA.
1181
+ Bleibt Corporate-Chrome (co) auch auf data-accent-Seiten, analog zu den Nav-Links. */
1182
+ .ep-nav-actions{display:inline-flex;align-items:center;gap:var(--s1);margin-left:auto}
1183
+ /* CTA (letztes Child) trägt sonst selbst margin-left:auto → würde den rechten Cluster auseinanderreißen.
1184
+ Wenn die Aktionen das Schieben übernehmen, bekommt der CTA nur noch einen kleinen Abstand.
1185
+ :not(.ep-nav-actions) → greift nur, wenn NACH den Aktionen noch ein CTA folgt; fehlt der CTA
1186
+ (Aktionen sind selbst letztes Child), behält .ep-nav-actions sein margin-left:auto und bleibt rechts. */
1187
+ .ep-topnav:has(.ep-nav-actions) > :last-child:not(.ep-nav-actions){margin-left:var(--s3)}
1188
+ .ep-nav-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:48px;height:48px;flex-shrink:0;border:1px solid transparent;border-radius:var(--r-full);background:none;color:var(--tx-secondary);cursor:pointer;transition:background var(--m-fast),color var(--m-fast)}
1189
+ .ep-nav-icon-btn:hover{background:var(--co-50);color:var(--co-700)}
1190
+ .ep-nav-icon-btn:focus-visible{outline:none;box-shadow:var(--focus-aa)}
1191
+ .ep-nav-icon-btn svg{width:22px;height:22px}
1192
+ /* Theme-Umschalter: Mond im Light (Klick → Dark), Sonne im Dark (Klick → Light) */
1193
+ .ep-nav-theme-toggle .ep-nav-icon-sun{display:none}
1194
+ [data-theme="dark"] .ep-nav-theme-toggle .ep-nav-icon-sun{display:block}
1195
+ [data-theme="dark"] .ep-nav-theme-toggle .ep-nav-icon-moon{display:none}
1196
+ /* Such-Popover: Disclosure unter dem Such-Button, spiegelt .ep-nav-sub (bg-surface, --e3, --bd) */
1197
+ .ep-nav-search{position:relative;display:inline-flex}
1198
+ .ep-nav-search.is-open .ep-nav-search-toggle{background:var(--co-50);color:var(--co-700)}
1199
+ .ep-nav-search-pop{display:none;position:absolute;top:calc(100% + var(--s3));right:0;z-index:10;width:320px;max-width:90vw;padding:var(--s4);background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-md);box-shadow:var(--e3)}
1200
+ .ep-nav-search.is-open .ep-nav-search-pop{display:block}
1201
+ .ep-nav-search-form{display:flex;gap:var(--s2);align-items:center}
1202
+ .ep-nav-search-input{flex:1;min-width:0;height:44px;padding:0 var(--s3);font:var(--ty-body-md);color:var(--tx-primary);background:var(--bg-surface);border:2px solid var(--field-border);border-radius:var(--r-md);outline:none;transition:border-color var(--m-fast),box-shadow var(--m-fast)}
1203
+ .ep-nav-search-input:focus{border-color:var(--co-500);box-shadow:var(--focus-ring)}
1204
+ .ep-nav-search-input::placeholder{color:var(--tx-secondary)}
1205
+ @media(max-width:760px){
1206
+ /* Erste Zeile: Logo links, dann Aktionen (Suche/Theme) + Kontakt + Burger rechtsaußen.
1207
+ Der Burger ist bewusst das äußerste rechte Element: So bleibt der Toggle beim Öffnen
1208
+ (Burger → X) an Ort und Stelle, statt seine Position mit dem Kontakt-Button zu tauschen.
1209
+ Nav-Links klappen darunter auf. */
1210
+ .ep-logo{order:1}
1211
+ .ep-nav-actions{order:2;margin-left:auto}
1212
+ .ep-topnav > .btn{order:3;margin-left:var(--s3)}
1213
+ .ep-nav-burger{display:inline-flex;order:4;margin-left:var(--s2)}
1214
+ /* Popover am rechten Rand statt rechtsbündig, damit es auf schmalen Screens nicht abgeschnitten wird */
1215
+ .ep-nav-search-pop{right:auto;left:0;width:min(320px,calc(100vw - var(--s8)))}
1216
+ .ep-nav-links{display:none;order:5;flex-basis:100%;width:100%;flex-direction:column;align-items:stretch;gap:0;margin-top:var(--s3);padding-top:var(--s3);border-top:var(--bd)}
1217
+ .ep-topnav.nav-open .ep-nav-links{display:flex}
1218
+ /* Dropdown-Parent: Label-Link + Caret in EINER Zeile (Label nimmt Restbreite, Caret ≥44px Tap-Target
1219
+ rechts), Submenü klappt in eigener Zeile darunter auf. Einfache Top-Level-Links bleiben full-width. */
1220
+ .ep-nav-item{display:flex;flex-wrap:wrap;align-items:center;width:100%;gap:0}
1221
+ .ep-nav-btn{width:100%;padding:var(--s3) 0}
1222
+ .ep-nav-item .ep-nav-btn{flex:1 1 auto;width:auto}
1223
+ .ep-nav-item-toggle{flex:0 0 auto;width:44px;min-height:44px;padding:var(--s3) 0}
1224
+ .ep-nav-item .ep-nav-sub{flex-basis:100%}
1225
+ .ep-nav-btn::after{display:none}
1226
+ /* Untermenü inline aufklappen statt als schwebendes Overlay */
1227
+ .ep-nav-sub{position:static;display:none;box-shadow:none;border:none;background:none;padding:0 0 var(--s2) var(--s4);min-width:0}
1228
+ .ep-nav-has-sub.is-open .ep-nav-sub{display:flex}
1229
+ .ep-nav-sub-btn{padding:var(--s2) var(--s3);white-space:normal}
1230
+ }
1231
+ .ep-hero-eyebrow{font:var(--ty-label-xs);letter-spacing:.12em;text-transform:uppercase;opacity:.8;margin-bottom:var(--s3)}
1232
+ .ep-hero-ctas{display:flex;gap:var(--s3);flex-wrap:wrap}
1233
+ .ep-section{padding:var(--s12) var(--s8);text-align:left}
1234
+ /* Mobile (≤ 768px): horizontaler Section-Innenabstand 32 → 24 px (--s6), im Rhythmus
1235
+ mit dem Card-Padding; vertikaler Abstand bleibt. Greift nicht auf Sektionen mit
1236
+ inline gesetztem padding-inline / padding-Shorthand (bewusste Einzelfälle). */
1237
+ @media(max-width:768px){
1238
+ .ep-section{padding-inline:var(--s6)}
1239
+ }
1240
+ /* Phone (≤ 520px): Hero-CTAs stapeln full-width für große Tap-Flächen. Erst hier, nicht
1241
+ schon ab 768px: Auf Phablet/kleinem Tablet (521–768px) liefen die Buttons sonst viel
1242
+ breiter als der (auf 520px gekappte) Intro-Text und wirkten überdehnt. Dort behalten sie
1243
+ ihre natürliche Breite + Wrap und folgen der Hero-Ausrichtung (justify-content). */
1244
+ @media(max-width:520px){
1245
+ .ep-hero-ctas{flex-direction:column;align-items:stretch}
1246
+ .ep-hero-ctas .btn{width:100%;justify-content:center}
1247
+ }
1248
+ /* Auszeichnungs-/Badge-Liste (z. B. „Ausgezeichnet als Arbeitgeber“): Desktop als zentrierte
1249
+ Reihe. Auf Mobile (≤ 768px) als 2×2-Grid statt flex-wrap: zentriertes Wrappen richtet jede
1250
+ Zeile einzeln aus, sodass die unterschiedlich breiten Einträge versetzt erscheinen; das Grid
1251
+ fluchtet sie in zwei saubere Spalten (minmax(0,1fr) lässt lange Labels umbrechen). */
1252
+ .ep-award-list{list-style:none;margin:var(--s5) 0 0;padding:0;display:flex;flex-wrap:wrap;justify-content:center;gap:var(--s4) var(--s8)}
1253
+ @media(max-width:768px){
1254
+ .ep-award-list{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));justify-content:stretch;gap:var(--s5)}
1255
+ .ep-award-list>li{justify-self:start}
1256
+ }
1257
+ .ep-section-label{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;margin-bottom:var(--s2)}
1258
+ .ep-section-h2{font:var(--ty-headline-md);color:var(--tx-primary);margin-bottom:var(--s2)}
1259
+ /* margin-bottom --s8 (32 px): Sub-Cards-Gap (32) ist bewusst kleiner als section-padding-bottom (48),
1260
+ damit das Auge die Card-Reihe als „optisch mittig“ wahrnimmt (psychologische Mitte liegt über der
1261
+ geometrischen). Verhältnis card-padding (24) : sub-cards-gap (32) : section-edge (48) = 1 : 1.33 : 2.
1262
+ Color tx-secondary als Lead-Default; macht Inline-Overrides im Markup überflüssig. */
1263
+ .ep-section-sub{font:var(--ty-body-md);color:var(--tx-secondary);margin-bottom:var(--s8)}
1264
+ /* Fakten-Liste: die Rahmendaten eines Angebots (Dauer, Format, Gruppe, Preis …) als Label/Wert-Paare
1265
+ untereinander. Bewusst OHNE eigenen Rahmen und ohne Fläche: die Liste zieht in einen vorhandenen
1266
+ Container ein (Angebots-Box, Sticky-Sidebar), ein eigener Rahmen ergäbe dort Kasten-im-Kasten.
1267
+ Einspaltig auf allen Breiten, deshalb keine Media-Query nötig — und lange Werte wie „Schriftliche
1268
+ Handlungsempfehlungen“ brechen innerhalb ihres Paares um, statt wie im früheren mehrspaltigen
1269
+ Streifen die Nachbarspalten zu verziehen. Bereichston der Labels über .t-XX im Markup (dark-safe),
1270
+ nie als Inline-Farbe. */
1271
+ .ep-facts{margin:0}
1272
+ .ep-facts > div + div{margin-top:var(--s4);padding-top:var(--s4);border-top:var(--bd)}
1273
+ .ep-facts dt{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;margin:0 0 var(--s1)}
1274
+ .ep-facts dd{font:var(--ty-body-md);color:var(--tx-primary);margin:0}
1275
+ /* Zwei-Spalten-Variante für Kästen, die neben Inhalt stehen: Einspaltig macht der Kasten dort mehr
1276
+ Höhe als der Inhalt daneben (gemessen 470 gegen 256 px, also 214 px Leerraum). Zweispaltig halbiert
1277
+ die Liste. auto-fit statt fixer Spaltenzahl, damit sie in schmalen Kästen und mobil von selbst
1278
+ einspaltig wird. Die Haarlinien entfallen dabei: Bei zwei Spalten trennen sie keine Zeilen mehr
1279
+ eindeutig, und der Abstand gliedert bereits. Nur für kurze Werte gedacht — lange wie „Schriftliche
1280
+ Handlungsempfehlungen“ brauchen die einspaltige Grundform. */
1281
+ .ep-facts.is-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:var(--s4) var(--s5)}
1282
+ .ep-facts.is-grid > div + div{margin-top:0;padding-top:0;border-top:0}
1283
+ /* Funktions-Vergleich: aufklappbar via native <details>/<summary>, default zugeklappt.
1284
+ Mirror des .article-toc-Musters; Marker entfernt, Caret rotiert im [open]-Zustand. */
1285
+ .ep-compare{margin-top:var(--s8);border-top:var(--bd);padding-top:var(--s5)}
1286
+ .ep-compare-summary{display:inline-flex;align-items:center;gap:var(--s2);padding:var(--s2) 0;font:var(--ty-label-md);letter-spacing:.05em;text-transform:uppercase;color:var(--ki-800);cursor:pointer;list-style:none}
1287
+ .ep-compare-summary::-webkit-details-marker{display:none}
1288
+ .ep-compare-summary:hover{color:var(--ki-900)}
1289
+ .ep-compare-summary:focus-visible{outline:none;box-shadow:var(--focus-aa);border-radius:2px}
1290
+ .ep-compare-caret{width:16px;height:16px;flex-shrink:0;transition:transform var(--m-fast)}
1291
+ .ep-compare[open] .ep-compare-caret{transform:rotate(180deg)}
1292
+ .ep-compare-table-wrap{overflow-x:auto;margin-top:var(--s5)}
1293
+ .ep-compare-table{width:100%;border-collapse:collapse;font:var(--ty-body-sm)}
1294
+ .ep-compare-table th,.ep-compare-table td{padding:var(--s3);border-bottom:var(--bd)}
1295
+ .ep-compare-table thead th{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--tx-secondary);text-align:center}
1296
+ .ep-compare-table thead th:first-child{text-align:left}
1297
+ .ep-compare-table thead th:not(:first-child){width:8rem}
1298
+ .ep-compare-table tbody th{text-align:left;font:var(--ty-body-sm);font-weight:400;color:var(--tx-secondary)}
1299
+ .ep-compare-table tbody td{text-align:center;color:var(--tx-secondary)}
1300
+ .ep-compare-table tbody tr:last-child th,.ep-compare-table tbody tr:last-child td{border-bottom:none}
1301
+ .ep-compare-table .ep-compare-pro{background:var(--ki-50)}
1302
+ .ep-compare-table thead .ep-compare-pro{color:var(--ki-800);border-bottom:2px solid var(--ki-500)}
1303
+ .ep-compare-yes{color:var(--ki-800);font-weight:700}
1304
+ .ep-compare-no{color:var(--tx-muted)}
1305
+ /* Gap --s6 (24 px) statt --s4 (16 px), damit der Card-Rhythmus konsistent zu .layout-grid bleibt
1306
+ (Wissensbeiträge, Veranstaltungen, Team nutzen ebenfalls --s6). Border-Radius und Box-Shadow
1307
+ der Cards tragen das Container-Gefühl, auch wenn padding ≈ gap ist. */
1308
+ .ep-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:var(--s6)}
1309
+ /* Padding 24 (--s6) statt 20 (--s5), damit Innen-Atem ≥ 1,5× Außen-Gap (--s4 = 16 px).
1310
+ Sonst lösen sich die Cards visuell auf — Innen- und Außenabstand wären zu nah beieinander. */
1311
+ /* Konvention „Elevation = Interaktivität“: statische Cards ruhen flach mit Rahmen (--bd-strong),
1312
+ kein Schatten. Schatten ist interaktiven Cards (.ep-card-link) vorbehalten → eindeutiges Affordanz-Signal. */
1313
+ .ep-card{display:flex;flex-direction:column;border-radius:var(--r-lg);padding:var(--s6);background:var(--bg-surface);border:var(--bd-strong)}
1314
+ /* Icon-Container 48×48 (war 40), SVG 32×32 (war 24). Substantiellere Präsenz im Verhältnis zum
1315
+ Card-Padding (24 px). Sizes folgen Icon-Sizing-System (siehe sec-icons/Größen). */
1316
+ /* Kachel-Fläche über --XX-50, den ruhigen Bereichston, und ohne Rand. Sie muss nicht als Fläche
1317
+ lesen: WCAG verlangt für eine dekorative Fläche nichts, das Glyph ist aria-hidden und wiederholt
1318
+ nur das Eyebrow daneben. Darüber entscheidet das Markenrad, und 48 px gesättigte Farbe sind das
1319
+ Gegenteil von „Ruhig“. Das Glyph trägt die Erkennbarkeit: -700/-800 auf dem Tint 7,5 bis 11,4:1,
1320
+ im Dark hebt dark-mode.css es auf -100 (6,9 bis 8,6:1). Die Farbe kommt aus der Komponente, nicht
1321
+ aus 76 inline gesetzten style-Attributen. */
1322
+ .ep-card-icon{width:48px;height:48px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;margin-bottom:var(--s4);background:var(--co-50)}
1323
+ .ep-card-icon[data-area="co"]{background:var(--co-50)}
1324
+ .ep-card-icon[data-area="ki"]{background:var(--ki-50)}
1325
+ .ep-card-icon[data-area="es"]{background:var(--es-50)}
1326
+ .ep-card-icon[data-area="wo"]{background:var(--wo-50)}
1327
+ /* stroke-sm (1.25) = wie die Outline-Icons inline gezeichnet sind; md (1.5) ueberschrieb das und
1328
+ wirkte auf dem 32px-Render (24er-viewBox, hochskaliert) zu fett. Gefuellte Brand-Icons ohne stroke
1329
+ sind unberuehrt. */
1330
+ .ep-card-icon svg{width:32px;height:32px;stroke-width:var(--icon-stroke-sm)}
1331
+ /* Area-aware Eyebrow, spiegelbildlich zu .card-eyebrow (700er-Token) */
1332
+ .ep-card-eyebrow{font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;color:var(--co-700);margin-bottom:var(--s2)}
1333
+ .ep-card-eyebrow[data-area="co"]{color:var(--co-700)}
1334
+ .ep-card-eyebrow[data-area="ki"]{color:var(--ki-800)}
1335
+ .ep-card-eyebrow[data-area="es"]{color:var(--es-700)}
1336
+ .ep-card-eyebrow[data-area="wo"]{color:var(--wo-700)}
1337
+ .ep-card-title{font:var(--ty-title-sm);color:var(--tx-primary);margin-bottom:var(--s2)}
1338
+ .ep-card-text{font:var(--ty-body-md);color:var(--tx-secondary)}
1339
+ /* Klickbare Karten-Variante: gesamte Karte ist Link, mit Hover-Elevation */
1340
+ /* Interaktive Karte: ruht auf --e1 (statt Rahmen), hebt auf Hover/Focus auf --e3 + translateY.
1341
+ border-color:transparent neutralisiert den statischen --bd-strong-Rahmen; ein inline border-top-Akzent bleibt erhalten. */
1342
+ .ep-card-link{text-decoration:none;color:inherit;cursor:pointer;border-color:transparent;box-shadow:var(--e1);transition:box-shadow var(--m-fast),transform var(--m-fast),background var(--m-fast)}
1343
+ .ep-card-link:hover{box-shadow:var(--e3);transform:translateY(-2px)}
1344
+ .ep-card-link:focus-visible{outline:none;box-shadow:var(--focus-ring),var(--e3)}
1345
+ /* CTA-Zeile: per margin-top:auto an Karten-Unterkante gepinnt, area-aware Farbe via [data-area] auf .ep-card */
1346
+ .ep-card-cta{font:var(--ty-label-md);color:var(--co-700);margin-top:auto;padding-top:var(--s4);display:inline-flex;align-items:center;gap:var(--s1)}
1347
+ .ep-card[data-area="co"] .ep-card-cta{color:var(--co-700)}
1348
+ .ep-card[data-area="ki"] .ep-card-cta{color:var(--ki-800)}
1349
+ .ep-card[data-area="es"] .ep-card-cta{color:var(--es-700)}
1350
+ .ep-card[data-area="wo"] .ep-card-cta{color:var(--wo-700)}
1351
+ /* Card-CTA-Link (z.B. „Beitrag lesen →“ am Karten-Fuß).
1352
+ Light: --co-700 #007575 auf #fff = 5.53:1 ✓ AA. Dark-Override in dark-mode.css.
1353
+ --pinned-Modifier für Flex-Karten, in denen der CTA an die Unterkante gepinnt werden soll. */
1354
+ /* Kein margin-top: den Abstand zur Zeile darüber trägt der gap des .card-body. Die --pinned-
1355
+ Variante setzt margin-top:auto und schiebt den CTA an die Unterkante, dort ersetzt das auto
1356
+ jeden festen Wert ohnehin. */
1357
+ .card-cta-link{font:var(--ty-label-md);color:var(--co-700)}
1358
+ /* Bereichsvariante (optional): trägt die Akzentfarbe statt Corporate-Teal, wenn der CTA in einer
1359
+ Bereichs-Sektion sitzt. Shades wie .ep-card-cta; Dark-Overrides (→ -200/-100) in dark-mode.css. */
1360
+ .card-cta-link[data-area="co"]{color:var(--co-700)}
1361
+ .card-cta-link[data-area="ki"]{color:var(--ki-800)}
1362
+ .card-cta-link[data-area="es"]{color:var(--es-700)}
1363
+ .card-cta-link[data-area="wo"]{color:var(--wo-700)}
1364
+ /* Pinned-Variante: margin-top:auto schiebt den Link an die Karten-Unterkante.
1365
+ padding-top:var(--s4) trennt die Action-Zone (CTA) sichtbar vom Info-Block (Meta + Anreißer) darüber. */
1366
+ .card-cta-link--pinned{margin-top:auto;padding-top:var(--s4)}
1367
+ /* Als echter Link (a.card-cta-link) verwendbar: kein Default-Underline, Underline erst bei Hover, sichtbarer
1368
+ Fokus-Ring. Gescoped auf a[…], damit die <span>-Nutzung in klickbaren .ep-card-link-Karten (kein Fremd-Hover) unberührt bleibt. */
1369
+ a.card-cta-link{display:inline-block;text-decoration:none}
1370
+ a.card-cta-link:hover{text-decoration:underline;text-underline-offset:2px}
1371
+ a.card-cta-link:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:2px}
1372
+ /* ── Offene Feature-Liste (flaches Icon-Layout, gruppiert nach Tier; Alternative zu Bild-Cards) ── */
1373
+ .ep-feature{display:flex;gap:var(--s4)}
1374
+ /* Icon-Kachel: Glyph hat AA-Kontrast zur Kachel — Core tx-secondary/n-100 5.3:1, Pro ki-800/ki-50 7.5:1.
1375
+ tx-secondary + n-100 sind theme-aware, Core flippt also automatisch (Dark 6.0:1).
1376
+ Pro braucht einen Dark-Override, weil --ki-800 dunkel bleibt, --ki-50 aber dunkel wird → dark-mode.css. */
1377
+ .ep-feature-icon{flex:0 0 48px;width:48px;height:48px;border-radius:var(--r-sm);display:inline-flex;align-items:center;justify-content:center;background:var(--n-100);color:var(--tx-secondary)}
1378
+ .ep-feature-icon svg{width:26px;height:26px;stroke-width:var(--icon-stroke-md)}
1379
+ .ep-feature-icon[data-area="ki"]{background:var(--ki-50);color:var(--ki-800)}
1380
+ .ep-feature-icon[data-area="co"]{background:var(--co-50);color:var(--co-800)}
1381
+ .ep-feature-icon[data-area="es"]{background:var(--es-50);color:var(--es-800)}
1382
+ .ep-feature-icon[data-area="wo"]{background:var(--wo-50);color:var(--wo-800)}
1383
+ .ep-feature-body{display:flex;flex-direction:column;gap:var(--s1)}
1384
+ /* Ausnahme, und sie gehört dem Container: der Gap ist hier absichtlich winzig (--s1), damit Titel
1385
+ und Text als eine Einheit gelesen werden. Für den CTA ist das zu eng, er soll sich vom Text
1386
+ lösen. Der Card-Body braucht das nicht, sein gap:var(--s3) trägt den Abstand schon. */
1387
+ .ep-feature-body>.card-cta-link{margin-top:var(--s2)}
1388
+ .ep-feature-title{font:var(--ty-title-sm);color:var(--tx-primary);margin:0}
1389
+ .ep-feature-text{font:var(--ty-body-md);color:var(--tx-secondary);margin:0}
1390
+ /* Tier-Trenner: Label + Hairline. Label area-aware (Pro = ki-800, Dark-Override → ki-100). Linie = --bd-strong-Ton (n-200). */
1391
+ .ep-tier{display:flex;align-items:center;gap:var(--s4);margin-bottom:var(--s6)}
1392
+ .ep-tier-label{font:var(--ty-label-md);letter-spacing:.06em;text-transform:uppercase;color:var(--tx-secondary);white-space:nowrap}
1393
+ .ep-tier-label[data-area="ki"]{color:var(--ki-800)}
1394
+ .ep-tier-rule{flex:1;height:1px;background:var(--n-200)}
1395
+ /* Timeline-Marker (Conciso-Story): heller Bereichston + dunkles Icon (ruhiger als gefüllter Punkt), auf der Schiene sitzend. Dark-Override (helles Icon auf dunklem Tile) in dark-mode.css. */
1396
+ /* Dekorative Fläche wie .ep-card-icon: ruhiger Tint, das Glyph trägt. */
1397
+ .ep-tl-icon{position:absolute;right:-20px;top:0;width:38px;height:38px;border-radius:var(--r-full);background:var(--co-50);color:var(--co-800);display:inline-flex;align-items:center;justify-content:center;box-shadow:0 0 0 4px var(--bg-surface)}
1398
+ .ep-tl-icon svg{width:24px;height:24px;stroke-width:var(--icon-stroke-sm)}
1399
+ /* ── FAQ-Accordion (native details/summary) ── */
1400
+ .ep-faq{max-width:none}
1401
+ .ep-faq details{border-top:var(--bd)}
1402
+ .ep-faq details:last-of-type{border-bottom:var(--bd)}
1403
+ .ep-faq summary{list-style:none;cursor:pointer;display:flex;justify-content:space-between;align-items:center;gap:var(--s4);padding:var(--s4) 0;font:var(--ty-title-sm);color:var(--tx-primary)}
1404
+ .ep-faq summary::-webkit-details-marker{display:none}
1405
+ .ep-faq summary:focus-visible{outline:none;box-shadow:var(--focus-ring)}
1406
+ .ep-faq-caret{flex:0 0 auto;color:var(--tx-secondary);transition:transform var(--m-fast)}
1407
+ .ep-faq details[open] .ep-faq-caret{transform:rotate(180deg)}
1408
+ .ep-faq-a{font:var(--ty-body-md);color:var(--tx-secondary);margin:0 0 var(--s4);max-width:680px}
1409
+ /* ── Download CTA ── */
1410
+ /* Kein Schatten: der Block ist statisch, die Interaktion liegt in den Buttons darin
1411
+ (Elevation = Interaktivität). Rahmen plus 4-px-Akzent oben tragen die Kartenform. */
1412
+ .cta-dl{display:flex;align-items:center;gap:var(--s6);background:var(--bg-surface);border:var(--bd-strong);border-top:4px solid var(--cta-accent,var(--co-500));border-radius:var(--r-lg);padding:var(--s6) var(--s8)}
1413
+ .cta-dl[data-area="co"]{--cta-accent:var(--co-500)}
1414
+ .cta-dl[data-area="ki"]{--cta-accent:var(--ki-500)}
1415
+ .cta-dl[data-area="es"]{--cta-accent:var(--es-500)}
1416
+ .cta-dl[data-area="wo"]{--cta-accent:var(--wo-500)}
1417
+ .cta-dl-icon{width:64px;height:64px;border-radius:var(--r-md);display:flex;align-items:center;justify-content:center;flex-shrink:0}
1418
+ .cta-dl[data-area="co"] .cta-dl-icon{background:var(--co-50);color:var(--co-700)}
1419
+ .cta-dl[data-area="ki"] .cta-dl-icon{background:var(--ki-50);color:var(--ki-700)}
1420
+ .cta-dl[data-area="es"] .cta-dl-icon{background:var(--es-50);color:var(--es-700)}
1421
+ .cta-dl[data-area="wo"] .cta-dl-icon{background:var(--wo-50);color:var(--wo-700)}
1422
+ .cta-dl-body{flex:1}
1423
+ .cta-dl-eyebrow{font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.08em;margin:0 0 var(--s1)}
1424
+ .cta-dl[data-area="co"] .cta-dl-eyebrow{color:var(--co-700)} /* co-600 war nur 3,28:1 (Uppercase-Label < AA) → co-700 = 5,5:1; jetzt konsistent mit ki-800/es-700/wo-700 */
1425
+ .cta-dl[data-area="ki"] .cta-dl-eyebrow{color:var(--ki-800)}
1426
+ .cta-dl[data-area="es"] .cta-dl-eyebrow{color:var(--es-700)}
1427
+ .cta-dl[data-area="wo"] .cta-dl-eyebrow{color:var(--wo-700)}
1428
+ .cta-dl-title{font:var(--ty-headline-sm);color:var(--tx-primary);margin:0 0 var(--s2)}
1429
+ .cta-dl-desc{font:var(--ty-body-md);color:var(--tx-secondary);margin:0 0 var(--s3)}
1430
+ .cta-dl-meta{display:flex;flex-wrap:wrap;gap:var(--s2);align-items:center}
1431
+ .cta-dl-actions{display:flex;flex-direction:column;gap:var(--s2);align-items:stretch;flex-shrink:0;min-width:152px}
1432
+ /* Compact strip */
1433
+ .cta-strip{display:flex;align-items:center;flex-wrap:wrap;gap:var(--s4);background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-md);padding:var(--s4) var(--s5)}
1434
+ .cta-strip-icon{width:40px;height:40px;border-radius:var(--r-sm);display:flex;align-items:center;justify-content:center;flex-shrink:0}
1435
+ .cta-strip[data-area="co"] .cta-strip-icon{background:var(--co-50);color:var(--co-700)}
1436
+ .cta-strip[data-area="ki"] .cta-strip-icon{background:var(--ki-50);color:var(--ki-700)}
1437
+ .cta-strip[data-area="es"] .cta-strip-icon{background:var(--es-50);color:var(--es-700)}
1438
+ .cta-strip[data-area="wo"] .cta-strip-icon{background:var(--wo-50);color:var(--wo-700)}
1439
+ .cta-strip-body{flex:1;display:flex;flex-direction:column;gap:2px}
1440
+ .cta-strip-title{font:var(--ty-label-md);color:var(--tx-primary)}
1441
+ .cta-strip-meta{font:var(--ty-body-xs);color:var(--tx-muted)}
1442
+ /* Minimal link */
1443
+ .cta-link{display:inline-flex;align-items:center;gap:var(--s2);font:var(--ty-label-md);text-decoration:none;padding:var(--s2) 0;border-bottom:1px solid transparent;transition:border-color var(--m-fast)}
1444
+ .cta-link[data-area="co"]{color:var(--co-700)}
1445
+ .cta-link[data-area="ki"]{color:var(--ki-800)}
1446
+ .cta-link[data-area="es"]{color:var(--es-700)}
1447
+ .cta-link[data-area="wo"]{color:var(--wo-700)}
1448
+ .cta-link:hover{border-bottom-color:currentColor}
1449
+ .cta-link-meta{font:var(--ty-body-xs);color:var(--tx-muted);margin-left:var(--s1)}
1450
+ /* Mit Vorschaubild */
1451
+ /* Kein Schatten, gleiche Begründung wie .cta-dl: statischer Block mit Button darin. */
1452
+ .cta-visual{display:flex;align-items:stretch;background:var(--bg-surface);border:var(--bd-strong);border-radius:var(--r-lg);overflow:hidden}
1453
+ .cta-visual-cover{width:180px;flex-shrink:0;overflow:hidden;background:var(--n-100);position:relative}
1454
+ .cta-visual-cover img{width:100%;height:100%;object-fit:cover;display:block}
1455
+ .cta-visual-content{flex:1;padding:var(--s6);display:flex;flex-direction:column;border-left:var(--bd)}
1456
+ .cta-visual-eyebrow{font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.08em;margin:0 0 var(--s1)}
1457
+ /* Alle vier auf --XX-ink: co lag auf co-600 und trug damit nur 3,29:1 auf Weiß. Das Ink-Token
1458
+ flippt im Dark auf den hellen Ton, ein festes -700/-800 wäre dort dunkel-auf-dunkel. */
1459
+ .cta-visual[data-area="co"] .cta-visual-eyebrow{color:var(--co-ink)}
1460
+ .cta-visual[data-area="ki"] .cta-visual-eyebrow{color:var(--ki-ink)}
1461
+ .cta-visual[data-area="es"] .cta-visual-eyebrow{color:var(--es-700)}
1462
+ .cta-visual[data-area="wo"] .cta-visual-eyebrow{color:var(--wo-700)}
1463
+ .cta-visual-title{font:var(--ty-headline-xs);color:var(--tx-primary);margin:0 0 var(--s2)}
1464
+ .cta-visual-desc{font:var(--ty-body-md);color:var(--tx-secondary);margin:0;flex:1}
1465
+ .cta-visual-footer{display:flex;align-items:center;gap:var(--s4);flex-wrap:wrap;margin-top:auto;padding-top:var(--s4);border-top:var(--bd)}
1466
+ .ep-cta-band{padding:var(--s12) var(--s8);text-align:center}
1467
+ .ep-cta-h2{font:var(--ty-headline-md);margin-bottom:var(--s2)}
1468
+ .ep-cta-sub{font:var(--ty-body-md);opacity:.85;margin-bottom:var(--s6)}
1469
+ /* Beispielseiten: iframes der Prototypen (volle Breite, kein Border) */
1470
+
1471
+ /* ── Tabelle ── */
1472
+ .tbl-wrap{overflow-x:auto}
1473
+ .tbl-wrap:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-xs)}
1474
+ .tbl{width:100%;border-collapse:collapse;font:var(--ty-body-md);color:var(--tx-primary)}
1475
+ .tbl caption{font:var(--ty-title-sm);color:var(--tx-primary);padding:0 0 var(--s5);text-align:left}
1476
+ .tbl thead th{font:var(--ty-label-xs);text-transform:uppercase;letter-spacing:.06em;color:var(--tx-secondary);padding:var(--s3) var(--s5);background:var(--n-50);border-bottom:2px solid var(--n-200);border-top:var(--bd);text-align:left;white-space:nowrap}
1477
+ .tbl tbody td,.tbl tbody th{padding:var(--s4) var(--s5);border-bottom:var(--bd);vertical-align:top}
1478
+ .tbl tbody tr:last-child td,.tbl tbody tr:last-child th{border-bottom:none}
1479
+ .tbl tbody tr:hover td,.tbl tbody tr:hover th{background:var(--bg-overlay)}
1480
+ .tbl tbody th{font:var(--ty-label-md);color:var(--tx-primary);text-align:left}
1481
+ .tbl tfoot td,.tbl tfoot th{padding:var(--s4) var(--s5) 0;font:var(--ty-label-sm);color:var(--tx-primary);border-top:2px solid var(--n-200);text-align:left}
1482
+ .tbl td[data-num],.tbl th[data-num]{text-align:right;font-variant-numeric:tabular-nums}
1483
+ /* Striped variant */
1484
+ .tbl--striped tbody tr:nth-child(even) td,.tbl--striped tbody tr:nth-child(even) th{background:var(--n-50)}
1485
+ .tbl--striped tbody tr:hover td,.tbl--striped tbody tr:hover th{background:var(--bg-overlay)}
1486
+ /* Sortierbare Spalten */
1487
+ .tbl-sort{display:inline-flex;align-items:center;gap:var(--s1);background:none;border:none;cursor:pointer;font:inherit;color:inherit;letter-spacing:inherit;text-transform:inherit;padding:0}
1488
+ .tbl-sort:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--r-xs)}
1489
+ .tbl-sort svg{opacity:.3;transition:opacity var(--m-fast)}
1490
+ .tbl-sort:hover svg{opacity:.7}
1491
+ thead th[aria-sort="ascending"] .tbl-sort svg,
1492
+ thead th[aria-sort="descending"] .tbl-sort svg{opacity:1;color:var(--co-600)}
1493
+
1494
+ /* ── Wissensbeitrag (Article) ── */
1495
+ /* Header: zentrierter Block mit Breadcrumb · Pill · Titel · Lead · Meta */
1496
+ .article-header{max-width:880px;margin:0 auto;text-align:center}
1497
+ .article-breadcrumb{font:var(--ty-body-sm);color:var(--tx-muted);margin-bottom:var(--s5)}
1498
+ .article-breadcrumb a{color:inherit;text-decoration:none}
1499
+ .article-breadcrumb [aria-current="page"]{color:var(--tx-primary);font-weight:500}
1500
+ .article-breadcrumb-sep{margin:0 var(--s2)}
1501
+ /* Pill: Kategorie · Format · Lesezeit, area-aware */
1502
+ /* Füllung über --XX-fill, gleiche Begründung wie beim Badge (siehe tokens.css). ES-Text auf -800
1503
+ statt -700: auf der kräftigeren Füllung trägt -700 nur noch 4,74:1, -800 gibt Reserve und ist
1504
+ derselbe Ton, den das ES-Badge längst nutzt. */
1505
+ /* width:fit-content hält die Pille eine Pille, auch als Flex- oder Grid-Item. Ein inline-block
1506
+ wird als Flex-Item zu block blockifiziert, und ein Kind mit auto-Cross-Size wird von
1507
+ align-items:stretch auf die volle Spaltenbreite gezogen: aus der Pille wird ein Balken
1508
+ (gemessen im Featured-Body bei 1280 px Kartenbreite: 448 px statt 146 px). Im normalen Fluss
1509
+ ist die Zeile ein No-Op, ein inline-block schrumpft dort ohnehin auf seinen Inhalt. Darum hier
1510
+ an der Komponente und nicht als align-self je Container: die Pille bringt ihre Form selbst mit,
1511
+ statt sie von jedem Layout einzeln zugewiesen zu bekommen. Deckt Flex und Grid in einem ab,
1512
+ denn eine definierte Cross-Size schlägt stretch in beiden. */
1513
+ .pill{display:inline-block;width:fit-content;font:var(--ty-label-xs);letter-spacing:.09em;text-transform:uppercase;padding:var(--s1) var(--s3);border-radius:var(--r-full);margin-bottom:var(--s5);background:var(--co-fill);color:var(--co-800)}
1514
+ .pill[data-area="co"]{background:var(--co-fill);color:var(--co-800)}
1515
+ .pill[data-area="ki"]{background:var(--ki-fill);color:var(--ki-800)}
1516
+ .pill[data-area="es"]{background:var(--es-fill);color:var(--es-800)}
1517
+ .pill[data-area="wo"]{background:var(--wo-fill);color:var(--wo-800)}
1518
+ .article-title{font:var(--ty-display-md);color:var(--tx-primary);margin:0 0 var(--s4);text-wrap:balance}
1519
+ /* Lead-Paragraph für Artikel-Header: 18 px, eine Stufe über Body-Md (16) und unter Title-Sm (20).
1520
+ Bewusst hardcoded statt eigenes Token, weil Lead nur in einer Komponente vorkommt. */
1521
+ .article-lead{font:400 1.125rem/1.75rem var(--font);color:var(--tx-secondary);margin:0 auto;max-width:680px;text-wrap:pretty}
1522
+ /* Meta-Strip: Avatar · Name/Rolle · Trenner · Datum */
1523
+ .article-meta{display:flex;align-items:center;justify-content:center;gap:var(--s4);margin-top:var(--s8);flex-wrap:wrap}
1524
+ .article-meta-author{display:flex;align-items:center;gap:var(--s3)}
1525
+ .article-meta-text{text-align:left}
1526
+ .article-meta-name{font:var(--ty-label-md);color:var(--tx-primary);margin:0}
1527
+ .article-meta-role{font:var(--ty-body-xs);color:var(--tx-muted);margin:0}
1528
+ .article-meta-sep{display:inline-block;width:1px;height:24px;background:var(--n-200)}
1529
+ .article-meta-date{font:var(--ty-body-sm);color:var(--tx-secondary);margin:0}
1530
+ /* Avatar (Initialen-Kreis), area-aware; .article-avatar-lg für Author-Card-Größe; <img> als Kind ersetzt die Initialen */
1531
+ .article-avatar{width:40px;height:40px;border-radius:var(--r-full);display:flex;align-items:center;justify-content:center;font:600 0.875rem/1 var(--font);letter-spacing:.04em;flex-shrink:0;background:var(--co-100);color:var(--co-800);position:relative;overflow:hidden}
1532
+ .article-avatar img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block}
1533
+ .article-avatar[data-area="co"]{background:var(--co-100);color:var(--co-800)}
1534
+ .article-avatar[data-area="ki"]{background:var(--ki-100);color:var(--ki-800)}
1535
+ .article-avatar[data-area="es"]{background:var(--es-100);color:var(--es-700)}
1536
+ .article-avatar[data-area="wo"]{background:var(--wo-100);color:var(--wo-800)}
1537
+ .article-avatar-lg{width:64px;height:64px;font-size:1.25rem}
1538
+ /* XL für Team-Tile-Grid auf Landing/Über-uns: 160 px (war 112 px). Mit 4 Tiles pro Reihe (col-3)
1539
+ füllt das Foto die Tile-Breite sinnvoll aus, statt verloren in der Whitespace zu wirken.
1540
+ Author-Card-Bios bleiben bei -lg (64 px), weil sie horizontal neben Bio-Text sitzen. */
1541
+ .article-avatar-xl{width:160px;height:160px;font-size:3rem}
1542
+ /* Mobile: spaltenrelativ, damit der Avatar (160px fix, flex-shrink:0) in den schmalen Spalten der
1543
+ 2-/3-spaltigen Team- und Roster-Grids nicht überläuft. 72 % der Tile-Breite, gedeckelt bei 112px;
1544
+ aspect-ratio:1 hält ihn quadratisch (height:auto statt der fixen 160px). Bei 3-Spalten/375px
1545
+ (~93px Spalte) → ~67px, bei breiteren Spalten bis max. 112px. Desktop bleibt bei 160px. */
1546
+ @media(max-width:768px){.article-avatar-xl{width:min(112px,72%);height:auto;aspect-ratio:1;font-size:1.875rem}}
1547
+ /* Multi-Author: Avatare gestapelt mit weißem Border-Halo zur visuellen Überlappung */
1548
+ .article-avatar-stack{display:inline-flex;align-items:center;flex-shrink:0}
1549
+ .article-avatar-stack .article-avatar{border:2px solid var(--bg-surface)}
1550
+ .article-avatar-stack .article-avatar + .article-avatar,
1551
+ .article-avatar-stack .article-avatar + .article-avatar-more{margin-left:-12px}
1552
+ .article-avatar-stack .article-avatar-lg + .article-avatar-lg,
1553
+ .article-avatar-stack .article-avatar-lg + .article-avatar-more{margin-left:-16px}
1554
+ /* "+N"-Indikator für 4+ Autor:innen */
1555
+ .article-avatar-more{width:40px;height:40px;border-radius:var(--r-full);background:var(--n-100);color:var(--tx-secondary);display:flex;align-items:center;justify-content:center;font:600 0.75rem/1 var(--font);letter-spacing:.02em;flex-shrink:0;border:2px solid var(--bg-surface)}
1556
+ /* Author-Card-Group: mehrere Author-Cards untereinander am Artikelende */
1557
+ .author-card-group{max-width:720px;margin:0 auto;display:flex;flex-direction:column;gap:var(--s6)}
1558
+ .author-card-group .author-card{margin:0;max-width:none}
1559
+ /* Zwei-Spalten-Variante der Gruppe: für Personen mit Kurz-Bio, wo die gestapelte Liste zu lang
1560
+ würde, typisch Trainer:innen auf einer Seminar-/Training-Landing (2 bis 4 Personen). Die Bio
1561
+ ist dort das Vertrauenselement und darf nicht wegfallen, deshalb Raster statt Tile-Grid
1562
+ (.article-avatar-xl ohne Bio, siehe #gt-article-team-tiles). 960 statt 720 px Container, weil
1563
+ zwei Karten nebeneinander sonst je ~340 px hätten und der 64-px-Avatar den Text auf ~260 px
1564
+ drückt. minmax(0,1fr) verhindert Grid-Blowout durch lange Namen. */
1565
+ .author-card-group.is-grid{max-width:960px;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:var(--s8)}
1566
+ /* Mobil einspaltig, konsistent mit dem Kollaps der .layout-grid bei 768px. Engerer Abstand,
1567
+ weil untereinander kein Spaltenabstand mehr trennt und --s8 dort als Loch wirken würde. */
1568
+ @media(max-width:768px){.author-card-group.is-grid{grid-template-columns:1fr;gap:var(--s6)}}
1569
+ /* Eine gemeinsame Gruppen-Überschrift („Über die Autor:innen“), ersetzt die Eyebrows der einzelnen Cards */
1570
+ .author-card-group-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--tx-muted);margin:0 0 var(--s2);max-width:720px;margin-left:auto;margin-right:auto}
1571
+ /* Die Überschrift steht als Geschwister VOR der Gruppe und muss deren Container-Breite mitgehen,
1572
+ sonst sitzt sie bei der Raster-Variante 120 px links neben der ersten Karte. */
1573
+ .author-card-group-eyebrow:has(+ .author-card-group.is-grid){max-width:960px}
1574
+ /* Body: 720px-Spalte mit Article-Typo, H2/Listen automatisch gestylt */
1575
+ .article-body{max-width:720px;margin:0 auto;font:var(--ty-body-md);color:var(--tx-primary);line-height:1.7}
1576
+ .article-body > p{margin:0 0 var(--s5)}
1577
+ .article-body > p:last-child{margin-bottom:0}
1578
+ .article-body h2{font:var(--ty-headline-sm);color:var(--tx-primary);margin:var(--s10) 0 var(--s4);text-wrap:balance}
1579
+ .article-body ul,.article-body ol{padding-left:var(--s5);margin:0 0 var(--s5)}
1580
+ .article-body ul li{margin-bottom:var(--s4)}
1581
+ .article-body ol li{margin-bottom:var(--s3)}
1582
+ /* In-Article Figure: redaktionelles Inline-Bild mit Bildunterschrift; alt beschreibt, figcaption ordnet ein */
1583
+ .article-figure{margin:var(--s8) 0}
1584
+ .article-figure img{width:100%;aspect-ratio:16/9;object-fit:cover;border-radius:var(--r-lg);display:block;background:var(--n-100)}
1585
+ .article-figcaption{font:var(--ty-body-md);color:var(--tx-secondary);text-align:center;margin:var(--s3) 0 0;text-wrap:balance}
1586
+ /* Inhaltsverzeichnis: aufklappbar via native <details>/<summary>, default zugeklappt; minimaler Stil — kein Container, nur dünne Trennlinien oben/unten */
1587
+ .article-toc{max-width:720px;margin:var(--s6) auto var(--s8);border-block:var(--bd)}
1588
+ .article-toc-summary{display:flex;align-items:center;justify-content:space-between;gap:var(--s3);padding:var(--s3) 0;font:var(--ty-label-md);color:var(--tx-primary);cursor:pointer;list-style:none}
1589
+ .article-toc-summary::-webkit-details-marker{display:none}
1590
+ .article-toc-summary:hover{color:var(--co-700)}
1591
+ .article-toc-summary:focus-visible{outline:none;box-shadow:var(--focus-aa);border-radius:2px}
1592
+ .article-toc-caret{width:16px;height:16px;flex-shrink:0;color:var(--tx-secondary);transition:transform var(--m-fast)}
1593
+ .article-toc[open] .article-toc-caret{transform:rotate(180deg)}
1594
+ .article-toc-list{list-style:none;counter-reset:toc;padding:var(--s2) 0 var(--s4);margin:0}
1595
+ .article-toc-list li{display:flex;gap:var(--s3);align-items:baseline;padding:3px 0}
1596
+ .article-toc-list li::before{content:counter(toc);counter-increment:toc;color:var(--tx-secondary);font:var(--ty-label-sm);font-variant-numeric:tabular-nums;flex-shrink:0;min-width:1.25em}
1597
+ .article-toc-list a{color:var(--tx-primary);text-decoration:none;font:var(--ty-body-md);line-height:1.5}
1598
+ .article-toc-list a:hover{text-decoration:underline;text-underline-offset:3px;color:var(--co-700)}
1599
+ .article-toc-list a:focus-visible{outline:none;box-shadow:var(--focus-aa);border-radius:2px}
1600
+ /* Callout: Aside im Body, area-aware. Border-Akzent in 500 (wie .bq), Eyebrow in 700 (wie .cta-dl-eyebrow) */
1601
+ .article-callout{background:var(--co-50);border-left:4px solid var(--co-500);border-radius:var(--r-md);padding:var(--s5) var(--s6);margin:var(--s8) 0}
1602
+ .article-callout[data-area="co"]{background:var(--co-50);border-left-color:var(--co-500)}
1603
+ .article-callout[data-area="ki"]{background:var(--ki-50);border-left-color:var(--ki-500)}
1604
+ .article-callout[data-area="es"]{background:var(--es-50);border-left-color:var(--es-500)}
1605
+ .article-callout[data-area="wo"]{background:var(--wo-50);border-left-color:var(--wo-500)}
1606
+ .article-callout-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--co-700);margin:0 0 var(--s1)}
1607
+ .article-callout[data-area="ki"] .article-callout-eyebrow{color:var(--ki-800)}
1608
+ .article-callout[data-area="es"] .article-callout-eyebrow{color:var(--es-700)}
1609
+ .article-callout[data-area="wo"] .article-callout-eyebrow{color:var(--wo-700)}
1610
+ .article-callout > p{font:var(--ty-body-md);color:var(--tx-primary);margin:0}
1611
+ /* Author-Card: Avatar + Bio am Ende des Artikels, area-aware */
1612
+ .author-card{max-width:720px;margin:0 auto;display:flex;gap:var(--s5);align-items:flex-start}
1613
+ .author-card-eyebrow{font:var(--ty-label-xs);letter-spacing:.08em;text-transform:uppercase;color:var(--tx-muted);margin:0 0 var(--s1)}
1614
+ .author-card-name{font:var(--ty-title-sm);color:var(--tx-primary);margin:0}
1615
+ .author-card-role{font:var(--ty-body-sm);color:var(--tx-secondary);margin:0 0 var(--s3)}
1616
+ .author-card-bio{font:var(--ty-body-md);color:var(--tx-primary);margin:0}
1617
+ /* Pull-Quote: typografische Hervorhebung autoreigener Sätze im Body — area-aware Linksakzent in 500 (analog .bq), aber ohne Background und ohne Quote-Icon */
1618
+ .article-pullquote{margin:var(--s10) 0;padding:var(--s4) var(--s6);border-left:4px solid var(--co-500);font-family:var(--font-display);font-style:italic;font-size:clamp(1.375rem, 1.222rem + 0.68vw, 1.75rem);line-height:1.4;color:var(--tx-primary);quotes:none}
1619
+ .article-pullquote[data-area="co"]{border-left-color:var(--co-500)}
1620
+ .article-pullquote[data-area="ki"]{border-left-color:var(--ki-500)}
1621
+ .article-pullquote[data-area="es"]{border-left-color:var(--es-500)}
1622
+ .article-pullquote[data-area="wo"]{border-left-color:var(--wo-500)}
1623
+
1624
+ /* ── Documentation tables (Verwendung, Barrierefreiheit, etc.) ── */
1625
+ .doc-table{width:100%;border-collapse:collapse;font:var(--ty-body-md)}
1626
+ .doc-table thead tr{border-bottom:var(--bd-strong)}
1627
+ .doc-table th{text-align:left;padding:var(--s2) var(--s3) var(--s2) 0;font:500 0.75rem/1rem var(--font);letter-spacing:.06em;text-transform:uppercase;color:var(--tx-secondary)}
1628
+ .doc-table th:last-child{padding-left:var(--s3)}
1629
+ .doc-table tbody tr{border-bottom:var(--bd)}
1630
+ .doc-table tbody tr:last-child{border-bottom:none}
1631
+ .doc-table td{padding:var(--s3) var(--s3) var(--s3) 0;color:var(--tx-secondary);vertical-align:top}
1632
+ .doc-table td:first-child{color:var(--tx-primary);font-weight:500}
1633
+ .doc-table td:last-child{padding-left:var(--s3)}