body { -webkit-font-smoothing: antialiased; }
.display { font-weight: 900; letter-spacing: -0.02em; line-height: 0.98; }
.eyebrow { font-weight: 600; letter-spacing: 0.22em; text-transform: uppercase; }

/* Wortmarke REDEKER: ueberall in Versalien + kursiv (Kundenwunsch Runde 3) */
.brand { font-style: italic; text-transform: uppercase; }

/* Bereichs-Trennlinie: sitzt zwischen kleiner Bereichsbezeichnung (Eyebrow) und Ueberschrift
   (Kundenwunsch Runde 3 - ruhiger, v.a. mobil). Dunkle Sektionen: .eyebrow-rule.on-dark */
.eyebrow-rule { display: block; height: 2px; width: 5.5rem; margin: .9rem 0 1.15rem; background: #0096D6; }
.eyebrow-rule.on-dark { background: rgba(0,150,214,.6); }

/* Umbruchverhalten fuer deutschen Fliesstext. Komposita wie
   "Leistungsbereiche" oder "Bodenstabilisierung" sind laenger als eine
   schmale Spalte auf dem Handy; ohne Trennstelle laufen sie aus der Box
   heraus statt umzubrechen (Screenshot 07.10.2026, Kennzahlen-Kacheln).

   overflow-wrap gilt ueberall als Sicherheitsnetz: ein Wort, das partout
   nicht passt, bricht hart um, statt das Layout zu sprengen.
   Echte Silbentrennung nur auf Mobile - auf dem Desktop ist genug Platz,
   und Trennstriche im Fliesstext wirken dort unruhig. lang="de" ist auf
   allen Seiten gesetzt, der Browser trennt daher nach deutschen Regeln. */
body { overflow-wrap: break-word; }

@media (max-width: 767px) {
  body {
    -webkit-hyphens: auto; hyphens: auto;
    /* Ohne Limit trennt der Browser auch kurze Woerter ("aus ei-ner Hand").
       Erst ab 8 Zeichen trennen, mindestens 4 davor und 3 danach stehen
       lassen. Aeltere Browser ignorieren die Zeile und trennen wie bisher. */
    -webkit-hyphenate-limit-before: 4; -webkit-hyphenate-limit-after: 3;
    hyphenate-limit-chars: 8 4 3;
  }
  /* Ueberschriften und Eyebrows bleiben ungetrennt - dort stoeren
     Trennstriche die Wirkung mehr, als der gewonnene Platz bringt.

     Dasselbe gilt fuer Bedienelemente: Navigationspunkte, Buttons und
     Footer-Links sind kurze Labels, bei denen eine Trennung immer wie ein
     Fehler aussieht ("Kon-takt"). Wichtig, weil Firefox
     hyphenate-limit-chars nicht unterstuetzt und dort sonst auch kurze
     Woerter getrennt wuerden - die Regel wirkt in jedem Browser. */
  h1, h2, h3, h4, .eyebrow,
  nav a, nav button, .nav-link, button, [role="button"], a.btn {
    -webkit-hyphens: none; hyphens: none;
  }
}

/* RT-Bildmarke als Hintergrund-Motiv (Pfad relativ zu dieser CSS-Datei in assets/) */
.motif { background-image: url('../images/redeker-kreis.png'); background-repeat: no-repeat; background-size: contain; background-position: center; }
.motif-dark { background-image: url('../images/redeker-kreis-white.png'); }

/* Eckakzent aus der Bildmarke. Frueher trug jede Instanz eine feste Pixelgroesse
   (380-600px). Auf dem Desktop war das ein dezenter Akzent in der Ecke - auf dem
   Handy war derselbe Kreis breiter als der Viewport und lag als graue Flaeche
   hinter dem Fliesstext (Screenshot 07.10.2026, Unternehmensprofil).
   Die Groesse skaliert jetzt mit der Viewportbreite und laeuft erst auf grossen
   Screens gegen den Desktop-Wert, der pro Instanz ueber --motif-size gesetzt wird.
   Unterhalb von ~1217px greift dadurch automatisch die vw-Stufe, was auch Tablets
   und schmale Desktopfenster mitnimmt. */
.motif-accent {
  position: absolute;
  width: clamp(150px, 46vw, var(--motif-size, 560px));
  aspect-ratio: 1 / 1;
  height: auto;
  pointer-events: none;
}

/* Auf Mobile zusaetzlich zurueckgenommen: der Akzent soll dort nicht mit dem
   Text konkurrieren. Die doppelte Klasse (.motif.motif-accent) hat hoehere
   Spezifitaet als die Tailwind-Utility .opacity-[...] und schlaegt sie daher
   ohne !important. */
@media (max-width: 767px) {
  .motif.motif-accent { opacity: .035; }
}

/* Foto-Platzhalter */
.ph { position: relative; background-color: #eef0f3; background-image: repeating-linear-gradient(135deg, rgba(122,136,142,.10) 0 1px, transparent 1px 13px); overflow: hidden; }
.ph::after { content: attr(data-label); position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 1rem; text-align: center; font-family: ui-monospace, Menlo, monospace; font-size: 11px; letter-spacing: 0.12em; text-transform: uppercase; color: #8a979c; }
.ph-dark { background-color: #1b1a40; background-image: repeating-linear-gradient(135deg, rgba(255,255,255,.05) 0 1px, transparent 1px 13px); }
.ph-dark::after { color: rgba(255,255,255,.5); }

/* Scroll-Reveal – der versteckte Startzustand gilt NUR mit aktivem JS (.js).
   Ohne JS (oder wenn die Reveal-Logik nicht startet) bleiben Inhalte sichtbar. */
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity .7s cubic-bezier(.2,.7,.2,1), transform .7s cubic-bezier(.2,.7,.2,1); }
.reveal.in { opacity: 1; transform: none; }

/* Richtungs-Reveal: Elemente fliegen abwechselnd von links bzw. rechts ein */
.js .reveal.from-left { transform: translateX(-56px); }
.js .reveal.from-right { transform: translateX(56px); }
.js .reveal.from-left.in, .js .reveal.from-right.in { transform: none; }
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.from-left, .reveal.from-right { opacity: 1 !important; transform: none !important; }
}

/* Sicherheitsnetz: springt die Reveal-Logik nicht an, setzt das Inline-Skript im
   <head> nach kurzer Zeit .reveal-fallback und macht alle Inhalte sichtbar. */
.reveal-fallback .reveal,
.reveal-fallback .reveal.from-left,
.reveal-fallback .reveal.from-right,
.reveal-fallback .hero-headline .hero-line > span,
.reveal-fallback .trust-item,
.reveal-fallback .trust-ico { opacity: 1 !important; transform: none !important; }

/* Nav-Unterstreichung */
.nav-link { position: relative; }
.nav-link::after { content: ''; position: absolute; left: 0; right: 0; bottom: -6px; height: 2px; background: #0096D6; transform: scaleX(0); transform-origin: left; transition: transform .3s ease; }
.nav-link:hover::after, .nav-link.active::after { transform: scaleX(1); }

/* Untermenue-Flyout in der Hauptnavigation (Briefing G-04). Oeffnet beim
   Ueberfahren des Hauptpunkts und - fuer Tastaturbedienung - sobald der Fokus im
   Menue steht. Der Hauptpunkt selbst bleibt ein Link auf die Seite; das Flyout
   ergaenzt nur die Sprungmarken zu den Sektionen.
   visibility statt display: so bleibt der Ein-/Ausblend-Uebergang animierbar und
   die Links sind im geschlossenen Zustand nicht per Tab erreichbar. */
.nav-sub {
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -6px);
  transition: opacity .22s ease, transform .22s ease, visibility .22s;
  z-index: 60;
}
.nav-item:hover > .nav-sub,
.nav-item:focus-within > .nav-sub {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}
/* Pfeil dreht sich, solange das Flyout offen ist bzw. das Akkordeon aufgeklappt ist */
.nav-caret { transition: transform .22s ease; }
.nav-item:hover > .nav-link .nav-caret,
.nav-item:focus-within > .nav-link .nav-caret,
.msub-btn.is-open .nav-caret { transform: rotate(-180deg); }

@media (prefers-reduced-motion: reduce) {
  .nav-sub, .nav-caret { transition: none; }
}

/* Header: durchgehend heller, farblich abgesetzter Balken (Kundenwunsch); Scroll verstaerkt nur den Schatten */
#site-header { position: fixed; inset-inline: 0; top: 0; z-index: 50; background: rgba(255,255,255,.92); backdrop-filter: blur(8px); box-shadow: 0 1px 0 rgba(22,21,52,.06); transition: background .3s ease, box-shadow .3s ease; }
#site-header .nav-link { color: #28275A; }
#site-header .nav-link:hover { color: #1f1e48; }
#site-header .nav-link.active { color: #0083bd; }
#site-header .hdr-icon { color: #7A888E; }
#site-header .hdr-icon:hover { color: #28275A; background: #f5f6f8; }
#site-header #menu-btn { color: #28275A; }
#site-header #hdr-cta { background: #28275A; color: #fff; }
#site-header #hdr-cta:hover { background: #36356e; color: #fff; }
#site-header.scrolled { box-shadow: 0 1px 0 rgba(22,21,52,.06), 0 12px 30px -20px rgba(22,21,52,.35); }

/* Startseite + die 6 Hub-Unterseiten (Unternehmen/Leistungen/Karriere/
   Referenzen/Aktuelles/Kontakt): alle nutzen denselben hellen Hero-Scrim
   (hero-scrim-light), darum startet der Header ueberall transparent darueber
   (Mockup Runde 5, seit Rundenerweiterung auch auf den Hub-Seiten). Ab 24px
   Scroll setzt chrome.js .scrolled und der weisse Balken blendet ueber die
   bestehende background-Transition wieder ein. .menu-open: bei geoeffnetem
   Mobile-Menue wird der Balken erzwungen, damit die obere Header-Zeile nicht
   transparent ueber dem Bild haengt. */
body[data-page="startseite"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="unternehmen"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="leistungen"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="karriere"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="referenzen"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="aktuelles"] #site-header:not(.scrolled):not(.menu-open),
body[data-page="kontakt"] #site-header:not(.scrolled):not(.menu-open) {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}
/* Transparenter Header ueber dem Blau-Overlay (G-03): Seit das Hero-Foto blau
   getoent ist, verlieren die dunklen Nav-Links und das dunkle Logo ihren
   Kontrast - solange der Balken transparent ueber dem Hero liegt, laeuft der
   Header deshalb in Weiss. Sobald chrome.js .scrolled setzt (weisser Balken),
   greifen wieder die Standardfarben weiter oben.
   Auswahl ueber :has(), damit jede Seite mit Hero-Overlay automatisch erfasst
   ist und die Liste nicht bei jeder neuen Unterseite nachgezogen werden muss. */
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .nav-link,
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #menu-btn {
  color: #fff;
  text-shadow: 0 1px 3px rgba(16, 15, 40, .45);
}
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .nav-link:hover,
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .nav-link.active {
  color: #7fccef;
}
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .hdr-icon {
  color: rgba(255, 255, 255, .88);
}
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .hdr-icon:hover {
  color: #28275A;
  background: rgba(255, 255, 255, .9);
}
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #hdr-cta {
  background: #fff;
  color: #28275A;
}
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #hdr-cta:hover {
  background: #7fccef;
  color: #161534;
}
/* Logo-Wechsel: Das Markup liefert beide Varianten, sichtbar ist immer nur eine. */
#logo-light { display: none; }
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #logo { display: none; }
body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #logo-light { display: block; }

