/* ============================================================
   PWR Innovia — Redesign 2026
   Token-CSS, handgeschrieben. Wahrheit für das Design-System.

   Quelle der Werte: pwr_designs/mockups/Styleguide.dc.html (Desktop)
   und HomeMobil.dc.html (Mobile). Regeln + Komponentenliste:
   docs/design-system.md · Architekturentscheidung: docs/adr/0008-*.md

   Aufbau:
     01 Fonts        02 Tokens       03 Basis        04 Layout
     05 Typografie   06 Buttons      07 Komponenten  08 Header
     09 Footer       10 Responsive   11 Motion
   ============================================================ */

/* ============================================================
   01 · Fonts (lokal gehostet — kein externer Server-Kontakt)
   Relative Pfade bewusst beibehalten (Vorsorge für späteren
   Vite-Build, siehe ADR-0008).
   ============================================================ */

/* --- Poppins (Body) --- */
/* latin-ext */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/poppins-400-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('../fonts/poppins-400-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/poppins-500-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 500;
    font-display: swap;
    src: url('../fonts/poppins-500-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* latin-ext */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/poppins-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Poppins';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/poppins-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* --- Playfair Display (Display) — nur 600, kein Kursivschnitt --- */
/* latin-ext */
@font-face {
    font-family: 'Playfair Display';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/playfair-display-600-latin-ext.woff2') format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
    font-family: 'Playfair Display';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('../fonts/playfair-display-600-latin.woff2') format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ============================================================
   02 · Tokens
   Einzige Quelle für Farben, Typo-Skala und Abstände.
   Im Stylesheet unterhalb dieses Blocks steht kein Farb- oder
   Schriftgrößen-Rohwert mehr (siehe docs/design-system.md).
   ============================================================ */
:root {
    /* --- Flächen und Farben --- */
    --c-navy: #0D1E44;              /* dunkle Sektionen, Buttons */
    --c-steel: #2D5C88;             /* Headlines auf hell, Links */
    --c-orange: #F7941E;            /* Akzent, Schlüsselwörter */
    --c-offwhite: #F0EEE9;          /* helle Flächen */
    --c-white: #FFFFFF;             /* Karten, Bänder */
    /* Grautöne halten auf Off-White mindestens 4,5:1 (WCAG AA für Text unter
       18,66 px). Die alten Werte lagen bei 4,0:1 (meta) und 2,2:1 (label) —
       Rangfolge läuft über Größe und Versalien, nicht über Helligkeit. */
    --c-text: #46505E;              /* Fließtext auf hell — 7,0:1 */
    --c-meta: #5A6473;              /* Meta-Text, Kartenbeschreibung — 5,2:1 */
    --c-label: #636C7B;             /* Labels, Daten — 4,6:1 */
    --c-node: #5B84AC;              /* Grafik-Knoten in den SVGs */

    /* Auf Navy */
    --c-on-navy: rgba(255, 255, 255, 0.78);         /* Fließtext */
    --c-on-navy-soft: rgba(255, 255, 255, 0.75);
    --c-on-navy-link: rgba(255, 255, 255, 0.75);
    --c-on-navy-muted: rgba(255, 255, 255, 0.6);
    --c-on-navy-label: rgba(255, 255, 255, 0.45);
    --c-on-navy-faint: rgba(255, 255, 255, 0.5);
    --c-on-navy-border: rgba(255, 255, 255, 0.55);  /* Outline-Buttons */

    /* Formular-Rückmeldungen. Beide Werte nachgerechnet: auf Weiß 6,5:1
       (error) und 6,5:1 (success), auf Off-White 5,6:1 und 5,6:1 — eine
       Fehlermeldung muss auch dort über AA liegen, sie ist der einzige
       Hinweis darauf, dass etwas nicht abgeschickt wurde. */
    --c-error: #B3261E;
    --c-success: #1E6B45;

    /* Linien und Ränder */
    --c-rule: rgba(13, 30, 68, 0.3);                /* Trennlinien hell */
    --c-rule-on-navy: rgba(255, 255, 255, 0.3);     /* Trennlinien dunkel */
    --c-card-border: rgba(13, 30, 68, 0.14);
    --c-badge-border: rgba(247, 148, 30, 0.6);
    --c-scrim: rgba(13, 30, 68, 0.45);              /* Overlay hinter Dialogen */
    --c-scrim-media: rgba(13, 30, 68, 0.75);        /* Verlauf ueber Kartenbildern */
    /* Fast deckend, und bewusst neutral statt navy: hinter einem freigestellten
       Projektfoto soll keine Farbe mitsprechen. */
    --c-scrim-lightbox: rgba(0, 0, 0, 0.92);

    /* --- Typografie --- */
    --font-display: 'Playfair Display', Georgia, serif;
    --font-body: 'Poppins', 'Segoe UI', system-ui, sans-serif;

    --fs-h1: 62px;
    --lh-h1: 1.12;
    --fs-h1-page: 56px;             /* H1 der Unterseiten (Seitenkopf) */
    --fs-h1-artikel: 38px;          /* H1 der Beitragsdetailseite */
    --fs-h2: 44px;
    --lh-h2: 1.18;
    --fs-h3: 21px;
    --lh-h3: 1.3;
    --fs-h4: 20px;                  /* Karten-Titel News */
    --fs-display-sm: 28px;          /* Bild-Untertitel, Zwischenaussagen */
    --fs-stat: 64px;

    --fs-lead: 17px;                /* Hero-Fließtext */
    --fs-body: 16px;
    --lh-body: 1.7;
    --fs-ui: 14px;                  /* Buttons, Navigation, Textlinks */
    --fs-sm: 13.5px;                /* Karten-Fließtext */
    --lh-sm: 1.6;
    --fs-card-title: 16.5px;        /* Titel in der nummerierten Liste */
    --fs-card-desc: 15px;           /* Beschreibung in der nummerierten Liste */
    --fs-row-title: 15.5px;         /* Titel in der Icon-Liste (Branchen) */
    --fs-faq-question: 16px;        /* aufklappbare FAQ-Zeile */
    --fs-faq-answer: 14.5px;        /* FAQ-Antworttext */
    --fs-meta: 13px;
    --fs-label: 12px;               /* Kicker, Daten */
    --fs-fineprint: 12.5px;         /* Footer-Fusszeile */
    --fs-eyebrow: 11px;             /* Footer-Spaltentitel */
    --fs-micro: 10.5px;             /* Badges, Kategorien */

    --ls-kicker: 2.6px;
    --ls-eyebrow: 2px;              /* Footer-Spaltentitel */
    --ls-num: 1.8px;                /* Ordnungszahlen 01…07 */
    --ls-micro: 1.4px;
    --ls-ui: 0.3px;

    /* --- Raster und Abstände --- */
    /* Die Seite wächst nicht endlos mit: 1440px ist die Entwurfsbreite
       (--container plus zweimal --gutter), auf breiteren Monitoren bleiben
       seitliche Ränder stehen. Ohne diese Grenze wachsen die Sektionsflächen
       und das Hero-Motiv über ihre Auflösung hinaus. */
    --site-max: 1440px;
    --container: 1210px;
    --gutter: 115px;
    --section-y: 100px;
    --section-y-sm: 72px;           /* Kennzahlen-Band */
    --section-y-lg: 110px;          /* Kontakt-Band */
    --header-h: 92px;

    --gap-grid: 32px;               /* Karten-Grid */
    --gap-cols: 40px;               /* Textspalten-Grid */
    --gap-split: 60px;              /* Text + Visual */
    --gap-stack: 22px;              /* Sektionskopf-Innenabstand */
    --gap-inline: 16px;             /* Button-Gruppen */

    --measure: 820px;               /* Lesebreite Sektionskopf */
    --measure-narrow: 720px;

    /* --- Formen --- */
    --radius: 2px;                  /* Buttons, Badges — bewusst fast kantig */
    --rule-w: 1px;
    --bar-w: 2px;                   /* Kicker-Strich */
    --bar-h: 16px;
    --icon-circle: 52px;
    --logo-marquee-h: 72px;         /* Zertifikatslogos („Über uns") */
    --field-h: 52px;                /* Eingabefeld, Höhe der Klickfläche */
    --map-h: 520px;                 /* Standortkarte (Kontakt) */
    --border-strong: 1.5px;

    /* --- Verläufe und Masken ---
       Als ganze Werte hinterlegt, nicht als Einzelfarben: ein Verlauf braucht
       mehrere Alphastufen derselben Farbe, und die gehören nicht als Rohwerte
       unter den Token-Block (Regel 1, docs/design-system.md). */
    --grad-hero-veil: linear-gradient(
        to right,
        rgba(13, 30, 68, 0.95) 0%,
        rgba(13, 30, 68, 0.8) 38%,
        rgba(13, 30, 68, 0) 68%
    );
    --grad-hero-veil-tight: linear-gradient(
        to right,
        rgba(13, 30, 68, 0.96) 0%,
        rgba(13, 30, 68, 0.88) 50%,
        rgba(13, 30, 68, 0.35) 100%
    );
    /* Blendet die obere Bildkante in die Sektionsfläche; nur der Alphaverlauf
       zählt, die Farbe ist bedeutungslos. */
    --mask-fade-top: linear-gradient(to bottom, transparent 0, rgba(0, 0, 0, 1) 18%);
    /* Dasselbe für die linke Kante eines eingerückten Seitenkopf-Motivs. Ohne
       sie stünde dort eine harte Kante: der Bildgrund (#061D47) und die
       Sektionsfläche (#0D1E44) liegen nah beieinander, aber nicht aufeinander,
       und die Wellenlinien des Motivs brächen mitten im Bild ab. */
    --mask-fade-left: linear-gradient(to right, transparent 0, rgba(0, 0, 0, 1) 16%);
    /* Weiche Kanten des Zertifikats-Laufbands. Als Verlauf über der
       Sektionsfläche, nicht als `mask-image`: eine Maske über einem animierten
       Layer wird auf iOS pro Frame neu angewendet und kostet dort Frames
       (ib-rieker, dort gemessen). Setzt eine Off-White-Sektion voraus. */
    --grad-marquee-fade-l: linear-gradient(to right, rgba(240, 238, 233, 1), rgba(240, 238, 233, 0));
    --grad-marquee-fade-r: linear-gradient(to left, rgba(240, 238, 233, 1), rgba(240, 238, 233, 0));

    /* --- Motion --- */
    --t-fast: 0.2s ease;
    --t-base: 0.35s ease;
    --t-hero-text: 0.7s;            /* Hero-Kaskade je Baustein */
    --t-hero-motiv: 1s;             /* Einfahrt des Hero-Motivs */
}

/* ============================================================
   03 · Basis
   ============================================================ */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    /* Pflicht-Kombi gegen horizontalen Scroll bei AOS-Fades,
       siehe docs/frontend-standards.md §2 */
    overflow-x: clip;
    scroll-behavior: smooth;
    /* Fläche neben der begrenzten Seite. Muss am html-Element stehen: sonst
       überträgt der Browser den Body-Hintergrund auf das ganze Canvas und die
       Ränder wären nicht vom Inhalt zu unterscheiden. */
    background: var(--c-offwhite);
}

body {
    /* Klare Seitengrenze statt Mitwachsen bis zur Monitorbreite */
    max-width: var(--site-max);
    margin: 0 auto;
    overflow-x: hidden;
    background: var(--c-white);
    color: var(--c-text);
    font-family: var(--font-body);
    font-size: var(--fs-body);
    font-weight: 400;
    line-height: var(--lh-body);
    -webkit-font-smoothing: antialiased;
}

img,
svg {
    max-width: 100%;
}

img {
    height: auto;
}

a {
    color: var(--c-steel);
    text-decoration: none;
    transition: color var(--t-fast);
}

a:hover {
    color: var(--c-orange);
}

p {
    margin: 0;
}

ul {
    margin: 0;
    padding: 0;
    list-style: none;
}

button {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    cursor: pointer;
}

:focus-visible {
    outline: var(--bar-w) solid var(--c-orange);
    outline-offset: 3px;
}

.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 100;
    padding: 12px 20px;
    background: var(--c-navy);
    color: var(--c-white);
    font-size: var(--fs-ui);
}

.skip-link:focus {
    left: 0;
    color: var(--c-white);
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ============================================================
   04 · Layout
   ============================================================ */

/* Inhaltsbreite 1210px + Gutter — bei 1440px Viewport ergibt das
   genau das Raster der Mockups (115px Außenabstand). */
.container {
    width: 100%;
    max-width: calc(var(--container) + 2 * var(--gutter));
    margin: 0 auto;
    padding: 0 var(--gutter);
}

.section {
    padding: var(--section-y) 0;
    background: var(--c-white);
}

/* Off-White-Sektionen tragen das Blueprint-Motiv als Grundmuster. Die Grafik hat
   einen transparenten Grund, damit die Sektionsfarbe exakt durchscheint
   (docs/assets.md); sie sitzt am unteren Rand und läuft über die volle Breite.
   Das `?v=` bustet den Browser-Cache: der Dateiname bleibt gleich, wenn sich die
   Deckkraft des Motivs ändert (zuletzt 02.09.2026, Alpha x4). */
.section--offwhite {
    background-color: var(--c-offwhite);
    background-image: url('../images/decor/blueprint-offwhite.webp?v=2');
    background-repeat: no-repeat;
    background-position: center bottom;
    background-size: 100% auto;
}

/* Zweiter Ausschnitt derselben Grafik: oben liegt der ruhige Teil (Raster und
   Achsen), unten die Wellen. Off-White-Sektionen wechseln sich damit ab, sonst
   endet jede von ihnen mit demselben Wellenband. */
.section--decor-top {
    background-position: center top;
}

/* Ohne Grundmuster. Fuer Off-White-Sektionen, die selbst eine Grafik tragen:
   die Startseiten-Sektion „Ueber PWR Innovia" zeigt die Standortkarte, und
   Blueprint-Raster und Kartenlinien konkurrieren im selben Bild
   (User, 03.09.2026). */
.section--decor-none {
    background-image: none;
}

.section--navy {
    background: var(--c-navy);
    color: var(--c-on-navy);
}

.section--band {
    padding: var(--section-y-sm) 0;
}

.section--cta {
    padding: var(--section-y-lg) 0;
}

/* --- Hero mit vollflächigem Motiv ---
   Fokuspunkt als Variable, damit der Beschnitt je Breakpoint steuerbar bleibt
   (gleiches Prinzip wie `--tga-image-focus` in ib-rieker, ADR-0010/0011).
   Der Startseiten-Hero ist durch den zweiabsätzigen Lead deutlich höher als
   das 2,45:1-Motiv, `cover` skaliert es entsprechend hoch. Ein Fokus rechts
   schnitte dann links weg und schöbe den Baukörper unter den Text — deshalb
   rechts beschneiden, auf allen Desktop-Breiten gleich (User, 13.10.2026). */
.hero {
    --hero-focus: 40% center;
    position: relative;
    overflow: hidden;
    min-height: 560px;
    display: flex;
    align-items: center;
}

/* Seitenkopf mit Motiv (Leistungen) — dieselbe Mechanik wie der Startseiten-Hero,
   nur flacher: die Unterseiten tragen Kicker, H1 und Lead statt zusätzlich
   Buttons. Ohne Motiv bleibt `.page-hero` die reine Navy-Fläche. */
.page-hero--media {
    --hero-focus: 72% center;
    position: relative;
    overflow: hidden;
    min-height: 420px;
    display: flex;
    align-items: center;
}

/* Das Motiv liegt hinter dem Text, nicht als CSS-Background: nur ein echtes
   <img> kann der Browser als LCP früh priorisieren. */
.hero__bg,
.page-hero__bg {
    position: absolute;
    inset: 0;
    z-index: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    /* Der Baukörper sitzt rechts, der Textfreiraum links — beim Beschnitt
       zuerst links wegnehmen. */
    object-position: var(--hero-focus);
}

/* Lesbarkeitsschleier, kein Deko-Element: je schmaler der Viewport, desto
   weiter rückt der helle Baukörper unter den Text. */
.hero::before,
.page-hero--media::before {
    content: '';
    position: absolute;
    inset: 0;
    z-index: 1;
    /* Ueberschreibbar ueber die Prop `veil` an x-page-hero: bringt ein Motiv
       seinen dunklen Grund selbst mit, verdunkelt der Schleier nur das Bild,
       ohne fuer die Headline etwas beizutragen (Kontaktseite, nachgemessen). */
    background: var(--hero-veil, var(--grad-hero-veil));
}

.hero__inner,
.page-hero--media .container {
    position: relative;
    z-index: 2;
}

/* Der Hero baut sich beim Laden auf — bewusst als CSS-Animation, nicht über
   AOS: AOS ist scroll-getriggert und ließe die H1 bis zum Trigger auf
   `opacity: 0`. Genau das war der NO_LCP-Fall mit Performance-Score 0
   (docs/performance.md). Eine Ladeanimation läuft immer und ist nach
   knapp einer Sekunde durch. Das Motiv selbst bleibt unanimiert — es ist
   das LCP-Element und soll sofort stehen. */
@keyframes hero-auftritt {
    from {
        opacity: 0;
        transform: translateY(18px);
    }
    to {
        opacity: 1;
        transform: none;
    }
}

.hero__text > * {
    animation: hero-auftritt var(--t-hero-text) ease-out both;
}

.hero__text > *:nth-child(1) { animation-delay: 0.08s; }   /* Kicker */
.hero__text > *:nth-child(2) { animation-delay: 0.20s; }   /* Headline */
.hero__text > *:nth-child(3) { animation-delay: 0.34s; }   /* Lead */
.hero__text > *:nth-child(4) { animation-delay: 0.48s; }   /* Buttons */

/* Das Motiv fährt von rechts ein — bewusst nur `transform`, ohne Deckkraft:
   als LCP-Element muss es vom ersten Frame an gemalt sein, sonst misst
   Lighthouse wieder kein LCP. Die Sektion clippt per `overflow: hidden`. */
@keyframes hero-motiv {
    from {
        transform: translateX(56px);
    }
    to {
        transform: none;
    }
}

.hero__bg,
.page-hero__bg {
    animation: hero-motiv var(--t-hero-motiv) cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

/* Der Seitenkopf bekommt dieselbe Ladekaskade wie der Startseiten-Hero —
   ohne AOS, weil die H1 sonst bis zum Scroll-Trigger unsichtbar bliebe
   (NO_LCP, docs/performance.md). Gilt nur mit Motiv: die reinen
   Navy-Seitenköpfe der Stubs animieren ihren Lead weiter über AOS. */
.page-hero--media .page-hero__inner > * {
    animation: hero-auftritt var(--t-hero-text) ease-out both;
}

.page-hero--media .page-hero__inner > *:nth-child(1) { animation-delay: 0.08s; }   /* Kicker */
.page-hero--media .page-hero__inner > *:nth-child(2) { animation-delay: 0.20s; }   /* Headline */
.page-hero--media .page-hero__inner > *:nth-child(3) { animation-delay: 0.34s; }   /* Lead */

.hero__text {
    display: flex;
    flex-direction: column;
    /* Bewusst großzügiger als `--gap-stack` (22px) der übrigen Textblöcke —
       der Hero trägt die Seite und darf atmen. */
    gap: 28px;
    max-width: 560px;
}

/* Mehrere Lead-Absätze bilden ein Flex-Kind, damit die gestaffelte
   Auftritt-Animation (nth-child oben) bei vier Kindern bleibt. */
.hero__lead {
    display: flex;
    flex-direction: column;
    gap: var(--gap-stack);
}

/* Text + Visual nebeneinander (Hero, Über uns) */
.split {
    display: flex;
    align-items: center;
    gap: var(--gap-split);
}

.split__text {
    display: flex;
    flex-direction: column;
    gap: var(--gap-stack);
    width: 620px;
    flex-shrink: 0;
}

.split__text--wide {
    width: 640px;
}

.split__visual {
    flex-grow: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 28px;
}

/* ============================================================
   05 · Typografie
   ============================================================ */

.display,
h1,
h2,
h3 {
    margin: 0;
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--c-steel);
}

h1,
.h1 {
    font-size: var(--fs-h1);
    line-height: var(--lh-h1);
}

h2,
.h2 {
    font-size: var(--fs-h2);
    line-height: var(--lh-h2);
}

h3,
.h3 {
    font-size: var(--fs-h3);
    line-height: var(--lh-h3);
}

.display--sm {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-display-sm);
    line-height: var(--lh-h2);
    color: var(--c-steel);
}

/* Signature-Muster: Schlüsselwort am Headline-Ende in Orange.
   Aufrecht — Kursiv ist projektweit gestrichen. */
.accent {
    font-style: normal;
    color: var(--c-orange);
}

/* Auf Navy: Headline weiß, Kicker orange */
.section--navy h1,
.section--navy h2,
.section--navy h3,
.section--navy .display--sm {
    color: var(--c-white);
}

.section--navy a:not(.btn) {
    color: var(--c-on-navy-link);
}

.section--navy a:not(.btn):hover {
    color: var(--c-orange);
}

.lead {
    font-size: var(--fs-lead);
    line-height: var(--lh-body);
    max-width: 560px;
}

.section--navy .lead,
.section--navy p {
    color: var(--c-on-navy);
}

.prose {
    font-size: var(--fs-body);
    line-height: var(--lh-body);
}

/* Poppins liegt nur in 400/500/600 vor — ohne diese Regel griffe der
   Browser-Default 700 und synthetisierte den Schnitt. */
strong {
    font-weight: 600;
}

/* Zweispaltiger Fließtext (Einleitung der Leistungsseite). Zwei kürzere
   Spalten lesen sich schneller als ein Block über die volle Containerbreite —
   dort liefe die Zeile auf über 120 Zeichen. */
.prose-cols {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gap-split);
}

