/* ============================================================
   siduvia — Komponenten
   Wiederverwendbare Bausteine. Nur Tokens aus styles.css.
   Benennung BEM (.block__element--modifier), Zustände über
   Attribute (aria-*, :disabled) statt Zusatzklassen.
   Reihenfolge: styles.css → add-styles.css → components.css
   ============================================================ */

/* -------------------- Header --------------------
   Sticky; Desktop: fährt mit dem Scrollen ein/aus (--header-offset,
   main.js), unter 960px steht er. Höhe = --header-height (add-styles.css).
   .is-compact / .is-open / .is-measuring setzt main.js.
------------------------------------------------- */
.header {
  position: sticky;
  top: 0;
  translate: 0 calc(var(--header-offset, 0px) * -1);
  will-change: translate; /* eigene Ebene → Verschieben ohne Neuzeichnen */
  z-index: 100;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--layout-spacing-container-gap-1x);
  /* feste Höhe (56px, Mobile 48px, + Safe-Area oben), kein Padding
     oben/unten außer der Safe-Area (Statusleiste) */
  height: var(--header-height);
  padding: env(safe-area-inset-top, 0px) var(--page-gutter-end) 0 var(--page-gutter-start);
  --header-surface: var(--surface-color-layer-2);
  background: var(--header-surface);
}

/* Header in den Farbthemen (Grey, Yellow, Green, Blue): Fläche der Seite
   (layer-1), Controls darin wie auf der Seite. In Default bleibt er
   Ebene 2 mit Controls eine Ebene weiter (wie eine Card). */
:is([data-theme='Grey'], [data-theme='Yellow'], [data-theme='Green'], [data-theme='Blue']) > .header,
.header:is([data-theme='Grey'], [data-theme='Yellow'], [data-theme='Green'], [data-theme='Blue']) {
  --header-surface: var(--surface-color-layer-1);
  --surface-color-cutout: var(--surface-color-layer-0);
  --surface-color-next: var(--surface-color-layer-2);
  --surface-color-next-2: var(--surface-color-layer-3);
}

/* Erstes Ausfahren nach dem Hero (Desktop): Scroll-Animation ab
   --header-hold (main.js) über die Headerhöhe — läuft synchron mit dem
   Scrollen, nahtlos nach dem Andocken der Links. transform statt
   translate: addiert sich zum JS-Versatz. main.js setzt .is-scroll-exit
   nur, solange der Header dieser Strecke folgt. */
@media (min-width: 960px) {
  @supports (animation-timeline: scroll()) {
    .header.is-scroll-exit:not(.is-open) {
      animation: header-exit linear both;
      animation-timeline: scroll(root block);
      animation-range: var(--header-hold, 0px) calc(var(--header-hold, 0px) + var(--header-height));
    }
  }
}

@keyframes header-exit {
  to {
    transform: translateY(-100%);
  }
}

/* Unter 960px fährt der Header nie aus → kein Versatz, keine eigene
   Ebene. Wichtig fürs mobile Menü: translate/will-change würden das
   position: fixed der Nav an den Header binden statt an den Viewport. */
@media (max-width: 959px) {
  .header {
    translate: none;
    will-change: auto;
  }
}

/* Logo: assets/logo/siduvia-diagnostik.svg, inline mit currentColor
   (→ Mode-Farbe). viewBox auf „siduvia*" zugeschnitten (0 0 105 17),
   „diagnostik" (.header__logo-suffix) zeichnet darüber hinaus
   (overflow: visible) — so zählt beim großen, skalierten Logo nur
   „siduvia*" zur Seitenbreite. Höhe 17px, Breite aus dem
   Seitenverhältnis --logo-ratio (viewBox-Breite / 17, Standard 105 / 17).
   App-Logos setzen es in ihrer App (siehe App-Header). */
.header__logo {
  --logo-height: calc(var(--rem-5-5x) * 17 / 22);

  flex: none;
  width: calc(var(--logo-height) * var(--logo-ratio, 105 / 17));
  color: var(--mode-color-logo);
}

.header__logo-svg {
  display: block;
  width: calc(var(--logo-height) * var(--logo-ratio, 105 / 17));
  height: var(--logo-height);
  overflow: visible;
  /* Klicks nur auf die Buchstaben, nicht auf die ganze (groß skalierte)
     Fläche — sonst trifft der Klick den Link über dem Seiteninhalt */
  pointer-events: none;
}

.header__logo-svg path {
  pointer-events: auto;
}

/* „diagnostik": erscheint, sobald das Logo seine normale Größe hat —
   Buchstabe für Buchstabe von links nach rechts eingeblendet (jeder
   Buchstabe ein eigener <path> mit --i = 0…9). Gesamtdauer = long
   (250ms): je Buchstabe die halbe Dauer, Versatz so verteilt, dass der
   letzte (i = 9) genau am Ende fertig ist. Beim Hochscrollen (Logo
   wird wieder größer) sofort weg.
   Auslöser: --logo-docked (0/1) setzt die Scroll-Animation am SVG
   (Ende der Schrumpf-Strecke, siehe großes Logo); per Style-Query
   startet das Einblenden, sobald es 1 wird, und entfällt sofort bei 0.
   Seiten ohne Hero: immer 1 → sichtbar.
   „Bewegung reduzieren": Dauer 0 → sofort sichtbar. */
@property --logo-docked {
  syntax: '<integer>';
  inherits: true;
  initial-value: 1;
}

.header__logo-suffix path {
  opacity: 0;
}

@container style(--logo-docked: 1) {
  .header__logo-suffix path {
    opacity: 1;
    animation: header-logo-letter-in calc(var(--transition-duration-long) / 2) var(--transition-easing-out) both;
    animation-delay: calc(var(--transition-duration-long) / 2 / 9 * var(--i, 0));
  }
}

@keyframes header-logo-letter-in {
  from {
    opacity: 0;
  }
}

/* Kleines Handy (< 375px, wie die Typo): Logo 25 % kleiner */
@media (max-width: 374px) {
  .header__logo {
    --logo-height: calc(var(--rem-5-5x) * 17 / 22 * 0.75);
  }
}

.header__nav {
  position: relative;
  z-index: 1; /* über dem (skalierten) Logo */
  flex: 1;
  min-width: 0;
}

/* Einzeilig, rechtsbündig — main.js misst, ob das passt */
.header__menu {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  flex-wrap: nowrap;
  gap: var(--layout-spacing-container-gap-1x);
}

/* -------- Darstellung (Light / Dark / System) --------
   Ein Element für Desktop und mobiles Menü: Kontextmenü-Button (⋮) mit
   Flyout — Überschrift (<p><small>), darunter Button-Group nur mit Icons
   (Sonne, Mond, Laptop). Desktop: letzter Eintrag im Menü (Seiten ohne
   Menü: direkt im Header). Mobiles Menü: nur die Button-Group, ohne
   Button, Flyout-Fläche und Überschrift — oben rechts unter dem X.
   Speichern und Anwenden: main.js (initModeSwitch), Start: js/mode.js.
   Icon 24px und bündig mit dem Seitenrand: Button (40px) um
   (Icon − Button) / 2 nach außen gezogen (wie der Burger). */
.header__mode {
  --toggle-icon: var(--rem-6x); /* Icon 24px wie Burger und X */

  margin-inline-end: calc((var(--toggle-icon) - var(--rem-10x)) / 2);
}

.header__mode > .flyout__toggle .btn__icon,
.header__mode > .flyout__toggle .btn__icon s-icon {
  width: var(--toggle-icon);
  height: var(--toggle-icon);
}

/* Überschrift und Button-Group gehören zusammen (wie Label und Feld):
   8px statt des Flyout-Standards (24px zwischen Blöcken) */
.header__mode .flyout__content {
  gap: var(--flyout-pad);
}

.header.is-compact .header__mode-item {
  --link-index: 0;
  position: absolute;
  top: var(--layout-spacing-container-gap-1x);
  right: var(--page-gutter-end);
}

.header.is-compact .header__mode {
  margin-inline-end: 0;
}

.header.is-compact .header__mode > .flyout__toggle,
.header.is-compact .header__mode .flyout__content > :not(.btn-group) {
  display: none;
}

/* Fenster und Inhalt lösen sich auf: die Button-Group steht direkt da */
.header.is-compact .header__mode :is(.flyout__window, .flyout__content) {
  display: contents;
}

.header.is-compact .header__mode .flyout__content > .btn-group {
  visibility: visible; /* das (aufgelöste) Fenster ist zu: hidden erbt sich */
  opacity: 1;
  animation: none;
}

.header__menu li {
  white-space: nowrap;
}

/* Burger-Button: System-Button Ghost, nur Icon
   (<button class="btn btn--ghost header__toggle">). Nur im kompakten
   Modus sichtbar. Ausnahme: Icon 1,5 × so groß (24px statt 16px).
   Der Button ist breiter als das Icon → rechts um die Differenz nach
   außen gezogen, damit das Icon bündig mit dem Seitenrand steht:
   (Icon − Buttonhöhe) / 2. */
.header .header__toggle {
  --toggle-icon: var(--rem-6x);

  /* immer eigene Ebene über dem (großen, scroll-animierten) Logo —
     nicht erst bei .is-open: sonst entscheidet iOS Safari beim Scrollen
     je Bild neu, was oben liegt → Burger flackert */
  position: relative;
  z-index: 3;
  display: none;
  margin-inline-end: calc((var(--toggle-icon) - var(--btn-height)) / 2);
}

.header .header__toggle .btn__icon,
.header .header__toggle .btn__icon s-icon {
  width: var(--toggle-icon);
  height: var(--toggle-icon);
}

/* -------- Kompakter Modus (.is-compact, gesetzt von main.js) -------- */
.header.is-compact .header__toggle {
  display: inline-flex;
}

/* Offenes Menü: fest unter der Leiste bis zum unteren Rand — auch wenn
   der Header (Mobile/Tablet, großes Logo) gerade noch höher ist. Unter
   960px hat der Header kein translate/will-change, fixed bezieht sich
   also auf den Viewport; darüber auf den Header (steht beim Öffnen oben).
   Fläche wie die Leiste (--header-surface), deckend.
   Öffnen: Fläche blendet ein (short, ease-out), die Inhalte gleiten
   gestaffelt von unten ein. Schließen: Fläche blendet aus (ease-in). */
.header.is-compact .header__nav {
  position: fixed;
  top: var(--header-height, 0px);
  left: 0;
  right: 0;
  height: calc(100dvh - var(--header-height, 0px));
  padding: var(--layout-spacing-container-gap-1x) var(--page-gutter-end) var(--layout-spacing-container-gap-1x) var(--page-gutter-start);
  padding-bottom: calc(var(--layout-spacing-container-padding) + env(safe-area-inset-bottom, 0px));
  background: var(--header-surface);
  overflow-y: auto;
  overscroll-behavior: contain;
  display: none;
  opacity: 0;
  transition:
    opacity var(--transition-duration-short) var(--transition-easing-in),
    display var(--transition-duration-short) var(--transition-easing-in) allow-discrete;
}

.header.is-compact.is-open .header__nav {
  display: flex;
  flex-direction: column;
  transition-timing-function: var(--transition-easing-out);
  opacity: 1;
}

@starting-style {
  .header.is-compact.is-open .header__nav {
    opacity: 0;
  }
}

/* Inhalte gleiten von unten ein und blenden dabei ein (je short,
   ease-out), nacheinander — jeder Schritt eine halbe short-Dauer (75ms)
   später: die Hauptlinks, danach Service-Links und Buttons. So bleiben die Abstände beim Einfahren erhalten.
   Reihenfolge (--link-index) setzt main.js, für jede Anzahl Links. */
.header.is-compact .header__menu li,
.header.is-compact :is(.header__extra, .header__actions) {
  translate: 0 var(--rem-6x);
  opacity: 0;
}

.header.is-compact.is-open .header__menu li,
.header.is-compact.is-open :is(.header__extra, .header__actions) {
  --link-delay: calc(var(--transition-duration-short) * var(--link-index, 1) * 0.5);
  translate: 0 0;
  opacity: 1;
  transition:
    translate var(--transition-duration-short) var(--transition-easing-out) var(--link-delay),
    opacity var(--transition-duration-short) var(--transition-easing-out) var(--link-delay);
}

@starting-style {
  .header.is-compact.is-open .header__menu li,
  .header.is-compact.is-open :is(.header__extra, .header__actions) {
    translate: 0 var(--rem-6x);
    opacity: 0;
  }
}

.header.is-compact .header__menu {
  flex-direction: column;
  align-items: flex-start;
  text-align: left;
}

/* Während main.js misst: keine Übergänge im Header (Menü würde beim
   Zurückschalten kurz sichtbar ausblenden). !important, weil die
   Zustände (.is-compact.is-open …) spezifischer sind — gilt nur für
   diesen kurzen Messzustand. */
.header.is-measuring,
.header.is-measuring * {
  transition: none !important;
}

/* -------- Mobiles Menü: Layout --------
   Alles unten angedockt (Daumenreichweite): Hauptlinks (linksbündig),
   darunter Service-Links und zwei Termin-Buttons (Primary): Mobile
   < 640px einspaltig, Tablet zweispaltig (Buttons 50 : 50).
   .header__extra und .header__actions gibt es nur im mobilen Menü
   (Desktop: ausgeblendet). */
.header__extra,
.header__actions {
  display: none;
}

.header.is-compact .header__menu {
  gap: var(--rem-2x);
  /* ans untere Ende geschoben: Hauptlinks sitzen direkt über dem
     Service-Bereich */
  margin-top: auto;
}

/* Abstände: Hauptlinks → Linie → Service-Links je gap-1x,
   Service-Links → Buttons doppelt (2 × gap-1x) */
.header.is-compact .header__extra {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--layout-spacing-container-gap-1x);
  margin-top: var(--layout-spacing-container-gap-1x);
  padding-block: var(--layout-spacing-container-gap-1x) 0;
}

.header__sub {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--rem-2x) var(--layout-spacing-container-gap-1x);
  margin: 0;
  padding: 0;
  list-style: none;
}

.header__sub a {
  color: var(--typography-color-text-secondary);
  text-decoration: none;
}