.svc-card:hover .svc-photo { transform: scale(1.05); }
.svc-card:hover .svc-arrow { transform: translateX(4px); color: #0096D6; }

/* Hero-Karussell: Crossfade + gerichteter Ken-Burns-Zoom-In (Salmen-Bau-Vorbild,
   Kundenwunsch Runde 4 / Briefing 2.2: deutlich schneller und mit groesserer
   Amplitude als bisher).
   Der Zoom ist an is-active gekoppelt, damit die Bewegung immer in dieselbe
   Richtung laeuft (kein "alternate" mehr, das mal rein- und mal rauszoomt).
   Damit beim Ausblenden trotzdem kein Ruecksprung entsteht, entspricht der
   RUHEZUSTAND der Slides exakt dem Endwert der Animation: Wird is-active
   entfernt, steht der Slide bereits auf dem Zielwert und faded sprungfrei aus.
   Voraussetzung: --hero-zoom-ms == Slide-Intervall im JS (index.html liest den
   Wert von dort aus, damit beides nicht auseinanderlaeuft). */
:root {
  --hero-zoom-from: 1.02;
  --hero-zoom-to: 1.30;
  --hero-zoom-ms: 6000ms;
}

.hero-slide {
  opacity: 0;
  transition: opacity 0.8s ease-in-out;
  transform-origin: 50% 50%;
  transform: scale(var(--hero-zoom-to)) translate3d(-6%, -1%, 0);
  will-change: opacity, transform;
}
/* ease-out statt linear: Bei linearem Zoom wirkt der Anfang zaeh, weil die
   Skalenaenderung relativ zur wachsenden Bildgroesse immer weniger ausmacht.
   Diese Kurve startet gut doppelt so schnell wie linear, laeuft aber bewusst
   nicht zu frueh aus - eine staerkere ease-out (z.B. .06/.62/.36/1) steht ab
   Sekunde 3 praktisch still (Briefing 2.2: dynamischer, aber durchgehend). */
.hero-slide.is-active {
  opacity: 1;
  animation: hero-kenburns var(--hero-zoom-ms) cubic-bezier(.2, .5, .45, 1) both;
}

@keyframes hero-kenburns {
  from { transform: scale(var(--hero-zoom-from)) translate3d(0, 0, 0); }
  to   { transform: scale(var(--hero-zoom-to)) translate3d(-6%, -1%, 0); }
}

/* Ruhige Variante fuer frontale Motive (Verwaltungsgebaeude, ST-01/ST-02):
   Der volle Ken-Burns-Zoom (1.30) schneidet bei einer formatfuellenden
   Frontalansicht Dach und Vorplatz an - das Gebaeude waere nur noch als
   Ausschnitt lesbar. Daher hier ein deutlich kleinerer Zoomweg; der
   Translate-Anteil ist mitskaliert, damit an den Raendern keine Luecke
   entsteht. */
.hero-slide.hero-slide--calm {
  transform: scale(1.06) translate3d(-1.5%, -0.5%, 0);
}
.hero-slide.hero-slide--calm.is-active {
  animation-name: hero-kenburns-calm;
}
@keyframes hero-kenburns-calm {
  from { transform: scale(1) translate3d(0, 0, 0); }
  to   { transform: scale(1.06) translate3d(-1.5%, -0.5%, 0); }
}

/* Barrierefreiheit: Zoom aus, sanfter Slide-Crossfade bleibt (Nutzerwunsch) */
@media (prefers-reduced-motion: reduce) {
  .hero-slide, .hero-slide.is-active { animation: none; transform: none; }
}

/* Unterseiten-Hero: nur 1 Bild statt Karussell, daher kein einmaliger
   Kenburns-Zoom (der wuerde nach Ablauf einfach eingefroren stehen bleiben,
   da kein zweites Bild zum Ueberblenden folgt). Stattdessen eine endlose
   Zoom-Schleife - wirkt lebendig wie die Startseite, ohne weitere Motive zu
   benoetigen. Zwei Animationen kombiniert: der erste Zoom (hero-zoom-intro)
   startet zuegig ohne Ease-In, damit die Bewegung beim Laden sofort
   auffaellt; ab dann uebernimmt die zweite (hero-zoom-loop, per Delay exakt
   im Anschluss) ein klassisches ease-in-out im Alternate-Loop, das an jedem
   Umkehrpunkt mit Geschwindigkeit 0 ankommt und startet - dadurch kein
   Ruckeln/Sprung an den Umkehrpunkten wie bei zwei "schnell-start"-Kurven
   hintereinander. Intro endet ebenfalls bei Geschwindigkeit 0 (gleiche
   Kurvenform wie zuvor), daher ist die Uebergabe an den Loop nahtlos. */
.hero-zoom-loop {
  transform-origin: 50% 50%;
  animation:
    hero-zoom-intro 9s cubic-bezier(.16,1,.3,1) 1 forwards,
    hero-zoom-loop 9s ease-in-out infinite alternate 9s;
  will-change: transform;
}
@keyframes hero-zoom-intro {
  from { transform: scale(1); }
  to   { transform: scale(1.15); }
}
@keyframes hero-zoom-loop {
  from { transform: scale(1.15); }
  to   { transform: scale(1); }
}

/* Kachel-Slideshow in den Leistungsbloecken (Kundenvorgabe "Aenderungen
   Grafiken": Kanalbau LF-05, Gewerbebau RF-03). Bewusst ohne Zoom - die Kachel
   steht direkt neben dem Fliesstext und soll ruhig laufen. Der Hover-Zoom
   sitzt auf dem umschliessenden Container, damit er die Opacity-Transition
   hier nicht ueberschreibt. */
.tile-slide {
  opacity: 0;
  transition: opacity 0.8s ease-in-out;
}
.tile-slide.is-active { opacity: 1; }
@media (prefers-reduced-motion: reduce) {
  .tile-slide { transition: none; }
}
@media (prefers-reduced-motion: reduce) {
  .hero-zoom-loop { animation: none; transform: none; }
}

/* Header-Scrim: dunkler Verlauf ueber den Headerbildern. Bewusst nur unten
   kraeftig (dort steht der Text), nach oben vollstaendig auslaufend -> das Bild
   bleibt sichtbar und wirkt (Kundenwunsch Runde 4 / Briefing 2.1: Seite wirkte
   "zu blastig/farbverlaufslastig"). Die Deckungsgrade sind zentral ueber die
   Custom Properties justierbar - nach Lieferung der finalen Headerbilder muss
   nur hier nachgeregelt werden, nicht in 15 HTML-Dateien. */
.hero-scrim {
  --scrim-bottom: .86;
  --scrim-mid: .48;
  --scrim-top: .10;
  --scrim-edge: 0;
  background: linear-gradient(to top,
    rgba(22, 21, 52, var(--scrim-bottom)) 0%,
    rgba(22, 21, 52, var(--scrim-mid)) 34%,
    rgba(22, 21, 52, var(--scrim-top)) 66%,
    rgba(22, 21, 52, var(--scrim-edge)) 100%);
}

/* Textreiche Header (Karriere, Unternehmen, Referenzen, Aktuelles, Kontakt): Die
   Copy fuellt hier die gesamte Headerhoehe, inkl. Breadcrumb ganz oben. Deshalb
   durchgehend mehr Deckung noetig - liegt aber weiterhin klar unter dem alten
   Stand (Flaechen-Layer + Verlauf). --scrim-edge sorgt dafuer, dass der Verlauf
   ganz oben (Breadcrumb-Hoehe) nicht komplett auf 0 auslaeuft - sonst ist die
   Breadcrumb bei hellen/unruhigen Bildmotiven kaum lesbar (Kundenfeedback). */
.hero-scrim--copy { --scrim-bottom: .88; --scrim-mid: .70; --scrim-top: .55; --scrim-edge: .50; }

/* Startseite: mobil traegt der vertikale Verlauf die Lesbarkeit allein (der Text
   nutzt die volle Breite), ab sm uebernimmt der horizontale Scrim von links -
   dann kann der vertikale deutlich zurueckgenommen werden und die rechte
   Bildhaelfte bleibt frei -> groessere Bildwirkung. Mid/Top gegenueber der
   ersten Fassung angehoben (Kundenfeedback: Eyebrow/Flieptext auf Mobile bei
   hellen Bildmotiven kaum lesbar - die sitzen auf Hoehe von scrim-mid/-top). */
.hero-scrim--home { --scrim-bottom: .82; --scrim-mid: .68; --scrim-top: .34; }

@media (min-width: 640px) {
  .hero-scrim--home { --scrim-bottom: .80; --scrim-mid: .30; --scrim-top: 0; }
  .hero-scrim--home::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: linear-gradient(to right,
      rgba(22, 21, 52, .74) 0%,
      rgba(22, 21, 52, .64) 38%,
      rgba(22, 21, 52, .32) 58%,
      rgba(22, 21, 52, .08) 76%,
      rgba(22, 21, 52, 0) 90%);
  }
}