/* Drei Absätze gehören in drei gleiche Spalten, nicht in zwei plus einen
   breiteren im Sektionskopf: drei verschiedene Textbreiten übereinander lesen
   sich unruhig (User, 27.08.2026). Ab 1200px zweispaltig, ab 900px einspaltig
   über die Grundregel weiter unten. */
/* Gestapelte Absätze in einem Textmaß, als Gegenstück zu `.prose-cols`: `p` hat
   global `margin: 0`, den Abstand setzt deshalb das Grid. Auf der Einleitung von
   /wissen-news standen zweispaltiger Text und ein Zusatzhinweis darunter in drei
   verschiedenen Breiten übereinander und lasen sich unruhig — ein Maß statt
   Spalten löst das (User, 03.09.2026, dieselbe Regel wie bei `.prose-cols--3`).
   Zwei Spalten bleiben richtig, wo beide gleich lang sind und nichts darunter
   folgt (Leistungen, Über uns). */
.prose-stack {
    display: grid;
    gap: var(--gap-stack);
    max-width: var(--measure);
}

.prose-cols--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-cols);
}

/* Gepunktete Linie über jeder Spalte — dasselbe Muster, mit dem die nummerierte
   Liste ihre Einträge im Raster verankert. Sie fasst die Spalten optisch
   zusammen und trägt jeden Umbruch ohne Sonderregel mit (User, 27.08.2026). */
.prose-cols--ruled > * {
    padding-top: var(--gap-stack);
    border-top: var(--rule-w) dotted var(--c-rule);
}

.section--navy .prose-cols--ruled > * {
    border-top-color: var(--c-rule-on-navy);
}

.prose--narrow {
    max-width: var(--measure-narrow);
}

/* Kicker: Versalien mit vertikalem Strich davor */
.kicker {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: var(--fs-label);
    font-weight: 500;
    letter-spacing: var(--ls-kicker);
    text-transform: uppercase;
    color: var(--c-steel);
}

.kicker::before {
    content: "";
    width: var(--bar-w);
    height: var(--bar-h);
    background: var(--c-orange);
    flex-shrink: 0;
}

.section--navy .kicker,
.kicker--on-dark {
    color: var(--c-orange);
}

/* Sektionskopf */
.section-head {
    display: flex;
    flex-direction: column;
    gap: var(--gap-stack);
    max-width: var(--measure);
}

.section-head--narrow {
    max-width: var(--measure-narrow);
}

/* Kopf links, Button rechts auf gleicher Grundlinie */
.section-head-row {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: var(--gap-cols);
}

.section-head-row .btn {
    white-space: nowrap;
}

.section-body {
    margin-top: 52px;
}

.section-body--tight {
    margin-top: var(--gap-cols);
}

.rule-dotted {
    border: 0;
    border-top: var(--rule-w) dotted var(--c-rule);
    margin: 0;
}

.section--navy .rule-dotted {
    border-top-color: var(--c-rule-on-navy);
}

/* ============================================================
   06 · Buttons und Textlinks
   ============================================================ */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 15px 30px;
    border: var(--border-strong) solid transparent;
    border-radius: var(--radius);
    font-size: var(--fs-ui);
    font-weight: 500;
    letter-spacing: var(--ls-ui);
    text-align: center;
    transition: background-color var(--t-base), border-color var(--t-base), color var(--t-base);
}

.btn--navy {
    background: var(--c-navy);
    border-color: var(--c-navy);
    color: var(--c-white);
}

.btn--navy:hover {
    background: var(--c-steel);
    border-color: var(--c-steel);
    color: var(--c-white);
}