@media (hover: hover) {
  .header__sub a:hover {
    color: var(--typography-color-text-primary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .header__sub a:active {
    color: var(--typography-color-text-primary);
  }
}

.header__sub a[aria-current='page'] {
  color: var(--typography-color-text-primary);
}

.header.is-compact .header__actions {
  display: grid;
  grid-template-columns: 1fr;
  /* doppelter Abstand zu den Service-Links (gap-2x ist nicht
     überall das Doppelte von gap-1x) */
  margin-top: calc(var(--layout-spacing-container-gap-1x) * 2);
  /* Spaltenabstand wie bei den Service-Links → Spalten fluchten */
  gap: var(--controls-spacing-container-gap-large) var(--layout-spacing-container-gap-1x);
}

@media (min-width: 640px) {
  .header__sub,
  .header.is-compact .header__actions {
    grid-template-columns: 1fr 1fr;
  }
}

.header__actions .btn {
  justify-content: space-between;
  min-width: 0;
}

/* Links wie im Sidemenu: inaktiv Regular + Secondary, Hover Primary,
   aktiv (aria-current="page", setzt main.js) Bold + Primary */
.header__link {
  text-decoration: none;
  font-weight: 400;
  color: var(--typography-color-text-secondary);
}

@media (hover: hover) {
  .header__link:hover {
    color: var(--typography-color-text-primary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .header__link:active {
    color: var(--typography-color-text-primary);
  }
}

.header__link[aria-current='page'] {
  font-weight: 700;
  color: var(--typography-color-text-primary);
}

/* Mobiles Menü: Links in h2-Größe, Schnitt wie .secondary (Light 300);
   der aktive Link ohne Secondary (Bold 700) */
.header.is-compact .header__link {
  font-size: var(--typography-font-size-h2);
  font-weight: 300;
  line-height: 1.25;
}

.header.is-compact .header__link[aria-current='page'] {
  font-weight: 700;
}

/* -------------------- Header: großes Logo über dem Hero --------------------
   Beginnt die Seite mit einem Hero (mit und ohne Bild):
   - Scroll 0: oben links, so groß, dass das Logo N Spalten breit ist:
     Desktop 3 von 12, Tablet 4 von 6, Mobile 3 von 4.
   - Beim Runterscrollen schrumpft es (scroll-driven, scale) auf die
     normale Größe — fertig, wenn die Oberkante des Heros die Header-
     Unterkante erreicht (Bild-Hero: Oberkante Bild; Hero ohne Bild:
     Oberkante Headline). Solange steht der Header.
   Strecke (--logo-shrink-end) misst main.js beim Laden und bei
   Größenänderung — hängt beim Bild-Hero vom Inhalt ab. Fallback bis
   dahin: ungefähr die freie Fläche über dem Bild.
   Startgröße: Zielbreite (--logo-start-width, als <length> registriert
   → in px aufgelöst) / Wortbreite rechnet main.js beim Laden und bei
   Größenänderung → --logo-start-scale (Zahl). Nicht per
   tan(atan2(a, b)) im CSS: Safari auf iPadOS rechnet das falsch
   (negativ → Logo auf dem Kopf, gespiegelt).
   Offenes Menü: Desktop — Skalierung bleibt; Mobile/Tablet — Logo
   gleitet in die Leiste (main.js, animateLogo).
   Browser ohne Scroll-Animationen (Firefox): Logo in normaler Größe.
--------------------------------------------------------------------------------------- */
@property --logo-start-width {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

/* Scharf auch in Safari: das SVG wird in der großen Startgröße gerendert
   und beim Scrollen HERUNTER skaliert (1 → 1 / Startfaktor). Hoch-
   skalieren einer kleinen Grafik würde Safari verpixeln. Das große SVG
   liegt absolut im Link — der behält seine normale Größe (Layout). */
body:has(> main > .hero:first-child) > .header .header__logo {
  position: relative;
  height: var(--logo-height);
}

body:has(> main > .hero:first-child) > .header .header__logo-svg {
  /* Startbreite = --logo-cols von --grid-cols Spalten (inkl. Gaps).
     Inhaltsbreite in vw wie --page-gutter (max. 1920px) — --page-gutter
     selbst rechnet mit %, das kann die registrierte <length> hier nicht
     auflösen. */
  --grid-cols: 12;
  --logo-cols: 3;
  --logo-start-width: calc(
    (min(100vw, 1920px) - var(--layout-spacing-container-padding) * 2 - var(--layout-spacing-container-gap-1x) * (var(--grid-cols) - 1))
    / var(--grid-cols) * var(--logo-cols)
    + var(--layout-spacing-container-gap-1x) * (var(--logo-cols) - 1)
  );

  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--logo-height) * 105 / 17 * var(--logo-start-scale, 1));
  max-width: none; /* globales max-width: 100% würde auf die Linkbreite begrenzen */
  height: calc(var(--logo-height) * var(--logo-start-scale, 1));
  transform-origin: 0 0;
  animation:
    header-logo-shrink linear both,
    header-logo-docked step-end both;
  animation-timeline: scroll(root block);
  animation-range: 0px var(--logo-shrink-end, 30svh);
}

/* 0 während des Schrumpfens, 1 am Ende → „diagnostik" (siehe Logo) */
@keyframes header-logo-docked {
  from {
    --logo-docked: 0;
  }

  to {
    --logo-docked: 1;
  }
}

@keyframes header-logo-shrink {
  from {
    scale: 1;
  }

  to {
    scale: calc(1 / var(--logo-start-scale, 1));
  }
}

/* Menü-Links (Desktop, nicht kompakt): bei Scroll 0 auf der Grundlinie
   der Hero-Headline, fahren beim Scrollen 1:1 mit dem Inhalt hoch und
   stehen dann an ihrem normalen Platz im Header. Reines CSS:
   translate von --nav-drop → 0 über die Scroll-Strecke bis dorthin, wo
   der Header losfährt (≥ --nav-drop, fast 1:1).
   --nav-drop = Grundlinie h1 − Grundlinie Links im Header:
     h1:    --hero-head (Unterkante Headline-Hero) − 32px (Hero-Padding, die
            h1 ist unten auf die Grundlinie getrimmt, siehe Hero)
     Links: Headermitte + (Ober- − Unterlänge) / 2 der Schrift
            (Suisse Intl: 0,984em − 0,3125em → 0,336em)
   Gilt nur, solange der Headline-Hero seine Mindesthöhe hat (Headline
   nicht höher als 50svh). Browser ohne Scroll-Animationen: Links
   bleiben im Header. */
/* registriert → berechneter Wert in px; main.js liest ihn und lässt
   den Header stehen, bis die Links angedockt sind (sonst führen sie
   doppelt so schnell: eigene Strecke + Ausfahren des Headers) */
@property --nav-drop {
  syntax: '<length>';
  inherits: false;
  initial-value: 0px;
}

@media (min-width: 960px) {
  @supports (animation-timeline: scroll()) {
    body:has(> main > .hero:first-child:not(.hero--image)) > .header:not(.is-compact) .header__menu {
      --nav-drop: calc(var(--hero-head) - var(--rem-8x) - var(--header-height) / 2 - 0.336em);

      animation: header-nav-dock linear both;
      animation-timeline: scroll(root block);
      /* Ende = wo der Header losfährt (main.js: max aus Hero-Kante und
         --nav-drop) → Links gehen nahtlos ins Ausfahren über, statt
         angedockt kurz stehen zu bleiben */
      animation-range: 0px max(var(--nav-drop), var(--header-hold, 0px));
    }
  }
}

@keyframes header-nav-dock {
  from {
    translate: 0 var(--nav-drop);
  }

  to {
    translate: none;
  }
}

/* Startbreite Tablet: 4 von 6 Spalten · Mobile: 3 von 4 */
@media (max-width: 959px) {
  body:has(> main > .hero:first-child) > .header .header__logo-svg {
    --grid-cols: 6;
    --logo-cols: 4;
  }
}

@media (max-width: 639px) {
  body:has(> main > .hero:first-child) > .header .header__logo-svg {
    --grid-cols: 4;
    --logo-cols: 3;
  }
}

/* Offenes Menü: Logo behält seine (skalierte) Größe und liegt über
   der Menüfläche (die Nav liegt sonst über dem Logo, z-index 1) */
.header.is-open .header__logo {
  position: relative;
  z-index: 2;
}

/* ====================================================================
   App-Bausteine (Praxis, Coaching und weitere Apps)
   Eine App-Seite scrollt nicht als Ganzes: oben die Kopfleiste, darunter
   die Ansicht als eigener Scrollbereich. Ansichtswechsel (data-view u. Ä.)
   regelt jede App selbst.
   <body>
     <div class="app">
       <header class="header app-header">…</header>
       <main class="app-scroll">
         <div class="page-head page-head--sticky grid" data-theme="Grey">…</div>
         <div class="page-body grid">…</div>
       </main>
     </div>
   </body>
   ==================================================================== */

/* -------------------- App-Layout -------------------- */
html:has(> body > .app),
body:has(> .app) {
  height: 100%;
}

body:has(> .app) {
  overflow: hidden;
}

.app {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto minmax(0, 1fr);
  height: 100dvh;
}

.app-scroll {
  min-height: 0;
  overflow-y: auto;
}

/* -------------------- App-Header --------------------
   .header (Fläche, Höhe, Seitenrand, Logo, Darstellung ⋮) in drei
   Spalten: links Logo der App, Mitte Bereiche (Button-Group), rechts
   Status, Werkzeuge und ⋮. Die äußeren Spalten sind gleich breit →
   Bereiche genau mittig. Links nie schmaler als das Logo, rechts darf
   schrumpfen (Apps können Werkzeuge dann ins Flyout verschieben).
   App-Logo: inline-SVG mit currentColor aus assets/logo/ (viewBox auf
   17 Höhe zugeschnitten), die App setzt das Seitenverhältnis:
     .app-header .header__logo { --logo-ratio: 173 / 17; }   siduvia*praxis
     .app-header .header__logo { --logo-ratio: 176 / 17; }   siduvia*coach
   __block: eigener Block im ⋮-Flyout über „Darstellung“ (z. B. Konto,
   Sicherheit), untereinander; Felder darin volle Breite.
   Mobil (< 640px): oben Logo und Navigation, die Bereiche in eigener
   Zeile darunter über die volle Breite (Buttons gleich breit).
   <header class="header app-header">
     <div class="app-header__brand"><span class="header__logo" role="img" aria-label="siduvia praxis"><svg class="header__logo-svg" viewBox="0 -0.5 173 17" …>…</svg></span></div>
     <div class="btn-group app-header__bereiche" role="group" aria-label="Bereich">…</div>
     <div class="app-header__nav">
       <small class="text-secondary">Status</small>
       <div class="flyout header__mode">… <div class="flyout__content">
         <div class="app-header__block">…</div>
         <p><small>Darstellung</small></p> …
       </div></div>
     </div>
   </header>
------------------------------------------------------------ */
.app-header {
  z-index: 10;
  display: grid;
  grid-template-columns: minmax(max-content, 1fr) auto minmax(0, 1fr);
}

.app-header__brand {
  display: flex;
  flex: none;
  grid-column: 1;
  align-items: center;
  gap: var(--layout-spacing-container-gap-1x);
}

.app-header__bereiche {
  grid-column: 2;
}

.app-header__nav {
  display: flex;
  grid-column: 3;
  align-items: center;
  justify-content: flex-end;
  gap: var(--controls-spacing-container-gap-large);
  min-width: 0;
}

.app-header__nav > * {
  flex: none;
}

/* Abstand nach unten wie zwischen Flyout-Blöcken (--flyout-gap),
   der Flyout-Inhalt setzt selbst nur --flyout-pad */
.app-header__block {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--controls-spacing-container-gap-medium);
  margin-block-end: calc(var(--flyout-gap) - var(--flyout-pad));
}

.app-header__block .field {
  align-self: stretch;
}

/* Mobil: zweite Zeile für die Bereiche; die erste behält die Leistenhöhe */
@media (max-width: 639px) {
  .app-header {
    grid-template-columns: minmax(max-content, 1fr) minmax(0, 1fr);
    grid-template-rows: calc(var(--header-height) - env(safe-area-inset-top, 0px)) auto;
    row-gap: 0;
    height: auto;
    padding-block-end: var(--controls-spacing-container-padding-large);
  }

  .app-header__nav {
    grid-column: 2;
    grid-row: 1;
  }

  .app-header__bereiche {
    display: flex;
    grid-column: 1 / -1;
    grid-row: 2;
  }

  .app-header__bereiche > .btn {
    flex: 1 1 0;
    justify-content: center;
  }
}

/* -------------------- Seitenkopf (.page-head) --------------------
   Kopf einer Ansicht unter der Kopfleiste, im Seitenraster (.grid) und
   als eine Fläche (data-theme="Grey"). Zeilen:
     __title    Headline links, rechts __actions (Buttons, Button-Group).
                Secondary Headline (<span class="secondary">) in eigener
                Zeile darunter (wie Card und Section-Head)
     __tools    optional: links Info (p secondary), rechts Werkzeuge;
                so hoch wie ein Formularfeld → Seitenköpfe mit Werkzeugen
                und mit Suche/Filter sind gleich hoch
     __kpis     optional, neben der Headline: Kennzahlen ohne Card, je
                Kennzahl Wert (h3), darunter Rubrik (h5 secondary); je 2
                Spalten, Mobil 2 nebeneinander
     weitere    beliebige Inhalte mit Grid-Klassen (z. B. Suche, Filter)
   --sticky: bleibt im Scrollbereich (.app-scroll) oben stehen; Mobil nur
   die Headline-Zeile (Kopf display: contents → jede Zeile trägt Fläche
   und Seitenrand selbst).
   .page-body: Inhalt darunter (Abstand oben 2x, unten 4x).
   <div class="page-head page-head--sticky grid" data-theme="Grey">
     <header class="page-head__title col-12 flex-layout flex-layout--between flex-layout--center flex-layout--nowrap">
       <h3>Headline <span class="secondary">Secondary Headline</span></h3>
       <div class="page-head__actions flex-layout flex-layout--gap-s flex-layout--nowrap">…</div>
     </header>
     <div class="page-head__tools col-12 flex-layout flex-layout--gap-s flex-layout--end flex-layout--center">…</div>
   </div>
   <div class="page-body grid">…</div>
------------------------------------------------------------ */
.page-head {
  align-items: end;
  padding-block: var(--layout-spacing-container-gap-2x);
}

/* Mit Kennzahlen oben bündig → Werte (h3) auf einer Linie mit der Headline */
.page-head:has(> .page-head__kpis) {
  align-items: start;
}

.page-head__title {
  min-width: 0;
}

.page-head__title :is(h1, h2, h3, h4) > span.secondary {
  display: block;
}

/* Höhe eines Formularfelds (.field: Padding + Label + Abstand + Eingabe) */
.page-head__tools {
  min-height: calc(var(--controls-spacing-container-padding-medium) * 2 + var(--rem-1rem)
    + var(--controls-spacing-container-gap-medium) + var(--rem-5x));
}

.page-head--sticky {
  position: sticky;
  top: 0;
  z-index: 1;
}

.page-head__kpis {
  display: grid;
  grid-template-columns: subgrid;
  row-gap: var(--layout-spacing-container-gap-1x);
}

.page-head__kpis > * {
  display: flex;
  flex-direction: column;
  gap: var(--rem-1x);
  grid-column: span 2;
}

.page-head__kpis:empty {
  display: none;
}

.page-body {
  align-content: start;
  padding-block: var(--layout-spacing-container-gap-2x) var(--layout-spacing-container-gap-4x);
}

.page-body > * {
  min-width: 0;
}

@media (max-width: 639px) {
  .page-head--sticky {
    display: contents;
  }

  .page-head--sticky > * {
    padding-inline: var(--page-gutter-start) var(--page-gutter-end);
    background: var(--surface-color-layer-1);
  }

  .page-head--sticky > .page-head__title {
    position: sticky;
    top: 0;
    z-index: 1;
    padding-block: var(--layout-spacing-container-gap-2x) var(--layout-spacing-container-gap-1x);
  }

  .page-head--sticky > :last-child {
    padding-block-end: var(--layout-spacing-container-gap-2x);
  }

  .page-head--sticky > :not(.page-head__title, :last-child) {
    padding-block-end: var(--layout-spacing-container-gap-1x);
  }

  .page-head__kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: var(--layout-spacing-container-gap-1x);
  }

  .page-head__kpis > * {
    grid-column: span 1;
  }
}

/* -------------------- Login --------------------
   Anmelde- oder Einrichtungsformular: Formular-Card (.card .card--form)
   im Seitenraster, senkrecht mittig, scrollt bei Bedarf. Desktop Spalte
   4–9, Tablet 2–5, Mobil volle Breite. In .app die Ansicht unter der
   Kopfleiste (die Kopfleiste zeigt dann nur das Logo).
   __content: darf schmaler werden als sein Inhalt (lange Wörter,
   Buttons) → bleibt auf dem Handy im Seitenrand.
   __error: Fehlermeldung, leer ausgeblendet.
   <main class="login grid">
     <div class="login__content col-6 col-start-4 col-t-4 col-t-start-2">
       <form class="card card--form">… <p class="login__error" aria-live="polite"></p> …</form>
     </div>
   </main>
------------------------------------------------------------ */
.login {
  align-content: center;
  min-height: 0;
  overflow-y: auto;
  padding-block: var(--layout-spacing-container-gap-2x);
}

.login__content {
  min-width: 0;
}

.login__error {
  color: var(--mode-error-foreground);
}

.login__error:empty {
  display: none;
}

/* -------------------- Sidemenu --------------------
   Layout (sticky, Leiste unter 960px): add-styles.css
------------------------------------------------- */
/* Sidemenu-Links: inaktiv Regular + Secondary, Hover Primary,
   aktiv (aria-current="location", setzt main.js) Bold + Primary */
.sidemenu a {
  text-decoration: none;
  font-weight: 400;
  color: var(--typography-color-text-secondary);
}

@media (hover: hover) {
  .sidemenu a:hover {
    color: var(--typography-color-text-primary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .sidemenu a:active {
    color: var(--typography-color-text-primary);
  }
}

.sidemenu a[aria-current='location'] {
  font-weight: 700;
  color: var(--typography-color-text-primary);
}

/* Linie oben nur, wenn das Sidemenu links steht (ab 960px).
   Auf der sticky nav, damit sie beim Scrollen mitläuft. */
@media (min-width: 960px) {
  .sidemenu nav {
    border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  }

  /* Jeder Link 16px Abstand oben (auch der erste, zur Linie) */
  .sidemenu__list > li {
    margin-top: var(--rem-1rem);
  }
}

/* -------------------- Breadcrumb --------------------
   Pfad zur aktuellen Seite. Trenner „/“ kommt aus dem CSS, nicht aus
   dem Text. Links wie im Sidemenu: Secondary, Hover Primary; die
   aktuelle Seite Primary. Größe wie der umgebende Text.
   Variante .breadcrumb--h4: Schrift wie h4.secondary (24px, Light),
   etwa als Rubrik über der Headline im Hero (Brand-System).
   <nav class="breadcrumb" aria-label="Pfad">
     <ol role="list">
       <li><a href="index.html">Brand-System</a></li>
       <li><span aria-current="page">Komponenten</span></li>
     </ol>
   </nav>
------------------------------------------------------------ */
.breadcrumb ol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0 var(--rem-2x);
  margin: 0;
  padding: 0;
  list-style: none;
}

.breadcrumb li {
  display: inline-flex;
  gap: var(--rem-2x);
}

.breadcrumb li + li::before {
  content: "/";
  color: var(--typography-color-text-secondary);
}

.breadcrumb a {
  text-decoration: none;
  color: var(--typography-color-text-secondary);
  transition: color var(--transition-duration-short) var(--transition-easing);
}

@media (hover: hover) {
  .breadcrumb a:hover {
    color: var(--typography-color-text-primary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .breadcrumb a:active {
    color: var(--typography-color-text-primary);
  }
}

.breadcrumb [aria-current='page'] {
  color: var(--typography-color-text-primary);
}

.breadcrumb--h4 {
  font-size: var(--typography-font-size-h4);
  font-weight: 300;
  line-height: 1.25;
}

/* Optischer Randausgleich wie bei Headlines im Section-Head
   (Light/Regular 0,086em), damit die Zeile mit der h1 darunter fluchtet */
.section-head > .breadcrumb--h4 {
  margin-inline-start: -0.086em;
}

/* -------------------- Offene Angabe (mark.todo) --------------------
   Markiert im Text, was vor der Veröffentlichung noch zu klären ist
   (z. B. Platzhalter in Rechtstexten). Fehler-Farbe, ohne Fläche.
   Vor Go-live darf keine mehr auf einer Seite stehen.
   <mark class="todo">[Anzahl]</mark>
------------------------------------------------------------ */
mark.todo {
  background: none;
  color: var(--mode-error-foreground);
}

/* -------------------- Icons (<s-icon>) --------------------
   Größe über size-Attribut, Farbe über `color` (erbt vom Elternelement).
------------------------------------------------------------ */
s-icon {
  display: inline-flex;
  flex: none;
  width: var(--rem-6x);
  height: var(--rem-6x);
  color: inherit;
  vertical-align: middle;
}

s-icon[size='xs'] { width: var(--rem-1rem); height: var(--rem-1rem); }
s-icon[size='sm'] { width: var(--rem-5x); height: var(--rem-5x); }
s-icon[size='lg'] { width: var(--rem-8x); height: var(--rem-8x); }

s-icon svg {
  width: 100%;
  height: 100%;
  fill: currentColor;
}

/* -------------------- Hero --------------------
   Startseite: Menü + Headline-Hero = 50svh, darunter das Bild in voller
   Höhe (100svh) → zusammen 150svh. Kleines Handy: 34svh + 100svh.
     .hero           Section-Head (Rubrik + Headline) auf der Fläche des
                     Farbthemas. Als erstes Element der Seite: zusammen
                     mit dem Menü 50svh hoch, Inhalt unten.
     .hero--image    Bild über die volle Breite, 100svh hoch, Ausschnitt
                     per object-fit: cover, Parallax, Farbstimmung beim
                     Scrollen (s. u.). Darin die USP-Card.
     .hero--image + .hero   Header unter dem Bild, sticky unten.
   <section class="hero hero--image">
     <div class="hero__media">
       <img class="hero__image" src="…" alt="">
     </div>
   </section>
   Bild dekorativ → alt="".
------------------------------------------------------------ */
/* Höhen: Menü + Headline-Hero (--hero-head) und Bild (--hero-image,
   immer 100svh). Kleines Handy (< 375px): Headline-Hero nur 34svh →
   beim Laden sind 66svh Bild zu sehen. */
:root {
  --hero-head: 50svh;
  --hero-image: 100svh;
}

@media (max-width: 374px) {
  :root {
    --hero-head: 34svh;
  }
}

/* Headline-Hero: oben/unten 32px (statt Section-Padding) */
.hero:not(.hero--image) {
  padding-block: var(--rem-8x);
}

/* Headline unten auf der Grundlinie abschneiden (statt Zeilenhöhe):
   Schrift steht damit 32px über der Kante — wie der Seitenrand links.
   Browser ohne text-box (Firefox): etwas mehr Abstand. */
.hero:not(.hero--image) .section-head > :last-child {
  text-box: trim-end cap alphabetic;
}

body > main > .hero:not(.hero--image):first-child {
  align-content: end;
  min-block-size: calc(var(--hero-head) - var(--header-height, 0px));
}

/* Headline-Hero als erstes Element ohne Bild darunter (Unterseiten):
   bleibt stehen (sticky an seiner Startposition unter dem Header), der
   Inhalt darunter scrollt über ihn hinweg. Der Inhalt bekommt dafür
   eine eigene Ebene und eine deckende Fläche (Fläche seines Themas). */
body > main > .hero:not(.hero--image):first-child:not(:has(+ .hero--image)) {
  position: sticky;
  top: var(--header-height, 0px);
  z-index: 0;
}

body > main > .hero:not(.hero--image):first-child:not(:has(+ .hero--image)) ~ * {
  position: relative;
  z-index: 1;
  background-color: var(--surface-color-layer-1);
}

/* Bild liegt über dem Header darunter; clip begrenzt die USP-Card */
.hero--image {
  position: relative;
  z-index: 1;
  overflow: clip;
}

/* Header direkt unter dem Hero-Bild (Aufbau wie der Hero oben):
   mind. 50svh, Inhalt unten. Klebt unten am Screen (sticky bottom)
   hinter dem Bild — das Bild scrollt über ihn hinweg und gibt ihn frei
   (wie der Footer). Ist er vollständig sichtbar, scrollt er normal mit. */
.hero--image + .hero {
  position: sticky;
  bottom: 0;
  z-index: 0;
  align-content: end;
  min-block-size: 50svh;
}

.hero__media {
  position: relative;
  isolation: isolate;
  block-size: var(--hero-image);
  overflow: clip;
}

.hero__image,
.hero__media::after {
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Mobile (Hochformat): das Querformat-Bild wird seitlich beschnitten —
   Ausschnitt so verschoben, dass das Gesicht (bei ca. 64 % / 29 % im
   Bild) etwa mittig sitzt. Gilt für das aktuelle Hero-Bild; bei einem
   neuen Bild den Wert anpassen. */
@media (max-width: 639px) {
  .hero--image .hero__image {
    object-position: 69% 30%;
  }
}

/* Leichter Parallax: Bild 20 % höher als der Rahmen, wandert beim
   Durchscrollen (view-timeline des Bildes) etwas langsamer als die
   Seite — von −8 % nach +8 % seiner Höhe. Ohne Scroll-Animationen
   (Firefox) oder bei „Bewegung reduzieren": ruhig, ohne Effekt. */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .hero--image .hero__image {
      inset: -10% 0;
      height: 120%;
      animation: hero-parallax linear both;
      animation-timeline: view();
    }
  }
}

@keyframes hero-parallax {
  from {
    translate: 0 -8%;
  }

  to {
    translate: 0 8%;
  }
}

/* Abdunklung über dem Bild */
.hero__media::after {
  content: '';
  background: color-mix(in srgb, var(--colors-black) 20%, transparent);
}

/* Scroll-driven Farbstimmung: vom Laden (Scroll 0) bis das Bild oben
   ankommt (Scroll --hero-head = Menü + Headline-Hero) läuft die
   Abdunklung von 20 % auf 0 und ein Gelb-Layer (--colors-yellow-60)
   blendet auf 60 % ein. Mischmodus über --hero-tint-blend (Standard
   overlay; im Dev-Menü umschaltbar). Ohne Scroll-Animationen
   (Firefox): statische Abdunklung, kein Gelb. */
@supports (animation-timeline: scroll()) {
  .hero--image .hero__media::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 0; /* über Bild und Abdunklung (beide −1) */
    background: var(--colors-yellow-60);
    mix-blend-mode: var(--hero-tint-blend, overlay);
    opacity: 0;
    pointer-events: none;
    animation: hero-tint-in linear both;
    animation-timeline: scroll(root block);
    animation-range: 0px var(--hero-head);
  }

  .hero--image .hero__media::after {
    animation: hero-shade-out linear both;
    animation-timeline: scroll(root block);
    animation-range: 0px var(--hero-head);
  }
}

@keyframes hero-tint-in {
  to {
    opacity: 0.6;
  }
}

@keyframes hero-shade-out {
  to {
    opacity: 0;
  }
}

/* -------------------- Hero-Overlay: Headline + USP-Card --------------------
   Über dem Hero-Bild (.hero__overlay, data-mode="Dark" → helle Schrift):
     - Kopie der h1, sticky oben (wie die h1 im Headline-Hero)
     - USP-Card, sticky unten
   Headline: steht von Anfang an fest dort, wo sie startet (Grundlinie
   32px über der Bild-Oberkante), das Bild scrollt darunter durch.
   Ab der Bildkante hell — reines CSS: zwei Exemplare an exakt derselben
   Bildschirmposition, jedes an der Kante seines Bereichs abgeschnitten
   (overflow: clip): h1 im Headline-Hero (zugänglich) und die Kopie hier
   (aria-hidden).
   Fest an der Grundlinie, egal wie hoch (ein-/mehrzeilig): das sticky
   Element ist 0 hoch (Anker auf der Grundlinie), der Text hängt nach
   oben heraus (Flex-Spalte, justify-content: flex-end). Sticky top =
   --hero-head − 32px = genau die Startposition.
   Ende der Headline:
     Desktop        32px über der Bild-Unterkante (wie die USP-Card)
     Mobile/Tablet  24px über der USP-Card (beide in einer Flex-Spalte:
                    Headline-Spalte flex: 1, Abstand 24px, Karte darunter)
   USP-Card: steht unten, bleibt 32px über dem unteren Bildschirmrand,
   bis das Bild endet (dann 32px über der Bild-Unterkante).
   Breite der Karte: Mobile volle Breite · Tablet 3 von 6 · Desktop 10–12.
------------------------------------------------------------ */

/* h1 im Headline-Hero: der Section-Head bekommt unten einen Platzhalter
   in Bildhöhe (::after) und dieselbe negative Margin → Layout unverändert,
   die h1 darf aber über den Hero hinaus sticky bleiben (abgeschnitten
   an der Bildkante). */
body > main > .hero:not(.hero--image):first-child:has(.hero__title) {
  overflow: clip;
}

.hero:not(.hero--image):has(.hero__title) .section-head {
  margin-block-end: calc(var(--hero-image) * -1);
}

.hero:not(.hero--image):has(.hero__title) .section-head::after {
  content: '';
  flex: none;
  block-size: var(--hero-image);
}

.hero__title {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  block-size: 0;
  position: sticky;
  top: calc(var(--hero-head) - var(--rem-8x));
}

/* Text unten auf die Grundlinie getrimmt → Grundlinie = Anker */
.hero__title > span {
  text-box: trim-end cap alphabetic;
}

/* Overlay: vom Headline-Hero (darüber, abgeschnitten) bis zur
   Bild-Unterkante */
.hero__overlay {
  position: absolute;
  inset: calc(var(--hero-head) * -1) 0 0;
  z-index: 1;
  pointer-events: none;
}

.hero__title-col {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

/* Kopie sieht aus wie die h1 im Section-Head (Größe, Schnitt,
   optischer Randausgleich) */
.hero__title--copy {
  align-self: flex-start; /* so breit wie der Text, wie die h1 */
  margin-inline-start: -0.066em;
  font-size: var(--typography-font-size-h1);
  font-weight: 700;
  line-height: 1.25;
  color: var(--typography-color-text-primary);
}

.usp {
  position: sticky;
  bottom: var(--rem-8x);
  margin-block-end: var(--rem-8x);
  pointer-events: auto;
}

/* Abstände wie die Sections (Spezifität über .card / .card--line) */
.usp.card {
  padding-block: var(--rem-1rem) 0;
}

/* Mobile/Tablet: eine Spalte — Headline füllt den Platz über der Karte */
@media (max-width: 959px) {
  .hero__overlay {
    display: flex;
    flex-direction: column;
    gap: var(--rem-6x);
  }

  .hero__title-col {
    flex: 1 1 0;
    min-height: 0;
  }

  .usp {
    flex: none;
  }
}

@media (min-width: 640px) and (max-width: 959px) {
  .usp.card {
    align-self: flex-start;
    width: calc((100% - var(--layout-spacing-container-gap-1x) * 5) / 6 * 3 + var(--layout-spacing-container-gap-1x) * 2);
  }
}

/* Desktop: Grid — Headline Spalten 1–6 (endet 32px über der Bild-
   Unterkante), Karte 10–12 unten */
@media (min-width: 960px) {
  .hero__title-col {
    grid-row: 1;
    margin-block-end: var(--rem-8x);
  }

  .usp {
    grid-column: 10 / -1;
    grid-row: 1;
    align-self: end;
  }
}

/* -------------------- USP-Card: Inhalt -------------------- */
/* Termin-Flyout (Doctolib / E-Mail): Buttons im Fenster gleich breit,
   Icon rechts außen */
.usp__flyout .flyout__content {
  align-items: stretch;
  gap: var(--flyout-pad);
}

/* Termin-Button volle Kartenbreite (alle Breakpoints) */
.usp__flyout {
  flex: 1 1 100%;
}

.usp__flyout .flyout__toggle {
  flex: 1 1 auto;
}

/* Liste in der Card: ul.list--icon (Aufbau und Abstand: add-styles.css) */

/* -------------------- Content-Section --------------------
   Kapitel im Content: Linie oben, Überschrift, darunter der Inhalt.
   <section class="content-section">
     <h2 class="h2">…</h2>
     <div>…</div>
   </section>
   Linie oben (padding-top 16, border-top 1px text-primary).
   Abstände:
     Überschrift → erster Inhalt     120px (Figma, bleibt)
     danach (Einleitung → Text …)    gap-1x (24px, Mobile 16px)
     zwischen Sections               2 × gap-4x (128px, Mobile 96px)
------------------------------------------------------------ */
.content-section {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  padding-top: var(--rem-1rem);
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

/* Überschrift → erster Inhalt: 120px (gap + Rest als Margin) */
:is(.content-section, .content-section__body) > .section-head + * {
  margin-block-start: calc(var(--rem-30x) - var(--layout-spacing-container-gap-1x));
}

/* Variante --wide: Section über alle 12 Spalten (außerhalb von
   .page-layout, in .page-sections). Rubrik (h5) links in 4 Spalten,
   sticky bis zur nächsten Section; Headline und Inhalt rechts in
   8 Spalten, beide mit eigener Linie oben (statt einer durchgehenden).
   Unter 960px untereinander mit einer Linie, Rubrik nicht sticky.
   <section class="content-section content-section--wide">
     <h5 class="content-section__label">Rubrik</h5>
     <div class="content-section__body">
       <header class="section-head"><h3>…</h3></header>
       …
     </div>
   </section>
------------------------------------------------------------ */
.content-section--wide {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: subgrid;
  column-gap: normal; /* = Gap vom Eltern-Grid (sonst 120px aus .content-section) */
  row-gap: var(--rem-6x);
  align-items: start;
}

.content-section__label {
  grid-column: 1 / -1;
  margin: 0;
}

.content-section__body {
  grid-column: 1 / -1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  min-width: 0;
}

@media (min-width: 960px) {
  .content-section--wide {
    padding-top: 0;
    border-top: 0;
  }

  .content-section__label,
  .content-section__body {
    padding-top: var(--rem-1rem);
    border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  }

  .content-section__label {
    grid-column: 1 / span 4;
    position: sticky;
    top: calc(var(--header-visible) + var(--layout-spacing-container-gap-1x));
  }

  .content-section__body {
    grid-column: 5 / -1;
  }
}

/* -------------------- Section-Head --------------------
   Einheitlicher Kopf für Hero und Kapitel: Rubrik, darunter Headline +
   Secondary Headline. Abstand Rubrik → Headline passt sich der Größe
   der Headline an (¼ ihrer Schriftgröße: h1 64px → 16px, h3 32px →
   8px). Kein Padding/Margin am Kopf selbst.
   <header class="section-head">
     <h5>Rubrik</h5>
     <h3>Headline <span class="secondary">Secondary Headline</span></h3>
   </header>
   Ebenen frei wählbar (Hero z. B. h4/h2, Kapitel h5/h3) — Größe kommt
   vom Tag. Secondary steht immer auf eigener Zeile, kein <br> nötig.
   Eine Überschrift für beide Zeilen → Screenreader lesen sie als eine.
------------------------------------------------------------ */
.section-head {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  margin: 0;
  padding: 0;
}

.section-head > * + * {
  margin-block-start: 0.25em; /* em = Schriftgröße der Headline */
}

/* Secondary Headline auf eigene Zeile, ohne Abstand */
.section-head :is(h1, h2, h3, h4, h5) .secondary {
  display: block;
}

/* Optischer Randausgleich links: Buchstaben haben links eine kleine
   Vorbreite, die mit der Schriftgröße wächst — eine große h1 steht
   dadurch sichtbar weiter rechts als die kleine Rubrik darüber.
   Ausgleich in em (wächst mit), je nach Schnitt, gemessen an den
   Grundstrichen (K, E, I, M …) der Suisse Intl:
     Bold 0,066em · Light/Regular (.secondary) 0,086em
   Runde Buchstaben (O, S) und A/T/V stehen damit minimal über — das
   ist optisch gewollt (Überhang). */
.section-head :is(h1, h2, h3, h4, h5) {
  margin-inline-start: -0.066em;
}

.section-head :is(h1, h2, h3, h4, h5).secondary {
  margin-inline-start: -0.086em;
}

/* Secondary-Zeile in einer fetten Headline: Differenz zum Bold-Ausgleich */
.section-head :is(h1, h2, h3, h4, h5):not(.secondary) .secondary {
  margin-inline-start: -0.02em;
}

/* -------------------- Marginalie (.note) --------------------
   Kurzer Hinweis, z. B. „Die Beispiele dienen der Orientierung …".
   Steht immer direkt unter dem Text (oder den Cards), auf den er sich
   bezieht, linksbündig. Kleine Schrift mit eigener Zeilenhöhe, Linie
   darüber eine Rasterspalte breit, höchstens 2 Rasterspalten breit
   (Mobile 3).
   <p class="note">…</p>
   (Fußnoten-Quellen bleiben normale Listen in kleiner Schrift.)
------------------------------------------------------------------- */
.note {
  --note-cols: 2;

  width: calc(var(--grid-col) * var(--note-cols) + var(--layout-spacing-container-gap-1x) * (var(--note-cols) - 1));
  max-width: 100%;
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
  text-wrap: pretty;
}

.note::before {
  content: '';
  display: block;
  width: var(--grid-col);
  margin-block-end: var(--rem-2x);
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

@media (max-width: 639px) {
  .note {
    --note-cols: 3;
  }
}

/* -------------------- Text-Columns --------------------
   Fließtext in so vielen Spalten, dass die Zeilen gut lesbar bleiben.
   Ziel: ca. 55–75 Zeichen pro Zeile (≈ 8–11 deutsche Wörter;
   Forschung: 50–75 Zeichen optimal, WCAG 1.4.8: max. 80).
     .text-columns-2   höchstens 2 Spalten
     .text-columns-3   höchstens 3 Spalten
     .text-columns-4   höchstens 4 Spalten
   Die Spaltenzahl wählt der Browser aus der verfügbaren Breite
   (Container Query auf das Elternelement): eine weitere Spalte kommt
   erst dazu, wenn jede Spalte mindestens ~55 Zeichen breit bleibt.
   Einspaltig wird die Zeile bei ~75 Zeichen begrenzt.
   Maße in em, gemessen an Suisse Intl: 1 Zeichen ≈ 0,45em
   (ch passt hier nicht: 1ch = Breite der "0" ≈ 0,66em).
     55 Zeichen ≈ 25em   ·   75 Zeichen ≈ 34em   ·   Gap 24px = 1,5em
   Spaltenabstand = Grid-Gap → 2 Spalten über die volle Content-Breite
   (8 Grid-Spalten) liegen genau auf dem Raster (je 4).
   Für Blöcke mit fester Spaltenzahl (Cards …): .content-columns-x
------------------------------------------------------------ */
:has(> :is(.text-columns-2, .text-columns-3, .text-columns-4)) {
  container-type: inline-size;
}

.text-columns-2,
.text-columns-3,
.text-columns-4 {
  column-gap: var(--layout-spacing-container-gap-1x);
  max-inline-size: 34em;
}

/* 2 Spalten ab 2 × 25em + Gap, je höchstens 34em */
@container (min-width: 51.5em) {
  .text-columns-2,
  .text-columns-3,
  .text-columns-4 {
    columns: 2;
    max-inline-size: 69.5em;
  }
}

/* 3 Spalten ab 3 × 25em + 2 Gaps */
@container (min-width: 78em) {
  .text-columns-3,
  .text-columns-4 {
    columns: 3;
    max-inline-size: 105em;
  }
}

/* 4 Spalten ab 4 × 25em + 3 Gaps */
@container (min-width: 104.5em) {
  .text-columns-4 {
    columns: 4;
    max-inline-size: 140.5em;
  }
}

/* -------------------- Content-Columns --------------------
   Feste Spaltenzahl für Inhaltsblöcke (Cards, Teaser, Bilder …),
   zeilenweise gefüllt. Die Zahl gilt für Desktop, auf Tablet wird
   halbiert (aufgerundet, mindestens 2), auf Mobile immer 1 Spalte:
                         Desktop ≥960  Tablet 640–959  Mobile <640
     .content-columns-2        2             2               1
     .content-columns-3        3             2               1
     .content-columns-4        4             2               1
     .content-columns-5        5             3               1
     .content-columns-6        6             3               1
   Breakpoints = Grid-Breakpoints (Viewport), nicht Container Queries:
   der Platz im Content ist auf Tablet oft breiter als auf Desktop
   (volle Breite vs. 8 von 12 Spalten) — die Stufen sollen aber dem
   Gerät folgen. Gap = Grid-Gap → 2 und 4 Spalten über 8 Grid-Spalten
   liegen genau auf dem Raster.
   Für Fließtext mit Fokus auf Zeilenlänge: .text-columns-x
------------------------------------------------------------ */
[class*='content-columns-'] {
  display: grid;
  grid-template-columns: repeat(var(--content-columns, 1), minmax(0, 1fr));
  gap: var(--layout-spacing-container-gap-1x);
  width: 100%;
}

.content-columns-2 { --content-columns: 2; }
.content-columns-3 { --content-columns: 3; }
.content-columns-4 { --content-columns: 4; }
.content-columns-5 { --content-columns: 5; }
.content-columns-6 { --content-columns: 6; }

@media (max-width: 959px) {
  .content-columns-2,
  .content-columns-3,
  .content-columns-4 { --content-columns: 2; }
  .content-columns-5,
  .content-columns-6 { --content-columns: 3; }
}

@media (max-width: 639px) {
  [class*='content-columns-'] { --content-columns: 1; }
}

/* -------------------- Tag --------------------
   Figma: Tag (13006:33058). Pill mit Icon (optional) + Label.
   Größen:    .tag--large · (Standard: medium) · .tag--small
   Varianten: (Standard: ghost = Kontur) · .tag--light = ausgestanzt
   Rund:      .tag--round = Kreis (Breite = Höhe), Inhalt mittig, für
              eine Zahl oder nur ein Icon (wie Button nur Icon)
   Avatar:    .tag--round.tag--avatar = Person (Kürzel oder Foto),
              mehrere in .tag-stack, siehe unten
   (--surface-color-cutout: auf der Seite layer-0, auf layer-2 layer-1)
     Größe   Höhe  Padding  Icon  Text
     large    40     10      20   h4 Light (24/32)
     medium   32      8      16   Paragraph (16/24)
     small    24      6      12   Paragraph small (12)
   <span class="tag tag--large tag--light">
     <s-icon name="circle-dash"></s-icon>
     <span class="tag__label">Label Text</span>
   </span>
   Icon-Größe setzt die Tag-Größe, kein size-Attribut nötig.
   Kontur als inset box-shadow: liegt wie in Figma innen und
   verändert die Maße nicht.
------------------------------------------------------------ */
.tag {
  --tag-height: var(--rem-8x);
  --tag-padding: var(--rem-2x);
  --tag-icon: var(--rem-1rem);

  display: inline-flex;
  align-items: center;
  height: var(--tag-height);
  padding: var(--tag-padding);
  border-radius: var(--radius-border-radius-100);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--controls-secondary-default-color-control-content);
  color: var(--controls-secondary-default-color-control-content);
  font-size: var(--typography-font-size-p);
  font-weight: 400;
  line-height: 1.5;
  white-space: nowrap;
  max-width: 100%;
}

.tag s-icon {
  flex: none;
  width: var(--tag-icon);
  height: var(--tag-icon);
}

.tag__label {
  min-width: 0;
  padding-inline: var(--controls-spacing-container-padding-large);
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Größen (Steps small übernimmt Tag small für seine Kreise) */
.tag--large {
  --tag-height: var(--rem-10x);
  --tag-padding: var(--rem-2-5x);
  --tag-icon: var(--rem-5x);
  font-size: var(--typography-font-size-h4);
  font-weight: 300;
  line-height: 1.333;
}

.tag--small,
.steps--small .tag {
  --tag-height: var(--rem-6x);
  --tag-padding: var(--rem-1-5x);
  --tag-icon: var(--rem-3x);
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
}

/* Rund: Kreis in Tag-Höhe, eine Zahl oder ein Icon mittig */
.tag--round {
  justify-content: center;
  width: var(--tag-height);
  padding: 0;
}

.tag--round .tag__label {
  padding-inline: 0;
}

/* Variante Light: Fläche statt Kontur */
.tag--light {
  background: var(--surface-color-cutout);
  box-shadow: none;
}

/* Avatar: Person als runder Tag, Kürzel (zwei Buchstaben) oder Foto.
   Fläche immer sichtbar: nächste Ebene wie Eingabefelder, neutral
   (Farbe bleibt dem Eintrag vorbehalten). Name für Screenreader per
   role="img" + aria-label, beim Foto über alt.
   <span class="tag tag--round tag--avatar" role="img" aria-label="Lena Muster" title="Lena Muster">
     <span class="tag__label">LM</span>
   </span>
   <span class="tag tag--round tag--avatar" title="Anna Beispiel">
     <img class="tag__img" src="…" alt="Anna Beispiel">
   </span>
   Größen wie Tag (.tag--large, .tag--small).
   Kürzel eine Schriftstufe kleiner als der Tag, damit zwei breite
   Buchstaben auch im Stapel Platz haben. */
.tag--avatar {
  position: relative;
  overflow: hidden;
  background: var(--surface-color-next);
  box-shadow: none;
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
}

.tag--large.tag--avatar {
  font-size: var(--typography-font-size-p);
  font-weight: 400;
  line-height: 1.5;
}

.tag__img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: inherit;
}

/* Avatar-Stapel: überlappend um 1/5 der Höhe, der erste liegt oben, jeder
   folgende ist dort, wo der vorige auf ihm liegt, mit 2 px Spalt
   ausgeschnitten (Maske, daher auf jeder Fläche passend). Kürzel mittig.
   Small steht nebeneinander mit 2 px Abstand, sonst würden die Kürzel
   angeschnitten. Zuletzt „+n“ als Avatar mit Zahl.
   <span class="tag-stack" role="group" aria-label="Beteiligte">
     <span class="tag tag--round tag--avatar" role="img" aria-label="Lena Muster"><span class="tag__label">LM</span></span>
     <span class="tag tag--round tag--avatar" role="img" aria-label="Tom Beispiel"><span class="tag__label">TB</span></span>
     <span class="tag tag--round tag--avatar" role="img" aria-label="3 weitere"><span class="tag__label">+3</span></span>
   </span>
   Alle Avatare eines Stapels in derselben Größe. */
.tag-stack {
  display: inline-flex;
  align-items: center;
}

.tag-stack > .tag {
  --tag-stack-overlap: calc(var(--tag-height) / 5);
  --tag-stack-gap: var(--rem-0-5x);
}

.tag-stack > .tag--small {
  --tag-stack-overlap: calc(var(--rem-0-5x) * -1);
}

.tag-stack > .tag + .tag {
  margin-inline-start: calc(var(--tag-stack-overlap) * -1);
}

/* Ausschnitt: Kreis des vorigen Avatars plus Spalt (0.5px weiche Kante) */
.tag-stack > .tag + .tag {
  --tag-stack-radius: calc(var(--tag-height) / 2);
  mask: radial-gradient(circle at calc(var(--tag-stack-overlap) - var(--tag-stack-radius)) 50%,
    transparent calc(var(--tag-stack-radius) + var(--tag-stack-gap)),
    #000 calc(var(--tag-stack-radius) + var(--tag-stack-gap) + 0.5px));
}

/* -------------------- Button --------------------
   Figma: Button (12997:9834). Runder Icon-Kreis + Label, ohne Fläche.
   <a class="btn" href="…">
     <span class="btn__icon"><s-icon name="arrow--right" size="xs"></s-icon></span>
     <span class="btn__label">Button Text</span>
   </a>
   Funktioniert als <a> und <button>.
------------------------------------------------------------ */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  min-height: var(--controls-size-container-min-height);
  padding: var(--controls-spacing-container-padding-large);
  border: 0;
  border-radius: var(--radius-border-radius-100);
  background: none;
  color: var(--controls-secondary-default-color-control-content);
  font: inherit;
  text-decoration: none;
  cursor: pointer;
}

.btn__icon {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: var(--rem-6x);
  height: var(--rem-6x);
  border-radius: var(--radius-border-radius-100);
  background: var(--controls-secondary-default-color-control-content);
  color: var(--controls-secondary-default-color-control-container);
}

.btn__label {
  padding-inline: var(--controls-spacing-container-padding-large);
  font-size: var(--typography-font-size-label);
  line-height: 1.25;
  white-space: nowrap;
}

/* -------------------- Button: Varianten --------------------
   Figma: Button / Primary (12659:4984); Secondary, Tertiary, Ghost
   davon abgeleitet. Paddings werden am Ende gemeinsam optimiert.
     .btn--primary    Fläche (Primary-Tokens), Icon im Kreis
     .btn--secondary  wie Primary umgekehrt (Secondary-Tokens)
                      Hover (beide): eine Farbstufe weiter + Fläche wächst
                      um 4px (box-shadow, Layout bleibt unverändert)
     .btn--tertiary   ohne Fläche/Rand, Hover Secondary-Fläche, Icon im
                      Kreis — immer links
     .btn--ghost      wie ein Link (Secondary-Text, Hover Primary),
                      Icon ohne Kreis — immer links
   Rand (inset) sonst nur beim Tastatur-Fokus.
   Größe:    Standard 40px · .btn--medium 32px
   Icon:     Kreis 32px (medium 24px), Icon 16px; Position bei Primary/
             Secondary = Reihenfolge im HTML (Figma: Label, dann Icon)
   Nur Icon: ohne .btn__label → runder Button (automatisch per :has),
             dann aria-label setzen
   <a class="btn btn--secondary btn--medium" href="…">
     <span class="btn__label">Label Text</span>
     <span class="btn__icon"><s-icon name="arrow--right"></s-icon></span>
   </a>
   Rand als inset box-shadow (verändert keine Maße).
------------------------------------------------------------ */

/* --- Aufbau (alle Varianten) ---
   :where() hält die Spezifität niedrig, damit Varianten und
   .btn--medium (stehen danach) ihre Werte überschreiben können. */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost) {
  --btn-height: var(--rem-10x);
  --btn-circle: var(--rem-8x);

  height: var(--btn-height);
  min-height: 0;
  /* Padding-Logik (Rand bis Inhalt):
     Label-Seite: 8px Button + 8px Label = 16px (wie Button-Group)
     Icon-Seite:  4px bis zum Kreis
     Nur Icon:    rundum 4px (Höhe − Kreis) / 2 */
  padding: 0 var(--controls-spacing-container-padding-large);
  gap: 0;
  box-shadow: none;
  background: none;
  transition:
    color var(--transition-short),
    background-color var(--transition-short),
    box-shadow var(--transition-long);   /* Wachsen beim Hover = Bewegung */
}

.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost) .btn__icon {
  width: var(--btn-circle);
  height: var(--btn-circle);
  transition:
    color var(--transition-short),
    background-color var(--transition-short);
}

.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost) .btn__icon s-icon {
  width: var(--rem-1rem);
  height: var(--rem-1rem);
}

/* Größe Medium: 32px, Kreis 24px */
.btn--medium {
  --btn-height: var(--rem-8x);
  --btn-circle: var(--rem-6x);
}

/* Mit Label + Icon: Icon-Seite 4px.
   Primary/Secondary: Seite laut HTML-Reihenfolge;
   Tertiary/Ghost: Icon steht immer links. */
.btn:where(.btn--primary, .btn--secondary):has(> .btn__label):has(> .btn__icon:last-child) {
  padding-inline-end: var(--controls-spacing-container-gap-medium);
}

.btn:where(.btn--primary, .btn--secondary):has(> .btn__label):has(> .btn__icon:first-child),
.btn:where(.btn--tertiary, .btn--ghost):has(> .btn__label):has(> .btn__icon) {
  padding-inline-start: var(--controls-spacing-container-gap-medium);
}

/* Gestreckt (z. B. Dialog-Footer mobil): das Label nimmt den freien
   Platz (Text am Anfang), das Icon bleibt am Rand; ohne Icon steht
   das Label mittig.
   Ohne Streckung ändert sich nichts. */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost) .btn__label {
  flex-grow: 1;
  text-align: start;   /* <button> zentriert sonst */
}

