/* ==========================================================================
   Bausteine
   ========================================================================== */

/* --------------------------------------------------------------------------
   Gestaltungselement Balken (CD S. 12) — 32 Grad, eine Kante schraeg,
   mindestens eine Seite im Anschnitt. Der Versatzfaktor 1.6003 = 1/tan(32deg)
   ist die einzige Stelle, an der der Winkel entsteht; alles andere leitet
   sich davon ab. Damit ist der Winkel messbar und kann nicht driften.
   -------------------------------------------------------------------------- */
.balken {
  --balken-h: 3rem;
  height: var(--balken-h);
  background: var(--cd-blau);
  clip-path: polygon(0 0, 100% 0, calc(100% - var(--balken-h) * var(--winkel-faktor)) 100%, 0 100%);
}


/* --------------------------------------------------------------------------
   Schaltflaechen — die Alt-Seite hatte Pillen (border-radius 25px). Hier
   traegt die Ecke die Marke: unten rechts im 32-Grad-Winkel angeschnitten.
   -------------------------------------------------------------------------- */
.knopf {
  --ecke: 0.85rem;
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  min-height: 3rem;                        /* Touch-Ziel                     */
  padding: 0.8rem 1.5rem;
  border: 0;
  background: var(--cd-blau);
  color: var(--cd-weiss);
  font: inherit;
  font-weight: 600;
  font-size: var(--step-0);
  letter-spacing: 0.005em;
  text-decoration: none;
  cursor: pointer;
  clip-path: polygon(
    0 0, 100% 0,
    100% calc(100% - var(--ecke)),
    calc(100% - var(--ecke) * var(--winkel-faktor)) 100%,
    0 100%);
  transition: background var(--dauer-kurz) var(--ease-aus),
              transform var(--dauer-kurz) var(--ease-aus);
}
.knopf:hover { background: color-mix(in oklab, var(--cd-blau) 84%, #000); }
.knopf:active { transform: translateY(1px); }

/* Die abgeschraegte Ecke entsteht per clip-path — und clip-path beschneidet
   auch die Fokus-Outline, die ausserhalb der Box liegt. Tastaturnutzer saehen
   sonst nicht, wo sie stehen. Der Fokusring wandert deshalb nach INNEN
   (box-shadow inset wird nicht weggeschnitten) und bekommt zusaetzlich einen
   Helligkeitswechsel, damit er auch ohne Farbwahrnehmung auffaellt. */
.knopf:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 3px var(--cd-weiss), inset 0 0 0 6px var(--grund);
}
.knopf--weiss:focus-visible {
  box-shadow: inset 0 0 0 3px var(--grund), inset 0 0 0 6px var(--cd-weiss);
}
.knopf--offen:focus-visible {
  box-shadow: inset 0 0 0 2px currentColor, inset 0 0 0 5px color-mix(in oklab, currentColor 35%, transparent);
}
.knopf .pfeil { transition: transform var(--dauer-kurz) var(--ease-aus); }
.knopf:hover .pfeil { transform: translateX(4px); }

.knopf--weiss { background: var(--cd-weiss); color: var(--grund); }
.knopf--weiss:hover { background: color-mix(in oklab, var(--cd-weiss) 88%, var(--cd-blau)); }

/* Sekundaerknopf: nur Kontur.
   Ein inset-Schatten folgt der rechteckigen Border-Box — die abgeschraegte
   Ecke schneidet ihn weg, unten rechts blieb die Kontur offen. Der Rahmen
   wird deshalb als eigene Ringflaeche gezeichnet: ein Polygon, das erst die
   Aussenkontur im Uhrzeigersinn umlaeuft und dann die um 2px eingerueckte
   Innenkontur gegen den Uhrzeigersinn. Nach der Nonzero-Regel hebt sich die
   Innenflaeche auf, uebrig bleibt exakt der Rahmen — inklusive Schraege.
   Die Korrekturen 1.11px und 0.57px sind der senkrechte 2px-Versatz der
   32-Grad-Kante, umgerechnet auf ihre Schnittpunkte mit den geraden Kanten. */
.knopf--offen {                            /* sekundaer                      */
  position: relative;
  background: transparent;
  color: currentColor;
  box-shadow: none;
}
.knopf--offen::before {
  content: "";
  position: absolute;
  inset: 0;
  background: currentColor;
  pointer-events: none;
  clip-path: polygon(
    0 0,
    100% 0,
    100% calc(100% - var(--ecke)),
    calc(100% - var(--ecke) * var(--winkel-faktor)) 100%,
    0 100%,
    0 0,
    2px 2px,
    2px calc(100% - 2px),
    calc(100% - var(--ecke) * var(--winkel-faktor) - 0.57px) calc(100% - 2px),
    calc(100% - 2px) calc(100% - var(--ecke) - 1.11px),
    calc(100% - 2px) 2px,
    2px 2px);
}
.knopf--offen:hover { background: color-mix(in oklab, currentColor 12%, transparent); }

/* Textlink mit Pfeil — fuer „weiterlesen"-Ziele */
.weiter {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  font-weight: 600;
  color: var(--cd-blau);
  text-decoration: none;
}
.weiter::after {
  content: "";
  width: 1.35rem; height: 2px;
  background: currentColor;
  transition: width var(--dauer-kurz) var(--ease-aus);
}
.weiter:hover::after { width: 2.25rem; }
.sektion--dunkel .weiter, .sektion--blau .weiter { color: var(--cd-weiss); }

/* --------------------------------------------------------------------------
   Leistungs-Chips
   -------------------------------------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: 0.4rem; padding: 0; margin: 0; list-style: none; }
.chips li {
  margin: 0;
  padding: 0.3rem 0.7rem;
  font-size: var(--step--1);
  line-height: 1.35;
  background: var(--flaeche-2);
  color: var(--ink);
}
.sektion--dunkel .chips li {
  background: color-mix(in oklab, var(--cd-weiss) 12%, transparent);
  color: var(--auf-dunkel);
}

/* --------------------------------------------------------------------------
   Bildwelt: Duotone. Das CD erlaubt „umgefaerbtes Bildmaterial (schwarz auf
   blauem Hintergrund)" (S. 11). Die Fotos sind Schwarzweiss — die Einfaerbung
   bindet Platzhalter und spaetere Shooting-Fotos in eine Bildsprache.
   -------------------------------------------------------------------------- */
/* Das Verfahren der Konzernseite: ein Graustufenbild im Blend-Mode multiply
   ueber einer blauen Flaeche. Helle Bildbereiche nehmen das Blau an, dunkle
   bleiben dunkel — daher die Tiefe. Eine halbtransparente Farbebene daruber
   (unsere frueherer Weg) faerbt zwar auch ein, laesst das Bild aber flach.
   isolation: isolate ist Pflicht: ohne eigenen Stacking-Kontext wuerde
   multiply gegen den Seitenhintergrund rechnen statt gegen das Blau.        */
.bild {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--cd-blau);
}
.bild img { width: 100%; height: 100%; object-fit: cover; }