.btn--orange {
    background: var(--c-orange);
    border-color: var(--c-orange);
    color: var(--c-navy);
    font-weight: 600;
}

.btn--orange:hover {
    background: var(--c-white);
    border-color: var(--c-white);
    color: var(--c-navy);
}

.btn--outline {
    border-color: var(--c-navy);
    color: var(--c-navy);
}

.btn--outline:hover {
    background: var(--c-navy);
    color: var(--c-white);
}

.btn--outline-light {
    border-color: var(--c-on-navy-border);
    color: var(--c-white);
}

.btn--outline-light:hover {
    background: var(--c-white);
    border-color: var(--c-white);
    color: var(--c-navy);
}

.btn--sm {
    padding: 12px 24px;
}

.btn--lg {
    padding: 16px 34px;
}

.btn-group {
    display: flex;
    gap: var(--gap-inline);
    margin-top: 8px;
}

/* Textlink mit Pfeil */
.link-arrow {
    font-size: var(--fs-ui);
    font-weight: 600;
    letter-spacing: var(--ls-ui);
    color: var(--c-steel);
}

.link-arrow--sm {
    font-size: var(--fs-sm);
}

/* Selektor bewusst mit Typ (a), damit er die allgemeine
   `.section--navy a:not(.btn)`-Regel überschreibt. */
.section--navy a.link-arrow {
    color: var(--c-orange);
}

/* ============================================================
   07 · Komponenten
   ============================================================ */

/* --- Kennzahlen --- */
.stats {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 48px;
}

.stat {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.stat__value {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-stat);
    line-height: 1;
    color: var(--c-steel);
}

.stat__label {
    font-size: var(--fs-ui);
    color: var(--c-text);
}

/* Kennzahlen-Band auf Navy (Startseite) */
.section--navy .stat__value {
    color: var(--c-white);
}

.section--navy .stat__label {
    color: var(--c-on-navy-muted);
}

/* --- Standortkarte (Über uns) --- */
.standorte-karte {
    width: 100%;
    max-width: 420px;
    height: auto;
}

/* Bildunterschrift mittig unter der Karte statt linksbündig */
.standorte-karte + .display--sm {
    text-align: center;
}

/* --- Personenkarte (Geschäftsführung) --- */
.person-card {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

/* `aspect-ratio` statt fester Höhe, Fokus je Person über die Variable —
   sonst schneidet der Hochformat-Ausschnitt die Köpfe an (ADR-0010/0011
   in ib-rieker). */
.person-card__portrait {
    /* Kantenbündig mit den Projektkarten der Sektion darüber: volle Spaltenbreite,
       quadratisch (User, 03.09.2026). Das Quadrat hält die Höhe des vorherigen
       4:5-Ausschnitts auf 85 % Breite, kostet also keine zusätzliche Dominanz.
       Aus dem 940×788-Motiv schneidet es nur seitlich — der Fokuspunkt entscheidet,
       wo der Kopf sitzt. */
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    object-position: var(--portrait-focus, 50% center);
    /* Ohne Stahlblau-Kante: die Porträts bringen ihren eigenen Studiogrund mit,
       die Linie las sich als Rand des Motivs (User, 02.09.2026). */
    margin-bottom: 18px;
}

.person-card__name {
    font-size: var(--fs-h3);
    line-height: var(--lh-h3);
}

.person-card__role {
    font-size: var(--fs-meta);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-label);
}

/* --- Nummerierte Liste (Leistungen) --- */
.numbered-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: var(--gap-cols);
    /* Als <ol> (Prozessschritte): die Nummer steht sichtbar im Eintrag. Nur
       der untere Rand — den oberen setzt `.section-body`. */
    margin-bottom: 0;
    padding: 0;
    list-style: none;
}

/* Sechs Prozessschritte (Arbeitsweise): zwei volle Reihen statt 4 + 2.
   Unter 1200px greifen die Zwei- und Einspalter der Grundform. */
.numbered-grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.section--navy .numbered-item {
    border-top-color: var(--c-rule-on-navy);
}

.section--navy .numbered-item__title {
    color: var(--c-white);
}

.section--navy .numbered-item__desc {
    color: var(--c-on-navy);
}

.numbered-item {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding-top: var(--gap-stack);
    border-top: var(--rule-w) dotted var(--c-rule);
}

/* Vertikal mittig in der Zelle — wie der Link in der Icon-Liste der Branchen,
   der dort über `align-items: center` der Zeile mittig steht. */
.numbered-item--action {
    justify-content: center;
}

.numbered-item__num {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: var(--ls-num);
    color: var(--c-orange);
}

.numbered-item__title {
    font-size: var(--fs-card-title);
    font-weight: 600;
    color: var(--c-navy);
}

.numbered-item__desc {
    font-size: var(--fs-card-desc);
    line-height: var(--lh-sm);
    color: var(--c-meta);
}

/* Klickbare Kachel (Leistungsraster). Linktext ist der Bereichsname: siebenmal
   „Mehr erfahren" untereinander unterscheidet die sieben Ziele nicht und ist
   auch fuer Screenreader nur ueber ein aria-label auseinanderzuhalten (User,
   03.09.2026). Der Titel behaelt sein Navy und nimmt nur das Hover-Orange der
   uebrigen Links an. */
.numbered-item__link {
    color: var(--c-navy);
}

/* Die ganze Kachel ist Klickflaeche: ein leeres Overlay des Links deckt sie ab,
   deshalb `position: relative` am Container. Der Pfeil kommt als generierter
   Inhalt — im Markup stuende er im Linktext und wuerde mitgelesen. */
.numbered-item--linked {
    position: relative;
}

.numbered-item__link::before {
    content: '';
    position: absolute;
    inset: 0;
}

.numbered-item__link::after {
    content: ' →';
    white-space: nowrap;
}

/* --- Leistungsumfang (Detailseite eines Leistungsbereichs) ---
   Gepunktete Oberlinie je Eintrag statt Listenpunkt-Zeichen — dasselbe
   Verankerungsmuster wie die nummerierte Liste, und damit eine Schmuck-Ebene
   statt zwei (Regel 3). Zwei Spalten, weil die Einträge ganze Halbsätze sind:
   im Vierspalter der nummerierten Liste brach der längste („Medienversorgungs-
   anlagen einschließlich medizinischer Druckluft …") auf sechs Zeilen um. */
.umfang-liste {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gap-cols);
}

.umfang-liste__item {
    padding-top: var(--gap-stack);
    border-top: var(--rule-w) dotted var(--c-rule);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--c-text);
}

/* Umfang-Punkt mit Titel und Erläuterung (KRITIS & Resilienz) — Titel wie
   in der nummerierten Liste, damit beide Listenformen gleich lesen. */
.umfang-liste__titel {
    display: block;
    margin-bottom: 6px;
    font-size: var(--fs-card-title);
    font-weight: 600;
    color: var(--c-navy);
}

/* Zwischenüberschrift in gestapelten Absätzen: Abstand nach oben doppelt,
   damit sie zum folgenden Absatz gehört, nicht zum vorigen. */
.prose-stack > h3:not(:first-child) {
    margin-top: var(--gap-stack);
}

/* --- Icon-Liste (Branchen) --- */
.icon-list {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    column-gap: 72px;
}

.icon-list__item {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: var(--gap-stack) 0;
    border-bottom: var(--rule-w) dotted var(--c-rule);
}

.icon-list__item--action {
    border-bottom: 0;
}

/* Schwerpunkt-Branchen: Off-White-Fläche statt Trennlinie (User, 14.10.2026;
   Variante A gegen einen Navy-Kasten). Gleiche Schriftgrößen wie die übrigen. */
.icon-list--fokus {
    gap: 24px 32px;
}

.icon-list--fokus .icon-list__item {
    padding: 28px 32px;
    border-bottom: 0;
    background: var(--c-offwhite);
}

.icon-list--fokus .icon-circle {
    background: var(--c-white);
}

.icon-list__text {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.icon-list__title {
    font-size: var(--fs-row-title);
    font-weight: 600;
    color: var(--c-navy);
}

.icon-list__desc {
    font-size: var(--fs-sm);
    line-height: 1.55;
    color: var(--c-meta);
}

.icon-circle svg {
    /* Icon skaliert mit dem Kreis (27/52 bzw. 21/40). Anteil 46 % → 52 %,
       seit die Motive Details tragen (Fensterachsen, LEDs, Markise): bei 24 px
       liefen sie zu; der Kreis selbst bleibt unverändert. */
    width: 52%;
    height: auto;
}

.icon-circle {
    width: var(--icon-circle);
    height: var(--icon-circle);
    border: var(--border-strong) solid var(--c-steel);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}

/* --- FAQ (aufklappbar) --- */
.faq {
    max-width: 900px;
    border-bottom: var(--rule-w) dotted var(--c-rule);
}

.faq__item {
    border-top: var(--rule-w) dotted var(--c-rule);
}

.faq__question {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 28px;
    padding: 26px 0;
    font-size: var(--fs-faq-question);
    font-weight: 600;
    color: var(--c-navy);
    cursor: pointer;
    list-style: none;
}

/* Standard-Dreieck abschalten — das Plus/Minus rechts übernimmt die Anzeige */
.faq__question::-webkit-details-marker {
    display: none;
}

.faq__question:focus-visible {
    outline: var(--rule-w) solid var(--c-orange);
    outline-offset: 4px;
}

.faq__sign {
    color: var(--c-orange);
    flex-shrink: 0;
}

.faq__sign-bar {
    transform-origin: center;
    transition: opacity var(--t-fast);
}

/* Offen: der senkrechte Strich verschwindet, das Plus wird zum Minus */
.faq__item[open] .faq__sign-bar {
    opacity: 0;
}

.faq__answer {
    max-width: 800px;
    padding-bottom: 26px;
    font-size: var(--fs-faq-answer);
    line-height: var(--lh-body);
    color: var(--c-text);
}

/* FAQ auf Navy (Startseite). Das `summary` ist kein Heading, deshalb greift
   keine der `.section--navy h2/h3`-Regeln — Farbe hier explizit. Das
   orangene Plus bleibt, es ist der Akzent auf Navy (wie der Kicker). */
.section--navy .faq,
.section--navy .faq__item {
    border-color: var(--c-rule-on-navy);
}

.section--navy .faq__question {
    color: var(--c-white);
}

.section--navy .faq__answer {
    color: var(--c-on-navy);
}

/* Aufklappbare Liste statt Antworttext (weitere Branchen, Startseite): volle
   Breite, die Icon-Liste bringt Schriftgrößen und Trennlinien selbst mit. */
.faq--aufklapp {
    max-width: none;
}

.faq--aufklapp .faq__answer {
    max-width: none;
    padding-bottom: 0;
}

/* --- Karten-Grid --- */
.card-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-grid);
}

/* --- Projektkarte --- */
/* Karten füllen immer die Zeilenhöhe des Grids, und der Fuß (Planungsansatz +
   Link) hängt unten — sonst enden unterschiedlich lange Texte auf
   unterschiedlichen Höhen und das Raster wirkt zufällig. */
.project-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    transition: border-color var(--t-base), transform var(--t-base);
}

.project-card:hover {
    border-color: var(--c-steel);
    transform: translateY(-4px);
}

.project-card__media {
    position: relative;
    height: 180px;
    background: var(--c-navy);
    display: flex;
    align-items: flex-start;
    padding: var(--gap-inline);
    overflow: hidden;
}

.project-card__media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    /* Der Bestand hat unterschiedliche Seitenverhältnisse — der Ausschnitt
       entsteht im Browser, damit keine Datei nachgeschnitten werden muss. */
    object-fit: cover;
}

/* Verlauf nur oben, damit das Branchen-Badge auf jedem Foto lesbar bleibt.
   Zählt als Lesbarkeitshilfe, nicht als zweite Schmuck-Ebene. */
.project-card__media::after {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 90px;
    background: linear-gradient(to bottom, var(--c-scrim-media), transparent);
}

/* Ohne Badge hat der Verlauf keine Aufgabe mehr und verdunkelt das Motiv nur
   noch — dann ist er die eine Schmuck-Ebene zu viel (Regel 3). */
.project-card__media--plain::after {
    display: none;
}

/* Deckende Fläche statt Rahmen: der Badge liegt auf Projektfotos, und
   nur eine volle Fläche bleibt über jedem Motiv lesbar. Navy auf Weiß statt
   Orange auf Weiß — Orange erreicht auf Weiß keinen ausreichenden Kontrast. */
.project-card__badge {
    position: relative;
    z-index: 1;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-navy);
    background: var(--c-white);
    padding: 5px 10px;
}

.project-card__body {
    display: flex;
    flex-direction: column;
    flex: 1;
    gap: 12px;
    padding: 26px;
}

