/* Basis-Stylesheet: Reset + generische Layout-/Komponentenregeln.
   Seiten-spezifisches liegt in eigenen CSS-Dateien (z.B. home.css). */

/* ------------------------------------------------------------------
   Schriften. Die woff2-Dateien lagen seit Lauf 1 im Repo (und wurden in
   base.html sogar vorgeladen), es gab aber NIRGENDS eine @font-face-Regel -
   dadurch rendete die gesamte Site in der System-Fallback-Schrift statt in
   Poppins/Inter. Das war die groesste einzelne optische Abweichung zum
   Original und betrifft jede Seite.
   Die Dateien sind byte-identisch mit denen des Originals (Poppins 400/700
   latin von fonts.gstatic.com, Inter 500/700 latin von framerusercontent);
   geprueft per md5sum. Kein unicode-range: fehlende Glyphen faellt der
   Browser ohnehin einzeln zurueck.
   ------------------------------------------------------------------ */
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/static/fonts/poppins-400.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("/static/fonts/poppins-500.woff2") format("woff2");
}
@font-face {
  font-family: "Poppins"; font-style: normal; font-weight: 700;
  font-display: swap; src: url("/static/fonts/poppins-700.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 400;
  font-display: swap; src: url("/static/fonts/inter-400.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 500;
  font-display: swap; src: url("/static/fonts/inter-500.woff2") format("woff2");
}
@font-face {
  font-family: "Inter"; font-style: normal; font-weight: 700;
  font-display: swap; src: url("/static/fonts/inter-700.woff2") format("woff2");
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  color: var(--color-text);
  background: var(--color-bg);
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
/* Jede Ueberschriftenstufe deklariert font-size UND line-height explizit.
   Ohne eigene line-height erbt eine Ueberschrift sonst den Body-Wert (1.5) -
   genau der Fehler, der bisher .footer-col__title, die Rechtstext-h2 und die
   News-Kartentitel getroffen hat (nur umgekehrt: sie erbten 1.2 statt 1.5).
   Regel des Originals: >= 18px -> 1.2, <= 15px -> 1.5. */
h1, h2, h3, h4 { font-family: var(--font-heading); font-weight: var(--fw-bold); margin: 0 0 var(--space-4); color: var(--color-text); }
h1 { font-size: var(--fs-h1); line-height: var(--lh-h1); }
h2 { font-size: var(--fs-h2); line-height: var(--lh-h2); }
h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); }
h4 { font-size: var(--fs-sub); line-height: var(--lh-sub); }

/* Rollenklassen fuer die Stufen, die sich nicht 1:1 auf eine Tag-Ebene
   abbilden lassen (das Original waehlt die Groesse nach Rolle, nicht nach
   Ueberschriftenrang - dieselbe h2 ist je nach Kontext 29px oder 24px). */
.page-title      { font-size: var(--fs-h1);   line-height: var(--lh-h1); }
.page-title--text{ font-size: var(--fs-h2);   line-height: var(--lh-h2); }
.card-title      { font-size: var(--fs-card); line-height: var(--lh-card); }
.section-title   { font-size: var(--fs-h2);   line-height: var(--lh-h2); }
.section-title--sm { font-size: var(--fs-sub); line-height: var(--lh-sub); }
.label-title     { font-size: var(--fs-h3);   line-height: var(--lh-h3); font-weight: var(--fw-bold); }
/* Fliesstext. Das Original setzt Absaetze durchgaengig in rgb(129,129,129)
   (nachgemessen auf /impressum/, /unternehmen/, /starkregengefahrenkarten/ und
   /starkregen-news/ - dort jeweils die mit Abstand haeufigste Textfarbe).
   Wir nehmen dafuer wie bisher die auf AA nachgedunkelte Variante #707070
   (4,8:1). Vorher stand hier --color-text-subtle (#333) - das war die im
   Original nur fuer FOOTER-Links gemessene Farbe und liess jeden Fliesstext
   der Site deutlich zu dunkel erscheinen. */
p { margin: 0 0 var(--space-4); color: var(--color-text-muted); }
button { font: inherit; }

/* Verhindert horizontalen Overflow durch einzelne sehr lange, nicht
   umbrechbare Woerter/URLs (z.B. lange deutsche Komposita in Ueberschriften,
   Web-Adressen in Fliesstext) - betrifft u.a. /veranstaltungen/, /datenschutz/
   und mehrere Blogposts bei 320px Breite. overflow-wrap:anywhere wirkt sich
   (anders als break-word) auch auf die min-content-Breite von Grid-/Flex-
   Spalten aus, siehe docs/DECISIONS.md ("CSS-Hygiene"). */
p, li, h1, h2, h3, h4, blockquote, a, dt, dd { overflow-wrap: anywhere; }

/* ---- Tastatur-Fokus: deutlich sichtbarer, eigener Fokusring statt nur
   Browser-Standard. outline-color: currentColor uebernimmt automatisch die
   fuer den jeweiligen Hintergrund bereits gewaehlte (kontrastreiche)
   Textfarbe der Komponente (z.B. weiss im dunklen Hero, dunkel auf hellem
   Grund) - so bleibt der Ring auf jedem Untergrund sichtbar. ---- */
:focus { outline: none; }
a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---- Bewegungsreduzierung respektieren ---- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }
}

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}

.container {
  max-width: var(--container-max);
  margin: 0 auto;
  padding: 0 var(--container-pad);
}
.text-center { text-align: center; }
/* Hervorgehobener Absatz (Original: 15px/700 statt 400 - z.B. der
   zusammenfassende Schlussabsatz auf /starkregenalarmsystem/). */
.text-strong { font-weight: var(--fw-bold); color: var(--color-text); }
.text-center p, .text-center h2 { margin-left: auto; margin-right: auto; }

/* ---- Buttons ---- */
/* Button-Beschriftung: am Original 15px/400/22.5 gemessen (identisch mit dem
   Fliesstext, nur das Chrome unterscheidet den Button). Bisher 14px/700. */
.btn {
  display: inline-flex; align-items: center; gap: var(--space-2);
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: var(--lh-body);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  /* Rahmenfarbe am Original nachgemessen (2026-07-28): die weissen
     Pill-Buttons tragen durchgaengig 1px rgb(201,201,201) ("Video"-Chip,
     Kontakt-CTA per --border-color, Highlights-Knopf per Pixelprobe) -
     nicht das hellere --color-border. */
  border: 1px solid #c9c9c9;
  background: var(--color-bg);
  color: var(--color-text);
  cursor: pointer;
  transition: background-color var(--duration-hover) var(--ease-smooth),
              border-color var(--duration-hover) var(--ease-smooth),
              transform var(--duration-hover) var(--ease-smooth),
              box-shadow var(--duration-hover) var(--ease-smooth);
}
/* Weiche Anhebung + dezenter Schatten beim Hover, wie Framers whileHover -
   signalisiert "anklickbar", ohne zu springen. */
.btn:hover { background: var(--color-surface); border-color: var(--color-text-muted); transform: translateY(-1px); box-shadow: var(--shadow-lift); }
/* Gedrueckt-Zustand: das Original gibt keine Rueckmeldung (nachgemessen, s.
   docs/qa/typo-audit.md) - ergaenzt wie die uebrigen Zustaende in Lauf 3. */