.bild--duotone img {
  filter: grayscale(1);
  mix-blend-mode: multiply;
}

.bild--duotone-tief::before {              /* Tiefe fuer Text darueber       */
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    color-mix(in oklab, var(--grund) 44%, transparent) 0%,
    color-mix(in oklab, var(--grund) 22%, transparent) 28%,
    color-mix(in oklab, var(--grund) 52%, transparent) 66%,
    color-mix(in oklab, var(--grund) 74%, transparent) 100%);
  z-index: 2;
  pointer-events: none;
}
.bild--zoom img {
  transition: transform var(--dauer-lang) var(--ease-aus-weich);
  will-change: transform;
}
.bild--zoom:hover img, a:hover .bild--zoom img { transform: scale(1.045); }

/* --------------------------------------------------------------------------
   Stimmen: Personenbeleg auf der Karriereseite.

   Eine Schiene mit scroll-snap statt eines Skript-Karussells. Ohne JavaScript
   bleibt sie vollstaendig bedienbar — wischen, scrollen, mit der Tastatur
   (role=region + tabindex, die Pfeiltasten scrollen dann nativ). Die
   Pfeil-Schaltflaechen kommen erst dazu, wenn das Skript laeuft; im Markup
   stehen sie auf hidden.
   -------------------------------------------------------------------------- */
.stimmen__kopf {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-4) var(--s-5);
  align-items: flex-end;
  justify-content: space-between;
}
/* Als Sektionseinstieg darf die Zeile breiter laufen als die 36ch, die .lead
   fuer Textspalten mitbringt — sonst bricht sie hier in drei kurze Fetzen. */
.stimmen__kopf .lead { margin-top: var(--s-4); max-width: 54ch; }

.stimmen__nav { display: flex; gap: var(--s-2); }
/* Ohne JavaScript bleibt die Steuerung weg. Das display oben wuerde das
   hidden-Attribut sonst ueberstimmen — die Pfeile staenden funktionslos da. */
.stimmen__nav[hidden] { display: none; }
.stimmen__pfeil {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  background: transparent;
  color: var(--cd-weiss);
  border: 1px solid color-mix(in oklab, var(--cd-weiss) 34%, transparent);
  cursor: pointer;
  transition: background var(--dauer-kurz) var(--ease-aus),
              border-color var(--dauer-kurz) var(--ease-aus);
}
.stimmen__pfeil:hover:not(:disabled) {
  background: color-mix(in oklab, var(--cd-weiss) 12%, transparent);
  border-color: var(--cd-weiss);
}
.stimmen__pfeil:disabled { opacity: 0.3; cursor: default; }
.stimmen__pfeil svg { width: 20px; height: 20px; }

.stimmen {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: 82%;
  gap: var(--s-5);
  margin-top: var(--s-6);
  padding-bottom: var(--s-2);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* Die native Leiste ist ausgeblendet; als Hinweis dienen die angeschnittene
     Karte am Rand und die Pfeile. */
  scrollbar-width: none;
}
.stimmen::-webkit-scrollbar { display: none; }
/* Die Schiene ist fokussierbar, also braucht sie einen sichtbaren Fokus. */
.stimmen:focus-visible { outline: 3px solid var(--blau-hell); outline-offset: 5px; }
/* Die Breiten sind so gewaehlt, dass die naechste Karte sichtbar angeschnitten
   bleibt. Bei 46 bzw. 31 Prozent ging sie genau auf und die Schiene sah aus
   wie ein fertiges Raster — niemand haette weitergescrollt. */
@media (min-width: 40rem) { .stimmen { grid-auto-columns: 44%; } }
@media (min-width: 64rem) { .stimmen { grid-auto-columns: 29.5%; } }

/* Drei Zeilen: Bild, Zitat, Fussnote. Die Fussnote sitzt unten, damit die
   Namenszeilen ueber alle Karten hinweg auf einer Linie stehen, auch wenn
   die Zitate unterschiedlich lang sind. */
.stimme {
  margin: 0;
  scroll-snap-align: start;
  display: grid;
  grid-template-rows: auto 1fr auto;
}
.stimme__bild {
  position: relative;
  overflow: hidden;
  aspect-ratio: 4 / 5;
  /* isolation ist Pflicht: ohne eigenen Stacking-Kontext rechnet multiply
     gegen den Seitenhintergrund statt gegen das Blau. */
  isolation: isolate;
  background: var(--cd-blau);
}
.stimme__bild img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
.stimme__blau { filter: grayscale(1); mix-blend-mode: multiply; }
/* Ohne JavaScript bleibt die Farbebene aus und das Bild steht im Duotone der
   uebrigen Seite — ein gueltiger Endzustand, kein Fehlerfall. */
.stimme__farbe { opacity: 0; }

.stimme blockquote {
  margin: var(--s-4) 0 0;
  font-size: var(--step-0);
  line-height: 1.5;
  color: var(--cd-weiss);
}
.stimme figcaption {
  margin-top: var(--s-4);
  padding-top: var(--s-3);
  border-top: 1px solid color-mix(in oklab, var(--cd-weiss) 22%, transparent);
  font-size: var(--step--1);
  color: var(--auf-dunkel-muted);
}
.stimme figcaption b {
  display: block;
  color: var(--cd-weiss);
  font-weight: 700;
  letter-spacing: -0.005em;
}

/* --------------------------------------------------------------------------
   Leitung: die beiden Geschaeftsfuehrer auf der Ueber-uns-Seite.

   Bewusst zurueckgenommen. Nicht die Stimmen-Schiene der Karriereseite und
   auch keine Karte — nur Portrait, Satz, Name. Die Duotone-Faerbung kommt
   vollstaendig aus .bild + .bild--duotone weiter oben; hier steht nur das
   Seitenverhaeltnis. Bewusst KEIN Farbwechsel: der bleibt der Kolonne auf
   der Karriereseite vorbehalten, wo er etwas bedeutet.
   -------------------------------------------------------------------------- */