/* Zwei Zeilen für den Titel reserviert, damit Ort und Leistungen in allen
   Karten auf derselben Höhe beginnen. */
.project-card h3 {
    min-height: calc(2 * var(--lh-h3) * 1em);
}

.project-card__meta {
    font-size: var(--fs-meta);
    color: var(--c-meta);
}

.project-card__facts {
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
    color: var(--c-text);
}

/* Der Link ist der Fuß-Anker, nicht der Planungsansatz: `note` bleibt bei den
   Bestandsprojekten leer (docs/redesign-schemabedarf.md), und hing der Anker
   daran, endeten die Karten wieder auf unterschiedlichen Höhen. */
.project-card__body .link-arrow {
    margin-top: auto;
    padding-top: 4px;
}

/* Planungsansatz — eine Zeile mit Orange-Strich als einzige Schmuck-Ebene. */
.project-card__note {
    display: flex;
    gap: 10px;
    align-items: flex-start;
    padding-top: 12px;
    border-top: var(--rule-w) dotted var(--c-rule);
    font-size: var(--fs-meta);
    line-height: 1.55;
    color: var(--c-meta);
}

.project-card__note::before {
    content: "";
    width: 14px;
    height: var(--bar-w);
    margin-top: 8px;
    background: var(--c-orange);
    flex-shrink: 0;
}

/* --- Beitragskarte --- */
/* Gleiches Kartenprinzip wie bei .project-card: volle Zeilenhöhe, Link unten. */
.post-card {
    display: flex;
    flex-direction: column;
    height: 100%;
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    transition: border-color var(--t-base), transform var(--t-base);
}

/* Textkarte ohne Bildfläche: die Karte trägt die Anrisse auf der Startseite
   und unter einem Beitrag. Die Übersicht zeigt Bilder, dort steht aber die
   Zeile `.post-row` — quadratische Titelbilder passen nicht in ein
   Dreier-Raster (User, 03.09.2026). */
.post-card__body {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 14px;
    padding: 28px;
}

.post-card .link-arrow {
    margin-top: auto;
    padding-top: 4px;
}

.post-card:hover {
    border-color: var(--c-steel);
    transform: translateY(-4px);
}

.post-card__head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.post-card__category {
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-orange);
}

.post-card__date {
    font-size: var(--fs-label);
    color: var(--c-label);
}

.post-card__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-h4);
    line-height: 1.35;
    color: var(--c-steel);
}

.post-card__teaser {
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
    color: var(--c-meta);
}

/* --- Beitragszeile (Beitragsübersicht) ---
   Text links, quadratisches Titelbild rechts. Struktur nach rieker-energie
   (`.blog-row`: 1fr + 340px mit 280er Quadrat, User 03.09.2026), Kanten und
   Farben aus dem Redesign. Grund für die Zeile statt der Karte: die
   Beitragsbilder sind quadratische Titelkarten mit eingebrannter Schrift — im
   Dreier-Raster stand über jedem Text ein 375px hohes Quadrat, und jeder
   Querformat-Ausschnitt hätte die Schrift abgeschnitten. */
.beitrag-liste {
    display: flex;
    flex-direction: column;
    gap: var(--gap-grid);
}

.post-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 260px;
    align-items: center;
    gap: var(--gap-split);
    padding: 32px;
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    transition: border-color var(--t-base);
}

.post-row:hover {
    border-color: var(--c-steel);
}

/* Ohne Bild traegt der Text die ganze Zeile — sonst blieb rechts eine leere
   Spalte stehen. Als Modifier statt `:not(:has(...))`: dieselbe Wirkung, aber
   ohne Abhaengigkeit von `:has()`. */
.post-row--text {
    grid-template-columns: minmax(0, 1fr);
}

.post-row__body {
    display: flex;
    flex-direction: column;
    gap: 14px;
    /* Die Lesebreite gilt auch hier: bei 1210px Container bleiben der Zeile
       sonst 830px, in denen der Teaser als Einzeiler ausläuft. */
    max-width: var(--measure-narrow);
}

.post-row__head {
    display: flex;
    align-items: center;
    gap: 14px;
}

.post-row__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-h3);
    line-height: 1.3;
}

.post-row__title a {
    color: var(--c-steel);
    text-decoration: none;
}

.post-row__title a:hover {
    color: var(--c-navy);
}

.post-row__teaser {
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
    color: var(--c-meta);
}

/* Quadratisch, weil die Titelkarten quadratisch vorliegen: `cover` hat damit
   nichts zu beschneiden. */
.post-row__media {
    justify-self: end;
    width: 260px;
    background: var(--c-navy);
    overflow: hidden;
}

.post-row__media img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

/* --- Suchergebnisse ---
   Aufbau der Beitragszeile (`.post-row`): dieselbe Karte, dasselbe Raster, nur
   ein kleineres Bild — die Liste mischt Seiten ohne Motiv mit Beiträgen und
   Projekten, und ein 260er Quadrat neben zwei Zeilen Text kippt das Gewicht. */
.suche-form {
    display: flex;
    gap: var(--gap-inline);
    max-width: var(--measure-narrow);
    margin-bottom: 40px;
}

.suche-form__feld {
    flex: 1;
    min-width: 0;
    height: var(--field-h);
    padding: 0 16px;
    font-family: inherit;
    font-size: var(--fs-body);
    color: var(--c-text);
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    border-radius: var(--radius);
    transition: border-color var(--t-fast);
}

.suche-form__feld::placeholder {
    color: var(--c-label);
}

.suche-form__feld:hover,
.suche-form__feld:focus {
    border-color: var(--c-steel);
}

.suche-anzahl {
    margin-bottom: var(--gap-stack);
    font-size: var(--fs-meta);
    color: var(--c-label);
}

.suche-leer {
    max-width: var(--measure-narrow);
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--c-text);
}

.suche-liste {
    display: flex;
    flex-direction: column;
    gap: var(--gap-inline);
}

.suche-treffer {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 140px;
    align-items: center;
    gap: var(--gap-cols);
    padding: 26px 32px;
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    transition: border-color var(--t-base);
}

.suche-treffer:hover {
    border-color: var(--c-steel);
}

.suche-treffer--text {
    grid-template-columns: minmax(0, 1fr);
}

.suche-treffer__body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    max-width: var(--measure-narrow);
}

.suche-treffer__head {
    display: flex;
    align-items: center;
    gap: 14px;
}

.suche-treffer__titel {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--fs-h4);
    line-height: 1.3;
}

.suche-treffer__titel a {
    color: var(--c-steel);
    text-decoration: none;
}

.suche-treffer__titel a:hover {
    color: var(--c-navy);
}

.suche-treffer__auszug {
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
    color: var(--c-meta);
}

.suche-treffer__media {
    justify-self: end;
    width: 140px;
    background: var(--c-navy);
    overflow: hidden;
}

.suche-treffer__media img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1 / 1;
    object-fit: cover;
}

/* --- Beitragsdetailseite ---
   Aufbau nach rieker-energie (`.post-hero` + `.post-card`, User 03.09.2026):
   ein schmales Navy-Band zur Einordnung, darunter der Beitrag als **eine**
   Lesespalte — Titel, Datum, Bild, Text. Vorher trug der Seitenkopf den Titel
   auf `--fs-h1-page`, und das Bild kam in eigener Sektion darunter: zwei
   Blöcke, die dasselbe sagten (das Bild trägt den Titel als Schrift). */
.beitrag-band {
    padding: 30px 0;
}

/* Zurueck-Link und Kategorie stehen buendig mit der Spalte darunter, nicht an
   der Containerkante — sonst haengt das Band links, waehrend der Beitrag
   mittig steht (User, 03.09.2026; rieker-energie fuehrt seinen Breadcrumb
   ebenso „buendig mit der Karte"). */
.beitrag-band__inner {
    display: flex;
    align-items: center;
    gap: 22px;
    max-width: var(--measure-narrow);
    margin-inline: auto;
}

/* Eine Kante fuer alles: Titel, Bild und Text stehen in derselben Lesespalte.
   Auf `--measure` (820px) lief der Text mit rund 90 Zeichen je Zeile aus dem
   lesetypografischen Optimum (50-75); rieker-energie fuehrt dieselbe Spalte
   mit 760px. Mittig statt linksbuendig (User, 03.09.2026): ein Beitrag ist
   eine Lesestrecke, keine Sektion mit Raum daneben. */
.beitrag {
    max-width: var(--measure-narrow);
    margin-inline: auto;
}

.beitrag__titel {
    font-size: var(--fs-h1-artikel);
    line-height: 1.2;
}

.beitrag__meta {
    margin: 12px 0 0;
    font-size: var(--fs-meta);
    color: var(--c-label);
}

/* Auf Spaltenbreite, also so breit wie Titel und Text (User, 03.09.2026):
   eine Kante fuer alles. Eingerueckt auf 560px stand das Bild als drittes Mass
   zwischen Titel und Text. */
.beitrag__bild {
    margin: 32px 0 0;
}

.beitrag__bild img {
    display: block;
    width: 100%;
    height: auto;
}

.beitrag__bild figcaption {
    margin-top: 10px;
    font-size: var(--fs-fineprint);
    color: var(--c-label);
}

.beitrag__text {
    margin-top: 36px;
}

/* --- Zertifikats-Laufband („Über uns") ---
   Übernommen aus ib-rieker (dort `.certifications-marquee`), auf die
   Redesign-Tokens gezogen. Die drei Entscheidungen von dort gelten mit:
   1. `transform: translate3d` statt `left`/`margin` — eigener
      Compositing-Layer, die Animation läuft ohne Main-Thread.
   2. Fade-Kanten als Verlaufs-Overlays statt `mask-image` (iOS-Frames).
   3. Pause und Zoom beim Hovern nur für echte Maus-Pointer: auf Touch bleibt
      `:hover` nach einem Tap hängen und das Laufband stünde dauerhaft still.
   Die Logos gehören fremden Institutionen und bleiben in ihren Originalfarben
   — Einfärben wäre eine Markenveränderung. */
@keyframes marquee-scroll {
    from { transform: translate3d(0, 0, 0); }
    to   { transform: translate3d(calc(-50% - var(--marquee-gap) / 2), 0, 0); }
}

.logo-marquee {
    position: relative;
    overflow: hidden;
    width: 100%;
    /* Luft für den Hover-Zoom: bei 1,3 steht ein 72px-Logo 11px über, und
       `overflow: hidden` schnitte es sonst oben und unten ab. */
    padding: 16px 0;
}

.logo-marquee::before,
.logo-marquee::after {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    width: 8%;
    z-index: 1;
    pointer-events: none;
}

.logo-marquee::before {
    left: 0;
    background: var(--grad-marquee-fade-l);
}

.logo-marquee::after {
    right: 0;
    background: var(--grad-marquee-fade-r);
}

.logo-marquee__track {
    --marquee-gap: 72px;
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--marquee-gap);
    width: max-content;
    min-width: max-content;
    animation: marquee-scroll 44s linear infinite;
    will-change: transform;
    backface-visibility: hidden;
}

.logo-marquee__item {
    flex-shrink: 0;
}

.logo-marquee__item img {
    /* Höhe statt Breite, damit die Logos optisch gleich schwer wirken —
       ihre Seitenverhältnisse gehen von 0,9 bis 5,5 auseinander. */
    display: block;
    width: auto;
    height: var(--logo-marquee-h);
    transition: transform var(--t-base);
    transform-origin: center;
}

@media (hover: hover) and (pointer: fine) {
    .logo-marquee:hover .logo-marquee__track {
        animation-play-state: paused;
    }

    /* Moderater als die 1,6 in ib-rieker: die Logos starten hier schon bei
       72px, und die Quelldateien sind 120px hoch — mehr Zoom skalierte sie
       über ihre Auflösung hinaus. */
    .logo-marquee__item img:hover {
        transform: scale(1.3);
    }
}

/* --- Zentriertes Kontakt-Band --- */
.cta-band {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 26px;
    text-align: center;
}

.cta-band h2 {
    max-width: 900px;
}

.cta-band p {
    max-width: var(--measure-narrow);
}

/* --- Seitenkopf (Unterseiten, Stubs) — Variante von .section--navy --- */
.page-hero {
    padding: var(--section-y-sm) 0 var(--section-y) 0;
}

/* Die Textspalte ist überschreibbar, weil sie bei einem Motiv-Seitenkopf nicht
   nur eine Lesebreite ist, sondern bestimmt, wo die Headline umbricht — und
   damit, ob das orangene Schlüsselwort noch im geschützten Teil des Schleiers
   landet. Gleiches Prinzip wie `--hero-focus` (Prop `measure` an x-page-hero). */
.page-hero__inner {
    display: flex;
    flex-direction: column;
    gap: var(--gap-stack);
    max-width: var(--hero-measure, var(--measure));
}