.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost):not(:has(> .btn__icon)) .btn__label {
  text-align: center;
}

/* Nur Icon: rund, Kreis mittig → rundum 4px */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost):not(:has(.btn__label)) {
  width: var(--btn-height);
  justify-content: center;
  padding: 0;
}

/* --- Primary: Fläche. Hover: eine Farbstufe weiter (Hover-Tokens)
       und die Fläche wächst um 4px nach außen (box-shadow, ohne
       Layout-Änderung) --- */
.btn--primary {
  background: var(--controls-primary-default-color-control-container);
  /* Schatten in Flächenfarbe mit 0px — so wächst er beim Hover aus
     derselben Farbe heraus, statt aus transparent */
  box-shadow: 0 0 0 0 var(--controls-primary-default-color-control-container);
  color: var(--controls-primary-default-color-control-content);
}

.btn--primary .btn__icon {
  background: var(--controls-primary-default-color-control-content);
  color: var(--controls-primary-default-color-control-container);
}

@media (hover: hover) {
  .btn--primary:hover {
    background: var(--controls-primary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-primary-hover-color-control-container);
    color: var(--controls-primary-hover-color-control-content);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--primary:active {
    background: var(--controls-primary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-primary-hover-color-control-container);
    color: var(--controls-primary-hover-color-control-content);
  }
}

@media (hover: hover) {
  .btn--primary:hover .btn__icon {
    background: var(--controls-primary-hover-color-control-content);
    color: var(--controls-primary-hover-color-control-container);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--primary:active .btn__icon {
    background: var(--controls-primary-hover-color-control-content);
    color: var(--controls-primary-hover-color-control-container);
  }
}

/* --- Secondary: wie Primary, nur umgekehrt; Hover wie Primary --- */
.btn--secondary {
  background: var(--controls-secondary-default-color-control-container);
  box-shadow: 0 0 0 0 var(--controls-secondary-default-color-control-container);
  color: var(--controls-secondary-default-color-control-content);
}

.btn--secondary .btn__icon {
  background: var(--controls-secondary-default-color-control-content);
  color: var(--controls-secondary-default-color-control-container);
}

@media (hover: hover) {
  .btn--secondary:hover {
    background: var(--controls-secondary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-secondary-hover-color-control-container);
    color: var(--controls-secondary-hover-color-control-content);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--secondary:active {
    background: var(--controls-secondary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-secondary-hover-color-control-container);
    color: var(--controls-secondary-hover-color-control-content);
  }
}

@media (hover: hover) {
  .btn--secondary:hover .btn__icon {
    background: var(--controls-secondary-hover-color-control-content);
    color: var(--controls-secondary-hover-color-control-container);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--secondary:active .btn__icon {
    background: var(--controls-secondary-hover-color-control-content);
    color: var(--controls-secondary-hover-color-control-container);
  }
}

/* Primary/Secondary: Flächenfarbe läuft mit derselben Dauer wie der
   wachsende Schatten (long) — sonst sind Fläche und Rand kurz
   unterschiedlich gefärbt und es entsteht eine sichtbare Kante. */
.btn:where(.btn--primary, .btn--secondary) {
  transition:
    color var(--transition-short),
    background-color var(--transition-long),
    box-shadow var(--transition-long);
}

/* --- Tertiary: ohne Fläche und Rand, Icon im Kreis links;
       Hover: Secondary-Fläche --- */
.btn--tertiary {
  color: var(--controls-secondary-default-color-control-content);
}

.btn--tertiary .btn__icon {
  background: var(--controls-secondary-default-color-control-content);
  color: var(--controls-secondary-default-color-control-container);
}

@media (hover: hover) {
  .btn--tertiary:hover {
    background: var(--controls-secondary-default-color-control-container);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--tertiary:active {
    background: var(--controls-secondary-default-color-control-container);
  }
}

/* Secondary/Tertiary auf einer Card: keine Sonderregel mehr — die
   Control-Werte stufen sich mit der Ebene (styles.css, next/next-2). */

/* --- Ghost: wie ein Link (Secondary-Text, Hover Primary), Icon ohne Kreis links --- */
.btn--ghost {
  color: var(--typography-color-text-secondary);
}

.btn--ghost .btn__icon {
  width: var(--rem-1rem);   /* kein Kreis → Icon-Fläche = Icon (16px) */
  height: var(--rem-1rem);
  background: none;
  color: inherit;
}

/* Ghost mit Label + Icon: 8px zwischen Icon und Text */
.btn--ghost:has(> .btn__label):has(> .btn__icon) {
  gap: var(--controls-spacing-container-gap-large);
}

.btn--ghost:has(> .btn__icon) .btn__label {
  padding-inline-start: 0;
}

@media (hover: hover) {
  .btn--ghost:hover {
    color: var(--typography-color-text-primary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn--ghost:active {
    color: var(--typography-color-text-primary);
  }
}

/* Tertiary und Ghost: Icon immer links, egal wo es im HTML steht */
.btn--tertiary .btn__icon,
.btn--ghost .btn__icon {
  order: -1;
}

/* --- Gesperrt (:disabled), Wird gesendet (aria-busy), Ergebnis (data-result) ---
   Gesperrt: Farben wie gesperrte Eingabefelder, kein Hover.
     Primary/Secondary: Fläche = Feld-Fläche gesperrt, Text/Icon grau
     Tertiary: ohne Fläche, Text und Icon-Kreis grau
     Ghost: Text und Icon grau
   Wird gesendet: aria-busy="true" am Button (nicht disabled), Farben
   bleiben, das Icon dreht sich (bei „Bewegung reduzieren" still).
   Ergebnis: data-result="sent" Icon-Kreis Signal-Grün, "error" Signal-
   Rot (nicht Ghost).
   Icon und Label tauscht main.js (Formular im Hintergrund senden). */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost):disabled {
  cursor: default;
  color: var(--inputs-primary-disabled-color-input-content);
}

.btn:where(.btn--primary, .btn--secondary):disabled {
  background: var(--inputs-primary-disabled-color-input-container);
  box-shadow: none;
}

.btn:where(.btn--tertiary):disabled {
  background: none;
}

.btn:where(.btn--primary, .btn--secondary, .btn--tertiary):disabled .btn__icon {
  background: var(--inputs-primary-disabled-color-input-content);
  color: var(--inputs-primary-disabled-color-input-container);
}

.btn[aria-busy="true"] {
  cursor: progress;
}

@media (prefers-reduced-motion: no-preference) {
  .btn[aria-busy="true"] .btn__icon s-icon {
    animation: btn-busy calc(var(--transition-duration-long) * 4) linear infinite;
  }
}

/* Ergebnis: data-result am Button (setzt main.js), Icon-Kreis in der
   Signalfarbe nach der Logik der Farbthemen (wie Eingabefelder in
   Green): Light Kreis 70, Icon 10 — Dark Kreis 30, Icon 90 */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary)[data-result='sent'] .btn__icon {
  background: light-dark(var(--colors-signaling-green-70), var(--colors-signaling-green-30));
  color: light-dark(var(--colors-signaling-green-10), var(--colors-signaling-green-90));
}

.btn:where(.btn--primary, .btn--secondary, .btn--tertiary)[data-result='error'] .btn__icon {
  background: light-dark(var(--colors-signaling-red-70), var(--colors-signaling-red-30));
  color: light-dark(var(--colors-signaling-red-10), var(--colors-signaling-red-90));
}

@keyframes btn-busy {
  to {
    rotate: -360deg;   /* gegen den Uhrzeigersinn, wie die Pfeile von renew */
  }
}

/* Fokus (Tastatur): Rand innen in der Focused-Farbe */
.btn:where(.btn--primary, .btn--secondary, .btn--tertiary, .btn--ghost):focus-visible {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--controls-primary-focused-color-control-border);
}

/* -------------------- Button-Group --------------------
   Figma: Button Group (12862:52329). Pille in Input-Fläche (40px,
   4px Innenabstand, 4px Abstand), darin Buttons in Medium-Höhe (32px)
   ohne Fläche; Hover und aktiv: ausgestanzt (--surface-color-cutout).
   Variante .btn-group--medium: Pille 32px, Buttons 24px.
   Variante .btn-group--vertical: Buttons untereinander.
   Aktiv wird ein Button über eines davon:
     aria-pressed="true"  (Umschalter, <button>)
     aria-current="page"  (Navigation, <a>)
     eine ausgewählte Radio-Option darin (Auswahl ohne JS, s. u.)
   Auswahl per Radio — nur eine aktiv, Wert wird mit dem Formular
   gesendet, Tastatur mit Pfeiltasten:
     <div class="btn-group" role="radiogroup" aria-label="Ansicht">
       <label class="btn"><input class="btn-group__input" type="radio"
         name="ansicht" value="a" checked><span class="btn__label">Liste</span></label>
       <label class="btn"><input class="btn-group__input" type="radio"
         name="ansicht" value="b"><span class="btn__label">Karte</span></label>
     </div>
------------------------------------------------------------ */
.btn-group {
  display: inline-flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-medium);
  height: var(--rem-10x);
  padding: var(--controls-spacing-container-padding-medium);
  border-radius: var(--radius-border-radius-100);
  background: var(--inputs-primary-default-color-input-container);
}

.btn-group > .btn {
  height: var(--rem-8x);
  min-height: 0;
  padding: 0 var(--controls-spacing-container-padding-large);
  gap: 0;
  box-shadow: none;
  background: none;
  color: var(--typography-color-text-primary);
  transition: background-color var(--transition-short), color var(--transition-short);
}

.btn-group > .btn:is([aria-pressed='true'], [aria-current], :has(> .btn-group__input:checked)) {
  background: var(--surface-color-cutout);
}

@media (hover: hover) {
  .btn-group > .btn:hover {
    background: var(--surface-color-cutout);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .btn-group > .btn:active {
    background: var(--surface-color-cutout);
  }
}

/* Nur Icon (ohne .btn__label): quadratisch wie die Buttonhöhe */
.btn-group > .btn:not(:has(.btn__label)) {
  width: var(--rem-8x);
  padding: 0;
  justify-content: center;
}

.btn-group > .btn .btn__icon {
  width: auto;
  height: auto;
  background: none;
  color: inherit;
}

.btn-group > .btn .btn__icon s-icon {
  width: var(--rem-1rem);
  height: var(--rem-1rem);
}

/* Variante medium: Pille 32px (4px Innenabstand), Buttons 24px.
   <div class="btn-group btn-group--medium" …>…</div> */
.btn-group--medium {
  height: var(--rem-8x);
}

.btn-group--medium > .btn {
  height: var(--rem-6x);
  padding: 0 var(--controls-spacing-container-padding-medium);
}

.btn-group--medium > .btn:not(:has(.btn__label)) {
  width: var(--rem-6x);
  padding: 0;
}

/* Variante vertical: Buttons untereinander, volle Breite, Label links.
   Radius = halbe Buttonhöhe + Innenabstand, damit die Ecken der
   Buttons konzentrisch in der Gruppe liegen (wie die Pille quer).
   Kombinierbar mit --medium.
   <div class="btn-group btn-group--vertical" …>…</div> */
.btn-group--vertical {
  flex-direction: column;
  align-items: stretch;
  height: auto;
  border-radius: calc(var(--rem-10x) / 2);
}

.btn-group--vertical.btn-group--medium {
  border-radius: calc(var(--rem-8x) / 2);
}

/* Radio unsichtbar, aber für Tastatur und Screenreader da */
.btn-group__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
  pointer-events: none;
}

/* Tastatur-Fokus auf dem Radio → Rand am Button */
.btn-group > .btn:has(> .btn-group__input:focus-visible) {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--controls-primary-focused-color-control-border);
}

/* -------------------- Card --------------------
   Figma: Card / Default (12997:9827).
   Die Komponente definiert nur Fläche und Aufbau — was in Header,
   Body und Footer steht (Tag, Headline, Text, Buttons …), bestimmt
   das HTML. Alle drei Bereiche sind optional.
   <div class="card">
     <div class="card__header">…</div>
     <div class="card__body">…</div>
     <div class="card__footer">…</div>
   </div>
   Breite kommt vom Layout, Höhe vom Inhalt. In mehrspaltigen
   Bereichen (text-columns) wird eine Card nie geteilt.
------------------------------------------------------------ */
.card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  width: 100%;
  padding: var(--layout-spacing-container-padding);
  border-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-layer-2);
  color: var(--typography-color-text-primary);
  break-inside: avoid;
}

/* Eingefärbte Card (Yellow, Green, Blue) auf neutraler Fläche
   (nächstes Farbthema darüber = Default): layer-1 des Themas statt
   layer-2, also eine Stufe heller (Light) bzw. dunkler (Dark).
   Grey bleibt bei layer-2. Ausschlussliste nur Farbthemen, denn
   <html> trägt data-theme für die Dichte (Desktop/Tablet/Mobile).
   Ausgestanztes auf der Card (Tag light, aktiver Button) zeigt die
   Seite: --surface-color-page hält layer-1 des nächsten Default.
   <div data-theme="Yellow" class="card">…</div> */
[data-theme='Default'] {
  --surface-color-page: var(--surface-color-layer-1);
}

.card:is([data-theme='Yellow'], [data-theme='Green'], [data-theme='Blue']):not(:is([data-theme='Grey'], [data-theme='Yellow'], [data-theme='Green'], [data-theme='Blue']) *) {
  --surface-color-cutout: var(--surface-color-page);
  --surface-color-next: var(--surface-color-layer-2);
  --surface-color-next-2: var(--surface-color-layer-3);
  background: var(--surface-color-layer-1);
}

/* Controls relativ zur Ebene: auf einer Fläche der Ebene 2 (Card,
   gefülltes Accordion/Sticky-Stack, Header, Floating Window) liegen
   Secondary-Button und Eingabefelder auf layer-3, Hover auf layer-4,
   Ausgestanztes auf layer-1 (styles.css rechnet die Control-Werte mit next/next-2). Card--line hat
   keine Fläche und bleibt beim Wert der Umgebung. */
.header,
.card:not(.card--line),
.accordion--filled,
.sticky-stack--filled,
.floating {
  --surface-color-cutout: var(--surface-color-layer-1);
  --surface-color-next: var(--surface-color-layer-3);
  --surface-color-next-2: var(--surface-color-layer-4);
}

/* Verschachtelt: Card bzw. gefülltes Accordion in einer Card liegt eine
   Ebene tiefer (layer-3), eine weitere darin auf layer-4. Nur ohne
   eigenes Farbthema. Ausgestanztes darin (cutout) nimmt jeweils die
   Ebene davor; auf layer-2 ist das layer-1 (Wert der Seite). */
:is(.card, .accordion--filled) :is(.card:not(.card--line), .accordion--filled):not([data-theme]) {
  --surface-color-cutout: var(--surface-color-layer-2);
  --surface-color-next: var(--surface-color-layer-4);
  --surface-color-next-2: var(--surface-color-layer-5);
  background: var(--surface-color-layer-3);
}

:is(.card, .accordion--filled) :is(.card, .accordion--filled) :is(.card:not(.card--line), .accordion--filled):not([data-theme]) {
  --surface-color-cutout: var(--surface-color-layer-3);
  --surface-color-next: var(--surface-color-layer-5);
  --surface-color-next-2: var(--surface-color-layer-6);
  background: var(--surface-color-layer-4);
}