/* Zwei Stufen unter den tragenden Sektionstiteln (die laufen in --step-4,
   im Themenblock in --step-3). Die Sektion stuetzt die Gruppen-Sektion
   darueber, sie tritt nicht gegen sie an. */
.leitung__titel { font-size: var(--step-2); }

.leitung {
  display: grid;
  gap: var(--s-6);
  margin-top: var(--s-5);
}
/* Erst ab 72 rem nebeneinander. Gemessen: bei 52 rem blieben je Person rund
   390 px — das Zitat lief auf fuenf Zeilen. Bei 64 rem waren es 435 px und
   „Geschaeftsfuehrer, Jaeger Tiefbau Herne" brach immer noch um. Bis dahin
   steht eine Person pro Zeile, mit voller Textbreite neben dem Portrait. */
@media (min-width: 72rem) {
  .leitung {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: clamp(2rem, 5vw, 4rem);
  }
  /* Nebeneinander wird die Spalte knapp — das Portrait gibt etwas ab, damit
     die Funktionszeile einzeilig bleibt. */
  .person { grid-template-columns: clamp(8rem, 13vw, 11.5rem) minmax(0, 1fr); }
}

.person { margin: 0; display: grid; gap: var(--s-4); align-content: start; }

/* Unter 34 rem gestapelt. Ein 4:5-Portrait ueber die volle Handybreite waere
   das Gegenteil von zurueckgenommen — deshalb die Deckelung auf 12 rem. */
.person__bild { aspect-ratio: 4 / 5; width: 100%; max-width: 12rem; }

@media (min-width: 34rem) {
  .person {
    /* Die Textspalte ist gedeckelt: untereinander stuende sie sonst ueber
       die volle Satzbreite und der Trennstrich liefe 760 px weit neben ein
       zweizeiliges Zitat. */
    grid-template-columns: clamp(8rem, 15vw, 11.5rem) minmax(0, 34rem);
    /* Die Fussnote sitzt am unteren Rand des Portraits, das Zitat oben.
       Dadurch stehen die Namenszeilen beider Personen auf einer Linie, auch
       wenn ein Zitat zwei und das andere drei Zeilen laeuft — vorher sassen
       sie sichtbar versetzt. Traegt sich selbst: die Zeilenhoehe der Karte
       kommt vom Portrait, und beide Portraits sind gleich hoch. */
    grid-template-rows: 1fr auto;
    column-gap: var(--s-5);
    row-gap: var(--s-3);
  }
  .person__bild      { grid-column: 1; grid-row: 1 / span 2; max-width: none; }
  .person blockquote { grid-column: 2; grid-row: 1; }
  .person figcaption { grid-column: 2; grid-row: 2; align-self: end; }
}

.person blockquote {
  margin: 0;
  font-size: var(--step-0);
  line-height: 1.5;
  color: var(--ink);
  hyphens: none;                 /* kurze Zitate nie trennen                  */
}
.person figcaption {
  padding-top: var(--s-3);
  border-top: 1px solid color-mix(in oklab, var(--cd-blau) 30%, transparent);
  font-size: var(--step--1);
  color: var(--ink-muted);
}
.person figcaption b {
  display: block;
  color: var(--ink);
  font-weight: 700;
  letter-spacing: -0.005em;
}
/* Offener Platzhalter — soll im Kundentermin als Luecke erkennbar sein und
   nicht als Name durchgehen. Faellt mit den echten Namen/Zitaten ersatzlos weg. */
.person .tbd {
  color: var(--cd-blau);
  font-weight: 700;
  border-bottom: 2px dotted color-mix(in oklab, var(--cd-blau) 55%, transparent);
}
/* Dieselbe Markierung auf dunklem Grund (.stimmen-Sektion) — cd-blau faellt dort
   gegen Schwarz unter AA, deshalb eigener, hellerer Ton. */
.stimme .tbd {
  color: var(--cd-weiss);
  font-weight: 700;
  border-bottom: 2px dotted color-mix(in oklab, var(--cd-weiss) 55%, transparent);
}

/* --------------------------------------------------------------------------
   Bildmarke als Gestaltungsflaeche (CD S. 5: gross im Anschnitt erlaubt,
   auch ohne definierten Schutzraum). Vektor, skaliert verlustfrei.
   -------------------------------------------------------------------------- */
.bogen-flaeche {
  position: absolute;
  pointer-events: none;
  color: rgba(0, 104, 181, 0.22);          /* Fallback ohne color-mix        */
  color: color-mix(in oklab, var(--cd-blau) 22%, transparent);
  z-index: 0;
}

/* --------------------------------------------------------------------------
   Kopfzeile
   -------------------------------------------------------------------------- */
.kopf {
  position: sticky; top: 0;
  z-index: var(--z-sticky);
  background: #ffffff;                     /* Fallback ohne color-mix        */
  background: color-mix(in oklab, var(--cd-weiss) 94%, transparent);
  border-bottom: 1px solid color-mix(in oklab, var(--cd-grau) 32%, transparent);
  transition: padding var(--dauer) var(--ease-aus);
}
/* Hier stand `backdrop-filter: blur(10px)`. Die Zeile hat das Aufklappmenue
   zerlegt: Ein backdrop-filter macht das Element zum Bezugsrahmen fuer
   position:fixed-Kinder — genau wie transform oder filter. Das Panel liegt im
   .kopf, sein `top: var(--kopf-h); bottom: 0` bezog sich damit nicht auf das
   Fenster, sondern auf die 96 px hohe Kopfzeile: gemessen 65 px hoch bei
   472 px Inhalt, sechs von sieben Menuepunkten abgeschnitten.
   Gekostet hat das nichts: Der Hintergrund ist zu 94 % deckend, durch 6 %
   Restdurchsicht ist eine Unschaerfe nicht wahrnehmbar. Gemessen wurde es
   trotzdem — Kopfzeile ueber der dunklen Sektion, mit und ohne die Zeile,
   `magick compare -metric AE`: **0 von 672.000 Bildpunkten** weichen ab, die
   Renderings sind bitgleich. Sollte der Hintergrund je durchsichtiger werden
   und die Unschaerfe damit sichtbar, gehoert sie in ein
   `.kopf::before { position:absolute; inset:0; z-index:-1 }` — dort wirkt sie
   gleich, ohne den Bezugsrahmen zu verschieben.
   Die `transition` auf `background` ist mit weggefallen: Keine Regel aendert
   den Hintergrund je, sie lief ins Leere.                                   */