/* Eingerücktes Motiv (Prop `inset`): das Bild füllt nicht die volle Breite,
   sondern sitzt rechts, links steht die Sektionsfläche.
   Gebraucht, wenn die hellen Flächen eines Motivs so früh beginnen, dass die
   Headline darauf landet — beim Branchen-Motiv setzt die beleuchtete
   Glasfassade schon bei 51 % der Bildbreite an, und dort erreichte das
   orangene Schlüsselwort nur 1,9:1. Ein dichterer Schleier hätte das Motiv
   zur Hälfte zugedeckt; eingerückt beginnt das Helle erst bei rund 60 %.
   Die linke Kante blendet über `--mask-fade-left` in die Fläche aus. */
.page-hero--inset .page-hero__bg {
    width: var(--hero-inset, 82%);
    left: auto;
    right: 0;
    -webkit-mask-image: var(--mask-fade-left);
    mask-image: var(--mask-fade-left);
}

/* Ein Motiv, das Inhalt traegt statt Stimmung, darf seinen Inhalt nicht
   verlieren: bei der Standortkarte im Team-Seitenkopf nahm `cover` rechts
   Berlin und Nuernberg weg (User, 01.09.2026).

   Zuerst trug der Kasten dafuer das Seitenverhaeltnis des Motivs. Das machte
   diesen Seitenkopf aber 90px hoeher als die uebrigen, die ihre Hoehe aus dem
   Text beziehen (User, 03.09.2026). Statt den Kasten zu binden, bekommt das
   Motiv nur eine feste Hoehe und behaelt sein Verhaeltnis: `height: 100%` mit
   `width: auto` an der rechten Kante. Damit ist der Kasten des Bildes genau so
   gross wie das Bild — kein Beschnitt, aber auch keine transparente Flaeche
   darin, in der die Sektionsflaeche als zweiter Navyton auffiele.

   Die linke Bildkante blendet wie beim eingerueckten Motiv in die Flaeche aus:
   der Bildgrund ist mit rgb(5,25,70) etwas dunkler als das Token rgb(13,30,68).

   Wird der Text hoeher als Kastenbreite / 2,45, laeuft das Motiv links aus dem
   Kasten — `overflow: hidden` schneidet dort die leere Flaeche weg, nicht die
   Karte. Ab 1024px stapelt der Seitenkopf ohnehin. */
.page-hero--uncropped .page-hero__bg {
    width: auto;
    height: 100%;
    left: auto;
    right: 0;
    -webkit-mask-image: var(--mask-fade-left);
    mask-image: var(--mask-fade-left);
}

.page-hero h1 {
    font-size: var(--fs-h1-page);
    line-height: 1.14;
}

.page-hero .lead {
    max-width: var(--measure-narrow);
}


.stub-note {
    display: flex;
    flex-direction: column;
    gap: 14px;
    max-width: var(--measure-narrow);
    padding-top: var(--gap-stack);
    border-top: var(--rule-w) dotted var(--c-rule);
}

.stub-note__label {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--c-label);
}

/* --- Cookie-Hinweis (informierend, keine Einwilligung) --- */
.cookie-banner {
    position: fixed;
    inset: 0;
    z-index: 100;
    display: flex;
    align-items: flex-end;
    justify-content: flex-end;
    /* Der Scrim deckt den ganzen Viewport, die Box richtet sich aber an der
       Seitengrenze aus — sonst klebt sie auf breiten Monitoren weit außerhalb
       der Seite am Bildschirmrand. */
    padding: 20px max(20px, calc((100% - var(--site-max)) / 2 + 20px));
    background: var(--c-scrim);
}

body.cookie-banner-open {
    overflow: hidden;
}

.cookie-banner__inner {
    width: 100%;
    max-width: 420px;
    max-height: calc(100dvh - 40px);
    overflow-y: auto;
    padding: 26px;
    background: var(--c-white);
    border-radius: var(--radius);
    color: var(--c-navy);
}

.cookie-banner__header {
    display: flex;
    align-items: center;
    gap: 12px;
}

.cookie-banner__logo {
    height: 32px;
    width: auto;
}

.cookie-banner__title {
    flex: 1;
    font-size: var(--fs-h3);
    font-family: var(--font-display);
    font-weight: 600;
    color: var(--c-steel);
}

.cookie-banner__close {
    padding: 4px;
    color: var(--c-meta);
}

.cookie-banner__close:hover {
    color: var(--c-orange);
}

.cookie-banner__divider {
    border-top: var(--rule-w) dotted var(--c-rule);
    margin: var(--gap-inline) 0;
}

.cookie-banner__text {
    font-size: var(--fs-meta);
    line-height: var(--lh-sm);
    color: var(--c-text);
}

.cookie-banner__actions {
    display: flex;
}

.cookie-banner__btn {
    flex: 1;
    padding: 13px 22px;
    border: var(--border-strong) solid var(--c-navy);
    border-radius: var(--radius);
    background: var(--c-navy);
    color: var(--c-white);
    font-size: var(--fs-ui);
    font-weight: 500;
    letter-spacing: var(--ls-ui);
    transition: background-color var(--t-base), border-color var(--t-base);
}

.cookie-banner__btn:hover {
    background: var(--c-steel);
    border-color: var(--c-steel);
}

.cookie-banner__doc-links {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px var(--gap-inline);
    margin-top: var(--gap-inline);
    padding-top: 12px;
    border-top: var(--rule-w) dotted var(--c-rule);
}

.cookie-banner__doc-links a {
    font-size: var(--fs-label);
    color: var(--c-label);
}

/* --- Branchenfilter (Projektübersicht) --- */
/* Chips statt Reiter: sieben Branchennamen bis 38 Zeichen passen in keine
   Reiterleiste, umbrechen aber sauber. Ohne JS bleibt die Leiste stehen und
   alle Karten sichtbar (public/js/kartenfilter.js). */
.filter-bar {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 18px;
    border: var(--rule-w) solid var(--c-rule);
    border-radius: 999px;
    background: transparent;
    font-family: inherit;
    font-size: var(--fs-meta);
    color: var(--c-text);
    cursor: pointer;
    transition: border-color var(--t-fast), color var(--t-fast), background-color var(--t-fast);
}

.filter-chip:hover {
    border-color: var(--c-steel);
    color: var(--c-steel);
}

.filter-chip.is-active {
    background: var(--c-navy);
    border-color: var(--c-navy);
    color: var(--c-white);
}

/* Die Anzahl ist die einzige Schmuck-Ebene des Chips — deshalb kein
   zusätzlicher Punkt oder Strich davor (Regel 3). */
.filter-chip__count {
    font-size: var(--fs-micro);
    font-weight: 600;
    color: var(--c-label);
}

.filter-chip.is-active .filter-chip__count {
    color: var(--c-on-navy-muted);
}

/* Spezifität über `.project-card`/`.post-card` (0,1,0), damit die Karte ihr
   `display: flex` nicht zurückholt — ohne `!important`
   (docs/frontend-standards.md §10). Beide Kartenarten laufen durch denselben
   Filter (public/js/kartenfilter.js); stand hier nur die Projektkarte, setzte
   das Skript auf der Beitragsübersicht die Klasse, ohne dass etwas verschwand. */
.project-card.is-hidden,
.post-card.is-hidden,
.post-row.is-hidden {
    display: none;
}

.filter-empty {
    margin: var(--gap-stack) 0 0;
    font-size: var(--fs-body);
    color: var(--c-meta);
}

/* Dieselbe Auswahl als Feld — ab 767px sichtbar, darüber die Chips. */
.filter-select {
    display: none;
    flex-direction: column;
    gap: 8px;
    max-width: var(--measure-narrow);
}

.filter-select__label {
    font-size: var(--fs-label);
    letter-spacing: var(--ls-kicker);
    text-transform: uppercase;
    font-weight: 500;
    color: var(--c-steel);
}

.filter-select__control {
    width: 100%;
    padding: 12px 14px;
    border: var(--rule-w) solid var(--c-rule);
    border-radius: var(--radius);
    background: var(--c-white);
    font-family: inherit;
    font-size: var(--fs-ui);
    color: var(--c-navy);
}

/* --- Projektdetailseite --- */
/* Zeile über dem Kicker des Seitenkopfs, bisher nur der Zurück-Link. */
.page-hero__topline {
    margin-bottom: 4px;
}

.link-arrow--back {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

/* Ort und Jahr unter der H1. Erscheint erst, wenn `location` im Panel gepflegt
   ist (docs/redesign-schemabedarf.md). */
.page-hero__meta {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0;
    font-size: var(--fs-meta);
    color: var(--c-on-navy-muted);
}

.page-hero__meta-rule {
    width: 14px;
    height: var(--rule-w);
    background: var(--c-rule-on-navy);
}

/* Hauptbild über die volle Containerbreite. `aspect-ratio` statt fester Höhe,
   damit der Ausschnitt beim Schmalerwerden nicht seitlich wegschneidet
   (Regel 7). Quelldateien sind auf 1200px begrenzt (docs/assets.md). */
.project-figure {
    margin: 0;
}

.project-figure img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 9;
    object-fit: cover;
}

.project-figure figcaption {
    margin-top: 12px;
    font-size: var(--fs-fineprint);
    color: var(--c-label);
}

.project-gallery {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--gap-grid);
    margin-top: var(--gap-grid);
}

.project-gallery__item {
    display: block;
    overflow: hidden;
    border: var(--rule-w) solid var(--c-card-border);
}

.project-gallery__item img {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    transition: transform var(--t-base);
}

.project-gallery__item:hover img {
    transform: scale(1.04);
}

/* Vollbild der Galerie. Bedienung (Klick, Esc, Pfeiltasten) kommt unverändert
   aus public/js/lightbox.js — dieselbe Datei wie auf den Altseiten. */
.lightbox {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 9999;
    background: var(--c-scrim-lightbox);
    align-items: center;
    justify-content: center;
}

.lightbox.active {
    display: flex;
}

.lightbox__img {
    max-width: 90vw;
    max-height: 85vh;
    object-fit: contain;
}

.lightbox__close,
.lightbox__prev,
.lightbox__next {
    position: absolute;
    background: none;
    border: 0;
    color: var(--c-white);
    font-family: inherit;
    line-height: 1;
    cursor: pointer;
}

.lightbox__close {
    top: 20px;
    right: 24px;
    font-size: var(--fs-h2);
}

.lightbox__prev,
.lightbox__next {
    top: 50%;
    transform: translateY(-50%);
    padding: 16px;
    font-size: var(--fs-h2);
}

.lightbox__prev { left: 16px; }
.lightbox__next { right: 16px; }

/* Redaktionelles HTML aus dem Admin-Panel (`portfolio_items.content`). Die
   Elemente kommen aus dem Editor, deshalb wird hier über den Container
   gestylt statt über Klassen im Markup. */
.rich-text {
    font-size: var(--fs-body);
    line-height: var(--lh-body);
    color: var(--c-text);
}

.rich-text > *:first-child {
    margin-top: 0;
}

.rich-text > *:last-child {
    margin-bottom: 0;
}

.rich-text h3 {
    margin: 32px 0 12px;
}

.rich-text p {
    margin: 0 0 20px;
}

.rich-text ul,
.rich-text ol {
    margin: 0 0 20px;
    padding-left: 22px;
}

.rich-text li {
    list-style: disc;
    margin-bottom: 6px;
}

/* Die Rechtstexte (Impressum, Datenschutz, Cookie-Richtlinie, Bildnachweise)
   laufen durch denselben Container: es ist derselbe lange Fließtext, nur
   handgeschrieben statt aus dem Panel. Sie bringen h2, h4 und Tabellen mit —
   die Regeln stehen deshalb hier, statt in einer zweiten Prosa-Klasse. */

/* Kapitelüberschrift. Nicht auf --fs-h2 (44px): die Rechtsseiten haben sechs
   bis zehn davon, und „Firma:" über einer dreizeiligen Adresse trüge das
   Gewicht einer Sektions-Headline. Die gepunktete Linie darüber trägt den
   Ebenenwechsel statt der Größe — nötig, weil h2 und h3 auf Phone nur 1px
   auseinanderliegen (20 zu 19px). Sie ist die einzige Schmuck-Ebene am
   Element (docs/design-system.md, Regel 3). */
.rich-text h2 {
    margin: 44px 0 14px;
    padding-top: var(--gap-stack);
    border-top: var(--rule-w) dotted var(--c-rule);
    font-size: var(--fs-display-sm);
    line-height: var(--lh-h2);
}

/* Am Anfang der Sektion stünde die Linie ohne Inhalt darüber. */
.rich-text > h2:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}