/* Startseite (Mockup Runde 5): heller Scrim statt dunklem ink-Verlauf. Startet
   links oben deckend weiss und laeuft diagonal nach rechts unten vollstaendig
   aus - links steht die dunkle Copy, rechts unten bleibt das (rechtszentrierte)
   Bildmotiv frei. Mobil dieselbe Diagonale, nur steiler: oben (Headline)
   kraeftig, nach unten auslaufend, damit das rechtsbuendige Motiv sichtbar
   bleibt. Nachregeln nach Bildlieferung nur an den Stops hier, nicht im HTML. */
/* G-03 (Kundenvorgabe "Aenderungen Grafiken", ersetzt den hellen Scrim aus
   Runde 5): Das Overlay ueber den Header-Fotos liegt jetzt im Redeker-Blau
   (#28275A aus Logo/CI) und erreicht hoechstens 40 % Deckkraft.
   Bewusst EINE Ebene - zwei uebereinanderliegende Verlaeufe wuerden sich
   multiplizieren und die 40 % ueberschreiten. Links (dort steht die Copy)
   liegen die vollen 40 %, nach rechts laeuft das Overlay auf 20 % aus, damit
   das Motiv sichtbar bleibt und die Navigation oben rechts trotzdem noch
   einen Untergrund hat. Nachregeln nur an den Stops hier, nicht im HTML.
   KA-05 ist damit ebenfalls erledigt (Karriere nutzt dieselbe Klasse). */