/* Variante: ohne Fläche, Linie oben (Figma: CTA im Footer) */
.card--line {
  padding-inline: 0;
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  border-radius: 0;
  background: none;
}

.card__header,
.card__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  row-gap: var(--rem-2x);
  width: 100%;
}

/* Secondary Headline in der Card: eigene Zeile (wie im Section-Head)
   <h4>Headline <span class="secondary">Secondary Headline</span></h4>
   Nur <span>: eine Hochstellung (<sup class="secondary">3</sup>, z. B.
   Anzahl) bleibt in der Zeile */
.card :is(h1, h2, h3, h4, h5) span.secondary {
  display: block;
}

.card__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  width: 100%;
}

/* -------------------- Dialog (Overlay) --------------------
   Modales Fenster über der Seite: natives <dialog> als Ebene, darin
   eine Card als Fläche (Abstände, Radius, Ebenen, Header/Body/Footer
   kommen von der Card). Öffnen, Schließen und Fokus macht der Browser:
     Öffnen     <button commandfor="id" command="show-modal">
     Schließen  Buttons im <form method="dialog">, ihr value landet in
                dialog.returnValue (z. B. "cancel", "save"); oder
                <button commandfor="id" command="close">
     Esc        immer
     daneben    Klick auf den Hintergrund schließt nur mit
                closedby="any" (sonst closedby="closerequest")
   Fehlt dem Browser commandfor oder closedby, ergänzt main.js beides
   (initDialogs).
   <button type="button" class="btn btn--primary" commandfor="id" command="show-modal">…</button>
   <dialog class="dialog" id="id" aria-labelledby="id-titel" closedby="closerequest">
     <form class="card" method="dialog">
       <header class="card__header">
         <h4 id="id-titel">Titel</h4>
         <button class="btn btn--ghost dialog__close" value="cancel" formnovalidate aria-label="Schließen">
           <span class="btn__icon"><s-icon name="close--large"></s-icon></span>
         </button>
       </header>
       <div class="card__body">…</div>
       <footer class="card__footer">
         <button class="btn btn--secondary" value="cancel" formnovalidate>…</button>
         <button class="btn btn--primary" value="save">…</button>
       </footer>
     </form>
   </dialog>
   Formular: .card--form an der Card (48px zwischen den Bereichen);
   Felder mit required halten den Dialog offen, Abbrechen und X
   schließen dank formnovalidate trotzdem. Fokus beim Öffnen: Feld
   mit autofocus, sonst der erste Button.
   Header, Body, Footer und X sind optional (wie bei der Card).
   Varianten:
     (Standard)       mittig, 600px breit
     .dialog--confirm 420px, Rückfrage: role="alertdialog" und
                      aria-describedby auf den Text
     .dialog--full    Vollfläche, Seitenrand (32px) zum Fenster
     .dialog--inspector  Details zu einem Element bearbeiten: rechts
                      unter dem Header, 420px, volle Höhe, fährt von
                      rechts ein, abgedunkelt ohne Weichzeichner; mit
                      closedby="any" schließt ein Klick daneben. Mobil
                      wie die anderen unten angedockt, Höhe nach Inhalt
   Größe: nie über den Seitenrand hinaus; Header und Footer stehen,
   der Body scrollt. Unter 960px unten angedockt (Seitenrand rundum)
   und fährt von unten ein; Footer-Buttons teilen sich die Breite.
   Hintergrund: Seite abgedunkelt (dunkle Seitenfläche des Themas,
   35 %) und weichgezeichnet. Ein-/Ausblenden: long (out/in).
   Platz im Markup: außerhalb von Cards (z. B. am Ende von <body>),
   sonst stuft die Card-Verschachtelung die Fläche eine Ebene tiefer.
------------------------------------------------------------ */
.dialog {
  --dialog-gap: var(--layout-spacing-container-padding);
  position: fixed;
  inset: 0;
  flex-direction: column;
  width: min(calc(100% - 2 * var(--dialog-gap)), var(--dialog-width, calc(var(--rem-30x) * 5)));
  max-width: none;
  height: fit-content;
  max-height: calc(100dvh - 2 * var(--dialog-gap));
  margin: auto;
  padding: 0;
  overflow: visible;
  border: 0;
  background: none;
  color: var(--typography-color-text-primary);
  opacity: 0;
  scale: 0.98;
  transition:
    opacity var(--transition-duration-long) var(--transition-easing-in),
    scale var(--transition-duration-long) var(--transition-easing-in),
    translate var(--transition-duration-long) var(--transition-easing-in),
    overlay var(--transition-duration-long) allow-discrete,
    display var(--transition-duration-long) allow-discrete;
}

.dialog[open] {
  display: flex;
  opacity: 1;
  scale: 1;
  transition-timing-function: var(--transition-easing-out);
}

@starting-style {
  .dialog[open] {
    opacity: 0;
    scale: 0.98;
  }
}

.dialog--confirm {
  --dialog-width: calc(var(--rem-30x) * 3.5);
}

.dialog--full {
  inset: var(--dialog-gap);
  width: auto;
  height: auto;
  max-height: none;
  margin: 0;
}

.dialog > .card {
  flex: 0 1 auto;
  min-height: 0;
}

.dialog--full > .card {
  flex-grow: 1;
}

/* Header: X rechts, bricht nie unter den Titel */
.dialog .card__header {
  flex: none;
  flex-wrap: nowrap;
  gap: var(--controls-spacing-container-gap-large);
}

.dialog__close {
  flex: none;
  margin-left: auto;
}

.dialog .card__body {
  flex: 1 1 auto;
  align-items: stretch;
  min-height: 0;
  overflow-y: auto;
}

.dialog .card__footer {
  flex: none;
  justify-content: flex-end;
  gap: var(--controls-spacing-container-gap-large);
}

/* Hintergrund: dunkle Seitenfläche des Themas, 35 % deckend, weichgezeichnet */
.dialog::backdrop {
  background: color-mix(in srgb, var(--surface-color-layer-1-dark) 35%, transparent);
  -webkit-backdrop-filter: blur(var(--rem-1x));   /* WebKit-Framework (WKWebView, Mac App) kennt nur die Präfix-Form */
  backdrop-filter: blur(var(--rem-1x));
  opacity: 0;
  transition:
    opacity var(--transition-duration-long) var(--transition-easing),
    overlay var(--transition-duration-long) allow-discrete,
    display var(--transition-duration-long) allow-discrete;
}

.dialog[open]::backdrop {
  opacity: 1;
}

@starting-style {
  .dialog[open]::backdrop {
    opacity: 0;
  }
}

/* Mobil: unten angedockt, fährt von unten ein */
@media (max-width: 959px) {
  .dialog:not(.dialog--full) {
    inset: auto var(--dialog-gap) calc(var(--dialog-gap) + env(safe-area-inset-bottom, 0px)) var(--dialog-gap);
    width: auto;
    margin: 0;
    scale: 1;
    translate: 0 calc(100% + var(--dialog-gap));
  }

  .dialog:not(.dialog--full)[open] {
    translate: 0 0;
  }

  @starting-style {
    .dialog:not(.dialog--full)[open] {
      translate: 0 calc(100% + var(--dialog-gap));
    }
  }

  .dialog .card__footer > .btn {
    flex: 1 1 auto;
  }
}

/* Inspektor: rechts am Rand, Seite abgedunkelt wie beim Dialog, aber
   ohne Weichzeichner (der Inhalt daneben bleibt lesbar) */