/* Poppins 600 statt der nächsten Playfair-Stufe: --fs-h4 liegt 1px unter h3
   und wäre als eigene Ebene nicht zu erkennen. Der Schriftwechsel trägt die
   Unterscheidung, nicht die Größe. */
.rich-text h4 {
    margin: 26px 0 10px;
    font-family: var(--font-body);
    font-weight: 600;
    font-size: var(--fs-body);
    line-height: var(--lh-h3);
    color: var(--c-steel);
}

/* Rechtstexte nennen Links ausgeschrieben. Ohne Umbruchpunkt schiebt eine
   URL wie dataprivacyframework.gov/participant/5448 den Container auf Phone
   über die Bildschirmbreite (docs/frontend-standards.md §2). */
.rich-text a {
    overflow-wrap: anywhere;
}

/* Kein Kursiv (Regel 2). Die em-Stellen der Rechtstexte sind Fußnoten —
   Stand-Datum der Cookie-Richtlinie, Quellenangabe der Datenschutzerklärung —
   und tragen deshalb den Meta-Ton statt einer Schräglage. */
.rich-text em {
    font-style: normal;
    color: var(--c-meta);
}

/* Die Cookie-Tabellen sind vierspaltig und passen auf Phone nicht in den
   Container — sie scrollen in ihrem eigenen Kasten, nicht die Seite. */
.rich-text__scroll {
    overflow-x: auto;
    margin: 0 0 24px;
}

/* Die Mindestbreite ist der Grund, warum der Kasten scrollt: ohne sie quetscht
   der Browser die vier Spalten auf Phone in Ein-Wort-Zeilen, statt den
   Scrollweg zu nutzen. */
.rich-text table {
    width: 100%;
    min-width: 560px;
    border-collapse: collapse;
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
}

.rich-text th,
.rich-text td {
    padding: 10px 14px;
    text-align: left;
    border: var(--rule-w) solid var(--c-card-border);
}

.rich-text th {
    font-weight: 600;
    color: var(--c-steel);
    background: var(--c-white);
    white-space: nowrap;
}

/* --- Formular (Kontaktseite) ---
   Sichtbare Labels statt Platzhalter-Beschriftung: ein Platzhalter verschwindet
   beim Tippen, und wer das Formular in mehreren Anläufen ausfüllt, sieht dann
   nicht mehr, was in welches Feld gehört. Der alte Startseiten-CTA arbeitete
   nur mit Platzhaltern — das ist mit dem Umzug hierher abgelöst. */
.form {
    display: flex;
    flex-direction: column;
    gap: 22px;
    align-items: flex-start;
}

.form__row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: var(--gap-inline);
    width: 100%;
}

.form__feld {
    display: flex;
    flex-direction: column;
    gap: 8px;
    width: 100%;
}

.form__feld label {
    font-size: var(--fs-ui);
    font-weight: 500;
    letter-spacing: var(--ls-ui);
    color: var(--c-navy);
}

.form__optional {
    font-weight: 400;
    color: var(--c-label);
}

.form input[type="text"],
.form input[type="email"],
.form input[type="tel"],
.form textarea {
    width: 100%;
    padding: 0 16px;
    height: var(--field-h);
    font-family: inherit;
    font-size: var(--fs-body);
    color: var(--c-text);
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    border-radius: var(--radius);
    transition: border-color var(--t-fast);
}

.form textarea {
    height: auto;
    padding: 14px 16px;
    line-height: var(--lh-body);
    resize: vertical;
}

.form input::placeholder,
.form textarea::placeholder {
    color: var(--c-label);
}

.form input:hover,
.form textarea:hover {
    border-color: var(--c-steel);
}

/* Der Fokusring kommt aus der globalen :focus-visible-Regel (orange). Hier
   wechselt zusätzlich die Rahmenfarbe, damit das aktive Feld auch dann zu
   erkennen ist, wenn der Ring vom Feldrand verdeckt wirkt. */
.form input:focus,
.form textarea:focus {
    border-color: var(--c-steel);
}

/* Element im Selektor, nicht nur das Attribut: die Grundregel oben ist
   `.form input[type="email"]` und damit gleich spezifisch — ein reines
   `.form [aria-invalid]` läge darunter und der rote Rand bliebe aus. */
.form input[aria-invalid="true"],
.form textarea[aria-invalid="true"] {
    border-color: var(--c-error);
}

.form__fehler {
    font-size: var(--fs-meta);
    line-height: var(--lh-sm);
    color: var(--c-error);
}

/* Ankreuzfeld: Kästchen und Text auf einer Grundlinie, der Text darf umbrechen
   ohne unter das Kästchen zu rutschen.
   Der Selektor nennt `.form__feld`, weil `.form__feld label` darüber Navy und
   500 setzt — das ist für eine Feldbeschriftung richtig, für den zwei Zeilen
   langen Einwilligungssatz nicht: er liest sich dann wie eine Überschrift. */
.form__feld label.form__check {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 12px;
    align-items: start;
    font-size: var(--fs-sm);
    font-weight: 400;
    line-height: var(--lh-sm);
    color: var(--c-text);
    cursor: pointer;
}

.form__check input {
    width: 18px;
    height: 18px;
    margin: 0;
    accent-color: var(--c-navy);
    /* Rückt das Kästchen auf die erste Textzeile statt an die Oberkante */
    translate: 0 2px;
}

.form__pflicht {
    font-size: var(--fs-meta);
    color: var(--c-label);
}

/* Rückmeldung nach dem Absenden. Nur eine Schmuck-Ebene: farbige Kante plus
   farbiger Text, keine zusätzliche Fläche (docs/design-system.md, Regel 3). */
.form-hinweis {
    margin-bottom: 28px;
    padding: 12px 0 12px 16px;
    border-left: var(--bar-w) solid currentColor;
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
}

.form-hinweis--ok {
    color: var(--c-success);
}

.form-hinweis--fehler {
    color: var(--c-error);
}

/* --- Kontaktseite: Formular neben Kontaktdaten --- */
/* Nicht `.split`: dort ist die Textspalte fest 620px breit und der Inhalt
   vertikal zentriert. Hier trägt die linke Spalte das Formular und ist die
   breitere, und beide Spalten stehen oben bündig. */
.kontakt-grid {
    display: grid;
    /* 340px, nicht 300: der Icon-Kreis nimmt 52px plus 20px Abstand, und
       „60486 Frankfurt am Main" braucht bei Fliesstextgroesse rund 190px. */
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: var(--gap-split);
    align-items: start;
}

.kontakt-grid__form {
    max-width: var(--measure-narrow);
}

.kontakt-grid__daten {
    display: flex;
    flex-direction: column;
    gap: var(--gap-stack);
}

.kontaktdaten {
    display: flex;
    flex-direction: column;
    margin: 0;
}

/* Dieselbe Zeilenform wie `.icon-list__item` (Branchen, Werte): Kreis links,
   Label und Wert rechts, gepunktete Linie darunter. Der Kreis ist der Grund,
   warum der Block jetzt trägt — ein reiner Textblock hatte kein Gewicht. */
.kontaktdaten__block {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: var(--gap-stack) 0;
    border-bottom: var(--rule-w) dotted var(--c-rule);
}

.kontaktdaten__block:first-child {
    border-top: var(--rule-w) dotted var(--c-rule);
}

.kontaktdaten__text {
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.kontaktdaten dt {
    font-size: var(--fs-label);
    font-weight: 600;
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--c-label);
}

/* Telefonnummer und Adresse sind die Handlung, nicht die Beschriftung —
   deshalb auf Fließtextgröße statt auf der kleineren Kartengröße. */
.kontaktdaten dd {
    margin: 0;
    font-size: var(--fs-body);
    line-height: var(--lh-h3);
    color: var(--c-text);
}

/* --- Standortkarte (Kontakt) --- */
/* Karte oben ueber die volle Containerbreite, Ortsliste darunter (User,
   01.09.2026). Nebeneinander blieb der Karte auf jeder Breite ein Viertel
   weniger Platz, obwohl die Liste ihre Hoehe nie ausfuellt. */
.standort-karte {
    display: flex;
    flex-direction: column;
    gap: var(--gap-split);
}

.standort-karte__map {
    height: var(--map-h);
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    border-radius: var(--radius);
}

/* Die 16 Orte als lesbare Liste — sie ist die eigentliche Information und
   steht auch ohne JavaScript vollständig da. Erst das Skript macht die
   Einträge anklickbar und vergibt dafür `.is-klickbar`. */
.standort-liste {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    column-gap: var(--gap-cols);
}

.standort-liste__item {
    padding: 9px 0;
    border-top: var(--rule-w) dotted var(--c-rule);
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
    color: var(--c-text);
}



.standort-liste__item.is-klickbar {
    cursor: pointer;
    transition: color var(--t-fast);
}

.standort-liste__item.is-klickbar:hover {
    color: var(--c-orange);
}

/* Eigener Marker statt der Leaflet-Standardgrafik: so stehen die Farben im
   CSS und folgen den Tokens (Regel 1). Navy-Tropfen mit orangenem Kern, wie
   das Standort-Symbol im Seitenkopf. Die weisse Kontur ist kein Schmuck: die
   OSM-Kacheln wechseln je Zoomstufe zwischen hellen Flaechen und dunklen
   Strassen, ohne sie verschwaende der Marker stellenweise. */
.standort-marker svg {
    display: block;
    width: 100%;
    height: 100%;
}

.standort-marker__pin {
    fill: var(--c-navy);
    stroke: var(--c-white);
    stroke-width: var(--border-strong);
}

.standort-marker__kern {
    fill: var(--c-orange);
}

/* Leaflet bringt eigene Schrift- und Farbwerte mit (Helvetica, #333, #ddd) —
   hier auf die Tokens gezogen, damit die Karte nicht als Fremdkörper zwischen
   den Sektionen steht.
   Jede Regel hängt an `.standort-karte__map`, und das ist keine Kosmetik:
   `leaflet.css` wird über @stack('styles') NACH redesign.css geladen, also
   gewinnt es bei gleicher Spezifität. Ohne den zusätzlichen Klassenselektor
   wäre dieser ganze Block wirkungslos (nachgemessen: die Attribution blieb
   auf #333). Der Kartencontainer selbst trägt beide Klassen. */
.standort-karte__map.leaflet-container {
    font-family: var(--font-body);
    font-size: var(--fs-meta);
    background: var(--c-offwhite);
}

.standort-karte__map .leaflet-popup-content-wrapper,
.standort-karte__map .leaflet-popup-tip {
    background: var(--c-white);
    color: var(--c-text);
    border-radius: var(--radius);
}

.standort-karte__map .leaflet-popup-content {
    margin: 12px 16px;
    font-size: var(--fs-sm);
    line-height: var(--lh-sm);
}

.standort-karte__map .leaflet-popup-content strong {
    color: var(--c-navy);
}

.standort-karte__map .leaflet-bar a,
.standort-karte__map .leaflet-bar a:hover {
    color: var(--c-navy);
    background: var(--c-white);
}

.standort-karte__map .leaflet-control-attribution {
    font-size: var(--fs-micro);
    color: var(--c-label);
}

.standort-karte__map .leaflet-control-attribution a {
    color: var(--c-steel);
}

/* ============================================================
   08 · Header und Navigation
   ============================================================ */

/* Stapelkontext für die aufklappende Suchkarte: sie hängt unter der Kopfleiste
   und muss über der ersten Sektion liegen, aber unter dem Drawer (z-index 40). */
.site-header {
    position: relative;
    z-index: 30;
    background: var(--c-offwhite);
}

.header-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--gap-cols);
    height: var(--header-h);
}

.header-logo {
    display: inline-flex;
    align-items: center;
}

.header-logo img {
    height: 46px;
    width: auto;
}

.header-nav {
    display: flex;
    align-items: center;
    gap: 36px;
}

/* Kein Umbruch in den Labels: „Branchen & Projekte" und „Wissen & News" stehen
   sonst zweizeilig und die Leiste franst aus (User, 02.09.2026). Der engere
   Abstand unter 1200px hält die sechs Einträge + CTA dafür in einer Zeile. */
.header-nav a {
    font-size: var(--fs-ui);
    font-weight: 500;
    color: var(--c-navy);
    white-space: nowrap;
}

.header-nav a:hover,
.header-nav a.is-active {
    color: var(--c-orange);
}

.header-nav .btn,
.header-nav .btn.is-active {
    color: var(--c-white);
}

.header-burger {
    display: none;
    padding: 8px;
    margin-right: -8px;
    color: var(--c-navy);
}

/* --- Suche in der Kopfleiste --- */
.header-suche {
    position: relative;
    display: flex;
    align-items: center;
    /* Rückt die Lupe an die Nav-Einträge heran: der 36px-Abstand der Leiste
       gilt zwischen Wörtern, neben einem Icon wirkt er als Loch. */
    margin-left: -14px;
}