.btn:active { background: var(--color-border); transform: translateY(0); box-shadow: none; }
.btn--outline { border-color: #c9c9c9; }
/* Zweiter Button-Typ des Originals, im Nachbau bisher gar nicht abgebildet:
   die gefuellten Akzent-CTAs ("Wir beraten Sie gerne!", "Zum SAS",
   "Unsere Referenzen" auf /starkregengefahrenkarten/, der Telekom-Link auf
   /starkregenalarmsystem/). Gemessen: 14px/700/16.8 INTER auf gefuellter
   Markenflaeche, radius 6-8px, padding ~15px - deutlich anders als die
   hellen Text-Buttons (15/400/22.5 Poppins). Bisher liefen beide Typen ueber
   dieselbe .btn--outline-Regel und sahen identisch aus.
   Flaechenfarbe: das Original nutzt rgb(2,179,255) mit weisser Schrift
   (~2.3:1, klar unter AA). Wie bei der Ankuendigungsleiste nehmen wir den
   HELLSTEN Wert derselben Farbachse, der AA noch besteht: #007eb1 (4,55:1).
   Das bisherige #006688 (6,45:1) war die Textvariante fuer Schrift auf Weiss
   und als Flaeche sichtbar zu dunkel - der gefuellte CTA war damit die
   groesste verbliebene Einzelabweichung des Heros von
   /starkregengefahrenkarten/ (allein 0,7 % der Bildflaeche). */
.btn--accent {
  font-family: var(--font-accent);
  font-size: var(--fs-cta); line-height: var(--lh-cta); font-weight: var(--fw-bold);
  background: #007eb1; color: #fff;
  border-color: transparent; border-radius: 8px;
  padding: var(--space-4) var(--space-5);
}
.btn--accent:hover { background: #006a94; border-color: transparent; }
.btn--accent:active { background: #005678; }
/* Telekom-Magenta-Variante (nur der Partner-Link auf /starkregenalarmsystem/,
   im Original ebenfalls gefuellt in der Telekom-Hausfarbe). */
.btn--accent-magenta { background: var(--color-brand-pink); }
.btn--accent-magenta:hover { background: #b8005e; border-color: transparent; }
.btn--accent-magenta:active { background: #96004c; }
/* Original: weisse Flaeche, Text in Grau (#818181 gemessen, 3,90:1 - unter AA).
   Wir nehmen den bereits vorhandenen, dafuer nachgedunkelten Token
   --color-text-muted (#707070, 4,95:1). Vorher stand hier das Marken-Blau,
   was im Original an dieser Stelle gar nicht vorkommt. */
/* Hoehe 46.5px wie im Original (Rect-Messung 2026-07-28: 160x46.5). */
.btn--announce { border: 0; color: var(--color-text-muted); background: #fff; height: 46.5px; box-sizing: border-box; }
/* Pfeil im Announce-Knopf: die Original-Glyphe (Linie + massive Spitze),
   20x12 wie im Live-Original gemessen - kein schmaler Text-Pfeil. */
.btn--announce .arrow-glyph { width: 20px; height: 12px; flex: none; }
/* Hover am Original nachgemessen (2026-07, getComputedStyle):
   Pill-Glow `0 0 47px rgba(0,0,0,.23)` + Text #818181->#333 + Pfeil-Swap -
   KEINE Anhebung, KEIN Fondwechsel. Die geerbte .btn:hover-Anhebung
   (translateY/Lift-Schatten/#f2f2f2) war erfunden. Farbachse bei uns wie
   ueberall der AA-Token-Analogon --color-text-muted -> --color-text. */
.btn--announce {
  transition: color var(--duration-hover) var(--ease-smooth),
              box-shadow var(--duration-hover) var(--ease-smooth);
}
.btn--announce:hover {
  background: #fff; transform: none;
  box-shadow: 0 0 47px rgba(0, 0, 0, .23);
  color: var(--color-text);
}
.btn--announce:active { background: #fff; transform: none; box-shadow: 0 0 47px rgba(0, 0, 0, .23); }
.btn--announce:hover .arrow-glyph {
  animation: hov-arrow-swap calc(var(--duration-hover) * 2.5) var(--ease-smooth);
}
/* Pfeil-Swap wie im Original: hinaus nach rechts, von links wieder herein.
   Identische Keyframe steht auch in home/forschung/allianzen.css (dortige
   Seiten-Scopes) - hier noetig, weil die Announce-Leiste auf JEDER Seite
   erscheint, auch ohne Seiten-CSS mit eigener Definition. */
@keyframes hov-arrow-swap {
  0%   { transform: translateX(0);     opacity: 1; }
  45%  { transform: translateX(18px);  opacity: 0; }
  55%  { transform: translateX(-18px); opacity: 0; }
  100% { transform: translateX(0);     opacity: 1; }
}
/* Video-Klick-Sweep 2026-07-28: der "Video"-Chip ist im Original ein echter
   Ausloeser (oeffnet das Video-Lightbox-Overlay) - daher cursor:pointer und
   font-family fuer das <button>-Element. Die uebrige Ghost-Optik (keine
   Anhebung beim Hover) bleibt; den Original-Glow setzt home.css. */
.btn--ghost { cursor: pointer; font-family: inherit; }
.btn--ghost:hover { background: var(--color-bg); transform: none; box-shadow: none; }
.btn-row { display: flex; gap: var(--space-3); flex-wrap: wrap; }

/* "Mehr erfahren"/"Zur Website"-Links: das Original gibt beim Hover keinerlei
   Rueckmeldung (Design-Pass-Fund, Quality-Floor-Verbesserung ueber die reine
   Replikation hinaus - der Auftraggeber hat diese Verbesserungen
   ausdruecklich freigegeben, s. docs/DECISIONS.md). Dezente Unterstreichung +
   ein 2px-Vorruecken des Pfeils signalisieren "das hier fuehrt weiter",
   respektiert prefers-reduced-motion (globale Regel weiter oben). */
.link-arrow {
  display: inline-flex; align-items: center; gap: var(--space-2);
  /* Original: 15px/400/22.5 (nachgemessen auf Startseite, /allianzen/ und
     /blog/ - ueberall identisch). Bisher faelschlich 600. */
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: var(--lh-body);
  color: var(--color-on-dark);
  text-underline-offset: 3px;
}
.link-arrow:hover { text-decoration: underline; }
.link-arrow span[aria-hidden] { transition: transform var(--duration-fast) var(--ease); display: inline-block; }
.link-arrow:hover span[aria-hidden] { transform: translateX(3px); }
.link-arrow:active span[aria-hidden] { transform: translateX(1px); }

.icon-btn {
  display: inline-flex; align-items: center; justify-content: center;
  position: relative;
  width: 40px; height: 40px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius-md);
  color: var(--color-text);
  transition: background-color var(--duration-hover) var(--ease-smooth),
              border-color var(--duration-hover) var(--ease-smooth),
              transform var(--duration-hover) var(--ease-smooth),
              box-shadow var(--duration-hover) var(--ease-smooth);
}
/* Original gab dem Mail-/Share-Icon keine Hover-Rueckmeldung (Design-Pass-
   Verbesserung, s. docs/DECISIONS.md). */
.icon-btn:hover { background: var(--color-surface); border-color: var(--color-text-muted); }
.icon-btn:active { background: var(--color-border); }
body.has-hero-header .site-header:not(.is-scrolled) .icon-btn:hover { background: rgba(255,255,255,.15); }
/* Grosser Kontakt-CTA ("Haben Sie Fragen?"). Original nachgemessen (2026-07,
   Framer "Contact Button", 78x69 -> 158x69): beim Hover Pill-Glow
   `0 0 47px rgba(0,0,0,.23)`, die Pille WEITET sich, ein "Kontakt"-Label
   blendet ein (opacity 0->1) und der Mail-Glyph "swappt". Der Glyph-Swap ist
   in Wahrheit ein reiner Farb-Crossfade: beide Original-SVGs ("Email Icon"/
   "Hovered Mail") sind PFADIDENTISCH, nur stroke #818181 -> #333333.
   Bei uns via currentColor + AA-Tokens, das Label ohne Markup-Umbau als
   ::after (Accessible Name bleibt das aria-label). KEINE Anhebung - die
   bisherige translateY(-2px)+Lift war erfunden. */
.icon-btn--lg {
  width: auto; min-width: 64px; height: 64px; padding: 0 var(--space-3);
  border-radius: var(--radius-lg);
  color: var(--color-text-muted);
  transition: color var(--duration-hover) var(--ease-smooth),
              box-shadow var(--duration-hover) var(--ease-smooth);
}
.icon-btn--lg::after {
  content: "Kontakt";
  font-family: var(--font-heading); font-size: var(--fs-body);
  font-weight: var(--fw-regular); line-height: var(--lh-body);
  white-space: nowrap; overflow: hidden;
  max-width: 0; opacity: 0;
  transition: max-width var(--duration-hover) var(--ease-smooth),
              opacity var(--duration-hover) var(--ease-smooth),
              margin-left var(--duration-hover) var(--ease-smooth);
}
.icon-btn--lg:hover, .icon-btn--lg:focus-visible {
  background: transparent; border-color: var(--color-border);
  transform: none; box-shadow: 0 0 47px rgba(0, 0, 0, .23);
  color: var(--color-text);
}
.icon-btn--lg:hover::after, .icon-btn--lg:focus-visible::after {
  max-width: 6em; opacity: 1; margin-left: var(--space-2);
}
.icon-btn--lg:active { background: transparent; transform: none; box-shadow: 0 0 47px rgba(0, 0, 0, .23); }
/* Das Mail-Icon im Kopf ist im Original ein rahmenloses 29x21-Piktogramm
   (gemessen: svgContainer 1342,26.5 29x21, kein Rahmen, keine Flaeche) - kein
   40x40-Kasten mit Umrandung. Der Kasten war 11px breiter als das Original und
   hat ueber `justify-content: space-between` die gesamte Navigation um rund
   5px nach links gezogen (sichtbar als Doppelkontur im Differenzbild).
   Die 44x44-Tippflaeche aus .icon-btn::before bleibt unveraendert erhalten. */
.site-header .icon-btn {
  width: 29px; height: 21px;
  border: 0; border-radius: 0;
}
.site-header .icon-btn:hover,
body.has-hero-header .site-header:not(.is-scrolled) .icon-btn:hover { background: transparent; opacity: .6; }
.site-header .icon-btn:active { background: transparent; opacity: .45; }
.site-header .icon-btn svg { width: 100%; height: 100%; }
/* Tippflaeche auf 44x44px vergroessern, ohne die sichtbare (gemessene)
   Icon-Groesse zu veraendern - unsichtbarer, zentrierter Hit-Bereich. */
.icon-btn::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: max(44px, 100%); height: max(44px, 100%);
  transform: translate(-50%, -50%);
}

/* Play-Kachel-Knopf: das Original rendert die YouTube-Facade-Schaltflaeche -
   abgerundetes RECHTECK 68x48 (Radius ~10), dunkles rgba(33,33,33,.8), weisses
   Dreieck ~17x16 (Pixelvermessung vd-home-l5b 2026-07-28). Der fruehere
   56px-Kreis mit .55-Fond war sichtbar anders. */
.play-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 68px; height: 48px; border-radius: 10px;
  background: rgba(33,33,33,.8); color: #fff; font-size: 19px;
  padding-left: 3px; /* Dreieck sitzt im Original optisch leicht rechts der Mitte */
}
.play-btn--sm { width: 24px; height: 24px; font-size: 11px; background: transparent; color: var(--color-text); }

/* ---- Announcement bar ---- */
/* Flaechenfarbe am Original gemessen: rgb(0,155,217) (#009bd9). Mit weisser
   15px/400-Schrift sind das nur 3,14:1 - unter WCAG AA (4,5:1), und Lighthouse
   Accessibility faellt damit unter 100. Der bisherige Wert #006688 (6,45:1) war
   dafuer sichtbar zu dunkel ("dunkles Petrol" statt Cyan). Gewaehlt ist jetzt
   der HELLSTE Farbwert auf derselben Farbachse, der AA noch besteht:
   #007eb1 = 4,55:1. Bewusste Restabweichung nach dem im Projekt etablierten
   Muster "Pixel-Treue wird der Lesbarkeit untergeordnet" - aber so nah am
   Original wie die Barrierefreiheit es zulaesst. Siehe docs/DECISIONS.md. */
/* POSITIONIERUNG - bewusste Reproduktion eines Original-Defekts, s.
   docs/DECISIONS.md ("Ankuendigungsleiste").
   Am Original nachgemessen (/opt/tooling/mob-ann3.mjs, Viewports
   1440/1200/1199/810/768/480/390/320):
     >= 1200px : Leiste fixiert bei top:0 (69px hoch, z-index 4),
                 Kopfzeile fixiert direkt darunter bei top:69 (74px, z 3).
     <  1200px : Kopfzeile fixiert bei top:0 (74px), Leiste fixiert bei
                 top:74 - sie liegt damit UEBER dem Seiteninhalt und
                 verdeckt dort Eyebrow und erste h1-Zeile.
   Beide sind `fixed`, nehmen also auf keiner Breite Platz im Fluss ein. */
.announce-bar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 41;
  /* Echter Extraktionswert (getComputedStyle Live-Original, gescrollt): die
     Ankuendigungsleiste ist rgb(0,155,217) = #009bd9 - dasselbe Marken-Blau
     wie das ews-Logo, nicht das dunklere #007eb1 der blinden Messung. */
  background: #009bd9; color: #fff;
}
.announce-bar__inner {
  /* Original: volle Breite mit 69px Seitenpolster, Text + Button als eine
     zentrierte Gruppe (gap 23px), Leistenhoehe 69px - nicht space-between
     in einem 1200er-Container. */
  padding: 11px 69px;
  display: flex; align-items: center; justify-content: center; gap: 23px;
  flex-wrap: wrap; min-height: 69px;
}
/* Original: Poppins 15/400 (nachgemessen) - nicht die geerbte Inter. Der
   Schriftwechsel aendert auf Mobil auch den Zeilenumbruch (3 statt 2 Zeilen,
   Leistenhoehe 183px wie im Original). Gilt fuer Text UND Knopf. */
.announce-bar__text { font-family: var(--font-heading); font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: var(--lh-body); }
.btn--announce { font-family: var(--font-heading); }

/* ---- Header / Nav ---- */
/* Gemessen am Original (framer-kbgm3r): 1440x74, weiss, KEINE Trennlinie,
   stattdessen ein weicher Schlagschatten `0 0 47px rgba(0,0,0,.23)`. Die
   bisherige 1px-Linie erzeugte auf jeder Seite eine harte Kante, die das
   Original nicht hat. */
/* Der Header ist im Original auf ALLEN Seiten und Breiten `position: fixed`
   und nimmt keinen Platz im Dokumentfluss ein - der Seiteninhalt beginnt bei
   y=0 und laeuft darunter hindurch (nachgemessen: /opt/tooling/hdrgeo.mjs,
   `mainY=0` auf jeder Stichprobenseite). Vorher stand er bei uns `sticky`,
   schob also jede Seite um 74px nach unten; auf Desktop war das per Hand
   zurueckgerechnet, auf Mobil nicht - daher dort der durchgaengige 74px-
   Versatz aller Seiten. Der Ausgleich sitzt jetzt zentral in `main`
   (s. unten), statt in jeder Hero-Regel einzeln. */
/* Milchglas-Kopfzeile wie im Original (framer-kbgm3r): halbtransparente weisse
   Flaeche + backdrop-filter blur, feine Unterkante statt harter Linie. Das
   Original misst rgba(255,255,255,.09)+blur(9px) und verlaesst sich dabei auf
   den weissen Seitengrund dahinter; wir nehmen einen etwas dichteren, ueber
   beliebigem Inhalt lesbaren Frost (0.72/blur 14px) - hochwertiger Milchglas-
   Streifen, der Text traegt WCAG-sicher. Weich eingeblendet ueber
   --duration-hover/--ease-smooth (kollabiert via prefers-reduced-motion). */
/* ECHTE EXTRAKTION (getComputedStyle des gescrollten Live-Originals @900,
   framer-kbgm3r): der "glassy" Header ist in Wahrheit KEIN Milchglas - er ist
   eine VOLLE weisse Flaeche rgb(255,255,255) OHNE backdrop-filter (blur 0px),
   OHNE Rahmen, mit einem einzigen weichen, diffusen Schlagschatten
   `0 0 47px rgba(0,0,0,.23)`. Der bisherige Frost (Alpha .72 + blur 14) war
   die Fehlinterpretation, die der Auftraggeber bemaengelt hat.
   Nebeneffekt der blur-Entfernung: backdrop-filter erzeugte einen Containing-
   Block, in dem das fixe Mobil-Menue-Overlay gefangen war (nur Header-hoch);
   ohne blur deckt das Overlay wieder die volle Ansicht. */
.site-header {
  position: fixed; top: 0; left: 0; right: 0; z-index: 40;
  background: rgb(255, 255, 255);
  border-bottom: 0;
  box-shadow: 0 0 47px rgba(0, 0, 0, .23);
  transition: background-color var(--duration-hover) var(--ease-smooth),
              box-shadow var(--duration-hover) var(--ease-smooth);
}
/* Seiten mit dunklem Hero (Startseite): der Header liegt transparent auf dem
   Foto (weisse Schrift) und blendet erst am Hero-ENDE weich zum Milchglas ueber.
   Der Umschlag ist SCROLL-SCRUBBED: main.js schreibt `--hdr-glass` (0..1) aus der
   Scroll-Position (Band `heroEnde-90px … heroEnde`), Alpha/Blur/Rand/Schatten
   interpolieren linear darueber - kein Ein-/Aus-Sprung mehr (frueher kippte der
   Header schon bei 8px, s. docs/qa/scroll-spec.md). Ohne JS bleibt `--hdr-glass`
   ungesetzt (Fallback 0) = transparent ueber dem Hero, Schrift weiss. */
body.has-hero-header .site-header {
  /* Uebergang transparent -> volle weisse Flaeche am Hero-Ende, scroll-scrubbed
     ueber --hdr-glass (0..1). Interpoliert werden Hintergrund-Alpha und
     Schatten-Alpha (0->.23). */
  background: rgba(255, 255, 255, var(--hdr-glass, 0));
  border-bottom: 0;
  box-shadow: 0 0 47px rgba(0, 0, 0, calc(.23 * var(--hdr-glass, 0)));
  /* Der Scrub kommt kontinuierlich ueber die Variable - keine eigene Transition
     noetig (sonst laeuft sie dem rAF-Scrub hinterher). */
  transition: none;
}
/* Startseiten-Navbar im Ruhezustand: das Original legt schon OBEN ein leichtes
   Milchglas ueber das Hero-Foto (getComputedStyle 2026-07-28: Navbar-Flaeche
   rgba(255,255,255,.09) + backdrop blur(9px)); die fruehere Messung "kein
   blur" galt dem gescrollten Zustand. Nur >=1200px - unterhalb erzeugte
   backdrop-filter frueher einen Containing-Block, der das fixe Mobil-Menue
   einfing (s.o.), und der Mobil-Header ist dort ohnehin anders aufgebaut. */
@media (min-width: 1200px) {
  body.has-hero-header .site-header {
    background: rgba(255, 255, 255, calc(.09 + .91 * var(--hdr-glass, 0)));
    -webkit-backdrop-filter: blur(9px);
    backdrop-filter: blur(9px);
  }
}
/* >=1200px liegt die Ankuendigungsleiste ueber der Kopfzeile, diese also
   um ihre Hoehe (69px) tiefer. Unterhalb 1200px sitzt die Kopfzeile oben
   und die Leiste darunter - s. Kommentar bei .announce-bar. */
@media (min-width: 1200px) {
  body.has-announce .site-header { top: 69px; }
}
/* Ausgleich fuer den aus dem Fluss genommenen Header. Randlose Heros
   (Startseite, /starkregengefahrenkarten/) beginnen im Original dagegen an
   der Dokumentoberkante und holen ihn wieder heraus. */
main { padding-top: 74px; }
main > .hero--home:first-child,
main > .hero--ews:first-child { margin-top: -74px; }
/* Kopfzeilen-Geometrie, an allen sechs Stichprobenseiten des Originals bei
   1440px identisch nachgemessen (/opt/tooling/header-cmp.mjs):
   Logo l=69 (161x23), Navigation 463..1110 mit 51px Abstand, Mail-Icon endet
   bei 1371 - also VOLLE Breite mit 69px Seitenpolster und space-between,
   nicht ein auf 1200px begrenzter, zentrierter Container.
   Der bisherige 1200er-Container hat das Logo um 75px nach innen und die
   Navigation um 190px nach rechts geschoben - dieselbe Klasse von Fehler wie
   beim Hero (Container-Geometrie), nur auf allen 24 Seiten. */
.site-header__inner {
  padding: 0 69px; min-height: 74px;
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-6);
}
.site-logo { display: inline-flex; align-items: center; position: relative;
  transition: opacity var(--duration-fast) var(--ease); }
/* Zustands-Audit Lauf 4: das Logo war der einzige Header-Link ohne jede
   Hover-Rueckmeldung. */
.site-logo:hover { opacity: .75; }
.site-logo:active { opacity: .6; }
/* Tippflaeche auf 44x44px vergroessern, ohne die sichtbare Logo-Groesse zu
   veraendern (Original-Logo bleibt 27px hoch). */
.site-logo::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: max(44px, 100%); height: max(44px, 100%);
  transform: translate(-50%, -50%);
}
/* Original: 161x23 gerendert (nachgemessen auf allen Seiten), nicht 27px hoch. */
/* Original: 161x23 (gemessen). Unsere Logodatei hat ein minimal anderes
   Seitenverhaeltnis (192x27 = 162,8px bei 23px Hoehe) - die Breite wird
   deshalb fest gesetzt, damit die space-between-Verteilung der Kopfzeile
   exakt die Original-Positionen ergibt. */
.site-logo__img { height: 23px; width: 161px; }
.site-logo__img--dark { display: none; }
body.has-hero-header .site-header.is-scrolled .site-logo__img--light,
body:not(.has-hero-header) .site-logo__img--light { display: none; }
body.has-hero-header .site-header.is-scrolled .site-logo__img--dark,
body:not(.has-hero-header) .site-logo__img--dark { display: inline-flex; }

/* Original: 51px Abstand zwischen den Hauptnav-Punkten (nachgemessen). */
.primary-nav > ul { display: flex; gap: 51px; align-items: center; }
.primary-nav > ul > li { position: relative; }
/* Hauptnav-Links: im Original 15px/700 (siehe docs/DECISIONS.md), nicht die
   allgemeine --fs-small-Skala - eigene, am Original gemessene Deklaration
   statt des bisherigen (zu kleinen/zu leichten) --fs-small/--fw-semibold. */
/* Echte Extraktion (Live-Original, getComputedStyle des sichtbaren Textknotens):
   Hauptnav ist POPPINS 15px/700, Farbe rgb(129,129,129) im gescrollten/inneren
   Zustand (ueber dem Hero weiss, s. Regel weiter unten). Vorher rendete unsere
   Nav in Inter (--font-body geerbt) mit #333 - beides daneben. rgb(129,129,129)
   selbst besteht auf Weiss den WCAG-AA-Kontrast fuer 15px-Fettschrift nicht
   (3.9:1); wir nehmen den hellsten AA-sicheren Grauton #767676 (4.54:1), der
   dem Original optisch am naechsten kommt und A11y=100 haelt. */
.nav-link, .primary-nav a { font-family: var(--font-heading); font-size: var(--fs-body); font-weight: var(--fw-bold); cursor: pointer; color: var(--color-text-muted); transition: opacity var(--duration-fast) var(--ease); }
/* Eigene Hover-Rueckmeldung fuer die obersten Nav-Ebene (nicht die
   Dropdown-Eintraege - die haben bereits ihre eigene Hintergrund-Hervor-
   hebung weiter unten). Opacity statt Farbwechsel, damit es unabhaengig vom
   hellen/dunklen Hero-Kontext funktioniert (Design-Pass-Verbesserung). */
.primary-nav > ul > li > a:hover, .primary-nav > ul > li > .nav-link:hover { opacity: .6; }
.primary-nav > ul > li > a:active, .primary-nav > ul > li > .nav-link:active { opacity: .45; }
/* .nav-link ist fuer die beiden Dropdown-Ausloeser ("Loesungen"/"Unternehmen")
   ein echtes <button>, damit es per Tastatur (Enter/Leertaste) bedienbar ist
   - Browser-Standard-Button-Chrome zuruecksetzen, damit es weiterhin wie der
   Original-Textlink aussieht.
   ACHTUNG: hier stand vorher die Kurzform `font: inherit`. Die setzt AUCH
   font-size und font-weight - und da `button.nav-link` (0,1,1) spezifischer
   ist als die Regel `.nav-link` (0,1,0) darueber, gewannen die geerbten
   Body-Werte: "Loesungen"/"Unternehmen" wurden mit font-weight 400 gerendert,
   die direkt danebenstehenden Nav-Links ("Referenzen", "Aktuelles") mit 700.
   Sichtbare Inkonsistenz in der Hauptnavigation, entstanden als Nebenwirkung
   des Tastatur-Fixes aus Lauf 3. Jetzt nur noch die wirklich gemeinten
   Eigenschaften zuruecksetzen. */
button.nav-link {
  background: none; border: 0; padding: 0; margin: 0;
  font-family: var(--font-heading); font-size: var(--fs-body); font-weight: var(--fw-bold);
  line-height: inherit; color: var(--color-text-muted); text-align: left;
}
body.has-hero-header .site-header:not(.is-scrolled) .nav-link,
body.has-hero-header .site-header:not(.is-scrolled) .primary-nav a,
body.has-hero-header .site-header:not(.is-scrolled) .icon-btn { color: #fff; border-color: rgba(255,255,255,.6); }
/* Die Dropdown-Panels sind IMMER weiss - ihre Links duerfen daher auch ueber
   dem Hero nicht auf Weiss umgestellt werden (sonst unsichtbar). Hoehere
   Spezifitaet als die Weiss-Regel darueber. */
body.has-hero-header .site-header:not(.is-scrolled) .dropdown a { color: var(--color-text); }

/* ---- Kopfzeile bei geoeffnetem Desktop-Menue -------------------------------
   Am Live-Original @1440 gemessen (Panel offen, Pixel + getComputedStyle):
   das weisse Panel beginnt an der KOPFZEILEN-OBERKANTE - die Kopfzeile wird
   also deckend weiss (Logo dunkel, Nav grau), das Hero-Foto scheint nicht
   mehr durch. An der Kopfzeilen-Unterkante liegt eine 1px-Haarlinie
   rgb(201,201,201) ueber die volle Breite; der diffuse Scroll-Schatten
   entfaellt (der Milchglas-Backdrop uebernimmt die Abgrenzung nach unten).
   main.js setzt `is-menu-open`, solange irgendein Dropdown offen ist.
   Die Regeln stehen NACH den is-scrolled-/Ueber-Hero-Regeln und gewinnen bei
   gleicher Spezifitaet durch die Reihenfolge. */
.site-header.is-menu-open,
body.has-hero-header .site-header.is-menu-open {
  background: #fff;
  box-shadow: inset 0 -1px 0 #c9c9c9;
}
body.has-hero-header .site-header.is-menu-open .site-logo__img--light { display: none; }
body.has-hero-header .site-header.is-menu-open .site-logo__img--dark { display: inline-flex; }
body.has-hero-header .site-header.is-menu-open .nav-link,
body.has-hero-header .site-header.is-menu-open .primary-nav a,
body.has-hero-header .site-header.is-menu-open .icon-btn { color: var(--color-text-muted); border-color: currentColor; }
/* Der Ausloeser des OFFENEN Panels steht dunkel (Original: rgb(51,51,51))
   und dimmt nicht ueber die Hover-Opacity. */
.primary-nav > ul > li.has-dropdown.is-open > .nav-link,
.primary-nav > ul > li.has-dropdown.is-open > .nav-link:hover,
body.has-hero-header .site-header.is-menu-open .has-dropdown.is-open > .nav-link { color: var(--color-text); opacity: 1; }

/* Dropdown-Panel im Stil des Original-Menues: reines Weiss, weicher, diffuser
   Schatten (wie der gescrollte Header 0 0 47px), KEINE harte 1px-Kante. */
.dropdown {
  display: none; position: absolute; top: 100%; left: 0; margin-top: var(--space-3);
  background: #fff; border: 0; border-radius: var(--radius-md);
  padding: var(--space-2); min-width: 240px; box-shadow: 0 18px 47px rgba(0, 0, 0, .18); z-index: 50;
}
.dropdown li a { display: block; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); color: var(--color-text); white-space: nowrap; }
.dropdown li a:hover { background: var(--color-surface); }
.dropdown li a:active { background: var(--color-border); }
.has-dropdown:hover .dropdown,
.has-dropdown.is-open .dropdown,
/* Fokus IM Panel haelt es offen (Tab durch die Links). Bewusst `.dropdown`
   selbst statt `.has-dropdown:focus-within`, damit ein fokussierter Ausloeser
   das Panel NICHT offen haelt - so schliesst Escape (Fokus zurueck zum
   Ausloeser) das Menue zuverlaessig. */
.dropdown:focus-within { display: block; }
/* HOVER-BRUECKE: der senkrechte Spalt zwischen Ausloeser und Panel (das
   margin-top bzw. die Kopfzeilenhoehe unter dem Button) liess das Menue
   zufallen, sobald die Maus hinunterwanderte. Ein unsichtbarer Streifen, der
   zum Panel gehoert (also selbst :hover haelt), ueberbrueckt die Luecke - die
   Maus verlaesst den Hover-Bereich auf dem Weg ins Panel nie. Ergaenzt wird
   das in main.js durch eine kleine Schliess-Verzoegerung (Hover-Intent). */
.dropdown::before {
  content: ""; position: absolute; left: 0; right: 0;
  top: -20px; height: 20px;
}
/* Das Mega-Panel sitzt an der Kopfzeilen-Unterkante, der Ausloeser aber auf
   halber Kopfzeilenhoehe - dazwischen liegen ~26px. Die Bruecke muss diesen
   ganzen Spalt bis zum Ausloeser abdecken, sonst reisst der Hover-Weg. */
.dropdown--mega::before { left: 0; right: 0; top: -34px; height: 34px; }

/* ---- Mega-Menue "Loesungen" -------------------------------------------------
   Das Original-Dropdown unter "Loesungen" ist KEIN kompaktes Panel, sondern
   eine volle, randlose weisse Flaeche unter der Kopfzeile mit zwei gleich
   breiten Loesungskarten (fas links, ews rechts). Am Live-Original @1440
   nachgemessen (getComputedStyle): Panel [0,143,1440,253], Karten je 720px
   mit Polster 51px 69px 39px, Wortmarke 296px breit, Beschreibung Poppins
   15/400 lh 22.5. Original-Textfarbe ist rgb(129,129,129) (3.9:1, faellt AA
   fuer 15px-Normaltext) - wir nehmen wie in der uebrigen Nav den AA-sicheren
   --color-text-muted (#767676, 4.54:1), optisch praktisch deckungsgleich.

   Positionierung: der auslloesende <li> steht auf `position:static` (s.u.),
   damit das absolut positionierte Panel seinen Bezug am fixen, VOLLBREITEN
   .site-header nimmt - so spannt left:0/right:0 ueber die ganze Ansicht, top
   100% sitzt genau an der Kopfzeilen-Unterkante. */
/* Spezifitaet muss `.primary-nav > ul > li { position:relative }` (0,1,3)
   schlagen, sonst bleibt der <li> Bezugsrahmen und das Panel wird nur so breit
   wie der Menuepunkt. */
.primary-nav > ul > li.has-mega { position: static; }
/* Original (Panel offen, getComputedStyle): reines Weiss, KEIN Radius, KEIN
   Schatten - die Abgrenzung nach unten uebernimmt der Milchglas-Backdrop
   (Pixelprobe: harte Kante Weiss -> geblurter Inhalt, kein Verlauf). */
.dropdown--mega {
  top: 100%; left: 0; right: 0; margin-top: 0;
  padding: 0; min-width: 0; border-radius: 0;
  box-shadow: none;
}
.mega { display: flex; align-items: stretch; }
/* Menue-interne Farbwerte: die Panels sind exakt am Live-Original gemessen
   (Text rgb(129,129,129), Zierelemente rgb(201,201,201), Hover rgb(51,51,51),
   Haarlinien rgb(201,201,201)). Bewusst NICHT auf die AA-Ersatztoene der
   sichtbaren Nav abgedunkelt: die Panels sind im Auslieferungszustand
   display:none (Kontrast-Audit prueft sie nicht), hier zaehlt die 1:1-Optik. */
.mega-card {
  flex: 1 1 50%; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start;
  /* am Original nachgemessen: 51px oben, 69px seitlich, 39px unten; der
     Karteninhalt ist vertikal ZENTRIERT (die kuerzere ews-Karte sitzt mittig:
     Logo y=208 statt 194). */
  justify-content: center;
  padding: 51px 69px 39px;
  color: #818181;
  transition: background-color var(--duration-hover) var(--ease);
}
/* 1px-Mittelkante zwischen den Karten, Original rgb(201,201,201) bei x=719 -
   also am rechten Rand der LINKEN Karte (die rechte beginnt exakt bei 720,
   ihr Logo bei 789). */
.mega-card--fas { border-right: 1px solid #c9c9c9; }
/* HOVER (Original): die GANZE Karte faerbt sich in ihrer Markenfarbe, die
   Wortmarke wechselt per Kreuzblende auf die weisse Variante, die
   Beschreibung wird weiss. "Mehr erfahren" + Pfeil BLEIBEN rgb(129,129,129)
   (so das Original - wirkt auf Rot/Blau bewusst zurueckgenommen). */
.mega-card--fas:hover, .mega-card--fas:active { background: #bd2734; }
.mega-card--ews:hover, .mega-card--ews:active { background: var(--color-brand-blue); }
.mega-card__logos {
  position: relative; width: 296px; max-width: 100%; margin-bottom: 21px;
}
.mega-card__logo { display: block; width: 100%; height: auto; }
.mega-card__logo--hover {
  position: absolute; inset: 0; opacity: 0;
  transition: opacity var(--duration-hover) var(--ease);
}
.mega-card__logo--rest { transition: opacity var(--duration-hover) var(--ease); }
.mega-card:hover .mega-card__logo--hover { opacity: 1; }
.mega-card:hover .mega-card__logo--rest { opacity: 0; }
.mega-card__desc {
  /* Original: max. 510px breit, gegenueber der Wortmarke 36px eingerueckt
     (x=105 vs. 69), 23px Abstand zum "Mehr erfahren". */
  max-width: 510px; margin: 0 0 23px 36px;
  font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: 1.5;
  color: #818181;
  transition: color var(--duration-hover) var(--ease);
}
.mega-card:hover .mega-card__desc { color: #fff; }
.mega-card__more {
  display: inline-flex; align-items: center; gap: 9px;
  margin-left: 36px;
  font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: 1.5;
  color: #818181;
}
/* Original-Pfeilglyphe (Linie + massive Spitze), 20x12 gerendert. */
.arrow-glyph { width: 20px; height: 12px; flex: none; transition: transform var(--duration-fast) var(--ease); }
.mega-card:hover .arrow-glyph { transform: translateX(3px); }
/* Ueber dem dunklen Hero bleiben die Mega-Texte in ihren Panel-Farben (das
   Panel ist weiss) - die Weiss-ueber-Hero-Regel darf sie nicht einfaerben.
   (No-JS-Fallback: mit JS erzwingt is-menu-open ohnehin die graue Nav.) */
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-card,
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-card__desc,
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-card__more,
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-link,
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-feature { color: #818181; }
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-card:hover .mega-card__desc { color: #fff; }
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-link:hover { color: var(--color-text); }
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-feature__title { color: #818181; }
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-links__eyebrow,
body.has-hero-header .site-header:not(.is-scrolled) .dropdown--mega .mega-feature__meta { color: #c9c9c9; }

/* ---- Mega-Menue "Unternehmen" ----------------------------------------------
   Am Live-Original @1440 nachgemessen (offenes Panel): links bei x=96 der
   Eyebrow "Über uns" (15/700 rgb(201,201,201)), 11px darunter eine 600px
   breite 1px-Haarlinie rgb(201,201,201), 21px darunter ein 2-spaltiges
   Raster (Spalten a 263px bei x=96/433, Spaltenfluss: links Unternehmen/
   Aktuelles/Veranstaltungen, rechts Karriere/Kontakt). Jeder Punkt: Titel
   15/700 rgb(129,129,129) (nur der Titel ist Link, Hover rgb(51,51,51)),
   5px darunter die Beschreibung 15/400 rgb(129,129,129); 15px zwischen den
   Punkten. Rechts die Aufmacherkarte [864,143,576,403]: EIN Link, Bild
   randlos bis zur rechten Viewport-Kante und buendig an der Panel-Oberkante
   (object-fit cover, kein Radius), davor die senkrechte 1px-Trennlinie
   rgb(201,201,201) bei x=863 ueber die volle Panelhoehe. */
.mega-links {
  flex: 1 1 auto; min-width: 0;
  padding: 51px 40px 39px 96px;
}
.mega-links__eyebrow {
  /* 11px Text->Linie, 20px Linie->erste Zeile (Original: 217/228/249). */
  margin: 0 0 20px; width: 600px; max-width: 100%;
  padding-bottom: 11px; border-bottom: 1px solid #c9c9c9;
  font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: 1.5;
  color: #c9c9c9;
}
.mega-links__grid {
  display: grid; grid-template-columns: 263px 263px;
  grid-template-rows: repeat(3, auto); grid-auto-flow: column;
  column-gap: 74px; row-gap: 15px; align-content: start;
}
.mega-item { min-width: 0; }
.mega-link {
  display: inline-block;
  font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: 1.5;
  color: #818181;
  transition: color var(--duration-fast) var(--ease);
}
.mega-link:hover { color: var(--color-text); }
.mega-link:active { opacity: .6; }
.mega-item__desc {
  margin: 5px 0 0;
  font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: 1.5;
  color: #818181;
}
/* Aufmacherkarte rechts (neuester Aktuelles-Beitrag): 577px-Spalte
   (576px Bild + 1px Trennlinie) = 40.07% von 1440. */
.mega-feature {
  flex: 0 0 40.07%; min-width: 0;
  display: flex; flex-direction: column; align-items: flex-start;
  padding: 0; border-left: 1px solid #c9c9c9;
  color: #818181;
}
.mega-feature__media {
  display: block; width: 100%; overflow: hidden;
  border-radius: 0; aspect-ratio: 576 / 268;
}
.mega-feature__img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  /* Ausschnitt gegen das Original korreliert (Pixelabgleich /opt/tooling):
     das Original beschneidet die Quelle oben nur ~17px (nicht mittig). */
  object-position: 50% 16%;
  transition: transform var(--duration-hover) var(--ease-smooth);
}
.mega-feature:hover .mega-feature__img { transform: scale(1.05); }
.mega-feature__meta {
  margin: 39px 47px 0; font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-regular); line-height: 1.5;
  color: #c9c9c9;
}
.mega-feature__title {
  margin: 12px 47px 38px; font-family: var(--font-heading);
  font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: 1.5;
  color: #818181;
  transition: color var(--duration-fast) var(--ease);
}
.mega-feature:hover .mega-feature__title { color: var(--color-text); }

/* ---- Milchglas-Backdrop hinter geoeffnetem Desktop-Menue --------------------
   Am Original gemessen: backdrop-filter blur(9px) + weisser Schleier
   rgba(255,255,255,.69) ueber dem Seiteninhalt. Liegt UNTER Kopfzeile (z 40)
   und Panel (z 50), aber ueber dem Inhalt - so bleibt Kopfzeile/Panel deckend
   scharf, nur der Hintergrund dahinter wird unscharf. Weich ein-/ausgeblendet;
   pointer-events:none, damit Hover/Klick nicht abgefangen werden. */
.nav-backdrop {
  position: fixed; inset: 0; z-index: 30;
  /* Original-Messwert: rgba(255,255,255,.69) + blur(9px). */
  background: rgba(255, 255, 255, .69);
  -webkit-backdrop-filter: blur(9px); backdrop-filter: blur(9px);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity var(--duration-hover) var(--ease-smooth),
              visibility var(--duration-hover) var(--ease-smooth);
}
.nav-backdrop.is-visible { opacity: 1; visibility: visible; }

/* ---- Scroll-Hinweis: dezente, wiederholende Bewegung des Pfeils ------------
   Im Original floatet der "Scrollen"-Pfeil leicht auf und ab (JS/Motion). Wir
   loesen es als sparsame CSS-Keyframe (1.8s, weiche Kurve) - nur der Pfeil-
   Glyph bewegt sich, nicht der Text. Unter prefers-reduced-motion still (die
   globale reduced-motion-Regel setzt die animation-duration ohnehin aus). */
@media (prefers-reduced-motion: no-preference) {
  .hero__scroll-hint span {
    display: inline-block;
    animation: scroll-cue-float 1.8s ease-in-out infinite;
  }
}
@keyframes scroll-cue-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(5px); }
}

/* Kontaktblock erscheint nur im Mobil-Overlay (s. Media-Query unten). */
.nav-contact { display: none; }
/* Zurueck-Pfeil des Mobil-Menues: nur auf Ebene 2 sichtbar (s. Media-Query). */
.nav-back { display: none; }

/* Menue-Symbol am Original nachgemessen (/opt/tooling/burger.mjs, Breiten
   1199/1000/810/390 identisch): sichtbare Flaeche 30x23 mit ZWEI Balken
   (je 30x3, Radius 9, rgb(129,129,129)) bei y=29 und y=43 - nicht drei
   22x2-Balken. Die rechte Kante liegt bei 39px Seitenabstand. */
.nav-toggle {
  display: none; align-items: center; justify-content: space-between; flex-direction: column;
  position: relative; background: none; border: 0; padding: 0;
  width: 30px; height: 23px; color: rgb(129, 129, 129);
  /* Original: cursor pointer (nachgemessen 2026-07-30). */
  cursor: pointer;
  /* Taps sofort ausloesen (kein Doppeltipp-Zoom-Zoegern auf Touch). */
  touch-action: manipulation;
}
/* Tap-/Press-Feedback (Kundenwunsch 2026-07-30): beim Antippen dunkeln
   die Balken in der Interaktionssprache der Site (#818181 -> #333, wie
   alle Hover/Aktiv-Zustaende) und das Symbol federt kurz ein. Das
   Original selbst zeigt beim Tippen KEINE sichtbare Reaktion (Touch-Hold
   und Klick @390 nachgemessen) - bewusste kleine Ergaenzung fuer
   spuerbares Mobil-Feedback. */
.nav-toggle { transition: transform .12s ease; }
.nav-toggle:active { color: var(--color-text); transform: scale(.88); }
@media (prefers-reduced-motion: reduce) {
  .nav-toggle { transition: none; }
  .nav-toggle:active { transform: none; }
}
/* Tippflaeche auf 44x44 vergroessern, ohne die gemessene Symbolgroesse zu
   veraendern - gleiches Muster wie bei .icon-btn und .site-logo. */
.nav-toggle::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 44px; height: 44px; transform: translate(-50%, -50%);
}
/* Nur die Balken ansprechen - NICHT das .sr-only-Span mit der
   Bildschirmleser-Beschriftung (das traegt eigene Masse). */
.nav-toggle__bar { display: block; width: 30px; height: 3px; border-radius: 9px; background: currentColor; }
/* Burger -> X-Morph (Kundenwunsch 2026-07-30): beim Oeffnen fahren die
   beiden Balken zur Mitte (Zentren 4,5/18,5 -> 11,5 = +-7px) und drehen
   federnd auf +-45 Grad; beim Schliessen zurueck. Leichter Overshoot in
   der Kurve fuer den "Snap". */
.nav-toggle__bar {
  transition: transform .32s cubic-bezier(.34, 1.56, .64, 1);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:first-child {
  transform: translateY(7px) rotate(45deg);
}
.nav-toggle[aria-expanded="true"] .nav-toggle__bar:nth-child(2) {
  transform: translateY(-7px) rotate(-45deg);
}
@media (prefers-reduced-motion: reduce) {
  .nav-toggle__bar { transition: none; }
}
/* Balken bei y=29 und y=43 innerhalb der 23px hohen Flaeche (y=26..49):
   also 3px oben, 3px unten, 11px dazwischen. */
.nav-toggle__bar:first-child { margin-top: 3px; }
/* ACHTUNG: nicht :last-of-type - das traefe das .sr-only-<span> (gleicher
   Elementtyp) statt des zweiten Balkens; der sass dadurch 3px zu tief. */
.nav-toggle__bar:nth-child(2) { margin-bottom: 3px; }

/* ---- Footer ---- */
/* Fusszeile ist im Original WEISS, nicht grau abgesetzt (nachgemessen
   rgb(255,255,255) auf allen Breiten, /opt/tooling/fbg.mjs). Der graue
   Kasten war auf jeder Seite und jeder Breite eine Flaechenabweichung. */
.site-footer { background: #fff; margin-top: var(--space-9); }
/* Folgt die Fusszeile direkt auf die Pfadleiste (alle Unterseiten), gibt es
   im Original KEINEN Zwischenraum - der 96px-Aussenabstand gilt nur ohne
   Band (Startseite). Nachgemessen @390: kontakt Band->Fusszeile 74px
   (= reines Spaltenpolster), Vergleichslauf 2026-07-24. */
.pfadleiste + .site-footer { margin-top: 0; }
.site-footer__columns {
  max-width: var(--container-max); margin: 0 auto; padding: var(--space-9) var(--container-pad) var(--space-7);
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--space-6);
}
/* Footer-Spaltentitel: Original 15px/700/22.5. Bisher 14px/600 mit 16.8px
   Zeilenhoehe - die Zeilenhoehe kam aus der h2-Regel (1.2), weil die Klasse
   selbst keine deklarierte. Betraf alle 24 Seiten. */
.footer-col__title {
  font-size: var(--fs-body); font-weight: var(--fw-bold); line-height: var(--lh-body);
  color: var(--color-text-faint); text-transform: none;
  border-bottom: 1px solid var(--color-border); padding-bottom: var(--space-2); margin-bottom: var(--space-3);
}
/* Der Titel ist ab 1200px reiner Text, darunter der Ausloeser einer
   Ausklappliste (s. Media Query). Der <button> traegt deshalb auf Desktop
   bewusst KEINE Knopf-Optik - er erbt die Titeltypografie unveraendert. */
.footer-col__toggle {
  display: flex; align-items: center; justify-content: space-between;
  width: 100%; padding: 0; border: 0; background: none; text-align: left;
  font-size: inherit; font-weight: inherit; line-height: inherit;
  font-family: inherit; color: inherit;
}
.footer-col__plus { display: none; }
.footer-col ul { display: flex; flex-direction: column; gap: var(--space-2); }
/* Fusszeilentext ist im Original auf JEDER Breite rgb(129,129,129)
   (nachgemessen 1440/768/390, /opt/tooling/fcol.mjs) - nicht #333. Wir
   nehmen die AA-taugliche Variante --color-text-muted. Betraf alle Verweise,
   die Urheberzeile und die Rechtstexte auf allen 24 Seiten. */
.footer-col a { color: var(--color-text-muted); font-size: var(--fs-body); transition: color var(--duration-hover) var(--ease-smooth); }
/* Hover am Original nachgemessen (2026-07): NUR Farbwechsel #818181->#333,
   KEINE Unterstreichung (die bisherige war erfunden). AA-Analogon wie
   ueberall: --color-text-muted -> --color-text. */
.footer-col a:hover { color: var(--color-text); }

.site-footer__bottom {
  max-width: var(--container-max); margin: 0 auto; padding: var(--space-5) var(--container-pad) var(--space-7);
  border-top: 1px solid var(--color-border);
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4); flex-wrap: wrap;
}
.footer-copy { margin: 0; font-size: var(--fs-body); color: var(--color-text-muted); }
.footer-legal { display: flex; gap: var(--space-5); }
/* Zustands-Audit Lauf 4: .footer-col a hatte einen Hover-Zustand,
   .footer-legal a (Impressum/Datenschutz) nicht - dieselbe Linkrolle,
   inkonsistente Rueckmeldung. Angeglichen. Hover wie .footer-col a am
   Original nachgemessen: nur Farbwechsel, keine Unterstreichung. */
.footer-legal a { font-size: var(--fs-body); color: var(--color-text-muted); transition: color var(--duration-hover) var(--ease-smooth); }
.footer-legal a:hover { color: var(--color-text); }
.footer-social { display: flex; gap: var(--space-3); }
.footer-social a { position: relative; color: var(--color-text-muted); }
/* Am Original nachgemessen (2026-07): die Social-SVGs faerben beim Hover
   DOCH um (fill #818181 -> #333, kein Opacity-Trick) - unser Farbwechsel
   war also schon deckungsgleich; nur die Tokens auf die einheitliche
   Hover-Sprache (--duration-hover/--ease-smooth) gezogen. */
.footer-social a { transition: color var(--duration-hover) var(--ease-smooth); }
.footer-social a:hover { color: var(--color-text); }
.footer-social a:active { color: var(--color-text-muted); }
/* Tippflaeche auf 44x44px vergroessern, ohne die sichtbare Icon-Groesse/den
   Zeilenabstand der Leiste zu veraendern. */
.footer-social a::before {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: max(44px, 100%); height: max(44px, 100%);
  transform: translate(-50%, -50%);
}

/* ---- Pfadleiste ueber der Fusszeile ----
   Original (1440): volle Breite, 69px hoch, weiss, Polster 23px/123px,
   Zwischenraum 23px. Augenmarke 45x23, Winkel 10x22 in rgb(201,201,201),
   Seitenname 15px/400. Fehlte im Nachbau auf allen Unterseiten und war
   damit auf jeder Seite ein 69px-Versatz der gesamten Fusszeile. */
.pfadleiste {
  display: flex; align-items: center; gap: 23px;
  padding: 23px 123px; background: #fff;
}
.pfadleiste__logo { display: block; line-height: 0; }
.pfadleiste__logo img { display: block; width: 45px; height: 23px; object-fit: cover; }
.pfadleiste__winkel { display: flex; align-items: center; }
.pfadleiste__seite {
  font-size: var(--fs-body); line-height: var(--lh-body); color: var(--color-text-muted);
}
/* Eltern-Segment (nur Blogartikel: "Aktuelles" verlinkt) - gleiche Optik wie
   das Seiten-Segment, keine Unterstreichung (wie im Original). */
a.pfadleiste__eltern { text-decoration: none; }
a.pfadleiste__eltern:hover { color: var(--color-text); }
@media (max-width: 1199px) {
  .pfadleiste { padding: 23px 39px; }
  /* Einstufig bricht das Original den Seitennamen NICHT um: @390 steht
     "Starkregen Risikomanagement" (231px breit) einzeilig ab x=140 und
     laeuft rechts ueber das 39px-Polster hinaus (bis x=371 < 390;
     nachgemessen Lauf 5, 2026-07-28). Bei uns brach er in zwei Zeilen -
     die Leiste war 91 statt 69px hoch, der Footer sass auf beiden
     Produktseiten 22px zu hoch. Auge und Winkel behalten ihre Masse
     (Original: 45x23 bei x=39, Winkel 10px bei x=107). Die zweistufige
     Blog-Variante bricht weiterhin um (eigene Regeln unten). */
  .pfadleiste:not(.pfadleiste--zweistufig) > * { flex-shrink: 0; }
  .pfadleiste:not(.pfadleiste--zweistufig) .pfadleiste__seite { white-space: nowrap; }
}
@media (max-width: 809px) {
  /* Der Seitenname steht im Original mobil in einer MINDESTENS 210px
     breiten Box und ist darin ZENTRIERT: kurzes "Forschung" (76px) sitzt
     bei x=207, langes "Starkregen Risikomanagement" (231px) laesst die Box
     mitwachsen und beginnt bei x=140 - beide Messungen 2026-07-28
     (fo-zone.mjs /forschung/ @390 bzw. Produktseiten Lauf 5). */
  .pfadleiste:not(.pfadleiste--zweistufig) .pfadleiste__seite {
    display: inline-block; min-width: 210px; text-align: center;
  }
}

/* Lauf 7b (2026-07-30): @320 bricht die EINSTUFIGE Pfadleiste im Original
   zweizeilig um (114,5 statt 69 hoch): Zeile 1 nur das Auge (x=39),
   Zeile 2 Winkel + Seitenname (Namenszone ab x=72, Text darin zentriert,
   z. B. "Impressum" x=108,4). Ohne den Umbruch sassen Footer und
   Seitenende auf JEDER Unterseite 45,5px zu hoch. */
@media (max-width: 359px) {
  .pfadleiste:not(.pfadleiste--zweistufig) { flex-wrap: wrap; row-gap: 23px; }
  /* Die ZWEISTUFIGE Blog-Variante wird @320 im Original DREIzeilig
     (182,5): Logo / Winkel+Aktuelles / Winkel+Titel (Titel ab x=72,
     zweizeilig 45) - Blogseiten endeten sonst 45,5px zu frueh. */
  .pfadleiste--zweistufig { flex-wrap: wrap; row-gap: 23px; }
  .pfadleiste--zweistufig .pfadleiste__logo { flex-basis: 100%; }
  .pfadleiste--zweistufig .pfadleiste__eltern { flex: 1 1 auto; }
  .pfadleiste--zweistufig .pfadleiste__seite:not(.pfadleiste__eltern) { flex: 1 1 0; min-width: 0; }
  .pfadleiste:not(.pfadleiste--zweistufig) .pfadleiste__logo { flex-basis: 100%; }
  .pfadleiste:not(.pfadleiste--zweistufig) .pfadleiste__seite {
    /* Name bleibt wie ab 390 EINZEILIG und laeuft rechts sichtbar ueber
       (Original @320: "Starkregen Frühalarmsystem" einzeilig, Leiste
       trotzdem 114,5). flex-basis 0: die Box schrumpft in die Zeile
       neben den Winkel, der nowrap-Text ragt heraus - mit basis:auto
       rutschte der Name in eine dritte Zeile (Leiste 159,5). */
    min-width: 0; flex: 1 1 0;
  }
}

/* ---- Fusszeile ab 1200px: Geometrie am Original nachgemessen ----
   (/opt/tooling/foot10.mjs, Viewport 1440, gemessen ueber die volle
   Seitenhoehe - der bisherige Abgleich reichte nur bis 900px, deshalb
   war die Fusszeile auf ALLEN 24 Seiten daneben.)

     Trennlinie      1px rgb(201,201,201), volle Breite, direkt ueber der
                     Fusszeile - KEIN 96px-Abstand davor
     Spaltenblock    74px Polster oben, vier SCHRUMPFENDE Spalten mit 96px
                     Zwischenraum, als Gruppe zentriert (x=358..1082) -
                     vorher ein 4x1fr-Raster ueber die volle Containerbreite
                     (x=144..1296), also 214px zu weit links
     Spaltentitel    22,5px hoch, 31,5px Abstand zur ersten Verweiszeile,
                     ohne Unterstrich
     Verweiszeilen   Schrittweite 37,5px (22,5px Zeile + 15px Abstand)
     Abbinder        volle Breite, Trennlinie oben, Polster 26px/123px/25px,
                     vier gleichrangige Elemente mit space-between
                     (Impressum/Datenschutz stehen NICHT als enge Gruppe)
     Sozialsymbole   27x27 mit 47px Zwischenraum (Rasterschritt 74px)      */
@media (min-width: 1200px) {
  .site-footer { margin-top: 0; border-top: 1px solid rgb(201, 201, 201); }
  /* Lauf 6 @1440 (impressum): Spaltentitel sitzen im Original 74px unter der
     Footer-OBERKANTE (inkl. Linie) - unsere border-top schob sie auf 75;
     pt 73 gleicht das aus. Titel -> erste Verweiszeile sind 32px (nicht
     31,5): erste Zeile bei Footer+128,5 wie im Original (1699,8). */
  .site-footer__columns {
    max-width: none; margin: 0; padding: 73px 0 74px;
    display: flex; justify-content: center; align-items: flex-start; gap: 96px;
  }
  .footer-col__title { border-bottom: 0; padding: 0; margin: 0 0 32px; }
  .footer-col ul { gap: 15px; }
  .footer-col li { line-height: var(--lh-body); }

  .site-footer__bottom {
    max-width: none; margin: 0; padding: 25px 123px;
    border-top: 1px solid rgb(201, 201, 201);
    flex-wrap: nowrap;
  }
  /* Loest die Zwischenverpackung auf, damit Impressum und Datenschutz
     eigenstaendige Flex-Elemente der Abbinderzeile werden - nur so
     entstehen die vier gleich grossen Zwischenraeume des Originals. */
  .footer-legal { display: contents; }
  /* Die Abbinderzeile ist im Original 23px hoch - die 27px grossen
     Sozialsymbole ragen symmetrisch darueber hinaus, ohne die Zeile zu
     dehnen. Ohne die feste Hoehe wurde die Zeile 34px hoch (Grundlinie des
     inline-a plus Symbol) und die Fusszeile damit auf JEDER Seite 11px zu
     hoch. */
  .footer-social { gap: 47px; align-items: center; height: 23px; }
  .footer-social a { display: flex; align-items: center; }
  .footer-social svg { width: 27px; height: 27px; }
}

/* ---- Generic section rhythm ---- */
.section { padding: var(--space-9) 0; }
/* Original-Intro-Spalte: 810px (nachgemessen @1440 auf Startseite/Partner,
   /kontakt/, /allianzen/ - 62ch (~558px) brach eine Zeile zu frueh um). */
.section-intro { max-width: 810px; color: var(--color-text-muted); font-size: var(--fs-body); }
/* Intro-Absaetze: das Original zentriert sie nur ab 1200px (per getComputedStyle
   an /allianzen/, /unternehmen/, /forschung/, /referenzen/, /veranstaltungen/,
   /kontakt/ nachgemessen: >=1200 text-align center, <=1199 left). Unter 1200px
   liefen die mehrzeiligen Absaetze bei uns zentriert - sichtbar abweichend vom
   linksbuendigen Original. Umschaltpunkt exakt 1200 (1200=center, 1199=left). */
@media (max-width: 1199px) {
  .section-intro { text-align: left; }
}
/* CSS-Hygiene-Fix (Design-Pass Lauf 3): war identisch in 7 Seiten-CSS-Dateien
   kopiert (allianzen/fas/referenzen/veranstaltungen/unternehmen/ews/
   forschung.css) - hierher konsolidiert, s. docs/DECISIONS.md. */
.section--intro { padding-top: var(--space-9); }

/* ---- Generic Formular-Bausteine (Kontakt, Newsletter) ---- */
/* Honeypot: fuer Sehende und Screenreader nicht wahrnehmbar, aber im DOM
   vorhanden - klassischer, abhaengigkeitsfreier Bot-Filter. */
.hp-field {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0,0,0,0); white-space: nowrap; left: -9999px;
}
.form-success {
  background: var(--color-surface); border-radius: var(--radius-md);
  padding: var(--space-6); border: 1px solid var(--color-border);
}
.form-error {
  background: #fdecea; color: #8a1c14; border: 1px solid #f3b3ac;
  border-radius: var(--radius-sm); padding: var(--space-3) var(--space-4);
  margin-bottom: var(--space-4); font-size: var(--fs-small);
}

/* ---- Dunkler Hero mit Foto-Hintergrund (jede Seite mit body.has-hero-header) ---- */
.hero { position: relative; color: var(--color-on-dark); overflow: hidden; }
.hero__bg { position: absolute; inset: 0; z-index: 0; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; }
/* Abdunkler ueber dem Hero-Foto.
   Am Original gemessen (Startseite): EIN flaechiges Overlay, kein Verlauf -
   `background: rgba(0,0,0,.69)` auf einem Element mit `opacity: .45`, also
   effektiv Schwarz mit Alpha .69 x .45 = .31. Unser bisheriger Verlauf
   (.55 oben / .35 bei 35% / .69 unten) war an beiden Enden rund doppelt so
   dunkel; die Berge im Foto wirkten dadurch fast schwarz statt satt gruen.
   Der Wert wird als Variable gefuehrt, weil /starkregengefahrenkarten/
   bewusst davon abweicht (s. u. und docs/DECISIONS.md). */
.hero { --hero-scrim: rgba(0, 0, 0, .31); }
.hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: var(--hero-scrim);
}
.hero__content { position: relative; z-index: 2; padding-top: var(--space-9); padding-bottom: var(--space-8); }
.hero__eyebrow { font-weight: var(--fw-bold); font-size: var(--fs-eyebrow); line-height: var(--lh-eyebrow); color: #fff; max-width: 46ch; }
/* CSS-Hygiene-Fix (Design-Pass Lauf 3): war nur in unternehmen.css definiert,
   wurde aber auch auf /starkregenalarmsystem/ (fas.html) verwendet, das
   unternehmen.css nicht einbindet - dort blieb die Eyebrow dadurch auf dem
   Hero-Weiss (#fff) haengen = unsichtbar auf hellem Grund. Jetzt zentral in
   base.css neben der Basisklasse, analog zur bereits dokumentierten Regel
   "geteilte Hero-Styles gehoeren nach base.css". Siehe docs/DECISIONS.md. */
.hero__eyebrow--light { color: var(--color-brand-blue-text); }
/* Kein max-width mehr: das Original erzwingt Zeilenumbrueche der Hero-H1
   durch manuelle <br>-Tags im Text (kein CSS-Constraint, max-width:none
   gemessen) - Umbrueche sind jetzt 1:1 im Template nachgebildet
   (home.html/ews.html), s. docs/DECISIONS.md. */
/* Der 51px-Hero-Titel ist im Original AUSSCHLIESSLICH die Startseite. Alle
   uebrigen Seiten mit Hero (fas, ews, unternehmen, allianzen, veranstaltungen,
   forschung, referenzen) haben 32px, die reinen Textseiten 29px - bisher
   liefen alle 24 Seiten auf 51px. Groesste Einzelabweichung des Nachbaus.
   `h1` traegt jetzt global die 32px-Stufe, `.hero__title` (nur home.html)
   hebt auf 51px an. */
.hero__title { color: #fff; font-size: var(--fs-hero); line-height: var(--lh-hero); }

/* ---- Responsive ---- */
@media (max-width: 1199px) {
  /* ---- Fusszeile als Ausklappliste ----
     Das Original schaltet die vierspaltige Fusszeile unterhalb 1200px auf
     vier EINGEKLAPPTE Zeilen um (nachgemessen /opt/tooling/footdetail.mjs
     @390/768/810/1000/1199 - Hoehe durchgaengig 548px statt 412px auf
     Desktop). Bei uns standen alle Links ausgeklappt untereinander; die
     Fusszeile war dadurch auf JEDER Seite rund 300px zu hoch.
     Geometrie (Werte relativ zur Fusszeilen-Oberkante, 390px):
       Polster        51px 39px 0        (Inhaltsbreite 312px)
       Zeile 1        y=51,  46px hoch   (ohne oberes Polster)
       Zeilen 2-4     69px hoch          (23px oben + 23px Titel + 23px unten)
       Trennlinien    y=97/166/235/304, 1px, rgb(201,201,201)
       Titel          15px/700 Poppins, rgb(129,129,129)
       Plus-Symbol    15x15, rechtsbuendig (x=336), auf Titelmitte
       Sozial-Symbole 27x27, y=482, x=39/105/171/237 (Rasterabstand 66px) */
  .site-footer__columns {
    display: block; max-width: none; margin: 0;
    padding: 51px 39px 0;
  }
  .footer-col { border-bottom: 1px solid rgb(201, 201, 201); }
  .footer-col__title {
    border-bottom: 0; margin: 0;
    padding: 23px 0;
    /* Original: rgb(129,129,129) - das sind nur 3,0:1 und liess
       Lighthouse-A11y auf 96 fallen. --color-text-muted (#767676, 4,54:1)
       ist die AA-taugliche Entsprechung, wie ueberall sonst im Projekt. */
    color: var(--color-text-muted);
  }
  /* Die erste Zeile hat im Original kein oberes Polster - die Fusszeile
     beginnt direkt mit dem Titel. */
  .footer-col:first-child .footer-col__title { padding-top: 0; }
  .footer-col__plus {
    display: block; position: relative;
    width: 15px; height: 15px; flex: 0 0 15px;
  }
  .footer-col__plus::before,
  .footer-col__plus::after {
    content: ""; position: absolute; top: 50%; left: 50%;
    background: currentColor; transform: translate(-50%, -50%);
  }
  .footer-col__plus::before { width: 15px; height: 1px; }
  .footer-col__plus::after  { width: 1px; height: 15px; }
  /* Ausgeklappt wird aus dem Plus ein Minus. */
  .footer-col:not(.is-collapsed) .footer-col__plus::after { height: 0; }
  /* Eingeklappt: im Original height 0 + overflow hidden. Der Zustand haengt
     an der Klasse `is-collapsed`, die AUSSCHLIESSLICH per JS gesetzt wird -
     ohne JS bleibt die Fusszeile damit vollstaendig ausgeklappt und
     `aria-expanded` behaelt seinen Ausgangswert `true`. So kann Markup und
     Vorlesebaum nie auseinanderlaufen. */
  .footer-col__panel {
    overflow: hidden;
    transition: max-height var(--duration-nav) var(--ease), visibility var(--duration-nav) var(--ease);
  }
  .footer-col.is-collapsed .footer-col__panel {
    max-height: 0; visibility: hidden;
  }
  .footer-col__panel > ul { padding-bottom: 23px; }
  /* Fusszeilen-Abbinder, Werte relativ zur Fusszeilen-Oberkante (390px):
     Trennlinie der letzten Zeile 304, © 345, Impressum 382, Datenschutz 420,
     Sozial-Symbole 482 (27x27), Fusszeilenende 548. */
  .site-footer__bottom {
    max-width: none; margin: 0; border-top: 0;
    padding: 39px;
    flex-direction: column; align-items: flex-start; gap: 15px;
  }
  .footer-legal { flex-direction: column; gap: 15px; }
  /* Original @390: ©=footer+345, Zeilenschritt 37.5 (Abstand 15), Symbole
     +24px unter "Datenschutz", Block 51 hoch, darunter 39 - Fusszeilenende
     footer+547.5. Frueher 40/14/25; zudem liefen die Symbol-Anker inline
     (Zeilenhoehe + 27px-SVG = 33.5) - die Fusszeile endete sitewide 6.5px
     zu tief (Lauf 5). */
  .footer-social { gap: 39px; padding-top: 24px; }
  .footer-social a { display: flex; }
  .footer-social svg { width: 27px; height: 27px; }
  /* ---- Seitenrand ----
     Unterhalb 1200px setzt das Original den Seitenrand ueberwiegend auf 39px
     (nachgemessen /opt/tooling/cpad.mjs - haeufigste linke Textkante auf
     /kontakt/, /forschung/, /impressum/, /allianzen/, /datenschutz/ und in
     Kopf-/Fusszeile). Drei Seiten weichen ab und setzen ihn in ihrer eigenen
     CSS-Datei zurueck: /unternehmen/, /starkregenalarmsystem/ und
     /veranstaltungen/ auf 23px, /starkregengefahrenkarten/ auf 20px.
     Bisher galt sitewide --space-5 (24px). */
  :root { --container-pad: 39px; }
  .container { max-width: none; }

  /* Original unterhalb 1200px: Kopfzeile 39px Seitenpolster (Logo l=39,
     Menue-Icon endet 39px vor der rechten Kante - bei 1199/810/768/390
     identisch nachgemessen), Ankuendigungsleiste 23px. */
  .site-header__inner { padding: 0 39px; }
  .announce-bar__inner { padding: 23px; justify-content: flex-start; }
  /* Unterhalb 1200px rutscht die Leiste UNTER die Kopfzeile und legt sich
     damit ueber den Seiteninhalt (Original-Verhalten, s. oben und
     docs/DECISIONS.md). z-index bleibt unter dem der Kopfzeile - genau wie
     im Original, wo beide auf z-index 3 stehen und die Leiste nur durch die
     spaetere DOM-Position darueber liegt. */
  .announce-bar { top: 74px; z-index: 39; }
  /* Das Original blendet die Leiste unterhalb 1200px beim Scrollen aus
     (opacity 0 ab scrollY>0, nachgemessen /opt/tooling/scrolled.mjs).
     Genau dieses Verhalten ist zugleich das einzige, was den verdeckten
     Text ueberhaupt wieder freigibt. */
  .announce-bar { transition: opacity var(--duration-fast) var(--ease); }
  .announce-bar.is-hidden { opacity: 0; pointer-events: none; }

  /* ---- Navigation ----
     Das Original klappt die Hauptnavigation schon bei 1200px ins Menue-Symbol
     ein, nicht erst bei 810px (nachgemessen /opt/tooling/burger.mjs: bei
     1199/1000/810/390 steht durchgaengig das 30x23-Symbol rechts, die
     Nav-Punkte sind ausgeblendet). Bei uns lief die Umschaltung bei 809px -
     zwischen 810 und 1199px stand deshalb die volle Desktop-Navigation. */
  /* Echte Extraktion Mobil (390, Original-Menue KORREKT geoeffnet und
     vermessen, /opt/tooling/m11-mob*.mjs + Frame-Sampler be-sample*.mjs):
     das Menue ist ein VOLLFLAECHIGES weisses Overlay, das sich beim Oeffnen
     als weisse Flaeche von der Kopfzeile aus nach UNTEN AUFZIEHT (Hoehe
     74 -> 844 in ~300-330ms, ease-in-out-Kurve). Die Inhalte stehen dabei
     schon an ihren Endpositionen (kein Hereinschieben, KEINE Staffelung),
     werden aber NICHT nur von der Flaeche freigegeben, sondern FADEN
     SYNCHRON zur Hoehen-Animation ein (opacity 0 -> 1, gleiche ~300ms,
     gemessen pro rAF-Frame: op .005/.094/.306/.497/.772/.946/1 waehrend die
     Flaeche 80/156/321/468/678/820/844 hoch ist). Schliessen ist exakt die
     Rueckwaertsfahrt (Hoehe 844 -> 74 UND opacity 1 -> 0, ~300ms).
     Das Logo verschwindet im offenen Menue (Overlay deckt es), der
     Doppelbalken bleibt beim OEFFNEN unveraendert Doppelbalken (die
     Framer-Variante "Clicked" mit X-Morph laeuft im Original dem Zustand
     einen Klick hinterher und zeigt das X erst im GESCHLOSSENEN Menue -
     ein Original-Bug, den wir bewusst nicht nachbauen).
     Ebene 1: fuenf Punkte linksbuendig bei x=39 ab y=113, Poppins 29/700
     rgb(129,129,129), 39px Luecke (Zeilenraster 74px); unten der Kontaktblock
     (Telefon + E-Mail, ebenfalls 29/700 mit Original-Symbolen, 39px unterm
     letzten Eintrag Platz zum Rand).
     Ebenenwechsel: Tipp auf Loesungen/Unternehmen schiebt die GANZE Ebene
     nach links hinaus (translateX -100%/-200%, ~350ms ease-in-out), die
     Unterebene gleitet von rechts herein; oben links erscheint an der
     Logo-Position ein Zurueck-Chevron (13x23). KEINE Akkordeons. */
  /* Geschlossen steht das Panel unsichtbar auf Kopfzeilen-Hoehe (74px) -
     die Hoehen-Fahrt laeuft dadurch exakt wie im Original 74 -> 844 statt
     0 -> 844. visibility (statt height:0) nimmt die Menue-Links im
     geschlossenen Zustand zugleich aus der Tab-Reihenfolge; die 0s-Fahrt
     mit .3s-Verzoegerung haelt das Panel waehrend der Zufahrt sichtbar. */
  .primary-nav {
    position: fixed; top: 0; left: 0; width: 100%; height: 74px;
    background: #fff; overflow: hidden; z-index: 60;
    visibility: hidden;
    transition: height .3s ease-in-out, visibility 0s linear .3s;
  }
  .primary-nav.is-open {
    height: 100vh; height: 100dvh; overflow-y: auto;
    visibility: visible;
    transition: height .3s ease-in-out, visibility 0s;
  }
  /* Die <ul> ist die gleitende Ebenen-Schiene: transform != none macht sie
     zugleich zum Bezugsrahmen fuer die absolut positionierten Unterebenen.
     Der Inhalt (alle Ebenen inkl. Kontaktblock) FADET synchron zur
     Hoehen-Fahrt des Panels - Frame-Messung s. Kommentar oben. */
  .primary-nav > ul {
    flex-direction: column; align-items: flex-start; gap: 39px;
    width: 100%; min-height: 100vh; min-height: 100dvh;
    padding: 113px 39px 39px;
    transform: translateX(0);
    opacity: 0;
    transition: transform .35s ease-in-out, opacity .3s ease-in-out;
  }
  .primary-nav.is-open > ul { opacity: 1; }
  /* Bewegungsreduzierung: sofort offen/zu - die globale Regel kuerzt zwar
     alle Dauern, aber nicht die .3s-visibility-VERZOEGERUNG der Zufahrt. */
  @media (prefers-reduced-motion: reduce) {
    .primary-nav { transition-delay: 0s; }
  }
  .primary-nav.is-sub-loesungen > ul { transform: translateX(-100%); }
  .primary-nav.is-sub-unternehmen > ul { transform: translateX(-200%); }
  .primary-nav > ul > li { width: 100%; }
  /* :not(.nav-contact) - die Kontaktzeilen im selben <ul> haben ein eigenes
     Flex-Layout (Symbol + Text) und duerfen hier nicht mitgetroffen werden. */
  .primary-nav > ul > li:not(.nav-contact) > .nav-link,
  .primary-nav > ul > li:not(.nav-contact) > a { display: inline-block; font-size: 29px; line-height: 1.2; color: #818181; }
  /* Unterebenen: vollflaechige Tafeln rechts neben Ebene 1 auf der Schiene
     (Loesungen bei 100%, Unternehmen bei 200%). main.js schaltet .is-open
     (Sichtbarkeit) + die is-sub-Klasse (Gleiten). */
  .primary-nav .dropdown {
    position: absolute; top: 0; left: 100%; right: auto;
    width: 100%; min-height: 100%; margin: 0;
    padding: 113px 39px 39px; box-shadow: none; border-radius: 0;
    background: #fff;
  }
  .primary-nav .dropdown--un { left: 200%; }
  .primary-nav .dropdown::before { display: none; }
  /* Loesungen-Ebene: Wortmarke + Beschreibung + "Mehr erfahren" schlicht
     gestapelt bei x=39 (KEINE Einrueckung, KEINE Farbflaechen/Hover-Karten,
     Original: Logo 296px, Beschreibung max 312px, zweiter Block 50px unterm
     ersten). */
  .primary-nav .mega { flex-direction: column; }
  .primary-nav .mega-card { padding: 0; justify-content: flex-start; color: #818181; }
  .primary-nav .mega-card + .mega-card { border-left: 0; margin-top: 50px; }
  .primary-nav .mega-card--fas:hover, .primary-nav .mega-card--fas:active,
  .primary-nav .mega-card--ews:hover, .primary-nav .mega-card--ews:active { background: transparent; }
  .primary-nav .mega-card:hover .mega-card__logo--rest { opacity: 1; }
  .primary-nav .mega-card:hover .mega-card__logo--hover { opacity: 0; }
  .primary-nav .mega-card:hover .mega-card__desc { color: #818181; }
  .primary-nav .mega-card__desc { margin: 0 0 23px; max-width: 312px; }
  .primary-nav .mega-card__more { margin-left: 0; }
  /* Unternehmen-Ebene: gestapelte Punkte (Titel 23/700 + Beschreibung 15/400,
     12px unter dem Titel, 30px zwischen den Punkten). Eyebrow/Haarlinie und
     Aufmacherkarte gibt es auf Mobil nicht. */
  .primary-nav .mega-links { padding: 0; }
  .primary-nav .mega-links__eyebrow { display: none; }
  .primary-nav .mega-links__grid { display: flex; flex-direction: column; gap: 30px; }
  .primary-nav .mega-link { font-size: 23px; line-height: 1.2; }
  .primary-nav .mega-item__desc { margin-top: 12px; }
  /* Die harten Desktop-Umbrueche der "Aktuelles"-Beschreibung entfallen auf
     Mobil (Original: dort zweizeilig fliessend). */
  .primary-nav .mega-item__desc br { display: none; }
  .primary-nav .mega-feature { display: none; }
  /* Desktop-Backdrop bleibt auf Mobil aus (Overlay ist bereits vollflaechig). */
  .nav-backdrop { display: none; }
  /* Der Doppelbalken muss UEBER dem Overlay liegen (bleibt im offenen Menue
     sichtbar und schliesst es wieder - wie das Original). */
  .nav-toggle { display: flex; z-index: 70; }

  /* Zurueck-Chevron auf Ebene 2: an der Logo-Position (39/26, 13x23), Farbe
     wie der Doppelbalken. position:fixed, damit es beim Gleiten der Schiene
     und beim Scrollen stehen bleibt (Vorfahre .primary-nav traegt selbst
     keinen transform). */
  .nav-back {
    display: block; position: fixed; top: 26px; left: 39px;
    width: 13px; height: 23px; padding: 0; border: 0; background: none;
    color: rgb(129, 129, 129); z-index: 70;
  }
  .nav-back[hidden] { display: none; }
  .nav-back svg { display: block; width: 100%; height: 100%; }
  /* Tippflaeche auf 44x44 vergroessern - gleiches Muster wie .nav-toggle. */
  .nav-back::before {
    content: ""; position: absolute; top: 50%; left: 50%;
    width: 44px; height: 44px; transform: translate(-50%, -50%);
  }

  /* Kontaktblock am Fuss von Ebene 1 (Telefon + E-Mail), Original: 29/700
     grau, Zeilenraster 74px (39px Luecke), Symbole 26x33 / 37x27 mit 18px
     Abstand zum Text. margin-top:auto drueckt ihn an die Unterkante. */
  .nav-contact { display: flex; flex-direction: column; gap: 39px; margin-top: auto; padding-top: 48px; }
  /* a.-Spezifitaet noetig: schlaegt die allgemeine `.primary-nav a`-Regel
     (15px) aus dem Desktop-Teil. */
  .primary-nav a.nav-contact__item { display: inline-flex; align-items: center; gap: 18px; font-size: 29px; line-height: 1.2;
    font-weight: var(--fw-bold); font-family: var(--font-heading); color: #818181; }
  .nav-contact__item svg { flex: none; }
  .nav-contact__item--tel svg { width: 26px; height: 33px; }
  .nav-contact__item--mail svg { width: 37px; height: 27px; }
  /* Auf Mobil ist die Kopfzeile IMMER weiss (die Ankuendigungsleiste schiebt
     sie unter den Hero) - die Nav-Schrift muss daher immer grau sein, auch im
     Nicht-gescrollten Zustand. Selektoren mit :not(.is-scrolled) matchen die
     Spezifitaet der Ueber-Hero-Weiss-Regel und stehen spaeter -> gewinnen.
     Farbe: Original-Messwert rgb(129,129,129) - die Menuetexte sind nur im
     geoeffneten (JS-)Overlay sichtbar, s. Farbkommentar im Mega-Block. */
  body.has-hero-header .site-header:not(.is-scrolled) .nav-link,
  body.has-hero-header .site-header:not(.is-scrolled) .primary-nav a,
  body.has-hero-header .site-header .nav-link,
  body.has-hero-header .site-header .primary-nav a { color: #818181; }

  /* Das Brief-Symbol steht im Original NUR ab 1200px in der Kopfzeile
     (nachgemessen: unterhalb bleiben nur Wortmarke links und Menue-Symbol
     rechts). Es hat das Menue-Symbol bei uns aus seiner Position gedraengt. */
  .site-header .icon-btn--mail { display: none; }

  /* Auf Seiten mit dunklem Hero liegt die Kopfzeile nur AB 1200px transparent
     ueber dem Bild. Darunter schiebt sich die Ankuendigungsleiste zwischen
     Kopfzeile und Hero, die Kopfzeile ist dort weiss mit dunkler Wortmarke
     (nachgemessen an der Startseite @390: Kopfzeilenflaeche rgb(255,255,255),
     Wortmarke rgb(131,131,131)). Bei uns stand dort die weisse Wortmarke auf
     weissem Grund - praktisch unsichtbar. */
  body.has-hero-header .site-header {
    background: #fff; box-shadow: 0 0 47px rgba(0, 0, 0, .23);
  }
  body.has-hero-header .site-logo__img--light { display: none; }
  body.has-hero-header .site-logo__img--dark { display: inline-flex; }
}
@media (max-width: 480px) {
  /* Die Typo-Umschaltung lag frueher hier (--fs-h1: 34px / --fs-h2: 24px ab
     480px) - beides falscher Umbruchpunkt und falsche Werte. Das Original
     schaltet bei 1200px und 810px; die Stufen stehen jetzt zentral in
     tokens.css. Diese Query regelt nur noch das Footer-Layout. */
  .site-footer__columns { grid-template-columns: 1fr; }
  .site-footer__bottom { flex-direction: column; align-items: flex-start; }
}

/* --- Bewegungssystem (reveal.js) --------------------------------------
   Framer blendet Inhalte beim Scrollen sanft ein. Nachbau in reinem JS.
   Progressive Enhancement: der versteckte Anfangszustand gilt NUR, wenn
   reveal.js aktiv ist (data-reveal-ready="on"). Ohne JS bleibt alles
   sichtbar — kein leerer Bildschirm bei Skriptfehler. */
/* Die Einblendung nutzt die EIGENSTAENDIGE `translate`-Eigenschaft (nicht
   `transform`). So bleibt `transform` frei fuer die Hover-Anhebungen: ein
   Reveal-Ziel (z.B. .hero-card) kann sich beim Hover anheben, ohne dass der
   Reveal-Endzustand die Anhebung ueberschreibt - beide Eigenschaften
   ueberlagern sich, statt sich per Spezifitaet zu verdraengen. */
html[data-reveal-ready="on"] [data-reveal] {
  opacity: 0;
  translate: 0 var(--reveal-shift);
  transition: opacity var(--reveal-duration) var(--ease-smooth),
              translate var(--reveal-duration) var(--ease-smooth);
  will-change: opacity, translate;
}
html[data-reveal-ready="on"] [data-reveal][data-inview] {
  opacity: 1;
  translate: 0 0;
}
@media (prefers-reduced-motion: reduce) {
  html[data-reveal-ready] [data-reveal] {
    opacity: 1 !important;
    translate: none !important;
    transform: none !important;
    transition: none !important;
  }
}

/* Zweistufige Pfadleiste (Blogartikel) mobil: das Original bricht in ZWEI
   Zeilen um - Zeile 1: Auge > Aktuelles, Zeile 2: Artikeltitel volle Breite
   (390px: Zeilen y2232/y2278, Bandhoehe 115; Vergleichslauf 2026-07-24).
   Ohne diese Regel quetschte sich alles in eine Zeile: das Auge schrumpfte
   auf 20px, "Aktuelles" brach vertikal um. */
@media (max-width: 1199px) {
  .pfadleiste--zweistufig { flex-wrap: wrap; }
  .pfadleiste--zweistufig > * { flex-shrink: 0; }
  .pfadleiste--zweistufig .pfadleiste__seite[aria-current="page"] {
    flex-basis: 100%; margin-top: 0;
  }
  /* Der Winkel vor dem Titel entfaellt mobil (das Original zeigt in Zeile 2
     nur den Titel). */
  .pfadleiste--zweistufig .pfadleiste__winkel:nth-of-type(2) { display: none; }
}

/* Pfeile in Buttons/Links: das Original zeichnet einen 20x12-SVG-Pfeil mit
   langem Schaft (kein Unicode-Glyph; @390 deutlich sichtbar duenner/kuerzer).
   Vergleichslauf 2026-07-24. */
.arrow-ico { display: inline-flex; align-items: center; line-height: 0; }

/* Dezenter Fliesstext-Link (SEO-Querverweise u. ae.) - dieselbe Sprache
   wie die Blog-Inline-Links: Markenblau, Unterstrich, dunkelt beim Hover. */
.text-link {
  color: var(--color-brand-blue-text); text-decoration: underline;
  transition: color var(--duration-hover) var(--ease-smooth);
}
.text-link:hover { color: #0065c8; }