.kopf__innen {
  display: flex; align-items: center; gap: var(--s-4);
  /* Schutzraum = 2x Balkenhoehe der Bildmarke. Logo-Hoehe 44px, Bildmarken-
     Balken darin = 55 * (24.34/111.48) = 12.0px -> Schutzraum 24px.         */
  padding-block: 1.25rem;
  transition: padding-block var(--dauer) var(--ease-aus);
}
.kopf--kompakt .kopf__innen { padding-block: 0.7rem; }
.kopf__logo { display: block; flex: 0 0 auto; }
/* Der Kopf-CTA bricht sonst zweizeilig um, sobald es eng wird — nur hier,
   nicht global: der Karriere-Knopf traegt eine Telefonnummer und darf auf
   dem Handy umbrechen.                                                    */
.kopf__innen > .knopf, .kopf .nav > .knopf { white-space: nowrap; }
.kopf__logo img { height: 55px; width: auto; }      /* 25% groesser, 27.07. */
.kopf--kompakt .kopf__logo img { height: 45px; }

.nav { margin-left: auto; }
.nav ul { display: flex; gap: var(--s-1); list-style: none; margin: 0; padding: 0; }
.nav li { margin: 0; }
.nav a {
  display: inline-flex; align-items: center;
  white-space: nowrap;                     /* sonst bricht „Straßen- und     */
                                           /* Ingenieurbau" mitten im Wort   */
  min-height: 48px;                        /* Touch-Ziel                     */
  padding: 0 0.7rem;
  font-size: var(--step--1);
  font-weight: 600;
  text-decoration: none;
  color: var(--ink);
  position: relative;
}
.nav a::after {
  content: "";
  position: absolute; left: 0.7rem; right: 0.7rem; bottom: 0.55rem;
  height: 2px;
  background: var(--cd-blau);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dauer-kurz) var(--ease-aus);
}
.nav a:hover::after { transform: scaleX(1); }
.nav a[aria-current="page"]::after { transform: scaleX(1); }
/* .nav a ist spezifischer als .knopf und wuerde dem Button im Aufklappmenue
   sonst dunkle Schrift auf Blau geben (2,94:1). */
.nav a.knopf { color: var(--cd-weiss); }
.nav a.knopf::after { content: none; }

.kopf .knopf { --ecke: 0.7rem; min-height: 48px; padding: 0.55rem 1.1rem; font-size: var(--step--1); }

/* Menuetaste (mobil) */
.menue-taste {
  display: none;
  width: 48px; height: 48px;
  margin-left: auto;
  border: 0; background: transparent;
  cursor: pointer; color: var(--ink);
}
.menue-taste span, .menue-taste span::before, .menue-taste span::after {
  content: ""; display: block;
  width: 24px; height: 2px;
  background: currentColor;
  transition: transform var(--dauer-kurz) var(--ease-aus),
              opacity var(--dauer-kurz) var(--ease-aus);
}
.menue-taste span { margin-inline: auto; position: relative; }
.menue-taste span::before { position: absolute; top: -7px; }
.menue-taste span::after  { position: absolute; top: 7px; }
.menue-taste[aria-expanded="true"] span { background: transparent; }
.menue-taste[aria-expanded="true"] span::before { transform: translateY(7px) rotate(45deg); }
.menue-taste[aria-expanded="true"] span::after  { transform: translateY(-7px) rotate(-45deg); }

/* Der Umbruchpunkt liegt bei 82rem = 1312px, nicht tiefer. Gemessen braucht die
   waagerechte Leiste 1181px Inhaltsbreite (Logo 154 + Menueliste 813 + Knopf 166
   + zwei Abstaende a 24) und traegt damit erst ab 1293px Viewport. Bei den
   vorherigen 76rem = 1216px stand sie schon da, ohne zu passen: gemessen bei
   1240px `scrollWidth 1180 > clientWidth 1128`, der Knopf endete 4px vor dem
   Fensterrand statt am Satzspiegel. Wer den Punkt verschiebt, rechnet neu —
   das Skript liest ihn nicht als Zahl, sondern an der Schaltflaeche ab. */