.header-suche__btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    color: var(--c-navy);
    transition: color var(--t-fast);
}

.header-suche__btn:hover,
.header-suche__btn[aria-expanded="true"] {
    color: var(--c-orange);
}

.header-suche__icon--zu {
    display: none;
}

.header-suche__btn[aria-expanded="true"] .header-suche__icon--lupe {
    display: none;
}

.header-suche__btn[aria-expanded="true"] .header-suche__icon--zu {
    display: block;
}

.header-suche__karte {
    position: absolute;
    top: calc(100% + 14px);
    right: 0;
    width: 320px;
    padding: 14px;
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    /* visibility erst nach dem Ausblenden umschalten (0s mit Verzögerung),
       sonst springt die Karte auf halber Strecke weg. */
    transition: opacity var(--t-fast), transform var(--t-fast), visibility 0s linear var(--t-fast);
}

.header-suche__karte.is-open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity var(--t-fast), transform var(--t-fast), visibility 0s;
}

.header-suche__form {
    display: flex;
    gap: 8px;
}

.header-suche__feld {
    flex: 1;
    min-width: 0;
    height: 44px;
    padding: 0 14px;
    font-family: inherit;
    font-size: var(--fs-ui);
    color: var(--c-text);
    background: var(--c-white);
    border: var(--rule-w) solid var(--c-card-border);
    border-radius: var(--radius);
    transition: border-color var(--t-fast);
}

.header-suche__feld::placeholder {
    color: var(--c-label);
}

.header-suche__feld:hover,
.header-suche__feld:focus {
    border-color: var(--c-steel);
}

.header-suche__submit {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    color: var(--c-white);
    background: var(--c-navy);
    border-radius: var(--radius);
    transition: background-color var(--t-fast);
}

.header-suche__submit:hover {
    background: var(--c-orange);
}

/* --- Mobile-Drawer --- */
.nav-drawer-backdrop {
    position: fixed;
    inset: 0;
    z-index: 40;
    background: var(--c-navy);
    opacity: 0;
    visibility: hidden;
    transition: opacity var(--t-base), visibility var(--t-base);
}

.nav-drawer-backdrop.is-open {
    opacity: 0.5;
    visibility: visible;
}

.nav-drawer {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    width: min(360px, 88vw);
    padding: 24px var(--gutter);
    background: var(--c-navy);
    transform: translateX(100%);
    transition: transform var(--t-base);
    overflow-y: auto;
}

.nav-drawer.is-open {
    transform: translateX(0);
}

.nav-drawer__close {
    display: flex;
    margin-left: auto;
    color: var(--c-white);
}

/* Suchfeld über dem Menü. Feld und Lupe bilden eine weiße Fläche: Orange
   bleibt dem CTA darunter vorbehalten, zwei orangene Flächen im selben Drawer
   nähmen ihm das Gewicht (docs/design-system.md, „weniger ist mehr"). */
.nav-drawer__suche {
    display: flex;
    margin-top: 20px;
}

.nav-drawer__suchfeld {
    flex: 1;
    min-width: 0;
    height: 44px;
    padding: 0 14px;
    font-family: inherit;
    font-size: var(--fs-ui);
    color: var(--c-text);
    background: var(--c-white);
    border: var(--rule-w) solid transparent;
    border-radius: var(--radius);
}

.nav-drawer__suchfeld::placeholder {
    color: var(--c-label);
}

.nav-drawer__suchbtn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 48px;
    height: 44px;
    color: var(--c-navy);
    background: var(--c-white);
    border-left: var(--rule-w) solid var(--c-card-border);
    border-radius: var(--radius);
}

.nav-drawer__menu {
    display: flex;
    flex-direction: column;
    gap: 4px;
    margin-top: 24px;
}

.nav-drawer__menu a {
    padding: 12px 0;
    border-bottom: var(--rule-w) dotted var(--c-rule-on-navy);
    font-size: var(--fs-lead);
    font-weight: 500;
    color: var(--c-white);
}

.nav-drawer__menu a:hover,
.nav-drawer__menu a.is-active {
    color: var(--c-orange);
}

.nav-drawer .btn {
    margin-top: var(--gap-stack);
    width: 100%;
}

/* ============================================================
   09 · Footer
   ============================================================ */

.site-footer {
    padding: 70px 0 36px 0;
    background: var(--c-navy);
}

.footer-grid {
    display: flex;
    flex-wrap: wrap;
    gap: 48px 100px;
}

.footer-brand {
    display: flex;
    flex-direction: column;
    gap: 18px;
    width: 300px;
}

.footer-brand img {
    height: 42px;
    width: auto;
    align-self: flex-start;
}

.footer-brand p {
    font-size: var(--fs-sm);
    line-height: 1.65;
    color: var(--c-on-navy-muted);
}

/* Der LinkedIn-Button ist Flex-Item der Brand-Spalte und würde sonst auf deren
   volle Breite wachsen; das Icon sitzt mit Abstand vor der Beschriftung. */
.footer-linkedin {
    align-self: flex-start;
    gap: 10px;
}

.footer-col {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.footer-heading {
    margin: 0;
    font-family: var(--font-body);
    font-size: var(--fs-eyebrow);
    font-weight: 600;
    letter-spacing: var(--ls-eyebrow);
    text-transform: uppercase;
    color: var(--c-on-navy-label);
}

.footer-col a {
    font-size: var(--fs-sm);
    color: var(--c-on-navy-link);
}

.footer-col a:hover {
    color: var(--c-orange);
}

.footer-bottom {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--gap-inline);
    margin-top: 48px;
    padding-top: 24px;
    border-top: var(--rule-w) dotted var(--c-rule-on-navy);
    font-size: var(--fs-fineprint);
    color: var(--c-on-navy-faint);
}

.footer-bottom a {
    color: var(--c-on-navy-faint);
}

.footer-bottom a:hover {
    color: var(--c-orange);
}

/* ============================================================
   10 · Responsive
   Breakpoints 1200px (Tablet), 1024px (Navigation), 900px, 767px (Phone)
   und 480px (kleines Phone) — wie in ib-rieker gestaffelt, weil ein Sprung
   von 1200 auf 767 die Zwischenbreiten ungeprüft lässt (ADR-0010/0011 dort).
   Angepasst wird zuerst über Tokens, danach über Layout-Regeln.
   ============================================================ */