.hero-scrim-light {
  background: linear-gradient(100deg,
    rgba(40, 39, 90, .40) 0%,
    rgba(40, 39, 90, .40) 42%,
    rgba(40, 39, 90, .33) 56%,
    rgba(40, 39, 90, .22) 76%,
    rgba(40, 39, 90, .20) 100%);
}
/* Lesbarkeitsverlauf hinter der Textspalte (RF-05, vom Kunden freigegeben):
   Auf hellen Motiven reichen 40 % Blau fuer weisse Schrift nicht aus. Dieser
   zweite Verlauf liegt ausschliesslich links hinter der Copy und ist bei 52 %
   Breite vollstaendig ausgelaufen - ueber der eigentlichen Bildflaeche rechts
   bleibt es damit bei den geforderten 40 %. */
.hero-scrim-light::before {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* Zwei Lagen, beide nur fuer die Lesbarkeit der Schrift:
     1) Kopfzone in Header-Hoehe (11rem) - dort stehen Navigation und CTA, die
        seit G-03 weiss laufen und sonst ueber hellen Motiven untergehen
        (entspricht dem frueheren weissen Kopfverlauf, nur invertiert).
     2) Textspalte links, bei 52 % Breite vollstaendig ausgelaufen. */
  background:
    linear-gradient(to bottom, rgba(16, 15, 40, .38) 0%, rgba(16, 15, 40, .14) 60%, rgba(16, 15, 40, 0) 100%) top / 100% 11rem no-repeat,
    linear-gradient(100deg,
      rgba(16, 15, 40, .42) 0%,
      rgba(16, 15, 40, .30) 26%,
      rgba(16, 15, 40, .12) 42%,
      rgba(16, 15, 40, 0) 52%);
}