.dialog--inspector::backdrop {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

@media (min-width: 960px) {
  .dialog--inspector {
    --dialog-width: calc(var(--rem-30x) * 3.5);
    inset: calc(var(--header-height) + var(--dialog-gap)) var(--dialog-gap) var(--dialog-gap) auto;
    height: auto;
    max-height: none;
    margin: 0;
    scale: 1;
    translate: calc(100% + var(--dialog-gap)) 0;
  }

  .dialog--inspector[open] {
    translate: 0 0;
  }

  @starting-style {
    .dialog--inspector[open] {
      scale: 1;
      translate: calc(100% + var(--dialog-gap)) 0;
    }
  }

  .dialog--inspector > .card {
    flex-grow: 1;
  }
}

/* -------------------- Steps (Schrittanzeige) --------------------
   Fortschritt eines mehrstufigen Ablaufs. Je Schritt ein runder Tag
   (Zahl, erledigt Häkchen) mit Namen, dazwischen eine Linie.
     erledigt  .steps__item--done   Häkchen auf nächster Ebene, Linie primary
                                    (als <button> zurück zum Schritt)
     aktuell   aria-current="step"  Primary-Fläche, Name fett
     offen     (Standard)           Kontur, Name und Linie secondary
   Vertikal:  .steps--vertical (Schritte untereinander, Linie senkrecht)
   Größen:    .steps--large · (Standard: medium) · .steps--small
              Kreise 40/32/24 px; large mit Schrift wie medium, small
              wie Tag small (Namen in Paragraph small); Tags im Markup
              ohne Größenklasse
   Passt die waagrechte Anzeige nicht in ihre Breite (main.js misst bei
   jeder Größenänderung): erst nur der Name des aktuellen Schritts
   (.steps--compact, auch fest setzbar), dann werden ferne Schritte zu
   einem Kreis mit drei Punkten zusammengefasst. Erster, letzter,
   aktueller Schritt und seine Nachbarn bleiben am längsten stehen.
   Passen nicht einmal diese drei, schaltet die Anzeige auf vertikal
   (alle Schritte mit Namen). Namen werden nie gekürzt.
   <ol role="list" class="steps" aria-label="Fortschritt">
     <li class="steps__item steps__item--done">
       <button type="button" class="steps__step"><span class="tag tag--round"><s-icon name="checkmark" label="erledigt"></s-icon></span><span class="steps__label">Kunde</span></button>
     </li>
     <li class="steps__item" aria-current="step">
       <span class="steps__step"><span class="tag tag--round"><span class="tag__label">2</span></span><span class="steps__label">Vorlage</span></span>
     </li>
     <li class="steps__item">
       <span class="steps__step"><span class="tag tag--round"><span class="tag__label">3</span></span><span class="steps__label">Start</span></span>
     </li>
   </ol>
   Im Wizard (unten) erzeugt main.js die Schritte aus den Panels.
------------------------------------------------------------ */
/* contain: die Mindestbreite der Schritte drückt die Umgebung (z. B.
   den Dialog) nicht breiter; passt es nicht, fasst main.js zusammen */
.steps:not(.steps--vertical) {
  contain: inline-size;
}

.steps {
  --steps-circle: var(--rem-8x);
  display: flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  padding: 0;
  list-style: none;
}

.steps__item {
  display: flex;
  flex: 1 1 auto;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  color: var(--typography-color-text-secondary);
}

.steps__item:last-child {
  flex: none;
}

.steps__step {
  display: flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  text-align: start;
}

button.steps__step {
  cursor: pointer;
}

.steps__step .tag {
  flex: none;
  color: inherit;
  box-shadow: inset 0 0 0 var(--rem-0-25x) currentColor;
}

.steps__label {
  flex: none;
  white-space: nowrap;
}

/* Linie zum nächsten Schritt in der Textfarbe des Schritts:
   nach erledigten primary, sonst secondary */
.steps__item:not(:last-child)::after {
  content: "";
  flex: 1 1 var(--rem-6x);
  min-width: var(--rem-6x);
  height: var(--rem-0-25x);
  background: currentColor;
}

.steps__item--done {
  color: var(--typography-color-text-primary);
}

.steps__item--done .tag {
  background: var(--surface-color-next);
  box-shadow: none;
  transition: background-color var(--transition-short);
}

@media (hover: hover) {
  button.steps__step:hover .tag {
    background: var(--surface-color-next-2);
  }

  button.steps__step:hover .steps__label {
    text-decoration: underline;
  }
}

.steps__item[aria-current="step"] {
  color: var(--typography-color-text-primary);
  font-weight: 700;
}

.steps__item[aria-current="step"]::after {
  background: var(--typography-color-text-secondary);
}

.steps__item[aria-current="step"] .tag {
  background: var(--controls-primary-default-color-control-container);
  box-shadow: none;
  color: var(--controls-primary-default-color-control-content);
  font-weight: 400;
}

/* Größen: Kreis (für die senkrechte Linie), Name und Abstände.
   Large: nur der Kreis wächst (40px, Icon 20px), Schrift bleibt wie
   medium und steht mittig */
.steps--large {
  --steps-circle: var(--rem-10x);
}

.steps--large .tag {
  --tag-height: var(--rem-10x);
  --tag-icon: var(--rem-5x);
}

.steps--small {
  --steps-circle: var(--rem-6x);
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
}

.steps--small,
.steps--small :is(.steps__item, .steps__step) {
  gap: var(--controls-spacing-container-gap-medium);
}

/* Vertikal: Linie senkrecht unter dem Kreis */
.steps--vertical {
  flex-direction: column;
  align-items: stretch;
  gap: var(--rem-1x);
}

.steps--vertical .steps__item {
  flex-direction: column;
  align-items: flex-start;
  gap: var(--rem-1x);
}

.steps--vertical .steps__item:not(:last-child)::after {
  flex: none;
  width: var(--rem-0-25x);
  min-width: 0;
  height: var(--rem-6x);
  margin-inline-start: calc((var(--steps-circle) - var(--rem-0-25x)) / 2);   /* Mitte des Kreises */
}

/* Zu eng (main.js misst): erst nur der Name des aktuellen Schritts
   (.steps--compact), dann ferne Schritte zu einem Kreis mit drei
   Punkten zusammengefasst (.steps__item--more), zuletzt vertikal */
.steps--compact .steps__item:not([aria-current]) .steps__label {
  display: none;
}

.steps__item[hidden] {
  display: none;
}

/* -------------------- Wizard --------------------
   Mehrstufiger Ablauf in einer Card (auch im Dialog): Schritte oben,
   je Schritt ein fieldset als Panel, unten Zurück / Weiter / Abschluss.
   main.js erzeugt die Schrittanzeige aus data-step der Panels, schaltet
   die Panels um und prüft beim Weiter die Pflichtfelder des Schritts.
   Erledigte Schritte sind klickbar (zurück). Der Inhalt hat immer die
   Höhe des höchsten Schritts (kein Springen). Enter in einem Feld geht
   zum nächsten Schritt, erst im letzten wird abgeschickt.
   Nur einsetzen, wo vieles auf einmal entsteht.
   <form class="card card--form wizard" aria-labelledby="…">
     <header class="card__header"><h4 id="…">Neues Projekt <span class="secondary">aus Vorlage</span></h4></header>
     <ol role="list" class="steps" aria-label="Fortschritt"></ol>
     <div class="card__body">
       <fieldset class="wizard__panel" data-step="Kunde">…</fieldset>
       <fieldset class="wizard__panel" data-step="Vorlage">…</fieldset>
     </div>
     <footer class="card__footer">
       <button type="button" class="btn btn--tertiary" data-wizard="back"><span class="btn__icon"><s-icon name="arrow--left"></s-icon></span><span class="btn__label">Zurück</span></button>
       <button type="button" class="btn btn--primary" data-wizard="next"><span class="btn__label">Weiter</span><span class="btn__icon"><s-icon name="arrow--right"></s-icon></span></button>
       <button type="submit" class="btn btn--primary" data-wizard="finish"><span class="btn__label">Projekt anlegen</span></button>
     </footer>
   </form>
   Ereignis „wizardstep“ (detail.index) bei jedem Wechsel, z. B. um die
   Zusammenfassung im letzten Schritt zu füllen.
------------------------------------------------------------ */
.wizard > .steps {
  flex: none;
  width: 100%;
}

/* Alle Panels liegen in derselben Zelle: der Inhalt ist so hoch wie
   der höchste Schritt, Card und Dialog springen beim Wechsel nicht.
   Verborgene Panels (inert, von main.js) bleiben in ihrem Layout, aber
   unsichtbar und ohne Fokus. */
.wizard > .card__body {
  display: grid;
}

.wizard__panel {
  grid-area: 1 / 1;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.wizard__panel[inert] {
  visibility: hidden;
}

.wizard [data-wizard][hidden] {
  display: none;
}

.wizard .card__footer {
  gap: var(--controls-spacing-container-gap-large);
}

.wizard .card__footer > :is([data-wizard="next"], [data-wizard="finish"]) {
  margin-inline-start: auto;
}

/* -------------------- Kalender <s-calendar> (B-016) --------------------
   Neutrale Komponente: Monat, Woche, Tag. Leiste aus vorhandenen
   Bausteinen (h5, Flyout mit .list, Switch, Button-Group, Buttons), neu
   sind nur Raster und Eintrag. Flächen statt Linien: Tage und Stunden
   layer-2 (Wochenende layer-3) mit 2 px Spalt wie .fields. Alles
   richtet sich nach der Breite der Komponente (Container Queries),
   nicht nach dem Fenster: dieselbe Komponente funktioniert ganzseitig
   und in einer schmalen Spalte.

   <s-calendar views="month week day" view="month" editable
               weekend-toggle week-numbers hours="8 18" step="15"
               aria-label="Kalender"></s-calendar>
     views            angebotene Ansichten (eine → kein Umschalter)
     editable         Anlegen, Verschieben, Dauer (ohne = nur lesen)
     weekend-toggle   Schalter „Wochenende“ in der Leiste
     hide-weekend     Wochenende ausgeblendet (Zustand des Schalters)
     week-numbers     KW in der ersten Zelle jeder Woche (Monat)
     hours, step      sichtbares Stundenfenster, Raster in Minuten
   Aktionen der App (z. B. „Termin anlegen“) als Kinder mit
   data-slot="actions": die Komponente setzt sie rechts neben „Heute“.
   Daten, Ereignisse und Methoden: js/calendar.js (nur Seiten mit
   Kalender laden es, als Modul: <script src="js/calendar.js" type="module">).
   Die Höhe gibt die Seite vor (z. B. Grid-Zelle oder feste Höhe).
------------------------------------------------------------ */

/* -------- Kalender: Hülle und Leiste -------- */
.calendar {
  --calendar-gap: var(--rem-0-5x);   /* Spalt zwischen Tagen und Stunden */
  --calendar-head: var(--rem-10x);   /* Wochentag- bzw. Tageskopf */
  --calendar-hours: var(--rem-14x);  /* Stundenspalte (Woche, Tag) */

  container: calendar / inline-size;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  min-width: 0;
  min-height: 0;
}

/* Leiste: Zeitraum (h5) mit Sprung-Flyout links; rechts Wochenende,
   Ansicht, ‹ Heute › und die Aktionen der App. Über der Ansicht,
   damit die Flyouts über dem Raster liegen. */
.calendar__bar {
  position: relative;
  z-index: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large) var(--layout-spacing-container-gap-1x);
  min-height: var(--rem-12x);
  padding-block-end: var(--rem-2x);
}

.calendar__period {
  margin-inline-end: auto;
}

.calendar__tools {
  flex-wrap: wrap;
  justify-content: flex-end;
}

/* „Heute“ und Aktionen immer rechts, auch wenn die Werkzeuge umbrechen */
.calendar__end {
  margin-inline-start: auto;
}

.calendar__paging,
.calendar__actions {
  gap: var(--controls-spacing-container-gap-small);
}

.calendar__actions:empty {
  display: none;
}

/* Wochenende: Label kurz, wenn es eng wird */
.calendar__short {
  display: none;
}

/* Sprung-Flyout: Liste scrollt ab etwa 12 Einträgen; Gruppen (Jahr
   bzw. Monat, small secondary) mit Abstand wie zwischen Flyout-Blöcken */
.calendar__jump {
  width: calc(var(--rem-30x) * 2);
  max-width: 100%;
  max-height: calc(var(--rem-8x) * 12);
}

.calendar__jump-groups {
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: var(--flyout-pad);
}

/* Schmal: höchstens zwei Zeilen. Oben Zeitraum, rechtsbündig „Sa/So“;
   darunter Ansicht links, „Heute“ und Aktionen rechts. Passt alles in
   eine Zeile (z. B. nur Monat, ohne Wochenende), bleibt es eine.
   ‹ › entfallen (Wischen blättert), sonst passt die Zeile auf dem
   Handy nicht. */
@container calendar (max-width: 639px) {
  .calendar__tools {
    flex: 1 1 auto;
    justify-content: flex-start;
  }

  .calendar__end {
    gap: var(--controls-spacing-container-gap-small);
  }

  .calendar__paging > [data-page='-1'],
  .calendar__paging > [data-page='1'],
  .calendar__long {
    display: none;
  }

  .calendar__short {
    display: inline;
  }
}

/* Ansicht: kein Markieren und kein Kontextmenü beim langen Druck
   (Ziehen mit Touch). --area-*: Lage der Tagesflächen für die Maske */
.calendar__view {
  --area-head: 0px;
  --area-side: 0px;
  --area-top: calc(var(--area-head) + var(--calendar-gap));
  --area-left: 0px;

  isolation: isolate;
  display: grid;
  grid-template-rows: minmax(0, 1fr);
  min-height: 0;
  -webkit-touch-callout: none;
  user-select: none;
}

/* Außenecken der Tagesflächen mit dem Radius der Card (innen bleiben
   die Abstände): Maske auf dem Scrollbereich. Kopf (und in Woche/Tag die
   Stunden) bleiben ganz sichtbar, die Fläche darunter bzw. rechts davon
   ist ein Rechteck mit runden Ecken – aus zwei Balken und vier Kreisen.
   Der Abstand dazwischen (2 px) bleibt leer, sonst schaute dort beim
   Scrollen ein Streifen des Tages über der runden Ecke heraus.
   Die Maske liegt fest auf dem sichtbaren Bereich, der Inhalt scrollt
   darunter durch. #000 steuert nur die Deckkraft, ist nie sichtbar. */
.calendar__view > * {
  --r: var(--radius-border-radius-6);
  --t: var(--area-top);
  --l: var(--area-left);

  mask:
    linear-gradient(#000 0 0) 0 0 / 100% var(--area-head) no-repeat,
    linear-gradient(#000 0 0) 0 0 / var(--area-side) 100% no-repeat,
    linear-gradient(#000 0 0) calc(var(--l) + var(--r)) var(--t) / calc(100% - var(--l) - 2 * var(--r)) calc(100% - var(--t)) no-repeat,
    linear-gradient(#000 0 0) var(--l) calc(var(--t) + var(--r)) / calc(100% - var(--l)) calc(100% - var(--t) - 2 * var(--r)) no-repeat,
    radial-gradient(closest-side, #000 calc(100% - 0.5px), transparent) var(--l) var(--t) / calc(2 * var(--r)) calc(2 * var(--r)) no-repeat,
    radial-gradient(closest-side, #000 calc(100% - 0.5px), transparent) 100% var(--t) / calc(2 * var(--r)) calc(2 * var(--r)) no-repeat,
    radial-gradient(closest-side, #000 calc(100% - 0.5px), transparent) var(--l) 100% / calc(2 * var(--r)) calc(2 * var(--r)) no-repeat,
    radial-gradient(closest-side, #000 calc(100% - 0.5px), transparent) 100% 100% / calc(2 * var(--r)) calc(2 * var(--r)) no-repeat;
}

/* Monat: unter dem Wochentagkopf; Woche und Tag: zusätzlich rechts
   der Stunden */
.calendar__view:has(> .calendar__month) {
  --area-head: var(--calendar-head);
}

.calendar__view:has(> .calendar__time) {
  --area-head: var(--calendar-head);
  --area-side: var(--calendar-hours);
  --area-left: calc(var(--area-side) + var(--calendar-gap));
}

/* -------- Kalender: Monat --------
   Scrollbereich über alle Wochen, Wochentagkopf klebt oben, rastet an
   Wochen ein. Wie viele Wochen die Höhe füllen, folgt der Höhe: sechs,
   und je weniger Platz, desto weniger (5, 4 … 1), jede Woche mindestens
   96 px hoch, immer ganze Wochen im Bild. Jeder Tag ist ein
   Container: ist er schmal (Handy, schmale Spalte), werden Einträge
   zu Punkten und der ganze Tag führt zum Tag (wie die Tageszahl).
   <div class="calendar__month" style="--cols: 7" data-month="2026-10">
     <div class="calendar__weekdays"><small>Mo</small> … </div>
     <div class="calendar__days">
       <div class="calendar__day" data-date="2026-10-26" data-month="2026-10" [data-weekend] [data-outside]>
         <small class="calendar__week secondary">KW 44</small>
         <button type="button" class="tag tag--small tag--round calendar__date" data-date="…" aria-label="…"><span class="tag__label">26</span></button>
         <div class="calendar__events">…Einträge…</div>
         <button type="button" class="calendar__more" data-date="…">2 weitere</button>
       </div> …
     </div>
   </div> */
.calendar__month {
  --head: var(--calendar-head);

  container: calendar-month / size;
  overflow-y: auto;
  overscroll-behavior: contain;
  scroll-snap-type: y mandatory;
  scroll-padding-block-start: calc(var(--head) + var(--calendar-gap));
}

.calendar__weekdays {
  position: sticky;
  top: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  gap: var(--calendar-gap);
  align-items: center;
  height: var(--head);
  background: var(--surface-color-layer-1);
}

.calendar__weekdays > * {
  padding-inline: var(--rem-2x);
  text-align: right;
}

.calendar__days {
  display: grid;
  grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
  grid-auto-rows: calc((100cqb - var(--head)) / var(--rows) - var(--calendar-gap));
  gap: var(--calendar-gap);
}

/* Wochen im Bild: n Wochen brauchen n × (96 + 2) + 40 px Höhe */
.calendar__days {
  --rows: 6;
}

@container calendar-month (max-height: 627px) {
  .calendar__days {
    --rows: 5;
  }
}

@container calendar-month (max-height: 529px) {
  .calendar__days {
    --rows: 4;
  }
}

@container calendar-month (max-height: 431px) {
  .calendar__days {
    --rows: 3;
  }
}

@container calendar-month (max-height: 333px) {
  .calendar__days {
    --rows: 2;
  }
}

@container calendar-month (max-height: 235px) {
  .calendar__days {
    --rows: 1;
  }
}

/* Schneidet nur senkrecht ab: Balken mehrtägiger Einträge ragen in
   die Nachbartage */
.calendar__day {
  --surface-color-cutout: var(--surface-color-layer-1);
  --surface-color-next: var(--surface-color-layer-3);
  --surface-color-next-2: var(--surface-color-layer-4);

  container-type: inline-size;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--rem-1x);
  min-width: 0;
  padding: var(--rem-1x);
  overflow: visible clip;
  background: var(--surface-color-layer-2);
  border-radius: var(--radius-border-radius-2);
  scroll-snap-align: start;
}

.calendar__day[data-weekend] {
  --surface-color-cutout: var(--surface-color-layer-2);
  --surface-color-next: var(--surface-color-layer-4);
  --surface-color-next-2: var(--surface-color-layer-5);

  background: var(--surface-color-layer-3);
}

/* Bearbeiten: Klick in einen leeren Tag legt an */
.calendar[editable] .calendar__day {
  cursor: pointer;
}

/* KW oben links, auf Höhe der Tageszahl */
.calendar__week {
  position: absolute;
  inset-block-start: var(--rem-1x);
  inset-inline-start: var(--rem-1x);
  display: flex;
  align-items: center;
  height: var(--rem-6x);
  padding-inline: var(--rem-1x);
  pointer-events: none;
}

.calendar:not([week-numbers]) .calendar__week {
  display: none;
}

/* Tageszahl: Tag rund small als Button (wie das Farbmuster), führt zum
   Tag. Heute wie Primary (Fläche), alle anderen wie Tertiary (ohne
   Fläche, Hover Secondary-Fläche). Am Monatsersten mit Monat, dann nicht rund.
   Nur lesen und schmal: der ganze Tag (::after).
   <button type="button" class="tag tag--small tag--round calendar__date" data-date="…" aria-label="…">
     <span class="tag__label">26</span>
   </button>
   heute zusätzlich .calendar__today */
.calendar__date {
  flex-shrink: 0;
  align-self: flex-end;
  border: 0;
  background: none;
  box-shadow: none;
  color: var(--controls-secondary-default-color-control-content);
  font-family: inherit;
  cursor: pointer;
  transition:
    color var(--transition-short),
    background-color var(--transition-short),
    box-shadow var(--transition-long);   /* Wachsen beim Hover = Bewegung */
}

.calendar__date::after {
  content: '';
  position: absolute;
  inset: 0;
  display: none;
}

.calendar:not([editable]) .calendar__date::after {
  display: block;
}

.calendar__date:focus-visible {
  outline: var(--rem-0-5x) solid var(--controls-primary-focused-color-control-border);
  outline-offset: var(--rem-0-5x);
}

/* Tertiary: Hover mit der Secondary-Fläche der Ebene (Tag layer-2 →
   next = layer-3, Wochenende layer-4); Touch: beim Drücken.
   Tage außerhalb des gezeigten Monats in secondary */
.calendar__day[data-outside] .calendar__date:not(.calendar__today) {
  color: var(--typography-color-text-secondary);
}

@media (hover: hover) {
  .calendar__day .calendar__date:not(.calendar__today):hover {
    background: var(--controls-secondary-default-color-control-container);
  }
}

@media (hover: none) {
  .calendar__day .calendar__date:not(.calendar__today):active {
    background: var(--controls-secondary-default-color-control-container);
  }
}

/* Heute: wie .btn--primary (Tageszahl, Tageskopf, Jetzt-Linie). Als
   Button bzw. im Tageskopf beim Hover eine Farbstufe weiter, und die
   Fläche wächst um 4 px nach außen (box-shadow, ohne Layout-Änderung);
   Touch: beim Drücken */
.calendar__today {
  background: var(--controls-primary-default-color-control-container);
  box-shadow: 0 0 0 0 var(--controls-primary-default-color-control-container);
  color: var(--controls-primary-default-color-control-content);
}

.calendar__colhead .calendar__today {
  transition:
    color var(--transition-short),
    background-color var(--transition-short),
    box-shadow var(--transition-long);
}

@media (hover: hover) {
  .calendar__date.calendar__today:hover,
  .calendar__time[data-view='week'] .calendar__colhead:hover .calendar__today {
    background: var(--controls-primary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-primary-hover-color-control-container);
    color: var(--controls-primary-hover-color-control-content);
  }
}

@media (hover: none) {
  .calendar__date.calendar__today:active,
  .calendar__time[data-view='week'] .calendar__colhead:active .calendar__today {
    background: var(--controls-primary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-primary-hover-color-control-container);
    color: var(--controls-primary-hover-color-control-content);
  }
}

.calendar__events {
  display: flex;
  flex-direction: column;
  gap: var(--calendar-gap);
  min-width: 0;
}

/* Hält die Spur eines mehrtägigen Eintrags frei (data-part: Tag, an
   dem der Balken des Vortags weiterläuft) */
.calendar__gap {
  flex-shrink: 0;
  height: var(--rem-6x);
  background: none; /* data-theme gäbe ihm die Fläche des Themas */
}

/* „n weitere“: führt zum Tag */
.calendar__more {
  position: relative;
  padding: 0 var(--rem-1x);
  border: 0;
  background: none;
  color: var(--typography-color-text-secondary);
  font: inherit;
  font-size: var(--typography-font-size-p-small);
  text-align: left;
  cursor: pointer;
}

.calendar__more:hover {
  color: var(--typography-color-text-primary);
}

/* -------- Kalender: Woche und Tag --------
   Ein Scrollbereich in beide Richtungen über alle Tage. Stunden kleben
   links, der Kopf jedes Tages oben. --days Tage füllen die Breite
   (Woche 5, schmal 3; Tag 1), das Stundenfenster (hours) die Höhe.
   Rastet waagrecht je Tag und senkrecht je Stunde ein.
   <div class="calendar__time" data-view="week" style="--hours: 10">
     <div class="calendar__grid" style="--count: 126">
       <div class="calendar__corner"></div>
       <div class="calendar__hours"><small style="--h: 1">01:00</small> …</div>
       <div class="calendar__snaps"><span class="calendar__snap" style="--h: 0"></span> …</div>
       <div class="calendar__col" data-date="…" [data-weekend]>
         <button type="button" class="calendar__colhead" data-date="…"><small>Mo</small><small>26.</small></button>
         <div class="calendar__slots" data-date="…">…Einträge, Jetzt-Linie…</div>
       </div> …
     </div>
   </div> */
.calendar__time {
  --days: 5;
  --time-col: var(--calendar-hours);
  --head: calc(var(--calendar-head) + var(--calendar-gap)); /* wie Monat: Kopf, Spalt */
  --day: calc((100cqi - var(--time-col)) / var(--days) - var(--calendar-gap));
  --hour: max(var(--rem-12x), calc((100cqb - var(--head)) / var(--hours)));

  container-type: size;
  overflow: auto;
  overscroll-behavior: contain;
  scroll-snap-type: both mandatory;
  scroll-padding-inline-start: calc(var(--time-col) + var(--calendar-gap));
  scroll-padding-block-start: var(--head);
}

.calendar__time[data-view='day'] {
  --days: 1;
}

@container calendar (max-width: 719px) {
  .calendar__time[data-view='week'] {
    --days: 3;
  }
}

/* Eine Achse je Geste: die Richtung erkennt calendar.js (data-axis),
   gesperrt wird hier */
.calendar__time[data-axis='x'] {
  overflow-y: hidden;
}

.calendar__time[data-axis='y'] {
  overflow-x: hidden;
}

.calendar__grid {
  position: relative;
  display: grid;
  grid-template-columns: var(--time-col) repeat(var(--count), var(--day));
  grid-template-rows: var(--head) calc(var(--hour) * 24);
  column-gap: var(--calendar-gap);
  width: max-content;
}

.calendar__corner {
  position: sticky;
  top: 0;
  left: 0;
  z-index: 4;
  grid-area: 1 / 1;
  background: var(--surface-color-layer-1);
}

.calendar__hours {
  position: sticky;
  left: 0;
  z-index: 2;
  grid-area: 2 / 1;
  background: var(--surface-color-layer-1);
}

/* Stundenzahl oben an ihrer Fläche (00:00 entfällt) */
.calendar__hours > small {
  position: absolute;
  top: calc(var(--h) * var(--hour));
  right: var(--rem-2x);
  color: var(--typography-color-text-secondary);
  translate: 0 -50%;
}

/* Rastpunkte senkrecht: je Stunde ein unsichtbares Band über die ganze
   Breite (nicht an den klebenden Stunden: beim Einrasten in zwei Achsen
   zählt Chrome nur Punkte, die in der anderen Achse im Bild liegen).
   Absolut im Raster: belegt keine Zellen, die Tage reihen sich frei. */
.calendar__snaps {
  position: absolute;
  inset: 0;
  grid-area: 2 / 1 / 3 / -1;
  pointer-events: none;
}

.calendar__snap {
  position: absolute;
  top: calc(var(--h) * var(--hour));
  right: 0;
  left: 0;
  height: var(--hour);
  scroll-snap-align: start none;
}

/* Tag: Kopf und Stunden in den Zeilen des Rasters (subgrid); der Kopf
   klebt oben, die Spalte (volle Höhe) ist der Rastpunkt waagrecht */
.calendar__col {
  display: grid;
  grid-row: 1 / 3;
  grid-template-rows: subgrid;
  scroll-snap-align: none start;
}

/* Wie der Wochentagkopf im Monat: rechtsbündig, gleiche Höhe */
.calendar__colhead {
  position: sticky;
  top: 0;
  z-index: 3;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--rem-2x);
  padding: 0 var(--rem-2x) var(--calendar-gap);
  border: 0;
  background: var(--surface-color-layer-1);
  color: var(--typography-color-text-primary);
  font: inherit;
  text-align: start;
  cursor: pointer;
}

.calendar__time[data-view='day'] .calendar__colhead {
  cursor: default;
}

.calendar__colhead:focus-visible {
  outline: var(--rem-0-5x) solid var(--controls-primary-focused-color-control-border);
  outline-offset: calc(var(--rem-0-5x) * -1);
}

.calendar__col[data-weekend] .calendar__colhead {
  color: var(--typography-color-text-secondary);
}

.calendar__slots {
  --surface-color-cutout: var(--surface-color-layer-2);
  --surface-color-next: var(--surface-color-layer-3);
  --surface-color-next-2: var(--surface-color-layer-4);

  position: relative;
  background: repeating-linear-gradient(to bottom,
    var(--surface-color-layer-2) 0 calc(var(--hour) - var(--calendar-gap)),
    transparent 0 var(--hour));
}

.calendar__col[data-weekend] .calendar__slots {
  --surface-color-cutout: var(--surface-color-layer-3);
  --surface-color-next: var(--surface-color-layer-4);
  --surface-color-next-2: var(--surface-color-layer-5);

  background: repeating-linear-gradient(to bottom,
    var(--surface-color-layer-3) 0 calc(var(--hour) - var(--calendar-gap)),
    transparent 0 var(--hour));
}

.calendar[editable] .calendar__slots {
  cursor: pointer;
}

/* Jetzt-Linie heute: 1 px in Textfarbe (wie die Linien im Brand
   System), Uhrzeit links darüber gefüllt wie „Heute“; kurz nach
   Mitternacht darunter (sonst unter dem Kopf) */
.calendar__now {
  position: absolute;
  top: calc(var(--now) / 60 * var(--hour));
  right: 0;
  left: 0;
  z-index: 1;
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  pointer-events: none;
}

.calendar__now > .tag {
  position: absolute;
  bottom: var(--rem-0-5x);
  left: 0;
}

.calendar__now[data-below] > .tag {
  top: var(--rem-0-5x);
  bottom: auto;
}

/* -------- Kalender: Eintrag --------
   Fläche next der Ebene, mit Farbe die Fläche des Themas (layer-2,
   Hover layer-3) bzw. der Signalfarbe (80, Hover 70; Dunkel 20 / 30).
   Was die Farbe bedeutet, legt die App fest.
   Zeile (Monat): Titel, Uhrzeit rechts (fällt in schmalen Tagen weg).
   Balken (Monat, mehrtägig): Zeile über mehrere Tage.
   Block (Woche, Tag): Zeit, Titel, Avatare über die Dauer; was nicht
   passt, fällt weg (erst Avatare, dann Zeit).
   <button type="button" class="calendar-event calendar-event--row" data-id="4" data-theme="Blue" data-start data-end>
     <span class="calendar-event__title">Interview</span><small class="calendar-event__time">10:00</small>
   </button>
   <button type="button" class="calendar-event calendar-event--block" data-id="4" data-signal="red" data-start data-end
           style="--from: 600; --length: 60; --lane: 0; --lanes: 1">
     <small class="calendar-event__time">10:00–11:00</small>
     <small class="calendar-event__title bold">Interview</small>
     <span class="tag-stack" …>…</span>
   </button>
   data-start / data-end: hier liegt Beginn bzw. Ende (nur dort lässt
   sich die Kante ziehen). data-locked: nicht ziehbar. data-status: von
   der App durchgereicht, Gestaltung folgt. */
.calendar-event {
  position: relative;
  display: flex;
  min-width: 0;
  border: 0;
  border-radius: var(--radius-border-radius-2);
  background: var(--surface-color-next);
  color: var(--typography-color-text-primary);
  font: inherit;
  text-align: left;
  cursor: pointer;
  transition: background-color var(--transition-short);
}

.calendar-event:hover,
.calendar-event[data-hover] {
  background: var(--surface-color-next-2);
}

.calendar-event:focus-visible {
  outline: var(--rem-0-5x) solid var(--controls-primary-focused-color-control-border);
  outline-offset: calc(var(--rem-0-5x) * -1);
}

/* Farbe: Thema (Yellow, Blue, Green) */
:is(.calendar-event, .calendar__gap, .calendar-color)[data-theme] {
  --surface-color-cutout: var(--surface-color-layer-1);
  --surface-color-next: var(--surface-color-layer-2);
  --surface-color-next-2: var(--surface-color-layer-3);
  --calendar-dot: var(--surface-color-layer-5);
}

/* Farbe: Signal (yellow, green, red) */
:is(.calendar-event, .calendar__gap, .calendar-color)[data-signal] {
  --surface-color-cutout: light-dark(var(--signal-90), var(--signal-10));
  --surface-color-next: light-dark(var(--signal-80), var(--signal-20));
  --surface-color-next-2: light-dark(var(--signal-70), var(--signal-30));
  --typography-color-text-primary: light-dark(var(--signal-10), var(--signal-90));
  --typography-color-text-secondary: light-dark(var(--signal-30), var(--signal-70));
  --calendar-dot: var(--signal-50);
}

[data-signal='yellow'] {
  --signal-10: var(--colors-signaling-yellow-10);
  --signal-20: var(--colors-signaling-yellow-20);
  --signal-30: var(--colors-signaling-yellow-30);
  --signal-50: var(--colors-signaling-yellow-50);
  --signal-70: var(--colors-signaling-yellow-70);
  --signal-80: var(--colors-signaling-yellow-80);
  --signal-90: var(--colors-signaling-yellow-90);
}

[data-signal='green'] {
  --signal-10: var(--colors-signaling-green-10);
  --signal-20: var(--colors-signaling-green-20);
  --signal-30: var(--colors-signaling-green-30);
  --signal-50: var(--colors-signaling-green-50);
  --signal-70: var(--colors-signaling-green-70);
  --signal-80: var(--colors-signaling-green-80);
  --signal-90: var(--colors-signaling-green-90);
}

[data-signal='red'] {
  --signal-10: var(--colors-signaling-red-10);
  --signal-20: var(--colors-signaling-red-20);
  --signal-30: var(--colors-signaling-red-30);
  --signal-50: var(--colors-signaling-red-50);
  --signal-70: var(--colors-signaling-red-70);
  --signal-80: var(--colors-signaling-red-80);
  --signal-90: var(--colors-signaling-red-90);
}

/* Farbe als Muster, z. B. in einer Farbauswahl der App: Tag rund mit
   der Fläche, die ein Eintrag dieser Farbe hätte. Ausgewählt mit Häkchen.
   <button type="button" class="tag tag--round calendar-color" data-theme="Blue" role="radio" aria-checked="true" aria-label="Blau">
     <s-icon name="checkmark"></s-icon>
   </button> */
.calendar-color {
  border: 0;
  background: var(--surface-color-next);
  box-shadow: none;
  color: var(--typography-color-text-primary);
}

/* Als Button (Auswahl); als <span> nur Anzeige, z. B. in einer Liste */
button.calendar-color {
  cursor: pointer;
}

button.calendar-color:hover {
  background: var(--surface-color-next-2);
}

.calendar-color:focus-visible {
  outline: var(--rem-0-5x) solid var(--controls-primary-focused-color-control-border);
  outline-offset: var(--rem-0-5x);
}

.calendar-event__title,
.calendar-event__time {
  min-width: 0;
  overflow-x: clip;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.calendar-event__time {
  color: var(--typography-color-text-secondary);
}

.calendar-event--row {
  justify-content: space-between;
  align-items: center;
  gap: var(--rem-1x);
  width: 100%;
  height: var(--rem-6x);
  padding-inline: var(--rem-1x);
  font-size: var(--typography-font-size-p-small);
}

.calendar-event--row .calendar-event__time {
  flex-shrink: 0;
}

@container (max-width: 120px) {
  .calendar-event--row .calendar-event__time {
    display: none;
  }
}

.calendar-event--block {
  --edge: var(--rem-0-5x);

  position: absolute;
  top: calc(var(--from) / 60 * var(--hour));
  left: calc((100% - var(--edge)) / var(--lanes) * var(--lane));
  width: calc((100% - var(--edge)) / var(--lanes) - var(--edge));
  height: calc(var(--length) / 60 * var(--hour) - var(--calendar-gap));
  container-type: size;
  flex-direction: column;
  align-items: flex-start;
  padding: var(--rem-1x) var(--rem-2x);
  overflow: hidden;
}

.calendar-event--block .tag-stack {
  margin-block-start: auto;
}

/* Avatare auf ausgestanzter Fläche (wie in der Termin-Card der Agenda) */
.calendar-event .tag--avatar {
  background: var(--surface-color-cutout);
}

/* Höhe ohne Innenabstand: Avatare ab rund 1,5 h, Zeit ab 30 min */
@container (max-height: 71px) {
  .calendar-event--block .tag-stack {
    display: none;
  }
}

@container (max-height: 29px) {
  .calendar-event--block .calendar-event__time {
    display: none;
  }
}

/* Monat (steht nach den Grundregeln des Eintrags, damit es sie schlägt).
   Breite Tage: mehrtägig als Balken je Woche vom ersten bis zum
   letzten Tag (--span Tage = Tagesbreite 100cqi plus Innenabstand und
   Spalt je weiterer Tag). Beginn links, „bis …“ rechts; gerade Kante,
   wo er in der Woche davor oder danach weitergeht. */
@container (min-width: 72px) {
  .calendar-event--bar {
    z-index: 1;
    flex-shrink: 0;
    justify-content: flex-start;
    width: calc((var(--span) - 1) * (100cqi + var(--rem-1x) * 2 + var(--calendar-gap)) + 100cqi);
  }

  .calendar-event--bar .calendar-event__title {
    flex: 1 1 auto;
  }

  /* Zeit auch in schmalen Tagen, solange der Balken mehrere Tage lang ist */
  .calendar-event--bar:not([data-short]) .calendar-event__time {
    display: block;
  }

  .calendar-event--row:not([data-start]) {
    border-start-start-radius: 0;
    border-end-start-radius: 0;
  }

  .calendar-event--row:not([data-end]) {
    border-start-end-radius: 0;
    border-end-end-radius: 0;
  }
}

/* Schmale Tage: Einträge als Punkte in ihrer Farbe, der Tag führt zum Tag */
@container (max-width: 71px) {
  .calendar__events {
    flex-direction: row;
    flex-wrap: wrap;
    justify-content: flex-end;
  }

  .calendar-event--row,
  .calendar__gap[data-part] {
    width: var(--rem-2x);
    height: var(--rem-2x);
    padding: 0;
    border-radius: var(--radius-border-radius-100);
    background: var(--calendar-dot, var(--typography-color-text-primary));
    pointer-events: none;
  }

  .calendar-event--row > *,
  .calendar__week,
  .calendar__gap:not([data-part]),
  .calendar__more,
  .calendar__month-name {
    display: none;
  }

  .calendar__date::after {
    display: block;
  }
}

/* -------- Kalender: Ziehen (editable) --------
   Nur der Cursor zeigt es, keine Griffe: Fläche = verschieben, 6 px an
   der Kante, wo Beginn bzw. Ende liegt = Dauer (Woche/Tag oben/unten,
   Monat links/rechts in ganzen Tagen). Nur mit Maus. */
.calendar[editable] .calendar-event:not([data-locked]) {
  cursor: grab;
}

.calendar[editable] .calendar-event--block:not([data-locked])[data-start]::before,
.calendar[editable] .calendar-event--block:not([data-locked])[data-end]::after {
  content: '';
  position: absolute;
  right: 0;
  left: 0;
  height: var(--rem-1-5x);
  cursor: ns-resize;
}

.calendar[editable] .calendar-event--block[data-start]::before {
  top: 0;
}

.calendar[editable] .calendar-event--block[data-end]::after {
  bottom: 0;
}

@container (min-width: 72px) {
  .calendar[editable] .calendar-event--row:not([data-locked])[data-start]::before,
  .calendar[editable] .calendar-event--row:not([data-locked])[data-end]::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: var(--rem-1-5x);
    cursor: ew-resize;
  }

  .calendar[editable] .calendar-event--row[data-start]::before {
    left: 0;
  }

  .calendar[editable] .calendar-event--row[data-end]::after {
    right: 0;
  }
}

/* Während des Ziehens rastet nichts ein, der Eintrag selbst ist
   ausgeblendet, die Vorschau (data-draft) zeigt die neue Lage; im Monat
   sind seine Tage markiert (eine Stufe zur Mitte, wie Hover) */
.calendar[data-drag] :is(.calendar__month, .calendar__time) {
  scroll-snap-type: none;
}

.calendar-event[data-source] {
  visibility: hidden;
}

.calendar__day[data-target] {
  background: var(--surface-color-next);
}

.calendar[data-drag='move'] * {
  cursor: grabbing;
}

.calendar:is([data-drag='start'], [data-drag='end']) * {
  cursor: ns-resize;
}

.calendar[data-drag='days'] * {
  cursor: ew-resize;
}

.calendar-event[data-draft] {
  z-index: 2;
  background: var(--surface-color-next-2);
  transition: none;
  pointer-events: none;
}

/* -------- Kalender: Termin-Dialog (Seitenbaustein) --------
   Dialog der App zum Kalender, aus Brand-Bausteinen (Dialog mit
   Card--form, Fields, Flyout, Avatar, Buttons). Jede Änderung gilt
   sofort; neu angelegt (data-new) unten „Verwerfen“ statt „Löschen“.
   Doku: seitenbausteine.html#termin-dialog.
   <dialog class="dialog calendar-dialog" [data-new] …>
     .calendar-dialog__title    Titelfeld, rechts Farbe (.calendar-color als Flyout-Toggle)
     .calendar-dialog__colors   Farbmuster im Flyout (zwei Reihen)
     .calendar-dialog__people   Teilnehmer: Avatar, Name, E-Mail, entfernen
     .calendar-dialog__discard  bzw. __delete im Footer
   Nur ansehen (Lese-Kalender): .calendar-dialog__list je Termin Farbe,
   Titel mit Zeit, Teilnehmer. */

/* Titel mit Farbe rechts daneben. Überbrückung: Das Flyout-Fenster
   ragt um --flyout-pad über den Button hinaus und wird am Rand der
   scrollenden Card abgeschnitten; darum Abstand zum Rand
   (Bug B-036: Flyout in scrollendem Container) */
.fields > .calendar-dialog__title {
  padding-block: 0; /* .fields gibt Zeilen mit .flex-layout sonst 8 px Luft */
  padding-inline-end: var(--controls-spacing-container-padding-large);
}

.calendar-dialog__title > .field {
  flex: 1 1 auto;
}

.calendar-dialog:not([data-new]) .calendar-dialog__discard,
.calendar-dialog[data-new] .calendar-dialog__delete {
  display: none;
}

.calendar-dialog__discard {
  margin-inline-end: auto;
}

/* Farben: „Ohne“ und Themenfarben, darunter Signalfarben */
.calendar-dialog__colors {
  display: grid;
  grid-template-columns: repeat(4, auto);
  gap: var(--controls-spacing-container-gap-large);
}

.calendar-dialog__colors > [data-signal='yellow'] {
  grid-column-start: 2;
}

.calendar-dialog__people {
  display: flex;
  flex-direction: column;
  gap: var(--rem-2x);
}

.calendar-dialog__people:empty {
  display: none;
}

.calendar-dialog__people > li {
  display: flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
}

.calendar-dialog__people p {
  flex: 1 1 auto;
  min-width: 0;
}

.calendar-dialog__list {
  display: flex;
  flex-direction: column;
  gap: var(--layout-spacing-container-gap-1x);
}

.calendar-dialog__list > li {
  display: flex;
  align-items: flex-start;
  gap: var(--controls-spacing-container-gap-large);
}

/* Farbpunkt bleibt rund (schrumpft sonst neben langen Namen) */
.calendar-dialog__list > li > .tag {
  flex-shrink: 0;
}

.calendar-dialog__list .stack-1 {
  flex: 1 1 auto;
  min-width: 0;
}

/* -------------------- Table --------------------
   Figma: Table Cells — Table Header (182:1521), Table Cell (182:1523).
   <table class="table">
     <thead><tr><th>…</th></tr></thead>
     <tbody><tr><td>…</td></tr></tbody>
   </table>
   - Kopf: Paragraph Bold, 8px Abstand nach unten, keine Linie
   - Zelle: Paragraph, Linie oben (1px text-primary); Zeilenhöhe von
     Linie zu Linie fest (inkl. Abstand und Linie), Text mittig
     dazwischen: Abstand oben/unten = (Höhe − Linie − Versalhöhe) / 2.
     Mehrzeilige Zellen wachsen.
   - oben und unten keine Trennlinie (ohne <thead>: erste Zeile ohne Linie)
   - zwischen den Spalten 24px wie im Grid (gap-1x); die Linie ist dort
     unterbrochen (border-spacing, der Rand außen wird per negativer
     Margin ausgeglichen)
   Text auf Versalhöhe/Grundlinie getrimmt (wie in Figma) → die 8px
   gelten bis zur Schrift.
   Zeilenhöhe (--table-row-height):
     .table--small     24px, Paragraph small (12px)
     .table            32px (Standard)
     .table--large     48px
   Tags und Buttons in Zellen zählen nur mit der Versalhöhe (negative
   margin-block) → Zeilenhöhe bleibt; sie stehen mittig zur Versalhöhe
   des Textes und ragen in den Zellenabstand. Buttons als eigener Block
   (z. B. .flex-layout), Tags im Text:
     <td><div class="flex-layout flex-layout--gap-s flex-layout--nowrap">
       <button class="btn btn--ghost" aria-label="…">…</button></div></td>
     <td>13,99 € <span class="tag tag--small">…</span></td>
   Button unter Text (mehrzeilige Zelle): Text in <p>/<small> davor →
   der Button zählt voll (kein negativer Rand):
     <td><p>…</p><button class="btn btn--ghost">…</button></td>
   Schmal: .table--list → Listeneinträge, wenn der Platz zu eng ist
     (Rollen je Spalte im Kopf: data-list="haupt|aktion|aus", s. u.)
   Varianten der Spaltenbreiten (nur CSS):
     .table            Auto — nach Länge des Inhalts (Standard)
     .table--even      Even — alle Spalten gleich breit
     .table--grid      Grid — Spalten auf den Spalten des Seitenrasters;
                       Breite je Tabellenspalte über die Grid-Klassen am
                       Kopf (col-1 … col-12, Standard 1 Rasterspalte),
                       die letzte Spalte füllt den Rest:
                       <thead><tr><th class="col-3">…</th><th class="col-3">…</th><th>…</th></tr></thead>
                       Bis zu 6 Spalten. Unter 960px wie Auto.
     .table--resizable mit .table--grid: Spalten im Kopf ziehen
                       (rastet an Rasterspalten ein; main.js) — auf allen
                       Breiten (12/6/4 Rasterspalten)
------------------------------------------------------------ */
.table {
  --table-gap: var(--layout-spacing-container-gap-1x);
  --table-row-height: var(--rem-8x);

  width: calc(100% + var(--table-gap) * 2);
  margin-inline: calc(var(--table-gap) * -1);
  border-collapse: separate;
  border-spacing: var(--table-gap) 0;
  font-size: var(--typography-font-size-p);
  line-height: var(--typography-line-height-p);
  color: var(--typography-color-text-primary);
}

.table :is(th, td) {
  text-align: left;
  vertical-align: top;
  /* schmale Spalten: Silbentrennung statt Überlaufen */
  hyphens: auto;
  overflow-wrap: break-word;
  text-wrap: pretty;
  text-box: trim-both cap alphabetic;
}

/* Auto: keine Silbentrennung — sonst darf der Browser kurze Spalten bis
   auf einzelne Silben zusammendrücken („Pu-bli-kum“), während lange
   Textspalten die ganze Breite bekommen. Mindestbreite einer Spalte =
   längstes Wort. Even und Grid (feste Breiten) trennen weiter. */
.table:not(.table--even, .table--grid) :is(th, td) {
  hyphens: manual;
}

.table th {
  padding: 0 0 var(--controls-spacing-container-padding-large);
  font-weight: 700;
}

.table td {
  --table-cap: 1cap;
  --table-ex: 1ex;

  padding: calc((var(--table-row-height) - var(--rem-0-25x) - 1cap) / 2) 0;
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  font-weight: 400;
}

/* Zeilenhöhe */
.table--small {
  --table-row-height: var(--rem-6x);
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
}

.table--large {
  --table-row-height: var(--rem-12x);
}

/* Tags und Buttons in Zellen: zählen nur mit der Versalhöhe der Zelle.
   Button (eigener Block): oben bündig = Versalhöhe → mittig.
   Tag (im Text): vertical-align: middle setzt die Mitte auf Grundlinie
   + ½ x-Höhe → um (x-Höhe − Versalhöhe) / 2 versetzen.
   cap/ex registriert → in der Schrift der Zelle aufgelöst, nicht in
   der kleineren Schrift des Tags. */
@property --table-cap {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

@property --table-ex {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

.table td .tag {
  position: relative;
  top: calc((var(--table-ex) - var(--table-cap)) / 2);
  margin-block: calc((var(--table-cap) - var(--tag-height)) / 2);
  vertical-align: middle;
}

/* Zelle mit Button unter Text (mehrzeilig) ausgenommen: der Button zählt
   voll, sonst überlappt er den Text darüber; Abstand wie im Umfeld */
.table td:not(:has(
  :is(p, small, ul, ol, h1, h2, h3, h4, h5) ~ .btn,
  :is(p, small, ul, ol, h1, h2, h3, h4, h5) ~ * .btn
)) .btn {
  margin-block: calc((var(--table-cap) - var(--btn-height)) / 2);
}

/* Ohne Kopf: erste Zeile ohne Linie und ohne Abstand oben */
.table > tbody:first-child > tr:first-child > td {
  padding-top: 0;
  border-top: 0;
}

/* Letzte Zeile: kein Abstand unten (keine Linie darunter) */
.table > tbody:last-child > tr:last-child > td {
  padding-bottom: 0;
}

/* Even: alle Spalten gleich breit */
.table--even {
  table-layout: fixed;
}

/* Grid: CSS-Grid statt Tabellen-Layout. Spuren = Spalten des
   Seitenrasters (Breite wie dort berechnet, 12/6/4 Spalten; Anzahl
   ergibt sich aus der Tabellenbreite), Abstand 24px wie im Raster.
   thead/tbody/tr lösen sich auf (display: contents), die Zellen liegen
   direkt im Grid. Die Linie oben ist pro Zelle → im Abstand zwischen
   den Spalten unterbrochen.
   Unter 960px hat der Inhalt nur 6 bzw. 4 Rasterspalten — feste
   Spannen passen dann nicht mehr → dort wie Auto (nach Inhalt; gleich
   breit würde kurze Spalten aufblähen und lange quetschen).
   Ausnahme .table--resizable: bleibt Grid, main.js passt die Spannen
   an die vorhandenen Rasterspalten an. */
.table--grid {
  --table-grid-cols: 12;
  --table-grid-col: calc(
    (min(100vw, var(--page-max, 1920px)) - var(--layout-spacing-container-padding) * 2
      - var(--table-gap) * (var(--table-grid-cols) - 1)) / var(--table-grid-cols)
  );

  display: grid;
  /* 4px Spielraum: 100vw enthält eine evtl. Scrollbar */
  grid-template-columns: repeat(auto-fill, minmax(calc(var(--table-grid-col) - var(--rem-1x)), 1fr));
  column-gap: var(--table-gap);
  width: auto;
  margin-inline: 0;
}

.table--grid :is(thead, tbody, tr) {
  display: contents;
}

/* Spannen aus den Grid-Klassen im Kopf (th.col-n → --span-k für
   Spalte k, gilt dann für alle Zellen dieser Spalte) */
.table--grid:has(> thead > tr > :nth-child(1).col-1) { --span-1: 1; }
.table--grid:has(> thead > tr > :nth-child(1).col-2) { --span-1: 2; }
.table--grid:has(> thead > tr > :nth-child(1).col-3) { --span-1: 3; }
.table--grid:has(> thead > tr > :nth-child(1).col-4) { --span-1: 4; }
.table--grid:has(> thead > tr > :nth-child(1).col-5) { --span-1: 5; }
.table--grid:has(> thead > tr > :nth-child(1).col-6) { --span-1: 6; }
.table--grid:has(> thead > tr > :nth-child(1).col-7) { --span-1: 7; }
.table--grid:has(> thead > tr > :nth-child(1).col-8) { --span-1: 8; }
.table--grid:has(> thead > tr > :nth-child(1).col-9) { --span-1: 9; }
.table--grid:has(> thead > tr > :nth-child(1).col-10) { --span-1: 10; }
.table--grid:has(> thead > tr > :nth-child(1).col-11) { --span-1: 11; }
.table--grid:has(> thead > tr > :nth-child(1).col-12) { --span-1: 12; }
.table--grid:has(> thead > tr > :nth-child(2).col-1) { --span-2: 1; }
.table--grid:has(> thead > tr > :nth-child(2).col-2) { --span-2: 2; }
.table--grid:has(> thead > tr > :nth-child(2).col-3) { --span-2: 3; }
.table--grid:has(> thead > tr > :nth-child(2).col-4) { --span-2: 4; }
.table--grid:has(> thead > tr > :nth-child(2).col-5) { --span-2: 5; }
.table--grid:has(> thead > tr > :nth-child(2).col-6) { --span-2: 6; }
.table--grid:has(> thead > tr > :nth-child(2).col-7) { --span-2: 7; }
.table--grid:has(> thead > tr > :nth-child(2).col-8) { --span-2: 8; }
.table--grid:has(> thead > tr > :nth-child(2).col-9) { --span-2: 9; }
.table--grid:has(> thead > tr > :nth-child(2).col-10) { --span-2: 10; }
.table--grid:has(> thead > tr > :nth-child(2).col-11) { --span-2: 11; }
.table--grid:has(> thead > tr > :nth-child(2).col-12) { --span-2: 12; }
.table--grid:has(> thead > tr > :nth-child(3).col-1) { --span-3: 1; }
.table--grid:has(> thead > tr > :nth-child(3).col-2) { --span-3: 2; }
.table--grid:has(> thead > tr > :nth-child(3).col-3) { --span-3: 3; }
.table--grid:has(> thead > tr > :nth-child(3).col-4) { --span-3: 4; }
.table--grid:has(> thead > tr > :nth-child(3).col-5) { --span-3: 5; }
.table--grid:has(> thead > tr > :nth-child(3).col-6) { --span-3: 6; }
.table--grid:has(> thead > tr > :nth-child(3).col-7) { --span-3: 7; }
.table--grid:has(> thead > tr > :nth-child(3).col-8) { --span-3: 8; }
.table--grid:has(> thead > tr > :nth-child(3).col-9) { --span-3: 9; }
.table--grid:has(> thead > tr > :nth-child(3).col-10) { --span-3: 10; }
.table--grid:has(> thead > tr > :nth-child(3).col-11) { --span-3: 11; }
.table--grid:has(> thead > tr > :nth-child(3).col-12) { --span-3: 12; }
.table--grid:has(> thead > tr > :nth-child(4).col-1) { --span-4: 1; }
.table--grid:has(> thead > tr > :nth-child(4).col-2) { --span-4: 2; }
.table--grid:has(> thead > tr > :nth-child(4).col-3) { --span-4: 3; }
.table--grid:has(> thead > tr > :nth-child(4).col-4) { --span-4: 4; }
.table--grid:has(> thead > tr > :nth-child(4).col-5) { --span-4: 5; }
.table--grid:has(> thead > tr > :nth-child(4).col-6) { --span-4: 6; }
.table--grid:has(> thead > tr > :nth-child(4).col-7) { --span-4: 7; }
.table--grid:has(> thead > tr > :nth-child(4).col-8) { --span-4: 8; }
.table--grid:has(> thead > tr > :nth-child(4).col-9) { --span-4: 9; }
.table--grid:has(> thead > tr > :nth-child(4).col-10) { --span-4: 10; }
.table--grid:has(> thead > tr > :nth-child(4).col-11) { --span-4: 11; }
.table--grid:has(> thead > tr > :nth-child(4).col-12) { --span-4: 12; }
.table--grid:has(> thead > tr > :nth-child(5).col-1) { --span-5: 1; }
.table--grid:has(> thead > tr > :nth-child(5).col-2) { --span-5: 2; }
.table--grid:has(> thead > tr > :nth-child(5).col-3) { --span-5: 3; }
.table--grid:has(> thead > tr > :nth-child(5).col-4) { --span-5: 4; }
.table--grid:has(> thead > tr > :nth-child(5).col-5) { --span-5: 5; }
.table--grid:has(> thead > tr > :nth-child(5).col-6) { --span-5: 6; }
.table--grid:has(> thead > tr > :nth-child(5).col-7) { --span-5: 7; }
.table--grid:has(> thead > tr > :nth-child(5).col-8) { --span-5: 8; }
.table--grid:has(> thead > tr > :nth-child(5).col-9) { --span-5: 9; }
.table--grid:has(> thead > tr > :nth-child(5).col-10) { --span-5: 10; }
.table--grid:has(> thead > tr > :nth-child(5).col-11) { --span-5: 11; }
.table--grid:has(> thead > tr > :nth-child(5).col-12) { --span-5: 12; }
.table--grid:has(> thead > tr > :nth-child(6).col-1) { --span-6: 1; }
.table--grid:has(> thead > tr > :nth-child(6).col-2) { --span-6: 2; }
.table--grid:has(> thead > tr > :nth-child(6).col-3) { --span-6: 3; }
.table--grid:has(> thead > tr > :nth-child(6).col-4) { --span-6: 4; }
.table--grid:has(> thead > tr > :nth-child(6).col-5) { --span-6: 5; }
.table--grid:has(> thead > tr > :nth-child(6).col-6) { --span-6: 6; }
.table--grid:has(> thead > tr > :nth-child(6).col-7) { --span-6: 7; }
.table--grid:has(> thead > tr > :nth-child(6).col-8) { --span-6: 8; }
.table--grid:has(> thead > tr > :nth-child(6).col-9) { --span-6: 9; }
.table--grid:has(> thead > tr > :nth-child(6).col-10) { --span-6: 10; }
.table--grid:has(> thead > tr > :nth-child(6).col-11) { --span-6: 11; }
.table--grid:has(> thead > tr > :nth-child(6).col-12) { --span-6: 12; }

/* Spalten explizit gesetzt: Start = 1 + Summe der Spannen davor */
.table--grid tr > :nth-child(1) { grid-column: 1 / span var(--span-1, 1); }
.table--grid tr > :nth-child(2) { grid-column: calc(1 + var(--span-1, 1)) / span var(--span-2, 1); }
.table--grid tr > :nth-child(3) { grid-column: calc(1 + var(--span-1, 1) + var(--span-2, 1)) / span var(--span-3, 1); }
.table--grid tr > :nth-child(4) { grid-column: calc(1 + var(--span-1, 1) + var(--span-2, 1) + var(--span-3, 1)) / span var(--span-4, 1); }
.table--grid tr > :nth-child(5) { grid-column: calc(1 + var(--span-1, 1) + var(--span-2, 1) + var(--span-3, 1) + var(--span-4, 1)) / span var(--span-5, 1); }
.table--grid tr > :nth-child(6) { grid-column: calc(1 + var(--span-1, 1) + var(--span-2, 1) + var(--span-3, 1) + var(--span-4, 1) + var(--span-5, 1)) / span var(--span-6, 1); }

/* letzte Spalte füllt bis zum Ende der Zeile */
.table--grid tr > :last-child {
  grid-column-end: -1;
}

@media (max-width: 959px) {
  .table--grid {
    --table-grid-cols: 6;
  }
}

@media (max-width: 639px) {
  .table--grid {
    --table-grid-cols: 4;
  }
}

/* Unter 960px ohne Ziehen: zurück zum Tabellen-Layout, nach Inhalt
   (wie Auto, ohne Silbentrennung) */
@media (max-width: 959px) {
  .table--grid:not(.table--resizable) {
    display: table;
    width: calc(100% + var(--table-gap) * 2);
    margin-inline: calc(var(--table-gap) * -1);
  }

  .table--grid:not(.table--resizable) :is(th, td) {
    hyphens: manual;
  }

  .table--grid:not(.table--resizable) thead { display: table-header-group; }
  .table--grid:not(.table--resizable) tbody { display: table-row-group; }
  .table--grid:not(.table--resizable) tr { display: table-row; }
}

/* Spalten ziehen (.table--resizable, mit .table--grid; main.js):
   Griff über dem Spaltenabstand, so hoch wie die ganze Tabelle
   (--table-h, main.js); sichtbar ist nur die Griff-Pille in der Mitte
   (Primary), mit Maus erst bei Hover über der Tabelle. Hover/Drücken: Pille wächst wie die Fläche der Primary-
   Buttons nach außen — hier 2px (bei der schmalen Pille wirken 4px wie
   beim Button zu groß); Tastatur-Fokus: Fokusfarbe. */
.table--resizable th {
  position: relative;
}

.table__resizer {
  position: absolute;
  top: 0;
  right: calc((var(--table-gap) + var(--rem-3x)) / -2);
  z-index: 1;
  width: var(--rem-3x);
  height: var(--table-h, 100%);
  cursor: col-resize;
  touch-action: none;
  --resizer-color: var(--controls-primary-default-color-control-container);
  --resizer-grow: 0px;
}

.table__resizer::before {
  content: '';
  position: absolute;
  top: 50%;
  left: 50%;
  width: var(--rem-1x);
  height: var(--rem-6x);
  border-radius: var(--radius-border-radius-100);
  background: var(--resizer-color);
  box-shadow: 0 0 0 var(--resizer-grow) var(--resizer-color);
  translate: -50% -50%;
  /* ausblenden: ease-in; Hover-Farbe und Wachsen: ease */
  transition:
    opacity var(--transition-duration-short) var(--transition-easing-in),
    background-color var(--transition-long),
    box-shadow var(--transition-long);
}

/* Mit Maus: Griff erst sichtbar, wenn die Tabelle überfahren wird
   (oder beim Ziehen / Tastatur-Fokus). Touch: immer sichtbar. */
@media (hover: hover) {
  .table__resizer::before {
    opacity: 0;
  }

  /* einblenden: ease-out */
  .table--resizable:is(:hover, .is-resizing) .table__resizer::before,
  .table__resizer:focus-visible::before {
    opacity: 1;
    transition:
      opacity var(--transition-duration-short) var(--transition-easing-out),
      background-color var(--transition-long),
      box-shadow var(--transition-long);
  }
}

@media (hover: hover) {
  .table__resizer:hover {
    --resizer-color: var(--controls-primary-hover-color-control-container);
    --resizer-grow: var(--rem-0-5x);
  }
}

.table__resizer:active,
.table--resizable.is-resizing .table__resizer:active {
  --resizer-color: var(--controls-primary-hover-color-control-container);
  --resizer-grow: var(--rem-0-5x);
}

.table__resizer:focus-visible {
  outline: none;
  --resizer-color: var(--controls-primary-focused-color-control-border);
  --resizer-grow: var(--rem-0-5x);
}

.table--resizable.is-resizing {
  cursor: col-resize;
  user-select: none;
}

/* Liste (.table--list): ist der Platz zu eng (Container < 40rem), wird
   jede Zeile ein Listeneintrag — Zeile 1: Hauptspalte links, Aktionen
   rechts; darunter alle übrigen Werte fließend in Paragraph small.
   Rolle je Spalte im Kopf (wie die Grid-Klassen bei .table--grid):
     <th data-list="haupt">   Zeile 1 links (z. B. Name, Dokument)
     <th data-list="aktion">  Zeile 1 rechts (Status-Tag, Buttons)
     <th data-list="aus">     ausgeblendet
     <th>                     Meta: darunter, fließend, 16px Abstand
   Optional Label vor dem Wert (secondary): <td data-label="Offen">
   Container = Elternelement der Tabelle (per :has, kein Zusatz-Markup);
   eine Tabelle selbst kann kein Container sein. Das Elternelement darf
   seine Breite nicht aus dem Inhalt beziehen (Block, Grid-Item).
   Kopf bleibt für Screenreader (unsichtbar). Zeilenhöhe der Größe
   (--table-row-height) gilt für Zeile 1. Bis zu 10 Spalten.
   Selektoren mit .table.table--list: schlagen die Tabellen-Rückstellung
   von .table--grid unter 960px. */
:has(> .table--list) {
  container-type: inline-size;
}

@container (max-width: 40rem) {
  .table.table--list {
    display: block;
    width: 100%;
    margin-inline: 0;
  }

  .table.table--list > thead {
    position: absolute;
    display: block;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .table.table--list > tbody {
    display: block;
  }

  .table.table--list > tbody > tr {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    column-gap: var(--rem-1rem);
    padding-block: calc((var(--table-row-height) - var(--rem-0-25x) - 1cap) / 2);
    border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  }

  .table.table--list > tbody > tr:first-child {
    padding-top: 0;
    border-top: 0;
  }

  .table.table--list > tbody > tr:last-child {
    padding-bottom: 0;
  }

  /* Zeilenumbruch nach Zeile 1 (Hauptspalte + Aktionen) */
  .table.table--list > tbody > tr::before {
    content: '';
    flex-basis: 100%;
    order: 1;
  }

  /* Meta (Standard): darunter, klein, Abstand nach oben 8px */
  .table.table--list > tbody > tr > td {
    order: 2;
    padding: var(--controls-spacing-container-gap-large) 0 0;
    border: 0;
    font-size: var(--typography-font-size-p-small);
  }

  .table.table--list > tbody > tr > td[data-label]::before {
    content: attr(data-label) ' ';
    color: var(--typography-color-text-secondary);
  }

  .table.table--list:has(> thead > tr > :nth-child(1)[data-list='haupt']) > tbody > tr > :nth-child(1),
  .table.table--list:has(> thead > tr > :nth-child(2)[data-list='haupt']) > tbody > tr > :nth-child(2),
  .table.table--list:has(> thead > tr > :nth-child(3)[data-list='haupt']) > tbody > tr > :nth-child(3),
  .table.table--list:has(> thead > tr > :nth-child(4)[data-list='haupt']) > tbody > tr > :nth-child(4),
  .table.table--list:has(> thead > tr > :nth-child(5)[data-list='haupt']) > tbody > tr > :nth-child(5),
  .table.table--list:has(> thead > tr > :nth-child(6)[data-list='haupt']) > tbody > tr > :nth-child(6),
  .table.table--list:has(> thead > tr > :nth-child(7)[data-list='haupt']) > tbody > tr > :nth-child(7),
  .table.table--list:has(> thead > tr > :nth-child(8)[data-list='haupt']) > tbody > tr > :nth-child(8),
  .table.table--list:has(> thead > tr > :nth-child(9)[data-list='haupt']) > tbody > tr > :nth-child(9),
  .table.table--list:has(> thead > tr > :nth-child(10)[data-list='haupt']) > tbody > tr > :nth-child(10) {
    order: 0;
    flex: 1 1 0;
    min-width: 0;
    padding: 0;
    font-size: inherit;
  }

  .table.table--list:has(> thead > tr > :nth-child(1)[data-list='aktion']) > tbody > tr > :nth-child(1),
  .table.table--list:has(> thead > tr > :nth-child(2)[data-list='aktion']) > tbody > tr > :nth-child(2),
  .table.table--list:has(> thead > tr > :nth-child(3)[data-list='aktion']) > tbody > tr > :nth-child(3),
  .table.table--list:has(> thead > tr > :nth-child(4)[data-list='aktion']) > tbody > tr > :nth-child(4),
  .table.table--list:has(> thead > tr > :nth-child(5)[data-list='aktion']) > tbody > tr > :nth-child(5),
  .table.table--list:has(> thead > tr > :nth-child(6)[data-list='aktion']) > tbody > tr > :nth-child(6),
  .table.table--list:has(> thead > tr > :nth-child(7)[data-list='aktion']) > tbody > tr > :nth-child(7),
  .table.table--list:has(> thead > tr > :nth-child(8)[data-list='aktion']) > tbody > tr > :nth-child(8),
  .table.table--list:has(> thead > tr > :nth-child(9)[data-list='aktion']) > tbody > tr > :nth-child(9),
  .table.table--list:has(> thead > tr > :nth-child(10)[data-list='aktion']) > tbody > tr > :nth-child(10) {
    order: 0;
    flex: none;
    padding: 0;
    font-size: inherit;
  }

  .table.table--list:has(> thead > tr > :nth-child(1)[data-list='aus']) > tbody > tr > :nth-child(1),
  .table.table--list:has(> thead > tr > :nth-child(2)[data-list='aus']) > tbody > tr > :nth-child(2),
  .table.table--list:has(> thead > tr > :nth-child(3)[data-list='aus']) > tbody > tr > :nth-child(3),
  .table.table--list:has(> thead > tr > :nth-child(4)[data-list='aus']) > tbody > tr > :nth-child(4),
  .table.table--list:has(> thead > tr > :nth-child(5)[data-list='aus']) > tbody > tr > :nth-child(5),
  .table.table--list:has(> thead > tr > :nth-child(6)[data-list='aus']) > tbody > tr > :nth-child(6),
  .table.table--list:has(> thead > tr > :nth-child(7)[data-list='aus']) > tbody > tr > :nth-child(7),
  .table.table--list:has(> thead > tr > :nth-child(8)[data-list='aus']) > tbody > tr > :nth-child(8),
  .table.table--list:has(> thead > tr > :nth-child(9)[data-list='aus']) > tbody > tr > :nth-child(9),
  .table.table--list:has(> thead > tr > :nth-child(10)[data-list='aus']) > tbody > tr > :nth-child(10) {
    display: none;
  }
}

/* -------------------- Footer --------------------
   Figma: Footer (13060:31164). 12er-Grid:
     Zeile 1  CTA (Spalte 1–6) · Linkliste (7–9) · Linkliste (10–12)
     Zeile 2  © (links)  ·  Wortmarke (rechte Hälfte, unten bündig)
   CTA = .card.card--line, Links = .footer__nav, Logo als CSS-Maske,
   damit es die Mode-Farbe (--mode-color-logo) annimmt.
   Farbe nur über data-theme am <footer> (wie Sections): Fläche =
   layer-1 des Themes, damit Controls (Buttons, Tags …) dieselben
   Abstufungen haben wie überall. Ohne data-theme: Theme der Seite.
------------------------------------------------------------ */
.footer {
  padding-block: var(--layout-spacing-container-padding);
  background: var(--surface-color-layer-1);
  color: var(--typography-color-text-primary);
}

.footer__grid {
  row-gap: var(--layout-spacing-container-gap-4x);
  align-items: start;
}

.footer__cta {
  grid-column: 1 / span 6;
}

.footer__nav {
  grid-column: span 3;
  padding-block: var(--layout-spacing-container-padding);
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

.footer__nav a {
  display: inline-block;
  line-height: var(--rem-6x);
  color: var(--typography-color-text-primary);
  text-decoration: none;
}

@media (hover: hover) {
  .footer__nav a:hover {
    color: var(--typography-color-text-secondary);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .footer__nav a:active {
    color: var(--typography-color-text-secondary);
  }
}

.footer__bottom {
  grid-column: 1 / -1;
  display: flex;
  align-items: flex-end;
  gap: var(--layout-spacing-container-gap-1x);
}

.footer__copy,
.footer__logo {
  flex: 1 1 0;
  min-width: 0;
}

.footer__logo {
  aspect-ratio: 676 / 115.632;
  background-color: var(--mode-color-logo);
  -webkit-mask: url('../assets/logo/siduvia-wortmarke.svg') no-repeat center / contain;
  mask: url('../assets/logo/siduvia-wortmarke.svg') no-repeat center / contain;
}

/* Tablet: CTA volle Breite, Linklisten je halb */
@media (max-width: 959px) {
  .footer__cta { grid-column: 1 / -1; }
  .footer__nav { grid-column: span 3; }
}

/* Mobile: alles untereinander, Wortmarke über dem © */
@media (max-width: 639px) {
  .footer__nav { grid-column: 1 / -1; }

  .footer__bottom {
    flex-direction: column-reverse;
    align-items: stretch;
  }
}

/* -------------------- Floating Window --------------------
   Figma: Floating Window (13006:33476). Standard-Fläche für alles,
   was über dem Inhalt schwebt: Dropdown-Listen, Kontextmenüs,
   Popover … Halbtransparent (layer-2, 85 % deckend) mit Weichzeichner.
   <div class="floating">…</div>
------------------------------------------------------------ */
.floating {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  padding: var(--controls-spacing-container-padding-large);
  border-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-floating-window);
  -webkit-backdrop-filter: blur(var(--rem-2x));   /* WebKit-Framework (WKWebView, Mac App) kennt nur die Präfix-Form */
  backdrop-filter: blur(var(--rem-2x));
}

/* -------------------- Flyout (Button + Floating Window) --------------------
   Button öffnet ein Floating Window. Das Fenster bekommt zusätzlich die
   Fläche des Buttons: es liegt hinter dem Button und umschließt ihn mit
   8px Abstand (= Padding des Floating Window); der Button liegt obenauf.
   Zwischen Button und Inhalt 24px (--flyout-gap). Ein Primary-Button
   wird bei offenem Flyout zum Secondary.
   <div class="flyout">
     <button class="btn btn--primary flyout__toggle" aria-expanded="false" aria-controls="id">…</button>
     <div class="floating flyout__window" id="id">
       <div class="flyout__content">…</div>
     </div>
   </div>
   Offen = aria-expanded="true" am Button (main.js, setFlyout).
   Richtung (data-flyout, setzt main.js nach verfügbarem Platz):
     down-right (Standard) · down-left · up-right · up-left
   Animation: Fläche wächst von „Button + 8px" (Pill-Form) auf die
   Endgröße (scale auf ::before, long — läuft auf der Grafikkarte) und
   blendet dabei ein (short); danach, nach kurzer Pause (½ short),
   blenden die Elemente in .flyout__content nacheinander ein (je long,
   Versatz ¼ short).
   Schließen: blendet aus (short).
   Startfläche: --flyout-btn-h und --flyout-sx/-sy (main.js); Höhe
   ohne JS: Standard 40px, mit .btn--medium 32px.
   Größe: so groß wie der Inhalt, nie über den Seitenrand (Container-
   Padding um die Website) hinaus — main.js setzt den Platz in der
   gewählten Richtung als --flyout-max-w/-h; reicht er nicht, scrollt
   .flyout__content (der Platz für den Button bleibt stehen).
------------------------------------------------------------ */
/* registriert → in px aufgelöst, main.js liest den Seitenrand */
@property --flyout-gutter {
  syntax: '<length>';
  inherits: true;
  initial-value: 0px;
}

.flyout {
  --flyout-gutter: var(--layout-spacing-container-padding);
  --flyout-pad: var(--controls-spacing-container-padding-large);
  --flyout-gap: var(--rem-6x); /* Button → Inhalt: 24px */
  --flyout-toggle-height: var(--rem-10x);

  position: relative;
  display: inline-flex;
}

.flyout:has(> .flyout__toggle.btn--medium) {
  --flyout-toggle-height: var(--rem-8x);
}

.flyout__toggle {
  position: relative;
  z-index: 1; /* über dem Fenster */
}

/* Primary-Button bei offenem Flyout als Secondary (Farben wie
   .btn--secondary, inkl. Hover/Drücken). Übergang wie beim Button. */
.flyout__toggle.btn--primary[aria-expanded='true'] {
  background: var(--controls-secondary-default-color-control-container);
  box-shadow: 0 0 0 0 var(--controls-secondary-default-color-control-container);
  color: var(--controls-secondary-default-color-control-content);
}

.flyout__toggle.btn--primary[aria-expanded='true'] .btn__icon {
  background: var(--controls-secondary-default-color-control-content);
  color: var(--controls-secondary-default-color-control-container);
}

@media (hover: hover) {
  .flyout__toggle.btn--primary[aria-expanded='true']:hover {
    background: var(--controls-secondary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-secondary-hover-color-control-container);
    color: var(--controls-secondary-hover-color-control-content);
  }

  .flyout__toggle.btn--primary[aria-expanded='true']:hover .btn__icon {
    background: var(--controls-secondary-hover-color-control-content);
    color: var(--controls-secondary-hover-color-control-container);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .flyout__toggle.btn--primary[aria-expanded='true']:active {
    background: var(--controls-secondary-hover-color-control-container);
    box-shadow: 0 0 0 var(--rem-1x) var(--controls-secondary-hover-color-control-container);
    color: var(--controls-secondary-hover-color-control-content);
  }

  .flyout__toggle.btn--primary[aria-expanded='true']:active .btn__icon {
    background: var(--controls-secondary-hover-color-control-content);
    color: var(--controls-secondary-hover-color-control-container);
  }
}

.flyout__window {
  /* Platz für den Button + 24px zum Inhalt (oben bzw. unten) */
  --flyout-reserve: calc(var(--flyout-pad) + var(--flyout-btn-h, var(--flyout-toggle-height)) + var(--flyout-gap));
  /* Start der Fläche: Button + 8px rundum, als Skalierung der Endgröße
     (--flyout-sx/-sy, main.js); Radius so, dass die Startfläche wie
     der Button eine Pill-Form hat (Ellipse, gleicht die ungleiche
     Skalierung aus) */
  --flyout-start-r: calc(var(--flyout-btn-h, var(--flyout-toggle-height)) / 2 + var(--flyout-pad));
  --flyout-origin: left top;

  position: absolute;
  top: calc(var(--flyout-pad) * -1);
  left: calc(var(--flyout-pad) * -1);
  display: none;
  /* Größe: der Inhalt (max-content), mindestens Button + 8px rundum
     (100% = .flyout = Buttonbreite), höchstens bis zum Seitenrand */
  width: max-content;
  min-width: calc(100% + var(--flyout-pad) * 2);
  max-width: var(--flyout-max-w, none);
  max-height: var(--flyout-max-h, none);
  padding-top: var(--flyout-reserve);
  /* Fläche liegt auf ::before (wird skaliert und geblendet, nicht das
     Fenster — Deckkraft am Fenster würde den Weichzeichner abschalten) */
  isolation: isolate;
  background: none;
  -webkit-backdrop-filter: none;   /* WebKit-Framework (WKWebView, Mac App) kennt nur die Präfix-Form */
  backdrop-filter: none;
  /* zu: noch „short" lang angezeigt, damit die Fläche ausblenden kann
     (display allein startet in Chrome keinen Übergang → visibility) */
  visibility: hidden;
  transition:
    visibility var(--transition-short),
    display var(--transition-short) allow-discrete;
}

.flyout__window::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-floating-window);
  /* Hintergrund weichgezeichnet, kräftiger und heller */
  -webkit-backdrop-filter: blur(var(--rem-2x)) saturate(2) brightness(1.5);   /* WebKit-Framework (WKWebView, Mac App) kennt nur die Präfix-Form */
  backdrop-filter: blur(var(--rem-2x)) saturate(2) brightness(1.5);
  transform-origin: var(--flyout-origin);
  opacity: 0;
  /* zu: blendet aus (solange das Fenster noch angezeigt wird) */
  animation: flyout-fade-out var(--transition-duration-short) var(--transition-easing-in) both;
}

/* Richtungen: Ecke am Button = Ursprung der Skalierung */
.flyout[data-flyout$='left'] > .flyout__window {
  --flyout-origin: right top;

  left: auto;
  right: calc(var(--flyout-pad) * -1);
}

.flyout[data-flyout^='up'] > .flyout__window {
  --flyout-origin: left bottom;

  top: auto;
  bottom: calc(var(--flyout-pad) * -1);
  padding-top: var(--flyout-pad);
  padding-bottom: var(--flyout-reserve);
}

.flyout[data-flyout='up-left'] > .flyout__window {
  --flyout-origin: right bottom;
}

/* Inhalt: zu = unsichtbar (beim Schließen sofort) */
.flyout__content > * {
  opacity: 0;
}

/* Offen: Fläche blendet ein (short) und wächst (long), danach — mit
   kurzer Pause — blenden die Inhalte nacheinander ein (je long). Keyframes starten bei jedem Öffnen neu, mit
   der gerade gewählten Richtung. Schließen: Fläche blendet aus (short). */
.flyout:has(> .flyout__toggle[aria-expanded='true']) > .flyout__window {
  display: flex;
  visibility: visible;
}

.flyout:has(> .flyout__toggle[aria-expanded='true']) > .flyout__window::before {
  opacity: 1;
  animation:
    flyout-fade var(--transition-duration-short) var(--transition-easing-out) both,
    flyout-grow var(--transition-duration-long) var(--transition-easing-out) both;
}

/* Inhalt: erst wenn die Fläche fertig gewachsen ist (long) plus eine
   kurze Pause (½ short); dann die Elemente der obersten Ebene einzeln
   nacheinander (Versatz ¼ short je Element, --i aus main.js, beliebig
   viele), je long eingeblendet */
.flyout:has(> .flyout__toggle[aria-expanded='true']) .flyout__content > * {
  opacity: 1;
  animation: flyout-fade var(--transition-duration-long) var(--transition-easing-out) both;
  animation-delay: calc(
    var(--transition-duration-long) + var(--transition-duration-short) / 2
    + var(--transition-duration-short) / 4 * var(--i, 0)
  );
}

@keyframes flyout-fade {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes flyout-fade-out {
  from {
    opacity: 1;
  }

  to {
    opacity: 0;
  }
}

@keyframes flyout-grow {
  from {
    scale: var(--flyout-sx, 1) var(--flyout-sy, 1);
    border-radius:
      calc(var(--flyout-start-r) / var(--flyout-sx, 1)) /
      calc(var(--flyout-start-r) / var(--flyout-sy, 1));
  }
}

/* Inhalt: Abstände/Ausrichtung wie das Fenster; scrollt, wenn das
   Fenster an den Seitenrand stößt */
.flyout__content {
  display: flex;
  flex-direction: column;
  align-items: inherit;
  gap: inherit;
  align-self: stretch;
  min-height: 0;
  /* Luft fürs Scrollen: Hover (Buttons wachsen 4px nach außen) und
     Fokusring werden sonst vom Scroll-Bereich abgeschnitten */
  margin: calc(var(--rem-1x) * -1);
  padding: var(--rem-1x);
  overflow: auto;
  overscroll-behavior: contain;
}

.flyout__content > * {
  flex-shrink: 0; /* Inhalt nie stauchen */
}

/* Messen (main.js): Endgröße ohne Anzeige und ohne Übergang */
.flyout.is-measuring > .flyout__window {
  display: flex;
  max-width: none;
  max-height: none;
  visibility: hidden;
  transition: none;
}

/* -------------------- List & List-Item --------------------
   Figma: List Item (12433:7357). Zeile mit optionalem Icon + Text;
   Hover: Fläche + 8px Einzug links (so in Figma).
   <ul class="list" role="list">
     <li><a class="list-item" href="…">
       <s-icon name="circle-dash"></s-icon>
       <span class="list-item__text">List Item</span>
     </a></li>
   </ul>
   .list-item funktioniert auf <a>, <button>, <li> und <option>.
   (Badge folgt später.)
------------------------------------------------------------ */
.list {
  display: flex;
  flex-direction: column;
  width: 100%;
}

.list-item {
  display: flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  width: 100%;
  min-height: var(--rem-8x);
  /* Figma: 8px oben/unten bei auf Versalhöhe beschnittenem Text (32px).
     Unsere Textzeile ist 20px hoch → 6px oben/unten ergibt dieselben 32px. */
  padding: var(--rem-1-5x) 0;
  border: 0;
  border-radius: var(--radius-border-radius-2);
  background: none;
  color: var(--controls-secondary-default-color-control-content);
  font: inherit;
  font-size: var(--typography-font-size-label);
  line-height: 1.25;
  text-align: start;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}

.list-item s-icon {
  width: var(--rem-1rem);
  height: var(--rem-1rem);
}

.list-item__text {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.list-item:focus-visible {
  padding-inline-start: var(--controls-spacing-container-padding-large);
  background: var(--controls-secondary-hover-color-control-container);
  outline: none;
}

@media (hover: hover) {
  .list-item:hover {
    padding-inline-start: var(--controls-spacing-container-padding-large);
    background: var(--controls-secondary-hover-color-control-container);
    outline: none;
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .list-item:active {
    padding-inline-start: var(--controls-spacing-container-padding-large);
    background: var(--controls-secondary-hover-color-control-container);
    outline: none;
  }
}

/* -------------------- Accordion --------------------
   Figma: Accordion (168:2774). Natives <details>/<summary> — auf- und
   zuklappen, Tastatur (Enter/Leertaste) und Screenreader ohne JS.
   Größe über das Überschrift-Tag (wie überall):
     Large  → <h3>   Medium → <h4>   Small → <h5>
   <details class="accordion" open>
     <summary class="accordion__header">
       <h4 class="accordion__title">Header</h4>
       <s-icon class="accordion__icon" name="add--large"></s-icon>
       <s-icon class="accordion__icon" name="subtract--large"></s-icon>
     </summary>
     <div class="accordion__body"><p>Content</p></div>
   </details>
   Icon: „+" geschlossen, „−" geöffnet. Nur eins offen gleichzeitig:
   allen <details> einer Gruppe dasselbe name-Attribut geben.
   Varianten:
     .accordion           Linie oben, ohne Fläche
     .accordion--filled   wie .card: layer-2, Radius, Padding;
                          direkt aufeinanderfolgende bilden eine
                          zusammenhängende Card mit Trennlinien
------------------------------------------------------------ */
/* Umschließendes Element einer Accordion-Gruppe immer volle Breite —
   sonst schrumpft es in Flex-Spalten (z. B. .content-section) auf den
   Inhalt und springt beim Auf-/Zuklappen in der Breite. */
:has(> .accordion) {
  align-self: stretch;
}

.accordion {
  width: 100%;
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
  color: var(--typography-color-text-primary);
}

.accordion__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--layout-spacing-container-gap-1x);
  padding-block: var(--rem-1rem);
  list-style: none;
  cursor: pointer;
  user-select: none;
}

.accordion__header::-webkit-details-marker {
  display: none;
}

.accordion__title {
  margin: 0;
  text-wrap: pretty;
}

.accordion__icon {
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
}

/* „+" geschlossen, „−" geöffnet. Beim animierten Schließen ist das
   Accordion noch [open] — .is-closing (main.js) zeigt schon das „+" */
/* Nur die eigenen Icons (> header >), nicht die verschachtelter Accordions */
.accordion:not([open]) > .accordion__header > .accordion__icon[name='subtract--large'],
.accordion[open]:not(.is-closing) > .accordion__header > .accordion__icon[name='add--large'],
.accordion.is-closing > .accordion__header > .accordion__icon[name='subtract--large'] {
  display: none;
}

.accordion__body {
  padding-block: var(--rem-1rem);
  text-wrap: pretty;
}

/* Variante filled: gestaltet wie .card. Aufeinanderfolgende Items
   = eine Card: Radius nur oben am ersten und unten am letzten Item */
.accordion--filled {
  padding-inline: var(--layout-spacing-container-padding);
  border-top: 0;
  border-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-layer-2);
}

.accordion--filled + .accordion--filled {
  border-start-start-radius: 0;
  border-start-end-radius: 0;
}

.accordion--filled:has(+ .accordion--filled) {
  border-end-start-radius: 0;
  border-end-end-radius: 0;
}

/* Innen wie das normale Accordion (1rem); außen Card-Padding:
   oben in der ersten Kopfzeile (bleibt klickbar), unten am letzten Item */
.accordion--filled .accordion__body {
  padding-block-start: 0;
}

.accordion--filled:not(.accordion--filled + .accordion--filled) .accordion__header {
  padding-block-start: var(--layout-spacing-container-padding);
}

.accordion--filled:not(:has(+ .accordion--filled)) {
  padding-block-end: calc(var(--layout-spacing-container-padding) - var(--rem-1rem));
}

/* Trennlinie zwischen den Items, bündig mit dem Inhalt (im Padding) */
.accordion--filled + .accordion--filled .accordion__header {
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

/* -------------------- Sticky-Stack --------------------
   Offene Blöcke (Header + Inhalt) untereinander. Beim Scrollen bleiben
   die Header oben stehen und stapeln sich; erst am Ende des letzten
   Blocks fahren alle zusammen weiter. Aussehen wie die Accordions
   (Linie oben bzw. Card), aber nichts klappt auf oder zu.
   Klasse am gemeinsamen Container — Sticky klebt nur im eigenen
   Elternelement, deshalb sind alle Header direkte Kinder:
   <div class="sticky-stack">
     <header class="sticky-stack__header"><h4>Header</h4></header>
     <div class="sticky-stack__body"><p>Content</p></div>
     <header class="sticky-stack__header"><h4>Header</h4></header>
     <div class="sticky-stack__body"><p>Content</p></div>
   </div>
   Varianten:
     .sticky-stack           Linie oben je Block, ohne Fläche
     .sticky-stack--filled   in einer Card (Trennlinien wie
                             .accordion--filled)
   Mit Section: Klasse direkt an die .content-section — ihr Kopf
   (.section-head, trägt dann die Linie) bleibt als oberste Lage stehen:
   <section class="content-section sticky-stack">
     <header class="section-head"><h4>…</h4></header>
     <header class="sticky-stack__header">…</header> …
   </section>
   Card in einer Section: <div class="sticky-stack sticky-stack--filled">
   als Kind der Section — stapelt unter dem Section-Kopf weiter.
   main.js misst nur die Höhen (bei Größenänderung, nicht beim Scrollen):
     --stack-top   Abstand des Headers unter dem Stapel darüber
     --stack-rest  Höhe der Header darunter — als margin-bottom
                   (der nächste Block gleicht sie mit --stack-pull als
                   negativem Margin aus): Sticky zählt die Margin-Box,
                   so verlassen alle Header den Container gleichzeitig.
   Oben: sichtbarer Header (+ Sidemenu-Leiste unter 960px).
------------------------------------------------------------ */
.sticky-stack {
  --stack-base: var(--header-visible, 0px);

  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 0;
  width: 100%;
  color: var(--typography-color-text-primary);
}

@media (max-width: 959px) {
  .page-layout .sticky-stack {
    --stack-base: calc(var(--header-visible, 0px) + var(--sidemenu-height, 0px));
  }
}

.sticky-stack > :is(.section-head, .sticky-stack__header) {
  position: sticky;
  top: calc(var(--stack-base) + var(--stack-top, 0px));
  z-index: 1;
  margin-block-end: var(--stack-rest, 0px);
  background: var(--surface-color-layer-1);
}

.sticky-stack > :is(.section-head, .sticky-stack__header) + * {
  margin-block-start: calc(var(--stack-pull, 0px) * -1);
}

.sticky-stack__header {
  display: flex;
  align-items: center;
  gap: var(--layout-spacing-container-gap-1x);
  padding-block: var(--rem-1rem);
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

.sticky-stack__header > * {
  margin: 0;
  text-wrap: pretty;
}

.sticky-stack__body {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--layout-spacing-container-gap-1x);
  padding-block: var(--rem-1rem);
  text-wrap: pretty;
}

/* Section als Stapel: Linie und Padding oben wandern an den Kopf
   (die Section selbst scrollt weg). Kopf → erster Block 120px wie sonst */
.content-section.sticky-stack {
  padding-top: 0;
  border-top: 0;
}

.sticky-stack > .section-head {
  padding-block: var(--rem-1rem);
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

.sticky-stack > .section-head + * {
  margin-block-start: calc(var(--rem-30x) - var(--rem-1rem) - var(--stack-pull, 0px));
}

/* Variante filled: eine Card. Header über die ganze Card-Breite
   (Fläche deckt beim Kleben auch das seitliche Padding), Trennlinie
   bündig mit dem Inhalt; erster Header ohne Linie, mit Card-Padding */
.sticky-stack--filled {
  padding: 0 var(--layout-spacing-container-padding) calc(var(--layout-spacing-container-padding) - var(--rem-1rem));
  border-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-layer-2);
}

.sticky-stack--filled > .sticky-stack__header {
  position: sticky;
  margin-inline: calc(var(--layout-spacing-container-padding) * -1);
  padding-inline: var(--layout-spacing-container-padding);
  border-top: 0;
  background: var(--surface-color-layer-2);
}

.sticky-stack--filled > .sticky-stack__header::before {
  content: '';
  position: absolute;
  inset: 0 var(--layout-spacing-container-padding) auto;
  border-top: var(--rem-0-25x) solid var(--typography-color-text-primary);
}

/* Erster Header: trägt die Rundung oben. Klebt er, läuft die Card
   darunter weiter — deshalb Seitenfläche als Hintergrund (deckt die
   Card in den Ecken ab) und die Card-Fläche gerundet als ::before */
.sticky-stack--filled > .sticky-stack__header:first-child {
  padding-block-start: var(--layout-spacing-container-padding);
  background: var(--surface-color-layer-1);
}

.sticky-stack--filled > .sticky-stack__header:first-child::before {
  inset: 0;
  z-index: -1;
  border: 0;
  border-start-start-radius: var(--radius-border-radius-6);
  border-start-end-radius: var(--radius-border-radius-6);
  corner-shape: var(--corner-shape-soft);
  background: var(--surface-color-layer-2);
}

/* ====================================================================
   Formular-Elemente: Radio · Checkbox · Switch · Field
   Farben ausschließlich aus den Input-Tokens (styles.css):
     --inputs-primary-{default|hover|active|focused|disabled}-color-input-{border|container|content}
   Fehler: --mode-error-foreground / --mode-error-background
   (für Fehler gibt es keine eigenen Input-Tokens).
   Rand als inset box-shadow (1px, innen) statt border: verändert
   keine Maße und kein Padding — wie die Kontur in Figma.
   Zustände, Rangfolge: Default < Hover < Focused = Active < Disabled < Error
     Hover         nur die Randfarbe ändert sich
     Focused/Active identisch (Maus, Tastatur, Touch)
   Native Inputs, per CSS gestaltet; Markierungen als Hintergrund
   (Firefox zeigt ::before auf Inputs nicht).
   ==================================================================== */

/* -------------------- Radio --------------------
   Figma: Radio Button (235:4694) + with Label (12999:31418).
   <label class="radio">
     <input class="radio__input" type="radio" name="gruppe" value="a">
     <span class="radio__label">Label Text</span>
   </label>
------------------------------------------------------------ */
/* Input mittig zur ersten Textzeile (wie Marker der Bullet-Listen):
   einzeilig = mittig, mehrzeilig bleibt es oben bei Zeile 1.
   Versatz = (Zeilenhöhe Label − Inputhöhe 16px) / 2 */
.radio,
.checkbox,
.switch {
  --choice-offset: calc((var(--typography-font-size-label) * 1.25 - var(--rem-1rem)) / 2);

  display: inline-flex;
  align-items: flex-start;
  cursor: pointer;
  user-select: none; /* Doppelklick markiert das Label nicht */
}

.radio:has(:disabled),
.checkbox:has(:disabled),
.switch:has(:disabled) {
  cursor: default;
}

.radio__input {
  appearance: none;
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
  margin: var(--choice-offset) 0 0;
  border: 0;
  border-radius: var(--radius-border-radius-100);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-default-color-input-border);
  background-color: var(--inputs-primary-default-color-input-container);
  background-repeat: no-repeat;
  cursor: inherit;
}

.radio__input:checked {
  background-image: radial-gradient(circle, var(--inputs-primary-default-color-input-content) 0 var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
}

.radio__input:disabled:checked {
  background-image: radial-gradient(circle, var(--inputs-primary-disabled-color-input-content) 0 var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
}

/* -------------------- Checkbox --------------------
   Figma: Checkbox (248:2736) + with Label (12999:31396).
   <label class="checkbox">
     <input class="checkbox__input" type="checkbox" name="…">
     <span class="checkbox__label">Label Text</span>
   </label>
   Intermediate: data-indeterminate (main.js) bzw. input.indeterminate = true
   Error: aria-invalid="true" bzw. [data-touched]:invalid (main.js)
------------------------------------------------------------ */
.checkbox__input {
  appearance: none;
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
  margin: var(--choice-offset) 0 0;
  border: 0;
  border-radius: var(--radius-border-radius-2);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-default-color-input-border);
  background-color: var(--inputs-primary-default-color-input-container);
  background-image: linear-gradient(var(--inputs-primary-default-color-input-content), var(--inputs-primary-default-color-input-content));
  background-position: center;
  background-size: 0 0;
  background-repeat: no-repeat;
  cursor: inherit;
}

/* checked: Quadrat 8×8 · intermediate: Strich 8×2 */
.checkbox__input:checked {
  background-size: var(--rem-2x) var(--rem-2x);
}

.checkbox__input:indeterminate {
  background-size: var(--rem-2x) var(--rem-0-5x);
}

.checkbox__input:disabled {
  background-image: linear-gradient(var(--inputs-primary-disabled-color-input-content), var(--inputs-primary-disabled-color-input-content));
}

/* -------------------- Switch --------------------
   Figma: Switch (12999:31430) + with Label (12999:31424).
   <label class="switch">
     <input class="switch__input" type="checkbox" role="switch" name="…">
     <span class="switch__label">Label Text</span>
   </label>
------------------------------------------------------------ */
.switch__input {
  appearance: none;
  flex: none;
  width: var(--rem-8x);
  height: var(--rem-1rem);
  margin: var(--choice-offset) 0 0;
  border: 0;
  border-radius: var(--radius-border-radius-100);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-default-color-input-border);
  background-color: var(--inputs-primary-default-color-input-container);
  background-image: radial-gradient(circle, var(--inputs-primary-default-color-input-content) 0 var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
  background-position: left center;
  background-size: var(--rem-1rem) var(--rem-1rem);
  background-repeat: no-repeat;
  cursor: inherit;
}

.switch__input:checked {
  background-position: right center;
}

.switch__input:disabled {
  background-image: radial-gradient(circle, var(--inputs-primary-disabled-color-input-content) 0 var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
}

/* -------------------- Range-Slider --------------------
   Figma: Range Slider (13365:26057). Natives <input type="range">,
   Fläche/Bullets/Füllung zeichnet der Wrapper (.range), das Input
   liegt transparent darüber und liefert nur den Griff.
     <div class="range">
       <input class="range__input" type="range" min="0" max="100" step="1" value="40">
     </div>
   Im Feld mit Label und Wert:
     <div class="field field--range">
       <label class="field__label" for="id">Label</label>
       <div class="field__control">
         <div class="range"><input class="range__input" id="id" type="range" …></div>
         <output class="range__value" for="id">40</output>
       </div>
     </div>
   - Spur 16px hoch, Pill, Fläche der Button-Gruppe (Input-Fläche)
   - Im Feld (.field--range): ohne Feld-Fläche; Label oben links,
     Wert oben rechts, Slider darunter
   - Griff: 8px Punkt (Primary-Fläche) auf 16px Fläche → läuft von
     8px bis Breite − 8px; Hover/Drücken auf den Griff: 12px
   - Hover/Drücken auf die Spur: wächst 4px nach außen wie Primary
   - Füllung links vom Griff: 4px hoch, Radius 2px (Secondary-Text)
   - Schritte: Bullets (4px, Körper-Fläche des Themes), solange zwischen zwei
     Schritten mind. 8px Platz ist — dann keine Füllung, sondern die
     Bullets links vom Griff in Primary
   main.js setzt --range-pct (0…1), --range-steps und data-bullets,
   und schreibt den Wert ins <output>.
------------------------------------------------------------ */
.range {
  --range-height: var(--rem-1rem);
  --range-inset: calc(var(--range-height) / 2); /* Griffmitte am Rand */
  --range-track: var(--inputs-primary-default-color-input-container);
  --range-grow: 0px;
  /* Bullet: Ø 4px; Mitte 3px vom Kachelrand (Radius + 1px Luft für die
     Kantenglättung — sonst schneidet die Kachel den Punkt an) */
  --range-dot-r: var(--rem-0-5x);
  --range-dot-c: calc(var(--range-dot-r) + 1px);

  position: relative;
  min-width: var(--rem-24x);
  height: var(--range-height);
}

/* Spur (+ Bullets) */
.range::before {
  content: '';
  position: absolute;
  inset: 0;
  padding-inline: calc(var(--range-inset) - var(--range-dot-c));
  border-radius: var(--radius-border-radius-100);
  background: linear-gradient(var(--range-track), var(--range-track)) border-box;
  box-shadow: 0 0 0 var(--range-grow) var(--range-track);
  transition: box-shadow var(--transition-long);
}

.range[data-bullets]::before {
  /* Bullets: Kachel = Schrittabstand, Punkt (Ø 4px) 3px vom linken
     Kachelrand. Inhaltsbereich beginnt 3px vor der ersten Griffmitte
     → Punkt k sitzt genau bei 8px + k × Schritt; Kacheln nach dem
     letzten Schritt schneidet content-box ab. */
  background:
    radial-gradient(circle at var(--range-dot-c) 50%, var(--surface-color-layer-1) var(--range-dot-r), transparent calc(var(--range-dot-r) + 0.5px))
      0 0 / calc((100% - var(--range-dot-c) * 2) / var(--range-steps)) 100% repeat-x content-box,
    linear-gradient(var(--range-track), var(--range-track)) border-box;
}

/* Füllung links vom Griff */
.range::after {
  content: '';
  position: absolute;
  top: 50%;
  left: var(--range-inset);
  width: calc((100% - var(--range-inset) * 2) * var(--range-pct, 0));
  height: var(--rem-1x);
  border-radius: var(--radius-border-radius-2);
  background: var(--typography-color-text-secondary);
  translate: 0 -50%;
  pointer-events: none;
}

/* Mit Bullets: keine Füllung — stattdessen die Bullets links vom Griff
   in Primary (Farbe des Griffs). Gleiches Punkt-Muster wie die Spur,
   rechts beim Griff abgeschnitten (clip-path). */
.range[data-bullets]::after {
  inset: 0;
  width: auto;
  height: auto;
  padding-inline: calc(var(--range-inset) - var(--range-dot-c));
  border-radius: 0;
  background:
    radial-gradient(circle at var(--range-dot-c) 50%, var(--controls-primary-default-color-control-container) var(--range-dot-r), transparent calc(var(--range-dot-r) + 0.5px))
      0 0 / calc((100% - var(--range-dot-c) * 2) / var(--range-steps)) 100% repeat-x content-box;
  translate: none;
  clip-path: inset(0 calc((100% - var(--range-inset) * 2) * (1 - var(--range-pct, 0)) + var(--range-inset) - var(--range-dot-c)) 0 0);
}

/* Hover / Drücken: Spur wächst 4px (wie Primary-Button) */
@media (hover: hover) {
  .range:hover {
    --range-grow: var(--rem-1x);
  }
}

.range:has(> .range__input:active) {
  --range-grow: var(--rem-1x);
}

/* Tastatur-Fokus: Rand um die Spur */
.range:has(> .range__input:focus-visible)::before {
  outline: var(--rem-0-5x) solid var(--controls-primary-focused-color-control-border);
  outline-offset: var(--rem-1x);
}

.range__input {
  position: relative;
  z-index: 1;
  display: block;
  width: 100%;
  height: 100%;
  margin: 0;
  appearance: none;
  background: none;
  cursor: pointer;
}

.range__input:focus-visible {
  outline: none; /* Fokus zeigt die Spur */
}

.range__input::-webkit-slider-runnable-track {
  height: 100%;
  background: none;
}

.range__input::-moz-range-track {
  height: 100%;
  background: none;
}

/* Griff: 16px Fläche, sichtbar ein 8px Punkt; skaliert auf 12px */
.range__input::-webkit-slider-thumb {
  width: var(--range-height);
  height: var(--range-height);
  border: 0;
  border-radius: 50%;
  appearance: none;
  background: radial-gradient(circle, var(--controls-primary-default-color-control-container) var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
  transition: scale var(--transition-long);
}

.range__input::-moz-range-thumb {
  width: var(--range-height);
  height: var(--range-height);
  border: 0;
  border-radius: 50%;
  background: radial-gradient(circle, var(--controls-primary-default-color-control-container) var(--rem-1x), transparent calc(var(--rem-1x) + 0.5px));
  transition: scale var(--transition-long);
}

@media (hover: hover) {
  .range__input::-webkit-slider-thumb:hover {
    scale: 1.5;
  }

  .range__input::-moz-range-thumb:hover {
    scale: 1.5;
  }
}

.range__input:active::-webkit-slider-thumb {
  scale: 1.5;
}

.range__input:active::-moz-range-thumb {
  scale: 1.5;
}

.range__input:disabled {
  cursor: default;
  opacity: 0.4;
}

/* Variante .range--dual: zwei Griffe auf einer Spur (z. B. von–bis).
   Beide Inputs liegen übereinander, nur die Griffe nehmen Klicks an;
   die Füllung liegt zwischen den Griffen (--range-from/--range-to,
   main.js). Ohne Bullets. Die Griffe dürfen sich überholen.
     <div class="range range--dual">
       <input class="range__input" type="range" … aria-label="Von">
       <input class="range__input" type="range" … aria-label="Bis">
     </div> */
.range--dual > .range__input {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.range--dual > .range__input::-webkit-slider-thumb {
  pointer-events: auto;
}

.range--dual > .range__input::-moz-range-thumb {
  pointer-events: auto;
}

.range--dual::after {
  left: calc(var(--range-inset) + (100% - var(--range-inset) * 2) * var(--range-from, 0));
  width: calc((100% - var(--range-inset) * 2) * (var(--range-to, 0) - var(--range-from, 0)));
}

/* Im Feld: ohne Feld-Fläche und Rand (auch bei Fokus/Hover). Oben
   Label (bündig mit dem Slider, ohne Chip) und Wert (rechtsbündig mit
   dem Slider), darunter der Slider über die volle Breite. */
.field.field--range,
.field.field--range:focus-within {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--rem-2x) var(--controls-spacing-container-gap-large);
  padding: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--typography-color-text-primary);
}

.field--range .field__control {
  display: contents;
}

/* Label und Wert eingerückt bis zum ersten / letzten Bullet (Kante
   des Punkts: Griffmitte 8px − Radius 2px = 6px) */
.field--range :is(.field__label, .range__value) {
  --range-text-inset: calc(var(--rem-1rem) / 2 - var(--rem-0-5x));
}

.field--range .field__label {
  grid-column: 1;
  height: auto;
  padding: 0 0 0 var(--range-text-inset);
  background: none;
}

.field--range .range__value {
  grid-column: 2;
  grid-row: 1;
  padding-inline-end: var(--range-text-inset);
}

.field--range .range {
  grid-column: 1 / -1;
  grid-row: 2;
}

.range__value {
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* -------------------- Zustände: Radio · Checkbox · Switch -------------------- */

/* Hover — nur Randfarbe. Spezifität bewusst 0,1,0: schlägt Default
   (steht danach), verliert gegen Focused/Active, Disabled, Error. */
@media (hover: hover) {
  :where(.radio, .checkbox, .switch):where(:hover) :is(.radio__input, .checkbox__input, .switch__input),
  :is(.radio__input, .checkbox__input, .switch__input):where(:hover) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  :where(.radio, .checkbox, .switch):where(:active) :is(.radio__input, .checkbox__input, .switch__input),
  :is(.radio__input, .checkbox__input, .switch__input):where(:active) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

/* Focused = Active (Tastatur-Fokus, Klick, Touch) */
:is(.radio__input, .checkbox__input, .switch__input):focus-visible,
:is(.radio__input, .checkbox__input, .switch__input):active:not(:disabled) {
  outline: none;
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-focused-color-input-border);
  background-color: var(--inputs-primary-focused-color-input-container);
}

/* Disabled */
:is(.radio__input, .checkbox__input, .switch__input):disabled {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-disabled-color-input-container);
  background-color: var(--inputs-primary-disabled-color-input-container);
}

/* Error (Checkbox) */
.checkbox__input:is([aria-invalid='true'], [data-touched]:invalid) {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--mode-error-foreground);
  background-color: var(--mode-error-background);
}

/* Labels: 16px, 8px Abstand; Disabled in der Disabled-Content-Farbe */
.radio__label,
.checkbox__label,
.switch__label {
  padding-inline: var(--controls-spacing-container-padding-large);
  font-size: var(--typography-font-size-label);
  line-height: 1.25;
  color: var(--inputs-primary-default-color-input-content);
}

.radio:has(:disabled) .radio__label,
.checkbox:has(:disabled) .checkbox__label,
.switch:has(:disabled) .switch__label {
  color: var(--inputs-primary-disabled-color-input-content);
}

/* -------------------- Field (Text-Input & Select) --------------------
   Figma: Input (12406:6566). Rahmen mit Label-Chip oben links,
   darunter Eingabe + Icon. Ein Aufbau für <input> und <select>.
   Text-Input (Icon = Leeren-Button, erscheint nur mit Inhalt):
     <div class="field">
       <label class="field__label" for="name">Name</label>
       <div class="field__control">
         <input class="field__input" id="name" name="name" type="text"
                autocomplete="name" placeholder="Type something…">
         <button class="field__clear" type="button" aria-label="Eingabe löschen">
           <s-icon name="misuse--outline"></s-icon>
         </button>
       </div>
     </div>
   Select (Icon = Pfeil):
     … <select class="field__input" …>…</select>
       <s-icon class="field__icon" name="chevron--down"></s-icon> …
   Error: aria-invalid="true" bzw. [data-touched]:invalid — main.js setzt
   data-touched erst nach dem Verlassen (change) oder beim Absenden;
   :user-invalid markiert in Safari schon beim Tippen.
   Autofill: autocomplete-Attribute; Browser-Einfärbung überdeckt.
   Passwort: statt Leeren-Button das Auge (Anzeigen/Verbergen):
     <button class="field__reveal" type="button" aria-label="Passwort anzeigen"
       aria-pressed="false"><s-icon name="view"></s-icon></button>
   Icon-Platz rechts: leer nichts, mit Inhalt Leeren-Button/Auge, Fehler
   Warn-Icon (s. u.). Platzhalter (Beispiel, Farbe secondary) und
   Eingabehilfen je Feldart setzt main.js, wenn sie im HTML fehlen.
   Label-Chip-Fläche: --surface-color-cutout (ausgestanzt, Fläche eine Ebene zurück).
   Höhe wie Figma: 4 + 16 (Label) + 4 + 20 (Zeile) + 4 = 48px.
------------------------------------------------------------------- */
.field {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--controls-spacing-container-gap-medium);
  min-width: var(--rem-24x);
  min-height: var(--rem-6x);
  padding: var(--controls-spacing-container-padding-medium);
  border-radius: var(--radius-border-radius-2);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-default-color-input-border);
  background: var(--inputs-primary-default-color-input-container);
  color: var(--inputs-primary-default-color-input-content);
}

/* Label-Chip: ausgestanzt (--surface-color-cutout = Fläche eine Ebene
   zurück), wie Tag light und der aktive Button der Button-Group. */
.field__label {
  display: inline-flex;
  align-items: center;
  height: var(--rem-1rem);
  padding-inline: var(--controls-spacing-container-padding-medium);
  border-radius: var(--rem-0-25x);
  background: var(--surface-color-cutout);
  font-size: var(--typography-font-size-p-small);
  line-height: 1.25;
  white-space: nowrap;
}

/* Zeile: Eingabe + Icon
   Figma: Zeile 20px inkl. 2px Padding oben/unten, Text dort auf die
   Versalhöhe beschnitten — unsere Textzeile ist schon 20px, daher
   oben/unten ohne Padding → gleiche Zeilenhöhe. */
.field__control {
  display: flex;
  align-items: center;
  gap: var(--controls-spacing-container-gap-large);
  width: 100%;
  min-height: var(--rem-5x);
  padding-inline: var(--controls-spacing-container-padding-medium) var(--controls-spacing-container-padding-small);
}

.field__input {
  flex: 1 1 auto;
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: inherit;
  font-size: var(--typography-font-size-label);
  line-height: 1.25;
  text-overflow: ellipsis;
  /* styles.css beschneidet Text in Inputs auf Versalhöhe/Grundlinie
     (text-box-edge: cap alphabetic) — das schneidet Unterlängen
     (g, y, p) ab. Im Feld aus: die Zeilenhöhe stimmt bereits. */
  text-box-trim: none;
}

/* Einzeilige Eingaben genau so hoch wie die Feldzeile: WebKit (Safari,
   Mac App) macht <input> sonst 1px höher als die Zeilenhöhe (21 statt
   20px) → Textfelder höher als Auswahllisten. Textarea bleibt frei. */
input.field__input {
  height: var(--rem-5x);
}

/* Suchfeld: ohne Systemdarstellung (WebKit gibt type="search" eigene
   Höhe, Rundung und Löschen-Knopf) — Löschen übernimmt .field__clear */
.field__input[type='search'] {
  appearance: none;
}

.field__input[type='search']::-webkit-search-decoration,
.field__input[type='search']::-webkit-search-cancel-button {
  appearance: none;
}

.field__input:focus-visible {
  outline: none; /* Fokus zeigt der Rand des Felds */
}

/* Platzhalter = Beispiel (main.js setzt es je nach Feldart): secondary */
.field__input::placeholder {
  color: var(--typography-color-text-secondary);
  opacity: 1;
}

.field__input:disabled {
  cursor: default;
}

/* Browser-Autofill: eigene Einfärbung (gelb/blau) überdecken */
.field__input:autofill {
  -webkit-text-fill-color: currentColor;
  box-shadow: inset 0 0 0 100vmax var(--inputs-primary-default-color-input-container);
}

/* Icons (Pfeil, Leeren-Button, Passwort-Auge) übernehmen die Textfarbe des Felds */
.field__icon,
.field__clear,
.field__reveal {
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
  color: inherit;
}

.field__icon {
  pointer-events: none;
}

.field__clear,
.field__reveal {
  display: inline-flex;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
}

.field__clear s-icon,
.field__reveal s-icon {
  width: 100%;
  height: 100%;
}

/* Icon-Platz rechts (Text-Input): zeigt je nach Zustand ein Icon —
     leer          nichts (ein X ohne Text verwirrt)
     mit Inhalt    Leeren-Button (X) bzw. bei Passwort das Auge
     Fehler        Warn-Icon statt X (auch leer, z. B. Pflichtfeld);
                   Passwort: Auge bleibt, Warn-Icon daneben. Mit Fokus
                   (Korrigieren) wieder das X
   Leer-Erkennung über :placeholder-shown — den Platzhalter setzt
   main.js, falls er im HTML fehlt. Warn-Icon (Outline) per CSS-Maske,
   im Markup steht nur der Button. */
.field:has(.field__input:placeholder-shown) :is(.field__clear, .field__reveal),
.field:has(.field__input:disabled) :is(.field__clear, .field__reveal) {
  visibility: hidden;
}

.field__control:has(> :is(.field__clear, .field__reveal))::after {
  content: '';
  display: none;
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
  background: currentColor;
  mask: url('../assets/icons/warning.svg') center / contain no-repeat;
}

/* Fehler-Icon nur ohne Fokus — beim Hineinklicken zum Korrigieren
   kommt der Leeren-Button zurück */
.field:has(.field__input:is([aria-invalid='true'], [data-touched]:invalid)):not(:focus-within) .field__clear {
  display: none;
}

.field:has(.field__input:is([aria-invalid='true'], [data-touched]:invalid)):not(:focus-within) .field__control::after {
  display: block;
}

/* Select: System-Pfeil aus, eigenes Icon zeigt die Richtung.
   Das Select nimmt die ganze Zeile ein, der Pfeil liegt darüber
   (klick-durchlässig) — ein Klick auf den Pfeil öffnet die Liste. */
/* Auswahlfeld: ganze Fläche klickbar (main.js öffnet die Liste) */
.field:has(select.field__input:not(:disabled)) {
  cursor: pointer;
}

select.field__input {
  appearance: none;
  cursor: pointer;
  padding-inline-end: calc(var(--rem-1rem) + var(--controls-spacing-container-gap-large));
}

/* Aufgeklappte Liste im siduvia-Design (Floating Window + List-Items).
   Neues CSS "appearance: base-select" — bisher Chrome/Edge; Safari und
   Firefox zeigen weiter die System-Liste (Feld sieht überall gleich aus). */
@supports (appearance: base-select) {
  select.field__input,
  select.field__input::picker(select) {
    appearance: base-select;
  }

  select.field__input {
    min-block-size: 0; /* Browser-Mindesthöhe 24px aufheben → Feld bleibt 48px */
  }

  /* Die Liste dockt am ganzen Feld an (nicht nur am Select darin):
     jedes Feld ist ein eigener Anker (anchor-scope). */
  .field:has(> .field__control > select) {
    anchor-name: --field;
    anchor-scope: --field;
  }

  /* Flex nur im geöffneten Zustand — sonst wäre die Liste immer sichtbar */
  select.field__input:open::picker(select) {
    display: flex;
    flex-direction: column;
  }

  select.field__input::picker-icon {
    display: none; /* eigener Pfeil (.field__icon) */
  }

  select.field__input::picker(select) {
    /* immer direkt unter dem Feld, links bündig, mindestens so breit */
    position-anchor: --field;
    position-area: block-end span-inline-end;
    position-try-fallbacks: none;
    min-inline-size: anchor-size(inline);
    margin: 0;

    padding: var(--controls-spacing-container-padding-large);
    border: 0;
    border-radius: var(--radius-border-radius-6);
    corner-shape: var(--corner-shape-soft);
    background: var(--surface-color-floating-window);
    -webkit-backdrop-filter: blur(var(--rem-2x));   /* WebKit-Framework (WKWebView, Mac App) kennt nur die Präfix-Form */
    backdrop-filter: blur(var(--rem-2x));
    color: var(--controls-secondary-default-color-control-content);
  }

  select.field__input option {
    display: flex;
    align-items: center;
    gap: var(--controls-spacing-container-gap-large);
    min-height: var(--rem-8x);
    padding: var(--rem-1-5x) 0; /* wie .list-item: 32px Zeilenhöhe */
    border-radius: var(--radius-border-radius-2);
    font-size: var(--typography-font-size-label);
    line-height: 1.25;
    white-space: nowrap;
    cursor: pointer;
  }

  select.field__input option::checkmark {
    display: none;
  }

  select.field__input option:focus-visible {
    padding-inline-start: var(--controls-spacing-container-padding-large);
    background: var(--controls-secondary-hover-color-control-container);
    outline: none;
  }

  @media (hover: hover) {
    select.field__input option:hover {
      padding-inline-start: var(--controls-spacing-container-padding-large);
      background: var(--controls-secondary-hover-color-control-container);
      outline: none;
    }
  }

  /* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
  @media (hover: none) {
    select.field__input option:active {
      padding-inline-start: var(--controls-spacing-container-padding-large);
      background: var(--controls-secondary-hover-color-control-container);
      outline: none;
    }
  }
}

.field__control:has(> select) {
  position: relative;
}

.field__control > select ~ .field__icon {
  position: absolute;
  inset-inline-end: var(--controls-spacing-container-padding-small);
  top: 50%;
  translate: 0 -50%;
}

/* --- Zustände --- */

/* Hover — nur Randfarbe; :where = niedrige Spezifität */
@media (hover: hover) {
  .field:where(:hover:not(:has(.field__input:disabled))) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .field:where(:active:not(:has(.field__input:disabled))) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

/* Focused = Active */
.field:focus-within,
.field:has(.field__input:active) {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-focused-color-input-border);
  background-color: var(--inputs-primary-focused-color-input-container);
  color: var(--inputs-primary-focused-color-input-content);
}

/* Disabled */
.field:has(.field__input:disabled) {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-disabled-color-input-container);
  background-color: var(--inputs-primary-disabled-color-input-container);
  color: var(--inputs-primary-disabled-color-input-content);
}

/* Error */
.field:has(.field__input:is([aria-invalid='true'], [data-touched]:invalid)) {
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--mode-error-foreground);
  color: var(--mode-error-foreground);
}

.field:has(.field__input:is([aria-invalid='true'], [data-touched]:invalid)) .field__label {
  background: var(--mode-error-foreground);
  color: var(--inputs-primary-default-color-input-border);
}

/* -------------------- Dropzone (Datei ablegen) --------------------
   Datei hierher ziehen oder klicken zum Auswählen. Fläche, Rand und
   Zustände wie ein Feld (.field): Hover Rand Hover-Farbe, Fokus und
   Darüberziehen (.is-over, setzt main.js) Rand Fokus-Farbe und Fläche
   Fokus. Inhalt mittig; nichts läuft über den Rand. Gewählte Datei als
   Tag, einzeilig gekürzt.
   <div class="dropzone" tabindex="0" role="button" aria-label="Datei ablegen oder auswählen">
     <s-icon name="upload"></s-icon>
     <small>Excel hier ablegen<br>oder klicken zum Auswählen</small>
     <span class="tag tag--light"><s-icon name="document"></s-icon><span class="tag__label">datei.xlsx | 61 Verfahren</span></span>
   </div>
   Auswahl und Ablegen selbst übernimmt das Script der Seite.
------------------------------------------------------------ */
.dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--controls-spacing-container-gap-large);
  min-width: 0;
  padding: var(--layout-spacing-container-padding);
  border-radius: var(--radius-border-radius-2);
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-default-color-input-border);
  background: var(--inputs-primary-default-color-input-container);
  color: var(--inputs-primary-default-color-input-content);
  text-align: center;
  overflow-wrap: anywhere;
  cursor: pointer;
  transition:
    box-shadow var(--transition-short),
    background-color var(--transition-short),
    color var(--transition-short);
}

.dropzone > * {
  max-width: 100%;
}

.dropzone > s-icon {
  flex: none;
  width: var(--rem-6x);
  height: var(--rem-6x);
}

@media (hover: hover) {
  .dropzone:where(:hover) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

@media (hover: none) {
  .dropzone:where(:active) {
    box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-hover-color-input-border);
  }
}

.dropzone:focus-visible,
.dropzone.is-over {
  outline: none;
  box-shadow: inset 0 0 0 var(--rem-0-25x) var(--inputs-primary-focused-color-input-border);
  background-color: var(--inputs-primary-focused-color-input-container);
  color: var(--inputs-primary-focused-color-input-content);
}

/* -------------------- Fields (Feldgruppe) --------------------
   Figma: Form (12159:716), „Fields". Zusammengehörige Felder (Input,
   Select, Textarea, Auswahl) mit 2px Abstand — horizontal und
   vertikal (--controls-spacing-container-gap-small).
   <div class="fields">                     einspaltig
   <div class="fields content-columns-2">   mehrspaltig (Stufen wie
                                            .content-columns-x)
     <div class="field">…</div>
     <div class="field">…</div>
     <label class="checkbox">…</label>      Auswahl und Hinweis (.note):
   </div>                                   volle Breite, 8px Luft oben/unten
   Gruppen lassen sich verschachteln (z. B. 2 Spalten, darunter eine
   Textarea über die ganze Breite).
------------------------------------------------------------------ */
.fields {
  --fields-columns: 1; /* nicht von einem äußeren .content-columns-x erben */

  display: grid;
  grid-template-columns: repeat(var(--fields-columns), minmax(0, 1fr));
  gap: var(--controls-spacing-container-gap-small);
  width: 100%;
}

/* Hinweis zur Gruppe (z. B. „keine Gesundheitsdaten"): breiter als die
   Standard-Note (2 Spalten), damit er nicht in vielen kurzen Zeilen steht */
.fields > .note {
  --note-cols: 4;
}

.fields[class*='content-columns-'] {
  --fields-columns: var(--content-columns);
}

.fields > :is(.checkbox, .radio, .switch, .flex-layout, .note) {
  grid-column: 1 / -1;
  padding-block: var(--controls-spacing-container-padding-large);
}

/* Formular-Card (Figma Form): Kopf, Headline, Felder, Fußzeile mit
   gap-3x (48px); Aktion in der Fußzeile rechts */
.card--form {
  gap: var(--layout-spacing-container-gap-3x);
}

.card--form .card__footer {
  justify-content: flex-end;
}

/* -------------------- Combobox (Auto-Complete) --------------------
   Feld + Floating-Liste: Tippen filtert und sortiert die Einträge,
   der Pfeil klappt die ganze Liste auf. Logik in main.js (initCombobox),
   Aussehen/Andocken hier. ARIA-Combobox-Muster (Tastatur: ↑ ↓ Enter Esc).
   <div class="field field--combobox">
     <label class="field__label" for="stadt">Stadt</label>
     <div class="field__control">
       <input class="field__input" id="stadt" name="stadt" type="text"
              role="combobox" aria-autocomplete="list" aria-expanded="false"
              aria-controls="stadt-liste" autocomplete="off" placeholder="…">
       <button class="field__toggle" type="button" tabindex="-1"
               aria-label="Liste öffnen" aria-controls="stadt-liste" aria-expanded="false">
         <s-icon name="chevron--down"></s-icon>
       </button>
     </div>
     <ul class="field__list floating list" id="stadt-liste" role="listbox" popover="manual">
       <li class="list-item" role="option">Berlin</li>
       …
     </ul>
   </div>
   Liste: dockt unter dem Feld an, mindestens Feldbreite, max. 8 Einträge
   hoch, danach scrollbar.
------------------------------------------------------------------- */
.field__toggle {
  display: inline-flex;
  flex: none;
  width: var(--rem-1rem);
  height: var(--rem-1rem);
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
}

.field__toggle s-icon {
  width: 100%;
  height: 100%;
}

.field--combobox {
  anchor-name: --field;
  anchor-scope: --field;
}

.field__list {
  /* Popover-Standards des Browsers zurücksetzen */
  inset: auto;
  margin: 0;
  border: 0;
  width: auto;   /* .list setzt 100 % — hier bestimmt der Anker die Breite */
  gap: 0;        /* .floating setzt 24px — Einträge liegen direkt untereinander */
  color: var(--controls-secondary-default-color-control-content);

  /* unter dem Feld andocken, links bündig, mindestens Feldbreite */
  position-anchor: --field;
  position-area: block-end span-inline-end;
  position-try-fallbacks: none;
  min-inline-size: anchor-size(inline);

  /* höchstens 8 Einträge (je 32px) + Innenabstand, dann scrollen */
  max-block-size: calc(var(--rem-8x) * 8 + var(--controls-spacing-container-padding-large) * 2);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.field__list:not(:popover-open) {
  display: none;
}

.field__list .list-item[hidden] {
  display: none;
}

/* Tastatur-Auswahl sieht aus wie Hover */
.field__list .list-item[aria-selected='true'] {
  padding-inline-start: var(--controls-spacing-container-padding-large);
  background: var(--controls-secondary-hover-color-control-container);
}

/* „Keine Treffer" */
.field__list .list-item--empty {
  color: var(--inputs-primary-disabled-color-input-content);
  cursor: default;
}

@media (hover: hover) {
  .field__list .list-item--empty:hover {
    padding-inline-start: 0;
    background: none;
  }
}

/* Touch: gleicher Zustand beim Drücken statt klebendem Hover */
@media (hover: none) {
  .field__list .list-item--empty:active {
    padding-inline-start: 0;
    background: none;
  }
}

/* -------------------- Übergänge --------------------
   Farbwechsel: var(--transition-short) (150ms)
   Bewegung/Größe: var(--transition-long) (250ms)
   (Tokens in add-styles.css.) Bewusst ohne Übergang: Header ein-/
   ausfahren und Sticky-Positionen (folgen direkt dem Scrollen).
------------------------------------------------------------ */

/* Links: Farbe (Buttons haben ihre Übergänge im Button-Abschnitt) */
.header__link,
.header__sub a,
.sidemenu a,
.footer__nav a {
  transition: color var(--transition-short);
}

/* Listen: Fläche (Farbe) + Einzug (Bewegung) beim Hover */
.list-item,
select.field__input option {
  transition:
    background-color var(--transition-short),
    padding var(--transition-long);
}

/* Formular-Elemente: Rand, Fläche, Text (Farbe);
   Checkbox-Markierung wächst, Switch-Punkt gleitet (Bewegung) */
.field,
.field__label,
.radio__input,
.checkbox__input,
.switch__input {
  transition:
    box-shadow var(--transition-short),
    background-color var(--transition-short),
    color var(--transition-short),
    background-size var(--transition-long),
    background-position var(--transition-long);
}

/* Accordion: Auf-/Zuklappen animiert main.js (Web Animations API,
   Höhe, --transition-long) — zuverlässig auch in Safari/iPadOS.
   Die reine CSS-Variante (::details-content + Grid-Zeilen) ruckelte
   dort. */