@media (max-width: 1200px) {
    .header-nav {
        gap: 22px;
    }

    :root {
        --fs-h1: 46px;
        --fs-h1-page: 42px;
        --fs-h1-artikel: 32px;
        --fs-h2: 36px;
        --fs-stat: 52px;
        --fs-display-sm: 24px;
        --gutter: 40px;
        --section-y: 76px;
        --section-y-sm: 56px;
        --section-y-lg: 84px;
        --gap-split: 40px;
    }

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

    .split__text,
    .split__text--wide {
        width: auto;
    }

    .numbered-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    /* Gestapelte Absätze in einem Textmaß, als Gegenstück zu `.prose-cols`: `p` hat
   global `margin: 0`, den Abstand setzt deshalb das Grid. Auf der Einleitung von
   /wissen-news standen zweispaltiger Text und ein Zusatzhinweis darunter in drei
   verschiedenen Breiten übereinander und lasen sich unruhig — ein Maß statt
   Spalten löst das (User, 03.09.2026, dieselbe Regel wie bei `.prose-cols--3`).
   Zwei Spalten bleiben richtig, wo beide gleich lang sind und nichts darunter
   folgt (Leistungen, Über uns). */
.prose-stack {
    display: grid;
    gap: var(--gap-stack);
    max-width: var(--measure);
}

.prose-cols--3 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .icon-list {
        grid-template-columns: minmax(0, 1fr);
        column-gap: 0;
    }

    .card-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .project-gallery {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .stats {
        gap: var(--gap-cols);
    }

    .footer-grid {
        gap: var(--gap-cols) 64px;
    }

    .hero {
        min-height: 500px;
    }

    /* Der Textblock rückt näher an den Baukörper — Motiv weiter nach rechts
       schieben, statt Höhe zu opfern. */
    .page-hero--media {
        --hero-focus: 82% center;
        min-height: 380px;
    }
}

@media (max-width: 1024px) {
    .header-nav {
        display: none;
    }

    .header-burger {
        display: flex;
    }

    /* Diese Seitenköpfe stapeln schon hier, nicht erst bei 767px. Grund ist
       derselbe Beschnitt: schmaler als das wird die Fläche flacher als das
       Motiv breit ist, also beschneidet `cover` zusätzlich horizontal — und
       `object-position` nimmt dabei genau die leere Fläche weg, auf der die
       Headline steht. 1024px, weil hier ohnehin der Drawer übernimmt.
       Zwei Auslöser, beide nachgemessen:
       · `--inset` (Branchen): bei 950px blieben 7px zwischen Textkante und
         heller Fläche, bei 800px lag die Headline 211px darin.
       · `--stack-early` (Kontakt): das Motiv ist zwar durchgehend dunkel, aber
         der Beschnitt zieht die Kontakt-Symbole nach links unter den Text —
         bei 820px reichte die Headline bis 69 % der Bildbreite, die Symbole
         liegen bei 58–66 %. Ein kleinerer `--hero-focus` half nicht: dann
         fällt bei 768px das Gebäude aus dem Bild (Regel 7, stapeln statt
         beschneiden). */
    .page-hero--inset,
    .page-hero--stack-early {
        display: flex;
        flex-direction: column;
        min-height: 0;
        padding-bottom: 0;
    }

    .page-hero--inset .page-hero__bg,
    .page-hero--stack-early .page-hero__bg {
        order: 1;
        position: static;
        width: 100%;
        height: auto;
        margin-top: 28px;
        aspect-ratio: 16 / 9;
        object-position: 78% center;
        -webkit-mask-image: var(--mask-fade-top);
        mask-image: var(--mask-fade-top);
    }

    /* Gestapelt wird das Motiv nicht kleiner, sondern zugeschnitten — aber
       ausschliesslich um die leere Navy-Flaeche links. Ueber die volle
       Bildbreite ergaebe das 2,45:1-Motiv auf 375px einen 153px hohen Streifen,
       in dem die Kartenbeschriftung nicht mehr lesbar ist. 4:3 an der rechten
       Kante zeigt die Karte ueber die volle Bildhoehe: sichtbar ist dann alles
       ab 39 % der Bildbreite, und die Karte beginnt erst bei 58 %.
       `cover` statt `contain` also genau hier — der Kasten ist schmaler als das
       Motiv, deshalb schneidet er seitlich statt vertikal.
       3:2 und nicht 4:3: bei 1024px waere der Kasten sonst 757px hoch und der
       Seitenkopf laenger als der halbe Bildschirm. Auf kleinen Phones kippt es
       auf 4:3, gleiche Staffelung wie bei den uebrigen Motiven. */
    .page-hero--uncropped .page-hero__bg {
        aspect-ratio: 3 / 2;
        object-position: var(--hero-focus);
    }

    /* Ohne Text über dem Motiv braucht es keinen Schleier mehr. */
    .page-hero--inset::before,
    .page-hero--stack-early::before {
        display: none;
    }
}

@media (max-width: 900px) {

    /* Dritte Stapel-Staffelung, nach `--inset`/`--stack-early` (1200px):
       derselbe Regelsatz, nur spaeter. Fuer Motive, deren Ausschnitt sich in
       schmalen Viewports nicht mehr verschieben laesst — sobald der Seitenkopf
       hoeher wird als Breite / 2,45, hat `cover` beim 2,45:1-Motiv keinen
       vertikalen Ueberschuss mehr, `object-position` wirkt nur noch
       horizontal, und ein Motiv, dessen Grafik unten sitzt, klebt am unteren
       Rand (Leistungs-Detailseite, User 03.09.2026: „schieb das Motiv mobil
       hoeher"). Als eigener Block mit eigenem Seitenverhaeltnis sitzt es
       direkt unter dem Text.
       Nicht `--stack-early` dafuer nehmen: das greift ab 1200px, und dort ist
       der Block ueber die volle Containerbreite 542px hoch — bei 1024px steht
       das Motiv noch besser neben dem Text. */
    .page-hero--stack-narrow {
        display: flex;
        flex-direction: column;
        min-height: 0;
        padding-bottom: 0;
    }

    .page-hero--stack-narrow .page-hero__bg {
        order: 1;
        position: static;
        width: 100%;
        height: auto;
        margin-top: 28px;
        aspect-ratio: 16 / 9;
        object-position: var(--hero-focus);
        -webkit-mask-image: var(--mask-fade-top);
        mask-image: var(--mask-fade-top);
    }

    /* Ohne Text ueber dem Motiv braucht es keinen Schleier mehr. */
    .page-hero--stack-narrow::before {
        display: none;
    }

    /* Die Eintraege des Leistungsumfangs sind ganze Halbsaetze — in zwei
       Spalten bleiben hier je rund 400px, in denen der laengste vierzeilig
       umbricht. Einspaltig liest er sich in zwei Zeilen. */
    .umfang-liste {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Beitragszeile stapelt: das Bild ueber den Text, wie bei jeder Karte.
       Nebeneinander blieben dem Text unter 260px Bild noch 330px, in denen
       Titel und Teaser in Vierwort-Zeilen zerfielen. */
    .post-row {
        grid-template-columns: minmax(0, 1fr);
        gap: 24px;
        padding: 24px;
    }

    .post-row__media {
        order: -1;
        justify-self: stretch;
        width: 100%;
        max-width: 320px;
    }

    /* Suchtreffer stapeln aus demselben Grund wie die Beitragszeile. */
    .suche-treffer {
        grid-template-columns: minmax(0, 1fr);
        gap: 20px;
        padding: 24px;
    }

    .suche-treffer__media {
        order: -1;
        justify-self: stretch;
        width: 100%;
        max-width: 220px;
    }

    .hero {
        min-height: 460px;
    }

    .hero::before,
    .page-hero--media::before {
        background: var(--hero-veil, var(--grad-hero-veil-tight));
    }

    .page-hero--media {
        --hero-focus: 88% center;
        min-height: 340px;
    }

    /* Zwei Spalten wären hier je unter 340px breit — die Absätze zerfielen
       in Vierwort-Zeilen. */
    .prose-cols {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--gap-stack);
    }

    /* Formular und Kontaktdaten stapeln: zweispaltig blieben für das Formular
       noch rund 480px, und die Nachricht wäre schmaler als die Labelzeile. */
    .kontakt-grid {
        grid-template-columns: minmax(0, 1fr);
        gap: var(--gap-split);
    }

    /* Gestapelt liegen die drei Kontaktblöcke nebeneinander statt untereinander
       — als Band unter dem Formular, nicht als dritte lange Spalte.
       Raster mit fester Spaltenzahl statt `flex-wrap`: dort lief der dritte
       Block über die volle Breite, sobald nur zwei in eine Reihe passten, und
       das Band stand zweizeilig mit ungleichen Blöcken da.
       Zwei Spalten, nicht drei: bei drei blieben der Adresse 170px, und
       „60486 Frankfurt am Main" braucht bei 16px rund 190px — sie brach auf
       vier Zeilen um (gemessen bei 900px). */
    .kontaktdaten {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: var(--gap-cols);
    }

    /* In der Reihe endet jede Spalte gleich — die Oberkante am ersten Block
       säße dann nur über der linken. */
    .kontaktdaten__block:first-child {
        border-top: 0;
    }

    /* Vier Spalten wären hier je unter 190px breit. */
    .standort-liste {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}

@media (max-width: 767px) {
    :root {
        --fs-h1: 36px;
        --lh-h1: 1.16;
        --fs-h1-page: 32px;
        --fs-h2: 28px;
        --lh-h2: 1.22;
        --fs-h3: 19px;
        --fs-h4: 18px;
        --fs-display-sm: 20px;
        --fs-stat: 52px;
        --fs-lead: 15px;
        --fs-body: 14px;
        --lh-body: 1.65;
        --fs-card-title: 15px;
        --fs-card-desc: 14px;
        --fs-row-title: 14px;
        --fs-sm: 13px;
        --fs-meta: 12.5px;
        --fs-label: 11px;
        --fs-fineprint: 12px;
        --fs-micro: 10px;
        --ls-kicker: 2.4px;
        --gutter: 20px;
        --section-y: 52px;
        --section-y-sm: 44px;
        --section-y-lg: 56px;
        --header-h: 68px;
        --bar-h: 14px;
        --icon-circle: 40px;
        --gap-grid: 20px;
        --gap-cols: 24px;
        --gap-stack: 18px;
        --map-h: 420px;
    }

    .header-logo img {
        height: 34px;
    }

    .stats {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 32px 20px;
    }

    /* Das Blueprint-Motiv wäre auf Phone-Breite so gestaucht, dass davon nichts
       mehr zu erkennen ist — dann lieber gar nicht laden. */
    .section--offwhite {
        background-image: none;
    }

    .numbered-grid,
    .card-grid,
    .project-gallery {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Die Chips weichen hier dem Auswahlfeld. Umbrochen stünde bei 375px jeder
       der sieben in eigener Zeile — rund 270px Leiste vor der ersten Karte;
       seitlich scrollend wurde der erste Chip am Bildrand mitten im Wort
       abgeschnitten und las sich wie ein Darstellungsfehler (User, 27.08.2026). */
    .filter-bar {
        display: none;
    }

    .filter-select {
        display: flex;
    }

    /* Ein 16:9-Ausschnitt schrumpft auf 335px Breite zum Streifen — auf Phone
       darf das Motiv höher stehen (Regel 7: stapeln statt beschneiden). */
    .project-figure img {
        aspect-ratio: 4 / 3;
    }

    /* Vertikal stapeln statt Spalten — keine Hover-/Absolute-Tricks */
    .numbered-grid {
        gap: 0;
    }

    .numbered-item {
        padding: 14px 0;
    }

    .icon-list__item {
        padding: 14px 0;
        border-bottom: 0;
        border-top: var(--rule-w) dotted var(--c-rule);
    }

    .icon-list--fokus {
        gap: 12px;
    }

    .icon-list--fokus .icon-list__item {
        padding: 18px 20px;
        border-top: 0;
    }

    /* Kleiner, aber gleiche Geschwindigkeit in Pixeln pro Sekunde: die Kopie
       wird schmaler, also darf sie auch kürzer brauchen. */
    :root {
        --logo-marquee-h: 60px;
    }

    .logo-marquee__track {
        --marquee-gap: 52px;
        animation-duration: 34s;
    }

    /* Einspaltig steht jede Karte für sich — reservierte Zeilen wären nur Luft. */
    .project-card h3,
    .project-card__note {
        min-height: 0;
    }

    /* Gestapelt statt beschnitten: als Hintergrund bliebe von einem 2,45:1-Motiv
       auf 375 px nur ein Drittel übrig, und der Text bräuchte einen so dichten
       Schleier, dass vom Bild nichts mehr zu sehen ist. Unten angesetzt zeigt es
       den Baukörper vollständig (Lehre aus ib-rieker ADR-0010/0011: kein
       Beschnitt über feste Höhen). */
    .hero {
        display: flex;
        flex-direction: column;
        min-height: 0;
        padding-bottom: 0;
    }

    /* Das Bild steht im Markup vor dem Text (LCP-Preload) — hier per `order`
       darunter, damit die Kernbotschaft zuerst kommt. */
    .hero__bg {
        order: 1;
        position: static;
        width: 100%;
        height: auto;
        margin-top: 36px;
        aspect-ratio: 16 / 9;
        object-position: 78% center;
        /* Die obere Bildkante läuft von rgb(18,30,65) links bis rgb(2,19,50)
           rechts — gegen die Sektionsfläche rgb(13,30,68) ergäbe das eine
           sichtbare Naht. Deshalb oben in die Fläche ausblenden. */
        -webkit-mask-image: var(--mask-fade-top);
        mask-image: var(--mask-fade-top);
    }

    /* Ohne Text über dem Bild braucht es keinen Schleier mehr. */
    .hero::before,
    .page-hero--media::before {
        display: none;
    }

    /* Seitenkopf gestapelt, gleiche Begründung wie beim Startseiten-Hero:
       ein 2,45:1-Motiv taugt auf Phone-Breite nicht als Textgrund. */
    .page-hero--media {
        display: flex;
        flex-direction: column;
        min-height: 0;
        padding-bottom: 0;
    }

    .page-hero__bg {
        order: 1;
        position: static;
        width: 100%;
        height: auto;
        margin-top: 28px;
        aspect-ratio: 16 / 9;
        object-position: 78% center;
        /* Der Bildgrund (#02122C) ist dunkler als die Sektionsfläche — ohne
           das Ausblenden zeichnet sich die obere Kante als Naht ab. */
        -webkit-mask-image: var(--mask-fade-top);
        mask-image: var(--mask-fade-top);
    }

    .faq__question {
        gap: 16px;
        padding: 18px 0;
        font-size: var(--fs-faq-question);
    }

    .faq__answer {
        padding-bottom: 18px;
        font-size: var(--fs-faq-answer);
    }

    .btn-group {
        flex-direction: column;
    }

    .btn-group .btn {
        width: 100%;
    }

    .section-head-row {
        flex-direction: column;
        align-items: stretch;
    }

    .section-head-row .btn {
        align-self: stretch;
    }

    .section-body {
        margin-top: 28px;
    }

    .project-card__media {
        height: 150px;
    }

    .project-card__body,
    .post-card__body {
        padding: 22px;
    }

    .footer-grid {
        flex-direction: column;
        gap: 26px;
    }

    .footer-brand {
        width: auto;
    }

    .footer-bottom {
        flex-direction: column;
        align-items: flex-start;
        gap: 10px;
        margin-top: 26px;
    }

    /* Dekorative Blueprint-Grafiken auf Mobile weglassen — im
       Mobile-Mockup tragen sie nichts und kosten eine halbe Bildschirmhöhe. */
    .decor {
        display: none;
    }

    .nav-drawer {
        padding: 20px var(--gutter);
    }

    .cookie-banner {
        padding: 10px;
    }

    .cookie-banner__inner {
        max-height: calc(100dvh - 20px);
        padding: 18px;
    }

    .standort-liste {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

@media (max-width: 480px) {
    :root {
        --gutter: 16px;
        --logo-marquee-h: 48px;
        --map-h: 340px;
    }

    .logo-marquee__track {
        --marquee-gap: 40px;
    }

    /* Hochformatiger Ausschnitt: 16/9 wird auf 320–480px zu flach, der
       Baukörper schrumpft zum Streifen. */
    .hero__bg,
    .page-hero__bg {
        aspect-ratio: 4 / 3;
    }

    /* Gleiche Begruendung, aber eigene Regel: das unbeschnittene Motiv traegt
       ab 1024px 3:2 und wuerde die Zeile darueber sonst wegen hoeherer
       Spezifitaet ueberstimmen. */
    .page-hero--uncropped .page-hero__bg {
        aspect-ratio: 4 / 3;
    }

    /* Kennzahlen bleiben zweispaltig — einspaltig steht jede Zahl allein in
       einer 343px-Zeile und der Block wirkt leer. */
    .stats {
        gap: 28px 16px;
    }

    /* Vor- und Nachname nebeneinander wären hier je rund 150px breit. */
    .form__row {
        grid-template-columns: minmax(0, 1fr);
    }

    .kontaktdaten {
        grid-template-columns: minmax(0, 1fr);
    }

    /* Feld und Knopf nebeneinander lassen dem Suchbegriff hier keine 180px. */
    .suche-form {
        flex-direction: column;
        align-items: stretch;
    }
}

/* ============================================================
   11 · Motion
   ============================================================ */

/* AOS bewegt standardmäßig 100px — für eine Seite, die auf „weniger ist mehr"
   ausgelegt ist, zu viel. Doppelter Selektor, weil aos.css nach redesign.css
   geladen wird. */
[data-aos="fade-up"][data-aos="fade-up"] {
    transform: translate3d(0, 24px, 0);
}

[data-aos="fade-right"][data-aos="fade-right"] {
    transform: translate3d(-24px, 0, 0);
}

[data-aos="fade-left"][data-aos="fade-left"] {
    transform: translate3d(24px, 0, 0);
}

@media (prefers-reduced-motion: reduce) {
    html {
        scroll-behavior: auto;
    }

    *,
    *::before,
    *::after {
        transition-duration: 0.01ms !important;
        animation-duration: 0.01ms !important;
        /* Ohne das bliebe die Hero-Kaskade bis zu ihrem Delay unsichtbar */
        animation-delay: 0ms !important;
    }

    /* AOS-Startzustände neutralisieren */
    [data-aos] {
        opacity: 1 !important;
        transform: none !important;
    }

    /* Das Laufband wird zur still stehenden, wischbaren Reihe. Die Regel oben
       allein genügt nicht: mit `animation-duration: 0.01ms` und `infinite`
       liefe es nur unsichtbar schnell weiter. */
    .logo-marquee {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .logo-marquee__track {
        animation: none !important;
        will-change: auto;
    }

    /* Fade-Kanten würden im scrollbaren Container mitscrollen */
    .logo-marquee::before,
    .logo-marquee::after {
        display: none;
    }

    /* Die zweite Kopie trägt nur die Endlosschleife */
    .logo-marquee__item[aria-hidden="true"] {
        display: none;
    }
}