/* Hero-Copy steht seit G-03 auf blau getoentem Foto -> weisse Auszeichnung.
   Der Textschatten ist kein zweites Overlay, sondern sitzt nur hinter der
   Schrift; die 40-%-Grenze ueber der Bildflaeche bleibt damit eingehalten.
   Elemente mit eigener Flaeche (weisse Chips, dunkle Buttons) bleiben
   unangetastet - sie bringen ihren Kontrast selbst mit. */
.hero-copy {
  color: #fff;
  /* Zwei Schatten: ein enger fuer die Kantenschaerfe, ein weicher als Halo -
     dadurch bleibt vor allem der kleinere Fliesstext auch ueber hellen
     Bildstellen lesbar, ohne dass eine sichtbare Flaeche entsteht. */
  text-shadow: 0 1px 3px rgba(16, 15, 40, .55), 0 2px 14px rgba(16, 15, 40, .45);
}
.hero-copy h1,
.hero-copy nav,
.hero-copy nav a {
  color: #fff;
}
.hero-copy > p {
  color: rgba(255, 255, 255, .92);
}
.hero-copy [class*="text-ink"]:not([class*="bg-"]) {
  color: rgba(255, 255, 255, .88);
}
.hero-copy [class*="text-electric"] {
  color: #7fccef;
}
.hero-copy nav a:hover {
  color: #fff;
  text-decoration: underline;
}
/* Sekundaerer (nur umrandeter) Button im Hero */
.hero-copy [class*="border-feh"] {
  border-color: rgba(255, 255, 255, .55);
  color: #fff;
}
.hero-copy [class*="bg-white"],
.hero-copy [class*="bg-ink"],
.hero-copy [class*="bg-electric"] {
  text-shadow: none;
}

/* Hero-Text: gestaffeltes, geschmackvolles Einblenden beim Laden (Ueberschrift,
   Trennlinie, Eyebrow, Untertext, Buttons steigen nacheinander sanft ein). */
.hero-copy > * {
  opacity: 0;
  animation: hero-rise .9s cubic-bezier(.2, .6, .2, 1) both;
}
.hero-copy > *:nth-child(1) { animation-delay: .15s; }
.hero-copy > *:nth-child(2) { animation-delay: .32s; }
.hero-copy > *:nth-child(3) { animation-delay: .44s; }
.hero-copy > *:nth-child(4) { animation-delay: .58s; }
.hero-copy > *:nth-child(5) { animation-delay: .74s; }