@media (max-width: 82rem) {
  .menue-taste { display: block; }

  /* Vollflaechige Uebernahme: Das Menue ist keine aufgeklappte Liste, sondern
     eine eigene dunkle Ebene ueber der ganzen Seite (--grund). isolation ist
     noetig, damit die Bildmarke mit z-index:-1 hinter dem Text, aber vor der
     Flaeche liegt.
     Warum jede Regel dieser Ebene an `html.js` haengt: Ohne JS gibt es kein
     hidden-Attribut, das die Flaeche wieder schliesst — sie laege dauerhaft
     deckend ueber dem Inhalt und die Seite waere unbedienbar. Ohne JS fliesst
     die Navigation stattdessen unter dem Logo mit; die Regeln dafuer stehen
     weiter unten unter `html.no-js`. */
  html.js .nav {
    position: fixed; inset: 0;
    background: var(--grund);
    padding: calc(var(--kopf-h, 76px) + var(--s-6)) var(--rand) var(--s-6);
    /* Waagerecht ausdruecklich beschnitten: Die angeschnittene Bildmarke ragt
       ueber die rechte Kante hinaus und machte die Flaeche sonst seitlich
       scrollbar (gemessen scrollWidth > clientWidth). Senkrecht bleibt es
       scrollbar — bei kurzem Fenster braucht die Liste den Weg. */
    overflow: hidden auto;
    display: flex; flex-direction: column;
    isolation: isolate;
  }
  /* Bildmarke gross im Anschnitt (CD S. 4/5 ausdruecklich erlaubt, ebenso
     Farbabstufungen). Als Maske statt als Hintergrundbild: bildmarke-j.svg
     fuellt mit `currentColor`, was ein externes Hintergrundbild nicht
     aufloesen kann — maskiert ist die Farbe frei waehlbar. */
  html.js .nav::after {
    content: "";
    position: absolute;
    /* Werte aus dem Seitenkopf uebernommen. Dort steht die Lektion bereits im
       Kommentar (sections.css): Auf einer flachen dunklen Flaeche liest sich
       die Bildmarke als Kasten, nicht als Marke — sie traegt nur sehr leise.
       Mit kraeftigem Blau (22 % auf --grund) war hier genau das zu sehen: ein
       loser Block mitten auf der Flaeche. Weiss bei 7 % liest sich dagegen als
       Lichtschimmer und nicht als Objekt. */
    /* Unten buendig, nicht ueberstehend: Ein Ueberhang nach unten machte die
       Flaeche senkrecht scrollbar, obwohl das Menue passt — man scrollte ins
       Leere. Seitlich darf sie hinausragen, das faengt `overflow: hidden auto`
       ab, ohne eine Bildlaufleiste zu erzeugen. */
    right: -10%; bottom: 0;
    width: min(62%, 32rem);
    /* Bewusst flacher als das natuerliche Verhaeltnis (128,11 : 111,48) und
       unten ausgerichtet: So faellt der Balken der Bildmarke oben aus dem
       Rahmen und nur der Haken bleibt. Vollstaendig gezeigt sass der Balken
       als loser Block auf der Flaeche.
       Als Verhaeltnis, nicht als feste Hoehe: Mit einem Pixelwert war der
       Rahmen auf schmalen Geraeten hoeher als die Maske dort natuerlich ist —
       dann stand der Balken wieder komplett im Bild. */
    aspect-ratio: 128.11 / 70;
    background: color-mix(in oklab, var(--cd-weiss) 7%, transparent);
    -webkit-mask: url(../assets/logo/bildmarke-j.svg) right bottom / 100% auto no-repeat;
            mask: url(../assets/logo/bildmarke-j.svg) right bottom / 100% auto no-repeat;
    pointer-events: none;
    z-index: -1;
  }
  /* Logo und Schliessen-Taste bleiben im Kopf stehen und werden ueber das
     Overlay gehoben — kein zweites Logo, keine zweite Schaltflaeche, kein
     Eingriff in die zehn HTML-Dateien. Beide sind im Normalfluss, das
     positionierte Overlay laege sonst darueber. */
  /* Nur die beiden Elemente werden gehoben, nicht ihr Container: `.kopf` ist
     sticky mit z-index und bildet bereits den Stapelkontext, in dem Logo,
     Schaltflaeche und Overlay gemeinsam liegen. Ein zweiter Kontext auf
     `.kopf__innen` war fuer eine inzwischen entfallene Abdunklung noetig und
     aendert an der Reihenfolge nichts mehr. Belegt in tools/pruefen.mjs,
     Abschnitt 5: elementFromPoint trifft in beiden Faellen Logo und ✕. */
  .kopf__logo, .menue-taste { position: relative; z-index: 1; }
  /* Auf dem dunklen Grund muessen beide invertieren. Das Logo wechselt auf die
     weisse Fassung als Hintergrundbild; das <img> wird nur durchsichtig, damit
     der Alternativtext erhalten bleibt. Die Datei steht in jedem Footer, liegt
     also bereits im Cache. */
  .kopf:has(.menue-taste[aria-expanded="true"]) .kopf__logo {
    background: url(../assets/logo/logo-jaeger-tiefbau-weiss.webp) left center / contain no-repeat;
  }
  .kopf:has(.menue-taste[aria-expanded="true"]) .kopf__logo img { opacity: 0; }
  /* Die Striche des ✕ zeichnen mit `background: currentColor` — gesetzt in
     `.menue-taste span, .menue-taste span::before, .menue-taste span::after`
     weiter oben. Sie folgen also der Textfarbe der Schaltflaeche. */
  .menue-taste[aria-expanded="true"] { color: var(--cd-weiss); }
  /* Bewusst OHNE Uebergang auf color und opacity. Ein solcher blieb im
     Rendering auf dem Ausgangswert stehen: Das ✕ zeichnete in --ink auf
     --grund und war praktisch unsichtbar (gemessen 13 % Helligkeit gegen
     reines Weiss). Der Wechsel darf hart sein — die aufblendende Flaeche
     verdeckt ihn ohnehin. */

  html.no-js .menue-taste { display: none; }
  html.no-js .kopf__innen { flex-wrap: wrap; }
  html.no-js .nav { width: 100%; margin-left: 0; }
  html.no-js .nav ul { flex-direction: row; flex-wrap: wrap; gap: 0 var(--s-2); }
  /* inline-flex kann nicht umbrechen: ein langer Menuepunkt liefe damit auf
     schmalen Viewports ueber den Rand. Im Fliess-Modus wird der Link ein
     normales Inline-Element und bricht wie Text um. */
  html.no-js .nav ul { display: block; }
  html.no-js .nav li { display: inline; }
  html.no-js .nav a {
    display: inline;
    width: auto; border-bottom: 0;
    font-size: var(--step--1);
    line-height: 2.6;
    padding-inline: 0 0.9rem;
    overflow-wrap: break-word;
  }
  html.no-js .nav a::after { display: none; }
  .nav { margin-left: 0; }
  .nav ul { flex-direction: column; gap: 0; }
  /* Sieht im JS-Pfad wirkungslos aus und ist es dort auch: `html.js .nav ul a`
     weiter unten ueberschreibt alle vier Eigenschaften. Trotzdem nicht loeschen
     — im Ohne-JS-Pfad ueberlebt `min-height`, weil `html.no-js .nav a` es nicht
     setzt. Folgenlos ist es auch dort nur, weil die Links inline laufen und
     min-height auf Inline-Elemente nicht wirkt. Wer die no-js-Navigation je auf
     Block umstellt, bekommt hier 56 px hohe Zeilen. */
  .nav a { min-height: 56px; font-size: var(--step-1); width: 100%; padding-inline: 0; }
  .kopf .knopf { display: none; }
  html.js .nav[hidden] { display: none; }

  /* Menuepunkte in der Anzeigeschrift, gross und in Versalien — dieselbe
     Setzung wie die Sektionstitel. Keine Trennstriche: Der Abstand traegt die
     Gliederung, Linien machten daraus wieder eine Liste.
     Es kommt keine zweite Familie dazu: seit 18.08.2026 ist Helvetica die
     Anzeigeschrift, dieselbe wie bei den Sektionstiteln, und eine frei
     gewaehlte Zusatzschrift gibt es gar nicht mehr (CD S. 6). */
  /* Ausdruecklich `ul a`, nicht `a`: Der Handlungsaufruf ist ebenfalls ein
     Link im Menue und wuerde die Anzeigeschrift sonst miterben — ein Knopf in
     Versalien-Anzeigeschrift sieht aus wie ein siebter Menuepunkt. */
  html.js .nav ul a {
    display: block;
    width: 100%;
    min-height: 0;
    /* s-3 statt s-2: „Tief- und Leitungstiefbau" und „Straßen- und Asphaltbau"
       brechen auf schmalen Geraeten zweizeilig um. Bei engerem Abstand lagen
       die beiden Zeilen eines Punktes genauso weit auseinander wie zwei
       Punkte — dann liest sich der Umbruch als zusaetzlicher Menuepunkt. */
    padding: var(--s-3) 0;
    border-bottom: 0;
    white-space: normal;              /* Basisregel setzt nowrap             */
    text-wrap: balance;               /* lange Komposita gleichmaessig teilen */
    font-family: var(--font-display);
    /* 700, nicht 800: Helvetica hat keinen 800er-Schnitt — gemessen rendern
       700/800/900 identisch. Siehe base.css, gleiche Begruendung.          */
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: -0.005em;
    line-height: 1.04;
    font-size: clamp(1.375rem, 4.6vw, 2.375rem);
    color: var(--cd-weiss);
  }
  /* Der Fokusring der Basisregel legt sich um die volle Zeilenbreite und sieht
     an diesen grossen Zeilen aus wie ein Eingabefeld. Enger angelegt bleibt er
     deutlich sichtbar, ohne die Setzung zu zerschneiden. */
  html.js .nav ul a:focus-visible { outline-offset: 2px; }
  /* Der Marker der aktiven Seite ist der CD-Balken, nicht ein Strich: gleiche
     32-Grad-Schraege wie ueberall (--winkel-faktor). Die vorhandene
     scaleX-Mechanik fuer Hover und aria-current bleibt unveraendert. */
  html.js .nav ul a::after {
    left: 0; right: auto;
    bottom: 0.18em;
    width: 2.4rem; height: 0.3rem;
    background: var(--cd-blau);
    clip-path: polygon(0 0, 100% 0, calc(100% - 0.3rem * var(--winkel-faktor)) 100%, 0 100%);
  }
  /* Auf einer leeren Flaeche wirkt ein Knopf ueber die volle Zeile billig. */
  html.js .nav .knopf {
    display: inline-flex;
    align-self: flex-start;
    width: auto;
    /* Die drei Werte wiederholen die Basis von .knopf — das sieht nach
       ueberfluessiger Doppelung aus, ist aber noetig: `.kopf .knopf` weiter
       oben schrumpft die Schaltflaeche fuer die schmale Desktop-Kopfzeile
       (Polsterung 8,8/17,6 px, Ecke 0,7 rem) und traegt dort die kleinere
       Schrift --step--1. Das Overlay liegt IM .kopf und erbt das mit. Beim
       Bau hatte ich nur die Schriftgroesse zurueckgeholt: gleiche Schrift in
       rund 30 % weniger Polsterung als jede andere Schaltflaeche der Seite.
       Dazu war der Anschnitt bei 0,7 rem exakt 18 px breit — genau der
       Abstand, den der Pfeil zur rechten Kante hatte. Er sass auf der
       Schraege. Mit 0,85 rem sind es 21,8 px Anschnitt bei 24 px Polsterung,
       der Pfeil steht wieder davor. Nicht entfernen. */
    --ecke: 0.85rem;
    min-height: 3rem;
    padding: 0.8rem 1.5rem;
    /* An die Unterkante geschoben statt direkt unter die Liste: Auf dem Handy
       blieb sonst ein Drittel der Flaeche leer, und der wichtigste Knopf sass
       in der Bildmitte. Unten liegt er im Daumenbereich. Der Mindestabstand
       kommt von der Liste, damit er bei kurzem Fenster nicht anklebt. */
    margin-top: auto;
    font-size: var(--step-0);
  }
  html.js .nav ul { margin-bottom: var(--s-6); }
}
@media (min-width: 82.01rem) {
  .nav[hidden] { display: block !important; }   /* Desktop: nie versteckt    */
  .nav > .knopf { display: none; }              /* nur im Aufklappmenue      */
  .nav { display: flex; align-items: center; }
}

/* --------------------------------------------------------------------------
   Fusszeile
   -------------------------------------------------------------------------- */
.fuss { background: var(--grund); color: var(--auf-dunkel); padding-block: var(--s-7) var(--s-5); }
.fuss a { color: var(--auf-dunkel-muted); text-decoration: none; }
.fuss a:hover { color: var(--cd-weiss); text-decoration: underline; text-underline-offset: 0.2em; }
.fuss__raster {
  display: grid;
  gap: var(--s-6);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
.fuss__logo img { height: 65px; width: auto; }      /* 25% groesser, 27.07. */
.fuss h3 { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.08em; color: var(--auf-dunkel-muted); font-weight: 700; margin-bottom: var(--s-3); }
.fuss ul { list-style: none; margin: 0; padding: 0; }
.fuss li { margin-bottom: 0.15rem; }
.fuss li a { display: inline-flex; align-items: center; min-height: 44px; }
.fuss__unten {
  display: flex; flex-wrap: wrap; gap: var(--s-2) var(--s-4);
  justify-content: space-between; align-items: center;
  margin-top: var(--s-6); padding-top: var(--s-4);
  border-top: 1px solid color-mix(in oklab, var(--cd-weiss) 14%, transparent);
  font-size: var(--step--1); color: var(--auf-dunkel-muted);
}

/* Kurze Zeilen brauchen weniger Durchschuss als der Fliesstext im Lesetext:
   1,62 stammt vom Body und zerfasert Absaetze unter ~50 Zeichen.            */
.katalog p, .stellen__text p, .schritte p, .fragen p { line-height: 1.55; }

/* --------------------------------------------------------------------------
   Standortkarte der Gruppe (Startseite).
   Die Karte kam aus einem Prototyp fuer weissen Grund. Auf der dunklen
   Sektion leuchtete sie unveraendert als helle Platte. Die Werte hier sind
   gemessen: die Flaeche haelt die Silhouette gegen den Grund (1,74:1), die
   Punkte stehen klar auf der Flaeche (6,6:1), die Binnengrenzen gliedern,
   ohne laut zu werden (3,1:1).
   -------------------------------------------------------------------------- */
.standortkarte {
  --karte-flaeche:  #2c4053;
  --karte-linie:    #6b8fae;
  --karte-punkt:    #8ad4ff;
  --karte-zentrale: #ffffff;
  --karte-grund:    var(--grund);
  position: relative;
}
.standortkarte svg { width: 100%; height: auto; display: block; overflow: visible; }
.standortkarte .laender path {
  fill: var(--karte-flaeche);
  stroke: var(--karte-linie);
  stroke-width: 2.4;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.standortkarte .glyph path { fill: var(--karte-punkt); }
.standortkarte .landmark { font-size: 15px; fill: var(--auf-dunkel-muted); }

/* Der Knopf traegt die Schraege der Seite statt der Pillenform des Prototyps */
.standortkarte__wieder {
  --ecke: 0.6rem;
  position: absolute; right: 0; bottom: 0;
  display: inline-flex; align-items: center; gap: 0.5rem;
  min-height: 44px;
  padding: 0.4rem 1rem;
  background: transparent;
  color: var(--auf-dunkel-muted);
  border: 0;
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--cd-weiss) 24%, transparent);
  font: inherit; font-size: var(--step--1);
  cursor: pointer;
  clip-path: polygon(0 0, 100% 0, 100% calc(100% - var(--ecke)),
    calc(100% - var(--ecke) * var(--winkel-faktor)) 100%, 0 100%);
  transition: color var(--dauer-kurz) var(--ease-aus),
              box-shadow var(--dauer-kurz) var(--ease-aus);
}
.standortkarte__wieder:hover {
  color: var(--cd-weiss);
  box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--cd-weiss) 55%, transparent);
}
.standortkarte__wieder:focus-visible {
  outline: none;
  box-shadow: inset 0 0 0 2px var(--blau-hell), inset 0 0 0 5px color-mix(in oklab, var(--blau-hell) 35%, transparent);
}
.standortkarte__wieder svg { width: 1rem; height: 1rem; }
@media (prefers-reduced-motion: reduce) { .standortkarte__wieder { display: none; } }