@keyframes hero-rise {
  from { opacity: 0; transform: translate3d(0, 26px, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Barrierefreiheit: Text sofort sichtbar, keine Bewegung */
@media (prefers-reduced-motion: reduce) {
  .hero-copy > * { opacity: 1; animation: none; }
}

/* Hero-Ueberschrift: dynamischer, zeilenweiser Reveal. Erste Zeile gleitet von
   rechts ein, zweite Zeile von links (statt Block-Einblendung von hero-rise).
   Nur Ueberschriften mit .hero-line-Markup (Startseite) bekommen diesen
   Zeilen-Reveal - die Override-Regel greift daher nur dort per :has(); ohne
   .hero-line faellt die Ueberschrift auf den normalen hero-rise-Fade der
   .hero-copy > *-Regel zurueck (Unterseiten ohne Zeilen-Markup). */
.hero-headline:has(.hero-line) { opacity: 1; animation: none; }
.hero-headline .hero-line {
  display: block;
  overflow: hidden;
  padding: 0.06em 0;
  margin: -0.06em 0;
}
.hero-headline .hero-line > span {
  display: block;
}
.js .hero-headline .hero-line > span {
  opacity: 0;
}
/* Animation nur bei sichtbarer Ueberschrift (.in) – so wird der Effekt beim
   erneuten Hochscrollen jedes Mal neu ausgeloest. */
.hero-headline.in .hero-line > span {
  animation: 1s cubic-bezier(0.16, 0.85, 0.28, 1) both;
}
.hero-headline.in .hero-line:nth-child(1) > span {
  animation-name: hero-line-right;
  animation-delay: 0.2s;
}
.hero-headline.in .hero-line:nth-child(2) > span {
  animation-name: hero-line-left;
  animation-delay: 0.36s;
}

@keyframes hero-line-right {
  from { opacity: 0; transform: translate3d(12%, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}
@keyframes hero-line-left {
  from { opacity: 0; transform: translate3d(-12%, 0, 0); }
  to   { opacity: 1; transform: translate3d(0, 0, 0); }
}

/* Barrierefreiheit: Ueberschrift sofort sichtbar, keine Bewegung */
@media (prefers-reduced-motion: reduce) {
  .hero-headline .hero-line > span { opacity: 1 !important; transform: none !important; animation: none !important; }
}

/* Trust-Leiste: Container selbst nicht einblenden (nur als Reveal-Trigger nutzen),
   stattdessen die einzelnen Punkte gestaffelt und knackig einfliegen lassen. */
.reveal.trust-bar { opacity: 1; transform: none; transition: none; }
.js .trust-item {
  opacity: 0;
  transform: translateY(24px) scale(0.96);
  transition: opacity .55s cubic-bezier(.2,.7,.2,1), transform .55s cubic-bezier(.2,.7,.2,1);
}
.trust-bar.in .trust-item { opacity: 1; transform: none; }
.trust-bar.in .trust-item:nth-child(1) { transition-delay: .06s; }
.trust-bar.in .trust-item:nth-child(2) { transition-delay: .18s; }
.trust-bar.in .trust-item:nth-child(3) { transition-delay: .30s; }
.trust-bar.in .trust-item:nth-child(4) { transition-delay: .42s; }

/* Icon: poppt beim Einblenden rein und reagiert auf Hover (glueht + kippt leicht) */
.js .trust-ico {
  transform: scale(0);
  transition: transform .5s cubic-bezier(.34,1.56,.64,1), box-shadow .3s ease;
}
.trust-bar.in .trust-item:nth-child(1) .trust-ico { transition-delay: .22s; }
.trust-bar.in .trust-item:nth-child(2) .trust-ico { transition-delay: .34s; }
.trust-bar.in .trust-item:nth-child(3) .trust-ico { transition-delay: .46s; }
.trust-bar.in .trust-item:nth-child(4) .trust-ico { transition-delay: .58s; }
.trust-bar.in .trust-ico { transform: scale(1); }
.trust-item:hover .trust-ico {
  transform: scale(1.14) rotate(-8deg);
  box-shadow: 0 0 0 4px rgba(0,150,214,.18), 0 6px 16px rgba(0,150,214,.35);
}

@media (prefers-reduced-motion: reduce) {
  .trust-item, .trust-ico { opacity: 1 !important; transform: none !important; transition: none; }
}

/* REDEKER-Laufband: Wortmarke laeuft endlos (ohne Stopp) von links nach rechts.
   Zwei identische Gruppen; die Animation verschiebt die Spur von -50% auf 0 und
   springt danach nahtlos zurueck, weil beide Gruppen deckungsgleich sind. */
.marquee { overflow: hidden; padding: 1.4rem 0 1.1rem; }
.marquee-track { display: flex; width: max-content; animation: marquee-ltr 34s linear infinite; will-change: transform; }
.marquee-group { display: inline-flex; align-items: center; flex: none; }
.marquee-word {
  font-weight: 900;
  font-style: italic;
  text-transform: uppercase;
  letter-spacing: -0.01em;
  line-height: 1;
  font-size: clamp(2.4rem, 7vw, 5.5rem);
  padding: 0 0.28em;
  color: rgba(255,255,255,.12);
}
.marquee-sep {
  font-size: clamp(2.4rem, 7vw, 5.5rem);
  line-height: 1;
  color: rgba(0,150,214,.55);
}
/* Variante fuer hellen Hintergrund: dunkle Wortmarke statt weiss (klar sichtbar) */
.marquee--light .marquee-word { color: rgba(40,39,90,.22); }
/* Trennpunkt in Grau statt Blau (Kundenwunsch Runde 4 / Briefing 2.3) - wirkt ruhiger */
.marquee--light .marquee-sep { color: rgba(122,136,142,.7); }
/* Laufband ueber dem Footer (Runde 6): Trennpunkt in derselben Farbe wie die
   REDEKER-Wortmarke selbst statt im blauen Akzent (Kundenwunsch) - wirkt ruhiger. */
.marquee--footer .marquee-sep { color: rgba(255,255,255,.12); }
@keyframes marquee-ltr {
  from { transform: translateX(-50%); }
  to   { transform: translateX(0); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee-track { animation: none; }
}

/* Blau-Schleier ueber grossen Fotoflaechen, die an eine dunkle Textspalte stossen
   (Karriere-Teaser Startseite, Maschinenpark Unternehmen).
   Briefing G-03 / ST-08 / UN-06: Der Schleier ueber dem Foto darf hoechstens 40 %
   Deckkraft haben - vorher lag er bei 55 % im Bildmittel und lief zur Textspalte
   hin auf 100 % zu, wodurch die Bereiche "sehr dunkel" wirkten.
   --veil-blend ist der schmale Streifen unmittelbar an der Panel-Kante, der weiter
   voll deckt: ohne ihn stiesse das Foto mit einer harten Kante gegen die solide
   ink-950-Flaeche daneben. Nachregeln nur hier, nicht in den HTML-Dateien. */
.photo-veil {
  --veil: .40;
  --veil-blend: 7%;
  position: absolute;
  inset: 0;
  pointer-events: none;
}
/* dunkle Textspalte liegt RECHTS vom Foto (Startseite, Karriere-Teaser) */
.photo-veil--right {
  background: linear-gradient(to left,
    rgba(22, 21, 52, 1) 0%,
    rgba(22, 21, 52, var(--veil)) var(--veil-blend),
    rgba(22, 21, 52, var(--veil)) 30%,
    rgba(22, 21, 52, 0) 85%);
}
/* dunkle Textspalte liegt LINKS vom Foto (Unternehmen, Maschinenpark) */
.photo-veil--left {
  background: linear-gradient(to right,
    rgba(22, 21, 52, 1) 0%,
    rgba(22, 21, 52, var(--veil)) var(--veil-blend),
    rgba(22, 21, 52, var(--veil)) 30%,
    rgba(22, 21, 52, 0) 85%);
}
/* Mobil steht das Foto als eigener Block unter bzw. ueber dem Text - dort gibt es
   keine Kante zur Textspalte, also auch keinen Blend-Streifen und einen gleichmaessig
   flachen Schleier von unten (haelt weisse Copy darueber lesbar). */
@media (max-width: 1023px) {
  .photo-veil--right, .photo-veil--left {
    background: linear-gradient(to top,
      rgba(22, 21, 52, var(--veil)) 0%,
      rgba(22, 21, 52, 0) 70%);
  }
}

/* Leichter Blau-Verlauf ueber den Leistungs-Bildern (Markenblau, laeuft nach oben aus) */
.svc-media { position: relative; overflow: hidden; }
.svc-media::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(to top, rgba(40,39,90,.5), rgba(40,39,90,.12) 55%, rgba(40,39,90,0)); }

/* Bildergalerie auf den Leistungs-Unterseiten (Kundenwunsch Runde 4 / Briefing 3.2:
   Slideshow mit Dots, Pfeilen und Auto-Play unterhalb des Text-Containers).
   Wie viele Kacheln nebeneinander stehen, entscheidet allein diese Datei ueber die
   flex-basis - das JS misst den Wert und muss nicht mitgepflegt werden.
   Der Abstand kommt ueber px-2 an den <li> plus -mx-2 am Track, damit die
   flex-basis-Rechnung exakt bleibt und der Offset ein glattes Vielfaches der
   Elementbreite ist. */
.gallery-track { transition: transform .6s cubic-bezier(.2,.7,.2,1); will-change: transform; }
.gallery-item { flex: 0 0 85%; } /* mobil: eine Kachel + angeschnittene naechste als Blaetter-Hinweis */
@media (min-width: 640px)  { .gallery-item { flex-basis: 50%; } }
@media (min-width: 1024px) { .gallery-item { flex-basis: 25%; } }

/* Barrierefreiheit: kein Auto-Play (siehe chrome.js), Pfeile springen ohne Bewegung */
@media (prefers-reduced-motion: reduce) { .gallery-track { transition: none; } }

.gal-dot { height: .5rem; width: .5rem; border-radius: 9999px; background: #b6bfc3; transition: background .3s ease, width .3s ease; }
.gal-dot[aria-current='true'] { width: 1.5rem; background: #0096D6; }

/* Themen-Filter auf Aktuelles.html (Briefing Abschnitt 7) */
.filter-btn { border-radius: .375rem; padding: .5rem 1rem; font-size: .875rem; font-weight: 500; border: 1px solid #d6dcdf; background: #fff; color: #28275A; transition: background .2s ease, color .2s ease, border-color .2s ease; }
.filter-btn:hover { border-color: #0096D6; color: #0083bd; }
.filter-btn.is-active { border-color: #28275A; background: #28275A; color: #fff; font-weight: 600; }
.filter-btn.is-active:hover { color: #fff; }

/* Standard-Buttons folgen dem Hero-CTA mit kleinerer Rundung. Bewusst
   ausgenommen bleiben Elemente mit fester Hoehe (Icon-Kreise wie Social-
   Links, Galerie-Pfeile und Lightbox-Schliesser) sowie Status-Badges. */
a.rounded-full:not([class*="h-"]),
button.rounded-full:not([class*="h-"]),
[aria-current="page"].rounded-full {
  border-radius: .375rem;
}

/* Referenz-Banner auf der Startseite (ST-06): breites Bildband, in dem die
   beiden Referenz-Luftaufnahmen wechseln. Eigenes Seitenverhaeltnis in CSS,
   damit kein zusaetzlicher Tailwind-Build noetig ist; mobil etwas hoeher,
   sonst wird das Motiv zu schmal. */
.ref-banner { aspect-ratio: 16 / 9; }
@media (min-width: 640px) { .ref-banner { aspect-ratio: 21 / 8; } }

/* ==========================================================================
   MOBILE: VOLLSTAENDIGE BILDER (Kundenvorgabe 07.10.2026)
   "Die meisten Besucher schauen sich ueber ein Smartphone die Webseite an,
   somit muss auch auf dem Smartphone das gesamte Bild zu sehen sein."

   Desktop bleibt unveraendert (formatfuellende Beschnitte, Ken-Burns-Zoom).
   Unter 768px (= Tailwind-Breakpoint md) gilt dagegen durchgehend:
   kein object-cover, kein Zoom - jede Box folgt dem Bildformat bzw. zeigt
   das Bild vollstaendig im Rahmen.

   Bewusst in reinem CSS und ohne !important: die Spezifitaet reicht ueber die
   Tailwind-Utilities (site.css wird nach tailwind.css geladen). Dadurch bleibt
   das HTML aller 27 Seiten unberuehrt - neue Unterseiten sind automatisch
   mit erfasst, solange sie dem bestehenden Hero-/Bildbox-Muster folgen.
   ========================================================================== */
@media (max-width: 767px) {

  /* --- 1. Hero -----------------------------------------------------------
     Die Headerbilder sind 21:9 bis 4:3 breit, die Copy lag bisher darueber -
     formatfuellend ging davon auf dem Handy mehr als die Haelfte verloren.
     Mobil wird daraus ein Stapel: Bildband im Dokumentfluss (volles Motiv,
     Originalformat), Copy darunter auf bg-paper. Die Section gibt dem Band
     oben den Platz des fixed #site-header (h-32 = 8rem) frei. */
  section:has(> .hero-copy) {
    min-height: 0;
    padding-top: 8rem;
  }
  /* Einzelbild-Hero (Unterseiten): Bild in den Fluss, Zoom-Schleife aus -
     ein skaliertes Bild waere wieder ein Ausschnitt. */
  section:has(> .hero-copy) > img {
    position: static;
    width: 100%;
    height: auto;
    object-fit: contain;
    transform: none;
    animation: none;
  }
  /* Slideshow-Hero (Startseite, Referenzen, Kanalbau): der Wrapper wird zum
     Bildband, das AKTIVE Bild steht darin im Fluss und gibt die Hoehe vor -
     damit ist kein Seitenverhaeltnis im CSS hinterlegt und jede Bildgroesse
     passt automatisch. Die uebrigen Slides liegen weiter deckungsgleich
     darueber, der Crossfade bleibt also unveraendert. */
  section:has(> .hero-copy) > div:has(> img.hero-slide) {
    position: relative;
    inset: auto;
    width: 100%;
  }
  section:has(> .hero-copy) img.hero-slide {
    object-fit: contain;
    transform: none;
    animation: none;
  }
  section:has(> .hero-copy) img.hero-slide.is-active {
    position: relative;
    inset: auto;
    height: auto;
  }
  /* Blau-Overlay (G-03) und Eckakzent lagen nur unter der Copy - ohne Text
     auf dem Bild wuerden sie das Motiv nur noch einfaerben bzw. verdecken. */
  section:has(> .hero-copy) > .hero-scrim-light,
  section:has(> .hero-copy) > .motif-accent {
    display: none;
  }
  /* Copy steht jetzt auf hellem Grund: Header-Freiraum raus (liegt oben an
     der Section), Weiss-auf-Foto zurueck auf die Markenfarben. */
  section:has(> .hero-copy) > .hero-copy {
    padding-top: 2rem;
    padding-bottom: 2.5rem;
    color: #28275A;
    text-shadow: none;
  }
  section:has(> .hero-copy) > .hero-copy h1,
  section:has(> .hero-copy) > .hero-copy nav,
  section:has(> .hero-copy) > .hero-copy nav a {
    color: #28275A;
    text-shadow: none;
  }
  section:has(> .hero-copy) > .hero-copy > p,
  section:has(> .hero-copy) > .hero-copy [class*="text-ink"]:not([class*="bg-"]) {
    color: rgba(22, 21, 52, .70);
  }
  section:has(> .hero-copy) > .hero-copy [class*="text-electric"] {
    color: #0083bd;
  }
  /* Der Header lief ueber dem Hero-Overlay transparent in Weiss. Ohne Foto
     hinter dem Balken (das Bild beginnt jetzt darunter) braucht es wieder den
     hellen Balken mit dunkler Schrift. Zusaetzliches html am Anfang nur fuer
     die Spezifitaet gegen die body[data-page]-Regeln weiter oben. */
  html body[data-page] #site-header:not(.scrolled):not(.menu-open) {
    background: rgba(255, 255, 255, .92);
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
    box-shadow: 0 1px 0 rgba(22, 21, 52, .06);
  }
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .nav-link,
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #menu-btn {
    color: #28275A;
    text-shadow: none;
  }
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) .hdr-icon {
    color: #7A888E;
  }
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #hdr-cta {
    background: #28275A;
    color: #fff;
  }
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #logo { display: block; }
  html body:has(.hero-scrim-light) #site-header:not(.scrolled):not(.menu-open) #logo-light { display: none; }

  /* --- 2. Inhaltsbilder --------------------------------------------------
     Muster im HTML: Box mit festem Seitenverhaeltnis (aspect-*) + Bild mit
     object-cover. Mobil gibt die Box ihr Verhaeltnis auf und uebernimmt das
     des Bildes - volles Motiv, keine Balken. Bildboxen, die schon
     object-contain nutzen (Zertifikatskacheln), bleiben unberuehrt. */
  [class*="aspect-"]:has(> img[class*="object-cover"]),
  [class*="aspect-"]:has(> [data-slideshow]) {
    aspect-ratio: auto;
    height: auto;
  }
  [class*="aspect-"] > img[class*="object-cover"] {
    height: auto;
    object-fit: contain;
  }
  /* Bilder, die ihr Verhaeltnis selbst tragen (z.B. Stellenanzeigen-Bild) */
  img[class*="aspect-"][class*="object-cover"] {
    aspect-ratio: auto;
    height: auto;
    object-fit: contain;
  }
  /* Kachel-Slideshows (Leistungsbloecke, Referenz-Banner): wie beim Hero gibt
     das aktive Bild die Hoehe vor. */
  .ref-banner {
    aspect-ratio: auto;
    height: auto;
  }
  [data-slideshow] {
    height: auto;
  }
  [data-slideshow] > img.tile-slide {
    object-fit: contain;
  }
  [data-slideshow] > img.tile-slide.is-active {
    position: relative;
    inset: auto;
    height: auto;
  }
  /* Halbseiten-Bilder (Startseite Karriere-Block, Unternehmen-Profil): das Bild
     liegt dort absolut in einer min-h-Box und wird beschnitten. */
  [class*="min-h-[320px]"] {
    min-height: 0;
  }
  [class*="min-h-[320px]"] > img {
    position: relative;
    inset: auto;
    width: 100%;
    height: auto;
    object-fit: contain;
  }
  /* --- 3. Galerie-Karussells --------------------------------------------
     Ausnahme von Regel 2: die Motive reichen von Hochformat 1:2 bis 16:9. Mit
     freier Hoehe wuerde die Kachelhoehe von Bild zu Bild springen und das
     Karussell waere so hoch wie das hoechste Motiv. Das quadratische Fenster
     bleibt daher stehen, das Bild liegt vollstaendig darin (die Box bringt mit
     bg-feh-200/40 bzw. bg-white/10 ihren eigenen Hintergrund mit). */
  .gallery .gallery-item > div[class*="aspect-"] {
    aspect-ratio: 1 / 1;
    height: auto;
  }
  .gallery .gallery-item > div[class*="aspect-"] > img {
    width: 100%;
    height: 100%;
    object-fit: contain;
  }
  /* --- 4. Hover-Zoom ----------------------------------------------------
     hover:scale-105 / group-hover:scale-105 beschneidet das Bild wieder und
     bleibt auf Touch-Geraeten nach dem Antippen haengen. Doppeltes Attribut
     nur fuer die Spezifitaet gegen die Tailwind-Hover-Utility. */
  [class*="hover:scale-"][class*="hover:scale-"] {
    transform: none;
  }
}