/* --------------------------------------------------------------------------
   Bewerbungs-Popup (karriere.html): natives <dialog>, ein Formular je Stelle.
   Die Melde-Knoepfe behalten ihren mailto-Fallback — ohne JavaScript oeffnet
   weiter der Mail-Entwurf, der Dialog ist reine Aufwertung.
   -------------------------------------------------------------------------- */
.bewerbung {
  border: none;
  padding: var(--s-6);
  max-width: 26rem;
  width: calc(100vw - 2 * var(--s-4));
  background: var(--cd-weiss);
  color: var(--ink);
}
.bewerbung::backdrop { background: rgba(6, 16, 26, 0.65); }
.bewerbung__zu-form { position: absolute; top: var(--s-3); right: var(--s-3); margin: 0; }
.bewerbung__zu {
  border: none; background: none; cursor: pointer;
  font-size: 1.75rem; line-height: 1; padding: 0.25rem 0.5rem;
  color: var(--ink-muted);
}
.bewerbung__zu:hover { color: var(--ink); }
/* Eine Stufe kleiner als die Sektions-h2: im schmalen Dialog brach die grosse
   Display-Stufe haesslich um. text-wrap: balance verteilt die Zeilen gleichmaessig
   (progressive Enhancement), hyphens: none verhindert Trennungen mitten in
   "Tiefbaufacharbeiter", overflow-wrap faengt 320-px-Geraete ab. */
.bewerbung__titel {
  font-size: var(--step-1);
  margin: 0 var(--s-5) var(--s-2) 0;
  hyphens: none;
  text-wrap: balance;
  overflow-wrap: anywhere;
}
.bewerbung__vorteile { color: var(--ink-muted); font-size: var(--step--1); margin: 0 0 var(--s-4); }
.bewerbung__form { display: grid; gap: var(--s-3); }
.bewerbung__form label {
  display: grid; gap: 0.3rem;
  /* Ohne min-width:0 erzwingt ein Grid-Item seine intrinsische Mindest-
     breite. Beim <select> ist das die Breite der laengsten Option — die
     Option „Anderer Berufsabschluss im Baugewerbe" zog bei 320px alle
     Felder auf 331px und damit ueber den Dialogrand (gemessen). */
  min-width: 0;
  font-size: var(--step--1); font-weight: 700; color: var(--ink);
}
.bewerbung__form input,
.bewerbung__form select {
  font: inherit; padding: 0.6rem 0.75rem;
  /* Feste Zeilenhoehe, damit die Feldhoehe nicht vom Browser-Default
     abhaengt. */
  line-height: 1.6;
  border: 1px solid color-mix(in oklab, var(--ink) 30%, transparent);
  background: var(--cd-weiss); color: var(--ink);
}
/* Chrome erzwingt bei nativen <select> line-height:normal — das Feld rendert
   dadurch 4px flacher als die Textfelder und die Reihe wirkt unruhig.
   Gemessen: Textfeld 46px, select 42px. Statt appearance:none (dann muesste
   der Aufklapp-Pfeil selbst gezeichnet werden) die Hoehe der Textfelder
   nachbilden: Zeilenhoehe + Polsterung + Rahmen. Skaliert mit der Schrift. */
.bewerbung__form select { min-height: calc(1.6em + 1.2rem + 2px); }
/* Zweite Sperre: Beide Feldarten sind Grid-Items im Label und setzen sonst
   ihre intrinsische Breite durch — das <select> die seiner laengsten Option
   (gemessen 331px statt 195px), das <input> die seines Standard-size von
   20 Zeichen (gemessen 195px in einem 176px breiten Formular). Beides fiel
   lange nicht auf, weil der Hinweistext die Mailadresse als unteilbares
   Wort enthielt und das Formular dadurch breit hielt. */
.bewerbung__form input,
.bewerbung__form select { min-width: 0; max-width: 100%; }
.bewerbung__form input:focus-visible,
.bewerbung__form select:focus-visible { outline: 2px solid var(--cd-blau); outline-offset: 1px; }
.bewerbung__form .knopf { margin-top: var(--s-2); justify-content: center; }
/* Sendezustand. Ohne diese Regel sah der gesperrte Knopf exakt aus wie der
   bedienbare (gemessen: opacity 1, cursor pointer) — die Seite wirkte tot,
   und der Bewerber drueckte ein zweites Mal. Bewusst nicht so blass wie
   `.stimmen__pfeil:disabled` (0.3): Die Beschriftung „Wird gesendet …" muss
   waehrend der bis zu 15 Sekunden lesbar bleiben. */
.bewerbung__form .knopf:disabled { opacity: 0.65; cursor: default; }
.bewerbung__form .knopf:disabled:hover { background: var(--cd-blau); }
.bewerbung__form .knopf:disabled:hover .pfeil { transform: none; }
.bewerbung__form .knopf:disabled:active { transform: none; }
.bewerbung__hinweis { color: var(--ink-muted); font-size: var(--step--1); margin: 0; }
/* Honeypot: fuer Menschen unsichtbar und nicht fokussierbar, fuer Bots ein
   normales Textfeld. display:none waere zu leicht erkennbar. */
.bewerbung__hp {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px; overflow: hidden;
}
/* Timegate-Hinweis: erscheint nur, wenn zu schnell abgeschickt wurde. */
.bewerbung__warnung { color: #a33; font-size: var(--step--1); margin: 0; }
/* Danke-Zustand: ersetzt das Formular nach erfolgreichem Versand. Bewusst
   ruhig gehalten — der Dialog soll bestaetigen, nicht feiern. */
.bewerbung__danke { display: grid; gap: var(--s-3); padding-block: var(--s-4); }
/* Die Box bekommt den Fokus per Skript, damit er nach dem Absenden nicht aus
   dem Dialog faellt. Sie ist aber kein Bedienelement — ein Fokusring waere
   hier irritierend, und ertabbt werden kann sie ohnehin nicht. */
.bewerbung__danke:focus { outline: none; }
.bewerbung__danke p { margin: 0; }
.bewerbung__danke-titel {
  font-size: var(--step-1); font-weight: 700; letter-spacing: -0.01em;
  color: var(--cd-blau);
}
/* Datenschutz-Einwilligung: Checkbox neben dem Text, nicht darueber
   (die Grid-Regel fuer .bewerbung__form label wuerde sonst stapeln). */
.bewerbung__ds {
  display: grid !important;
  grid-template-columns: auto 1fr;
  gap: 0.6rem;
  align-items: start;
  font-size: var(--step--1);
  font-weight: 400 !important;
  color: var(--ink-muted);
}
.bewerbung__ds input { margin-top: 0.2rem; accent-color: var(--cd-blau); }
.bewerbung__ds a { color: var(--cd-blau); }
/* Bildmarke als Wasserzeichen unten rechts — Stilmittel, rein dekorativ.
   Als CSS-Maske in Markenblau (die SVG-Fuellung ist currentColor und wuerde
   als background-image schwarz rendern). Faellt die Maske aus, fehlt nur
   das Wasserzeichen. */
/* Bildmarke als Wasserzeichen: blau, leicht transparent, im oberen Drittel
   und bewusst im Anschnitt. Die Box endet an der Dialogkante, die Maske
   schiebt die (groessere) Bildmarke darueber hinaus — der Anschnitt entsteht
   an der Boxkante, ohne dass der Dialog overflow: hidden braucht. */
.bewerbung::before {
  content: "";
  position: absolute;
  right: 0;
  /* Box-Hoehe passt die Bildhoehe (16rem Breite * 111.48/128.11 ≈ 13.9rem)
     vollstaendig ein — eine Maske kann nie ueber die Elementgrenzen
     hinauszeichnen, eine zu knappe Box schneidet sonst oben/unten ab. */
  top: calc(28% - 1.75rem);
  width: 12rem;
  height: 14rem;
  background: var(--cd-blau);
  opacity: 0.12;
  -webkit-mask: url("../assets/logo/bildmarke-j.svg") no-repeat right -4rem center / 16rem auto;
  mask: url("../assets/logo/bildmarke-j.svg") no-repeat right -4rem center / 16rem auto;
  pointer-events: none;
}


/* --------------------------------------------------------------------------
   Consent-Banner (js/consent.js) — erscheint nur, wenn dort ein Dienst
   konfiguriert ist. Beide Entscheidungs-Knoepfe teilen bewusst dieselbe
   Klasse und damit Groesse/Schrift/Farbigkeit: gleichwertiges Ja/Nein auf
   Ebene 1 (VG Hannover 10 A 5385/22, DSK OH v1.2) — nicht "verschoenern".
   -------------------------------------------------------------------------- */
.consent-modal {
  border: none;
  padding: var(--s-6);
  max-width: 28rem;
  width: calc(100vw - 2 * var(--s-4));
  background: var(--cd-weiss);
  color: var(--ink);
  text-align: center;
}
.consent-modal::backdrop { background: rgba(6, 16, 26, 0.65); }
.consent-modal__logo { display: block; margin: 0 auto var(--s-4); max-width: 154px; height: auto; }
.consent-modal__titel { font-size: var(--step-1); margin-bottom: var(--s-3); }
.consent-modal .consent__text { margin-inline: auto; }
.consent-modal .consent__knoepfe { justify-content: center; margin-top: var(--s-4); }
.consent__text { margin: 0; font-size: var(--step--1); max-width: 70ch; }
.consent__knoepfe { display: flex; flex-wrap: wrap; gap: var(--s-2); align-items: center; }
.consent__knopf {
  font: inherit; font-size: var(--step--1); font-weight: 600;
  padding: 0.6rem 1.1rem;
  background: var(--cd-weiss);
  color: var(--cd-blau);
  border: 2px solid var(--cd-blau);
  cursor: pointer;
}
.consent__knopf:hover { background: var(--cd-blau); color: var(--cd-weiss); }
.consent__einstellungen {
  font: inherit; font-size: var(--step--1);
  background: none; border: none; cursor: pointer;
  color: var(--ink-muted); text-decoration: underline;
  padding: 0.6rem 0.25rem;
}
.consent-dialog {
  border: none;
  padding: var(--s-6);
  max-width: 30rem;
  width: calc(100vw - 2 * var(--s-4));
  background: var(--cd-weiss);
  color: var(--ink);
}
.consent-dialog::backdrop { background: rgba(6, 16, 26, 0.65); }
.consent-dialog h2 { font-size: var(--step-1); margin-bottom: var(--s-3); }
.consent-dialog__hinweis { color: var(--ink-muted); font-size: var(--step--1); margin-bottom: var(--s-4); }
.consent-dialog__kategorie {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-2);
  align-items: start;
  margin-bottom: var(--s-3);
  font-size: var(--step--1);
}
.consent-dialog__kategorie input { margin-top: 0.2rem; accent-color: var(--cd-blau); }
.consent-dialog .consent__knoepfe { margin-top: var(--s-4); }
