/*
  X INTERNETDIENSTE – websiteweite Bausteine.
  Wird von der Startseite (app/Views/pages/home.php) UND vom Basis-Layout
  (app/Views/layouts/base.php) geladen, damit Formulare, Checkboxen, Links
  und die Tag-Cloud überall identisch aussehen.
*/

:root {
  /* Gemeinsame Flaeche fuer die Navbar im Scroll-Zustand und die unterste
     Fussleiste. Im Template (index-8.html) sind beide identisch rgb(28,37,57) –
     gemessen, nicht geschaetzt. Ein Wert, damit sie nicht auseinanderlaufen. */
  --x-bar-background: rgba(28, 37, 57, 1);
  --footer-bottom-background: var(--x-bar-background);
  --x-accent: #0b7d6c;   /* Akzent auf hellem Grund (kontraststark) */
  --x-accent-light: #17e4c2; /* Akzent auf dunklem Grund */
  --x-navy: #1c2539;
  --x-slate: #5d666f;

  /* Akzent nach Hintergrundhelligkeit. Ein einziger Farbwert reicht nicht:
     #0b7d6c erreicht auf Navy nur 3,03:1 und wirkt dort tot, das
     Template-Mint #17e4c2 kommt auf Weiss nur auf 1,63:1. Gemessene
     Kontrastwerte der hier gesetzten Paare:
       #0b7d6c auf #ffffff   5,04:1   AA
       #08594c auf #ffffff   8,26:1   AA
       #6cebd4 auf #1c2539  10,56:1   AA
       #9df1e3 auf #1c2539  11,77:1   AA

     Der dunkle Akzent ist bewusst heller als das Template-Mint: die Footer-Box
     liegt auf einem Foto, dessen Helligkeit schwankt. Am hellsten gemessenen
     Bildpunkt (rgb(82,88,101) auf der Startseite) kam #4be3c6 nur auf 4,45:1
     und verfehlte AA knapp; #6cebd4 erreicht dort 4,92:1. */
  --x-accent-on-light: #0b7d6c;
  --x-accent-hover-on-light: #08594c;
  --x-accent-on-dark: #6cebd4;
  --x-accent-hover-on-dark: #9df1e3;

  /* Einheitliche Uebergangsdauer fuer Links und Schaltflaechen. */
  --x-transition: 180ms;
  --x-transition-ease: cubic-bezier(.4, 0, .2, 1);
}

/* ---------------- Header / Navigation (global, Start- und Unterseiten) ----------------
   Oben transparent (nur Startseite mit header-floating), beim Scrollen volle Navy-Flaeche
   ueber die gesamte Breite. Ohne diese Regeln faerbt sich nur der mittlere .header-grid. */
.header-1 { background: #fff; }

/* Der schwebende Header liegt ueber dunklem Grund – die Unterkante ist deshalb
   hell, genau wie im Template (gemessen aus index.html: rgba(255,255,255,.2)).

   WICHTIG: Der Hintergrund wird hier ueber die Template-Variable gesetzt, nicht
   direkt. Das Template faerbt den Header ausschliesslich ueber
   --color-background (.header-1 und .header-grid lesen beide diese Variable)
   und schaltet sie in
       .header-1.header-floating:hover
   auf rgba(28,37,57,1) um. Stand hier ein hartes "background: transparent",
   lief die Hover-Regel ins Leere: nur die ebenfalls dort gesetzte
   border-bottom verschwand, die Flaeche blieb durchsichtig. Genau dieses Bild
   zeigte die Startseite. Ueber die Variable greift die Original-Hover-Regel
   wieder, ohne dass wir eine eigene Farbe erfinden muessen. */
.header-1.header-floating {
  --color-background: rgba(28, 37, 57, 0);
  background: var(--color-background);
  border-bottom-color: rgba(255, 255, 255, .2);
}

/* Tastaturbedienung: dasselbe Bild wie beim Hover, sobald ein Element im
   Header den Fokus hat. Das Template kennt nur :hover – ohne diese Ergaenzung
   bliebe der Header beim Durchtabben transparent und die Menuepunkte staenden
   je nach Hero-Motiv auf hellem Grund. */
.header-1.header-floating:focus-within {
  --color-background: rgba(28, 37, 57, 1);
  border-bottom-color: rgba(255, 255, 255, 0);
}

/* Die durchgehende senkrechte Linie ist die rechte Kante von .header-nav.
   Das Template-Raster gibt der Aktionsspalte feste 290px. Unsere Aktionsleiste ist
   breiter (laengerer deutscher CTA + zusaetzlicher Offcanvas-Schalter) und ragte
   dadurch nach links ueber diese Linie – das Suchsymbol stand links davon statt
   rechts. Die Spalte waechst jetzt mit ihrem Inhalt, die Menuespalte gibt nach. */
@media (min-width: 992px) {
  .header-1 .header-grid { grid-template-columns: 290px 1fr auto; }
}

/* Die beiden senkrechten Zierstriche links vom CTA. Im Template ist die
   Aktionsleiste schmaler ("Let's Talk"); unser laengerer deutscher Button und der
   zusaetzliche Offcanvas-Schalter quetschten das 11px breite SVG auf 0. */
.header-1 .header-separator { flex: 0 0 auto; }
.header-1 .header-separator svg { width: 11px; height: 53px; flex: 0 0 auto; }

/* Ruhezustand: dunkle, gut lesbare Elemente.
   Bewusst NICHT .header-actions einfaerben: darin liegt auch das Such-Overlay.
   Faerbt man den Container, erbt der Schliessen-Button (fill="currentColor")
   die dunkle Kopfzeilenfarbe und verschwindet auf dem dunklen Overlay. */
.header-1 .header-search,
.header-1 .header-search svg,
.header-1 .header-separator svg { color: #0e1528; }

/* Gescrollt: komplette Navy-Flaeche + helle Elemente.
   Wichtig: derselbe Selektor wie fuer die Textfarben. Waren Hintergrund und Text an
   unterschiedliche Klassen gebunden, wurde die Schrift auf Unterseiten weiss, bevor
   der Hintergrund umschlug – die Menuepunkte waren dann unsichtbar. */
.header-1.scrolled-past-header,
.header-1.scrolled-past-header .header-grid { background: var(--x-bar-background); }
/* Der zweite Selektor ist absichtlich so spezifisch wie die Hover-Regel des
   Templates (.header-1.header-floating:hover) und steht spaeter in der
   Ladereihenfolge. Sonst wuerde beim Ueberfahren des bereits gescrollten
   Headers dessen Unterkante verschwinden – ein sichtbares Zucken. */
.header-1.scrolled-past-header,
.header-1.header-floating.scrolled-past-header,
.header-1.header-floating.scrolled-past-header:hover,
.header-1.header-floating.scrolled-past-header:focus-within {
  border-bottom: var(--style-border-width, 1px) solid rgba(255, 255, 255, .08);
}
.header-1.scrolled-past-header .header-search,
.header-1.scrolled-past-header .header-search svg,
.header-1.scrolled-past-header .header-separator svg { color: #fff; }

/* Menuepunkte nur ab Desktop einfaerben. Darunter liegt das Off-canvas-Panel mit
   hellem Hintergrund – dort gelten die Farbvariablen des Templates (.header-nav),
   sonst waeren die Links im Scroll-Zustand weiss auf hellgrau. */
@media (min-width: 992px) {
  .header-1 .menu-link-main { color: #0e1528; }
  .header-1 .nav-item:hover > .menu-link-main { color: #0b7d6c; }
  .header-1.scrolled-past-header .menu-link-main { color: #fff; }
  .header-1.scrolled-past-header .nav-item:hover > .menu-link-main { color: #17e4c2; }

  /* Startseite: der Header liegt ueber dem bildstarken Hero -> helle Schrift wie im Template.
     Nur die Menuepunkte stehen hier in der Desktop-Abfrage: darunter liegen sie im
     hellen Off-canvas-Panel und muessen dunkel bleiben. */
  .header-1.header-floating:not(.scrolled-past-header) .menu-link-main { color: #fff; }
  .header-1.header-floating:not(.scrolled-past-header) .nav-item:hover > .menu-link-main { color: #17e4c2; }
}

/* Suchsymbol und Zierstriche liegen in .header-actions und damit auf JEDER Breite
   auf der Kopfleiste – nie im Off-canvas-Panel. Ihre helle Farbe gehoert deshalb
   ausserhalb der Desktop-Abfrage. Stand sie darin, fiel das Symbol unter 992 px auf
   die dunkle Grundfarbe (#0e1528) zurueck und war auf dem transparenten Header ueber
   dem dunklen Hero praktisch unsichtbar – genau der gemeldete Fehler.
   Das Template arbeitet hier mit currentColor am Pfad und faerbt ueber
   .header-actions { color: var(--color-foreground) }; die Abstufung Ruhe/Hover
   kommt dort aus .header-search { opacity: .6 } bzw. :hover/:focus { opacity: 1 }. */
.header-1.header-floating:not(.scrolled-past-header) .header-search,
.header-1.header-floating:not(.scrolled-past-header) .header-search svg,
.header-1.header-floating:not(.scrolled-past-header) .header-separator svg { color: #fff; }

/* Ausnahme fuer Seiten mit eigenem Hero ohne dunkles Grossbild (/online-marketing/):
   Die Navigationsleiste ist dort schon im Ruhezustand gefuellt, nicht erst nach dem
   Scrollen. Gesteuert ueber die Body-Klasse, damit der generierte Header-Partial
   unveraendert bleibt. Dieselben Werte wie im Scroll-Zustand – eine Quelle fuer
   beide Zustaende gibt es nicht, weil der Scroll-Zustand per JS-Klasse kommt. */
.page-header-solid .header-1,
.page-header-solid .header-1 .header-grid { background: var(--x-bar-background); }
.page-header-solid .header-1 { border-bottom-color: rgba(255, 255, 255, .08); }
.page-header-solid .header-1 .header-search,
.page-header-solid .header-1 .header-search svg,
.page-header-solid .header-1 .header-separator svg { color: #fff; }
@media (min-width: 992px) {
  .page-header-solid .header-1 .menu-link-main { color: #fff; }
  .page-header-solid .header-1 .nav-item:hover > .menu-link-main { color: #17e4c2; }
}
.page-header-solid .header-1 .header-actions .button--secondary {
  border-color: rgba(255, 255, 255, .3);
  color: #fff;
}
.page-header-solid .header-1 .header-actions .button--secondary .svg-wrapper {
  background: #0e1528;
  color: #fff;
}
/* Die Kopfzeile liegt fest ueber dem Inhalt und belegt keinen Platz im Fluss.
   In index-5.html steht der Header dagegen im Fluss (position: static), dadurch
   hat der Hero dort 100 px Luft zur Kopfzeile statt 19 px. Die Hoehe wird von
   main.js in --header-height geschrieben und ist je Breite unterschiedlich. */
.page-header-solid main { padding-block-start: var(--header-height, 80px); }

/* --header-height im Voraus setzen – gegen Layoutverschiebung.

   Das Template rechnet an mehreren Stellen mit calc(var(--header-height) + …),
   etwa style.css:1318 fuer .with-floating-header .slider-card (/webdesign/) und
   style.css:2813 fuer .hero-banner-2.with-floating-header (/online-marketing/).
   Gesetzt wurde die Variable aber ausschliesslich von main.js, und das laeuft
   als defer-Script erst nach dem ersten Paint. Bis dahin ist der Wert unbekannt,
   die ganze calc()-Deklaration damit ungueltig – der reservierte Platz fehlte
   und der Hero sprang beim Nachtragen um bis zu 84 px. Auf /webdesign/ ergab
   das mobil einen CLS von 0,151.

   Die Werte hier sind die gemessenen Kopfhoehen des Templates je Breite. Sie
   sind bewusst nur der Startwert: main.js ueberschreibt sie unmittelbar mit der
   tatsaechlich gemessenen Hoehe als Inline-Stil, der jede Regel hier schlaegt.
   Das Endlayout bleibt deshalb exakt wie bisher, nur der Platz steht vom ersten
   Frame an bereit. Aendert sich die Kopfzeile, korrigiert main.js weiterhin
   selbsttaetig – hier waere dann lediglich der Startwert nachzuziehen. */
:root { --header-height: 61px; }
@media (min-width: 768px)  { :root { --header-height: 69px; } }
/* 992–1066 px: die Hauptnavigation bricht in zwei Zeilen um (Template-Verhalten). */
@media (min-width: 992px)  { :root { --header-height: 161px; } }
@media (min-width: 1067px) { :root { --header-height: 81px; } }
@media (min-width: 1609px) { :root { --header-height: 100px; } }

/* Footer ist eine dunkle Flaeche. Unser globales --color-border ist bewusst dunkel
   (fuer helle Flaechen wie Formularfelder) und waere hier unsichtbar – die Trennlinie
   ueber den Footer-Spalten fehlte dadurch. Das Template scoped im Footer ebenso
   Hintergrund und Schrift; wir ergaenzen die Rahmenfarbe im selben Muster. */
.footer-main {
  --color-border: rgba(255, 255, 255, .3);
  /* Hintergrundmotiv global im Footer; die Farbe bleibt als Rueckfall bestehen,
     falls das Bild nicht laedt – die helle Schrift bleibt so immer lesbar. */
  background-image: url("/assets/images/footer.jpg");
  background-repeat: no-repeat;
  background-position: center;
  background-size: cover;
}

/* Bildspalte der globalen Kontaktsektion.
   Das Template gibt .contact-media ab 992px height:100% und dem Bild object-fit:cover.
   Unser Motiv ist hochkant (1024x1536): ohne feste Bildhoehe bestimmte es die
   Spaltenhoehe ueber sein Seitenverhaeltnis (636 / 0,667 = 954px) und machte die
   Sektion hoeher als die Formularspalte. Jetzt fuellt es die Spalte und wird
   beschnitten – ohne Verzerrung.
   Eine reine Prozenthoehe genuegt dafuer nicht: sie kann sich nicht aufloesen,
   solange das Bild selbst die Zeilenhoehe bestimmt. Das Bild wird deshalb absolut
   positioniert – dann gibt die Formularspalte die Hoehe vor. */
@media (min-width: 992px) {
  .footer-contact .contact-media {
    position: relative;
    height: 100%;
    overflow: hidden;
  }
  .footer-contact .contact-media img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
  }
}

/* Nur die unterste Leiste bekommt die eigene Flaeche – die Hauptflaeche des
   Footers (mit dem Hintergrundmotiv) bleibt unangetastet. */
.footer-main .footer-bottom { background: var(--footer-bottom-background); }

/* Such-Overlay: das Template deklariert fuer .modal-search bereits
   --color-foreground: #fff, bindet die Variable aber nirgends an color. Der
   Schliessen-Button nutzt fill="currentColor" und blieb dadurch dunkel.
   Eine Regel, die genau die Template-Variable verwendet – wirkt auf allen Seiten. */
.theme-modal { color: var(--color-foreground); }

/* Sichtbarer Fokus fuer die per Tastatur bedienbaren Overlay-Schalter */
.header-1 .header-search:focus-visible,
.theme-modal .search-close:focus-visible {
  outline: 2px solid #17e4c2;
  outline-offset: 3px;
  border-radius: 50%;
}

/* Logo: ueber die Hoehe skalieren, Breite ergibt sich daraus */
.header-1 .header-logo { max-width: none; }
.header-1 .header-logo img {
  max-height: 44px;
  width: auto;
  height: auto;
  margin-left: auto;
}
@media (max-width: 767px) {
  .header-1 .header-logo img { max-height: 36px; }
}

/* Hero-Ueberschriften auf zwei Zeilen umbrechen */
.hero-slider .content-box .heading { max-width: 17ch; }
@media (max-width: 991px) {
  .hero-slider .content-box .heading { max-width: 15ch; }
}

/* Hero-Slides abdunkeln, damit Schrift und Navigation sicher lesbar bleiben.
   Die Abdunklung liegt auf .slider-card (nicht auf dem <picture>, das sonst sein
   Layout verliert) und bleibt hinter dem Textinhalt. */
.hero-slider .slider-card.overlay::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(90deg, rgba(14, 21, 40, .80) 0%, rgba(14, 21, 40, .50) 55%, rgba(14, 21, 40, .30) 100%);
}
.hero-slider .slider-card.overlay > .slider-content { position: relative; z-index: 2; }

/* CTA im Header: einzeilig und in beiden Zustaenden mit deckendem Hintergrund */
.header-1 .header-actions .button--secondary {
  white-space: nowrap;
  background: #0e1528;
  border-color: #0e1528;
  color: #fff;
}
.header-1 .header-actions .button--secondary .svg-wrapper { background: #fff; color: #0e1528; }
.header-1 .header-actions .button--secondary:hover {
  background: #17e4c2; border-color: #17e4c2; color: #0e1528;
}
.header-1 .header-actions .button--secondary:hover .svg-wrapper { background: #0e1528; color: #fff; }
.header-1.scrolled-past-header .header-actions .button--secondary {
  background: #fff; border-color: #fff; color: #0e1528;
}
.header-1.scrolled-past-header .header-actions .button--secondary .svg-wrapper { background: #0e1528; color: #fff; }
.header-1.scrolled-past-header .header-actions .button--secondary:hover {
  background: #17e4c2; border-color: #17e4c2; color: #0e1528;
}

/* Offcanvas-Umschalter im Header: in beiden Header-Zustaenden sichtbar
   (weisse Flaeche mit dunklen Linien).

   Die Groesse stand hier auf 52 px mit dem Vermerk "wie im Template" – gemessen
   ist der Schalter in index-2.html aber 36 x 36 (style.css:793). Das SVG traegt
   in beiden Faellen die Attribute 52 x 52 und wird per CSS herunterskaliert;
   das Template begrenzt es auf 36, hier fehlte diese Begrenzung. */
@media (min-width: 992px) {
  .header-1 .header-actions .menu-open {
    width: 36px; height: 36px; min-width: 36px;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .header-1 .header-actions .menu-open svg { width: 36px; height: 36px; }
  .header-1 .header-actions .menu-open svg circle { fill: #fff; stroke: rgba(14, 21, 40, .18); }
  .header-1 .header-actions .menu-open svg path { fill: #0e1528; }
  .header-1 .header-actions .menu-open:hover svg circle { fill: #17e4c2; stroke: #17e4c2; }
}

/* Bild-Kachel im Leistungs-Megamenue: Breitformat wie im Template (1000x668).
   Die Quelldatei ist quadratisch und wird per object-fit mittig beschnitten. */
.header-megamenu .megamenu-image-wrap picture,
.header-megamenu .megamenu-image-wrap img {
  display: block;
  width: 100%;
  aspect-ratio: 1000 / 668;
  object-fit: cover;
  object-position: center;
}

/* ---------------- Seitenkopf ohne eigenes Motiv ----------------
   Das Template-Standardbanner ist ein Platzhalterbild ("1920 x 520").
   Statt dessen ein ruhiger Markenverlauf. */
.page-banner--plain {
  background: linear-gradient(135deg, #0e1528 0%, #16213c 55%, #0b2c34 100%);
}
.page-banner--plain::before { opacity: .35; }

/* ---------------- Leistungs-Uebersichtsseiten (Hub) ---------------- */
.image-text-content .text + .text { margin-top: 14px; }
.image-text-content .button { margin-top: 28px; }

/* Abstand zwischen Abschnitts-Ueberschrift und Einleitungssatz */
.x-hub .section-headings,
.page-service-details .section-headings { margin-bottom: 40px; }
.x-hub .section-headings .heading + .text { margin-top: 14px; }
.x-hub .section-headings.text-center .text { max-width: 62ch; margin-inline: auto; }

/* Karten gleich hoch, damit das Raster ruhig bleibt */
.x-hub .product-grid > [class*="col-"] { display: flex; }
.x-hub .multicolumn-card { width: 100%; }

/* "Mehr erfahren" darf nicht umbrechen */
.x-hub-more {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 18px; color: var(--color-accent, #17e4c2);
}
.x-hub-more .svg-wrapper { display: inline-flex; }

/* Bildkacheln im Leistungsraster von /online-marketing/. Das Raster in
   index-4.html mischt zwei breite und vier schmale Karten; die beiden breiten
   nehmen bei uns je eine Grafik auf. Gleiche Kartenflaeche wie die
   Leistungskacheln, nur ohne Innenabstand. */
.multicolumn-card--media {
  overflow: hidden;
  display: flex;
  height: 100%;
}
/* contain statt cover: es sind Diagramme mit Beschriftung. Beim Zuschneiden
   fehlten die Achsenbeschriftungen und die Aussage ging verloren. */
.multicolumn-card--media img {
  width: 100%;
  height: 100%;
  min-height: 240px;
  object-fit: contain;
  object-position: center;
}

/* Gemessen: in der schmalen Kachel stehen bei 36px Innenabstand 246px zur
   Verfuegung, "Suchmaschinen-" braucht bei 28px aber 248px. Zwei Pixel zu wenig –
   dadurch griff overflow-wrap und trennte mitten im Wort ("Suchmaschine /
   noptimierung") statt am weichen Trennzeichen. Vier Pixel weniger Innenabstand
   auf jeder Seite geben 262px und damit 14px Reserve. Betrifft nur die schmalen
   Kacheln ab 1200px; darunter sind die Karten ohnehin breiter. */
@media (min-width: 1200px) {
  #leistungen .col-xl-3 .multicolumn-card {
    padding-inline: 32px;
  }
}

/* Hero der Landingpage: .hero-banner-2 .section-headings-left ist im Template auf
   560px begrenzt. "Online-Marketing" braucht bei 64px genau 591px und brach dadurch
   nach dem Bindestrich um, obwohl die Sektion daneben noch Platz hat. Die Grenze
   waechst auf die Textbreite; die rechte Spalte (Zaehler und Knoepfe) behaelt ihren
   Platz, weil das Raster erst darunter umbricht. */
.hero-banner-2 .section-headings-left { max-width: 620px; }
@media (min-width: 1200px) {
  .hero-banner-2 .section-headings-left { max-width: 660px; }
}
/* Zwischen 992 und 1199px reicht die Zeile fuer Ueberschrift, Zaehler und beide
   Knoepfe nebeneinander nicht: die linke Spalte wurde auf 397px gedrueckt. Das
   Template loest denselben Fall bereits unterhalb von 992px durch Umbruch der
   Zeile – dieselbe Regel gilt hier bis 1199px, damit die Ueberschrift die volle
   Breite bekommt statt nach dem Bindestrich zu brechen. */
@media (max-width: 1199px) {
  .hero-banner-2 .section-headings-horizontal { flex-wrap: wrap; gap: 30px; }
  .hero-banner-2 .section-headings-left { max-width: 100%; }
}

/* Bildkacheln im Leistungsraster: reine Abbildungen ohne Ziel. Das Template
   faerbt .multicolumn-card bei Hover dunkel ein (--color-background) – das
   signalisiert Klickbarkeit, die hier nicht besteht. Selektor bewusst mit
   .multicolumn davor, damit er die Hover-Regel des Templates (0,3,0) schlaegt. */
.multicolumn .multicolumn-card--media,
.multicolumn .multicolumn-card--media:hover,
.multicolumn .multicolumn-card--media:focus,
.multicolumn .multicolumn-card--media:focus-within {
  --color-background: rgba(242, 242, 242, 1);
  transition: none;
  cursor: default;
}

/* ---------------- Fail-safe fuer die Scroll-Animationen ----------------
   AOS setzt per vendor.css [data-aos^=fade]{opacity:0} und hebt das erst beim
   Scrollen auf. Laedt die Bibliothek nicht oder initialisiert sie nicht, blieben
   die Inhalte dauerhaft unsichtbar. main.js setzt in diesem Fall die Klasse
   .aos-unavailable auf <html>; die Regel hier macht alles sofort sichtbar.
   Bewusst mit erhoehter Spezifitaet statt !important, damit sie die
   AOS-Regel (0,2,0) sicher schlaegt. */
html.aos-unavailable body [data-aos] {
  opacity: 1;
  transform: none;
  transition: none;
}

/* Leistungsueberschrift der Startseite ("Leistungen, die Ihr Unternehmen
   voranbringen"). Ursache des fruehen Umbruchs: .headings-width des Templates
   begrenzt den Kopfbereich auf 645px, waehrend der Container bei 1440px bereits
   1320px breit ist. Gemessen brauchte die Zeile ohne Umbruch 1042px (44px
   Schrift) beziehungsweise 1184px (50px Schrift) – sie stand deshalb auf drei
   Zeilen, obwohl daneben ueber 600px frei blieben.
   Nur dieser eine Kopfbereich wird verbreitert, Schriftgroesse, Laufweite und
   Text bleiben unveraendert. Unterhalb 1200px gilt weiter der Template-Wert,
   die mobile Darstellung aendert sich nicht. */
@media (min-width: 1200px) {
  .our-services-3 .section-headings.headings-width { max-width: 900px; }
}
@media (min-width: 1600px) {
  .our-services-3 .section-headings.headings-width { max-width: 1200px; }
}

/* Zertifikats-Badges im Laufband: .image-logo ist ein weisser Kreis
   (border-radius 50%) mit 8px Innenabstand. Die Zertifikatsgrafiken sind
   quadratisch (400x400) und wurden mit 64px Kantenlaenge eingesetzt – in einen
   Kreis von 80px passt aber nur ein Quadrat von 56px Kantenlaenge. Die vier
   Ecken ragten dadurch sichtbar aus dem Kreis heraus.
   Behoben in der Komponente: der Kreis beschneidet jetzt, das Bild uebernimmt
   seine Rundung. Kreisgroesse, Abstaende, Laufgeschwindigkeit und Reihenfolge
   bleiben unveraendert. */
.x-expertise .image-logo {
  overflow: hidden;
}
.x-expertise .image-logo img {
  border-radius: inherit;
}

/* ---------------- Reduced Motion ----------------
   Frueher wurde prefers-reduced-motion ueber die AOS-Option "disable"
   abgefangen. AOS entfernt dabei aber alle data-aos-Attribute – die Seite lief
   fuer jeden Besucher mit abgeschalteten Systemanimationen dauerhaft ohne
   Scrollanimationen, und genau das war unter Windows mit deaktivierten
   "Animationseffekten" der Normalfall.

   Jetzt bleibt AOS in jedem Fall aktiv und blendet die Inhalte beim Scrollen
   weiterhin ein – mit derselben Dauer, Verzoegerung und Beschleunigung wie im
   Template. Reduziert wird ausschliesslich die *Bewegung*: die Verschiebung
   beziehungsweise Skalierung entfaellt, das weiche Aufblenden bleibt.

   Eine kuerzere Dauer waere hier falsch: sie liesse die Inhalte hart
   aufblitzen statt sanft erscheinen. Genau das ist der Unterschied, den
   prefers-reduced-motion adressiert – Bewegung, nicht Sichtbarkeitswechsel.

   Spezifitaet: AOS setzt die Transformationen mit (0,3,0)
   ([data-aos][data-aos][data-aos^="fade-up"]). Die Regel hier liegt mit (0,4,2)
   darueber, deshalb ohne !important. */
@media (prefers-reduced-motion: reduce) {
  html body [data-aos][data-aos][data-aos][data-aos] {
    transform: none;
  }
}

/* Hinweiszeile im Seitenkopf (z. B. Trefferzahl bei aktivem Themenfilter).
   Liegt auf dunklem Grund -> heller Akzent, kein Unterstrich, weicher Uebergang. */
.page-banner-note {
  margin-top: 18px;
  color: rgba(255, 255, 255, .85);
}
.page-banner-note a {
  color: var(--x-accent-light);
  text-decoration: none;
  font-weight: 500;
  transition: color .2s ease-in-out;
}
.page-banner-note a:hover,
.page-banner-note a:focus-visible {
  color: #fff;
  text-decoration: none;
}

/* ---------------- Themenfilter der Kartenraster ----------------
   Nutzt die Template-Klassen subheading/subheading-bg, damit die Chips wie die
   uebrigen Kategoriemarken der Vorlage aussehen. */
.x-filter { margin-bottom: 40px; }
.x-filter-list {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 0;
}
.x-filter-link {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  transition: background-color .2s ease, color .2s ease;
}
.x-filter-link.active {
  background: var(--x-bar-background);
  color: #fff;
  border-color: var(--x-bar-background);
}
.x-filter-link:focus-visible,
.blog-category:focus-visible,
.pagination-link:focus-visible {
  outline: 2px solid var(--x-accent);
  outline-offset: 2px;
}

/* Aktives Thema in der Blog-Seitenleiste sichtbar machen */
.blog-category { text-decoration: none; }
.blog-category.active {
  background: var(--x-bar-background);
  color: #fff;
}

/* Deaktivierte Blaetter-Schalter klar als solche kennzeichnen */
.pagination-link[aria-disabled="true"] {
  opacity: .4;
  pointer-events: none;
  cursor: default;
}

/* ---------------- Projekt-/Produktraster (project.html) ----------------
   Das Template rechnet mit Bildern im Format 645x690 und fuellt die Karte per
   object-fit: cover. Unsere Karten zeigen dort aber Kundenlogos, keine Fotos –
   und drei davon liegen nur mit 265 bis 336 px Kantenlaenge vor. Mit cover
   wurden sie doppelt beschaedigt: hochskaliert (unscharf) und seitlich
   beschnitten, sodass bei "karriere" und "BRO'S INK" Buchstaben fehlten.

   Deshalb bestimmt jetzt die Karte selbst das Seitenverhaeltnis, und das Logo
   sitzt zentriert darin – nie breiter als seine natuerliche Groesse
   (--x-logo-max je Projekt aus content/portfolio/projects.php) und nie
   beschnitten. Die Kartenhoehe bleibt damit exakt wie zuvor. */
.card-project {
  aspect-ratio: 645 / 690;
  display: flex;
  align-items: center;
  justify-content: center;
}

.card-project img {
  width: 100%;
  max-width: var(--x-logo-max, 100%);
  height: auto;
  max-height: 100%;
  margin-inline: auto;
  object-fit: contain;
  object-position: center;
}

/* Der Merkmalsblock der Produktseite ist im Template auf 548px begrenzt, waehrend
   die Absaetze darueber die volle Spaltenbreite (746px) nutzen. Die deutschen Texte
   sind laenger als die englischen Demotexte und brachen dadurch zu frueh um.
   Unterhalb des Breakpoints hebt das Template die Begrenzung ohnehin selbst auf. */
.project-details-content .project-challenge { max-width: 100%; }

/* ---------------- Aktuelles ----------------
   Beitragstitel in Ueberschriftenfarbe (wie im Template), Akzent beim Hover. */
.card-blog-heading a { color: var(--color-foreground-heading); transition: color .2s ease-in-out; }
.card-blog-heading a:hover,
.card-blog-heading a:focus-visible { color: var(--x-accent); }
.button--cta:hover,
.button--cta:focus-visible { color: var(--x-accent); }

/* Platzhalter fuer noch fehlende Produktabbildungen – gleiche Flaeche und
   Rundung wie ein echtes Bild, im Seitenstil statt als Demo-Dummy. */
.x-img-placeholder {
  width: 100%;
  aspect-ratio: 800 / 791;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  background: linear-gradient(135deg, #f2f2f2 0%, #e8edf0 100%);
  color: #5d666f;
  text-align: center;
  padding: 24px;
}
.x-img-placeholder svg { width: 40px; height: 40px; opacity: .45; }

/* Externer Produktlink in der Sidebar */
.service-contact .x-external {
  display: inline-block; margin-top: 14px;
  color: #fff; text-decoration: underline; text-underline-offset: 3px;
}
.service-contact .x-external:hover { color: var(--color-accent, #17e4c2); }

/* ---------------- Zertifikats-Laufband (Online-Marketing) ----------------
   Zwei identische Gruppen, Verschiebung um genau eine Gruppe -> nahtlose Schleife. */
.x-expertise { overflow: hidden; background: #20282d; }
.x-expertise .content-inner { display: flex; width: max-content; overflow: hidden; }
.x-expertise .content-lists {
  display: flex; align-items: center; width: max-content;
  animation: x-marquee-expertise 42s linear infinite;
}
@keyframes x-marquee-expertise {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.x-expertise .content-lists:hover { animation-play-state: paused; }
.x-expertise .content-item { display: flex; align-items: center; gap: 48px; padding-right: 48px; flex: 0 0 auto; }
.x-expertise .heading {
  color: rgba(255, 255, 255, .92);
  white-space: nowrap;
  margin: 0;
  font-size: clamp(28px, 4vw, 56px);
}
.x-expertise .image-logo {
  flex: 0 0 auto;
  width: 76px; height: 76px;
  border-radius: 50%;
  background: #fff;
  display: grid; place-items: center;
  padding: 8px;
}
.x-expertise .image-logo img { width: 100%; height: 100%; object-fit: contain; }
@media (max-width: 767px) { .x-expertise .content-lists { animation-duration: 24s; } }

/* ---------------- Leistungs-Detailseite ---------------- */
/* Kontaktkarte in der Sidebar.
   Das Hintergrundbild liegt laut Template auf z-index:-1 und waere damit hinter dem
   hellen Kartenhintergrund unsichtbar. Im Template rettet das nur die AOS-Animation,
   die per transform einen Stacking-Kontext erzeugt. Wir erzwingen ihn selbst –
   sonst stuende weisse Schrift auf hellgrauem Grund. */
.service-contact { position: relative; z-index: 0; overflow: hidden; }
.service-contact .media-bg { position: absolute; inset: 0; }
/* Zusaetzliche Abdunklung, damit der Text auch auf hellen Motiven sicher lesbar bleibt */
.service-contact .media-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(14, 21, 40, .55) 0%, rgba(14, 21, 40, .8) 100%);
}
.service-contact .media-bg img { width: 100%; height: 100%; object-fit: cover; }
.service-contact .service-contact-content { position: relative; z-index: 2; }
.service-contact .service-contact-content .heading,
.service-contact .service-contact-content .contact-number { color: #fff; }
.service-contact .service-contact-content .contact-text { color: rgba(255, 255, 255, .8); }
/* Nummer und Button gehoeren untereinander, sonst draengen sie sich auf eine Zeile */
.service-contact .service-contact-content .contact-number { display: block; margin-top: 16px; }
.service-contact .service-contact-content .button { display: inline-flex; margin-top: 18px; }

/* Nutzen- und Leistungslisten in der Detailseite lesbar gliedern */
.service-choose-us .text-item {
  position: relative;
  padding-left: 30px;
  margin-bottom: 14px;
  line-height: 1.6;
}
.service-choose-us .text-item::before {
  content: "";
  position: absolute;
  left: 0;
  top: 4px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: #17e4c2 url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230e1528' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 11px no-repeat;
}
.service-choose-us .row h3 { margin-bottom: 8px; }
.service-choose-us .row > [class*="col-"] { margin-bottom: 26px; }
.service-choose-us .choose-us-desc { margin-bottom: 22px; }

/* Offcanvas-Panel (Schnellkontakt) */
.theme-drawer.drawer-additional .drawer-heading { color: #0e1528; font-weight: 600; }
.theme-drawer.drawer-additional .menu-link { gap: 12px; }
.theme-drawer.drawer-additional .menu-link.no-hover { cursor: default; }

/* ---------------- Formularfelder ---------------- */
/* Kein margin-bottom: das Template setzt die Zeilenabstaende ausschliesslich ueber
   den row-gap des Formulars (24px). Ein zusaetzlicher Aussenabstand addierte sich
   darauf – jede Zeile war 42px statt 24px auseinander und der Button rutschte nach unten. */
.form .field,
.contact-form .field {
  display: flex;
  flex-direction: column;
}

.form input[type="text"],
.form input[type="email"],
.form input[type="tel"],
.form textarea,
.contact-form input[type="text"],
.contact-form input[type="email"],
.contact-form input[type="tel"],
.contact-form textarea {
  width: 100%;
  padding: 14px 18px;
  font: inherit;
  color: var(--x-navy);
  background: #fff;
  border: 1px solid rgba(93, 102, 111, 0.75);
  border-radius: 8px;
  transition: border-color .2s ease, box-shadow .2s ease;
  appearance: none;
}

.form textarea,
.contact-form textarea {
  resize: vertical;
  /* 146px = gemessene Textarea-Hoehe der Template-Kontaktsektion (index.html) */
  min-height: 146px;
}

/* Platzhalter ohne Deckkraftabsenkung.
   Die 0,75 machten aus #5d666f effektiv rgb(134,140,147); auf dem weissen
   Feld ergab das 3,39:1 und damit weniger als die geforderten 4,5:1 –
   auf beiden Formularen. Dieselbe Markenfarbe voll deckend erreicht 5,65:1
   auf Weiss und 4,82:1 auf der hellgrauen Feldflaeche der Kontaktseite. */
.form input::placeholder,
.contact-form input::placeholder,
.form textarea::placeholder,
.contact-form textarea::placeholder {
  color: var(--x-slate, #5d666f);
  opacity: 1;
}

.form input:hover,
.form textarea:hover,
.contact-form input:hover,
.contact-form textarea:hover {
  border-color: rgba(93, 102, 111, 0.9);
}

.form input:focus,
.form textarea:focus,
.contact-form input:focus,
.contact-form textarea:focus {
  outline: none;
  border-color: var(--x-accent-light);
  box-shadow: 0 0 0 3px rgba(23, 228, 194, 0.22);
}

.contact-form label:not(.visually-hidden):not(.x-consent) {
  font-weight: 600;
  font-size: 14px;
  margin-bottom: 8px;
  color: var(--x-navy);
}

/* Fehlerzustand */
.field.has-error input,
.field.has-error textarea {
  border-color: #d64545;
}
.field-error {
  color: #c0392b;
  font-size: 13px;
  margin-top: 6px;
}
.field-error:empty { display: none; }

/* Statusmeldungen */
/* Solange keine Meldung steht, darf die Statuszeile keinen Platz beanspruchen:
   das Formular ist ein Flex-Container, ein leeres Kind erzeugt sonst eine
   zusaetzliche Zeile samt row-gap unter dem Button. */
.form-status:empty { display: none; }
.form-status { margin-top: 16px; font-size: 15px; border-radius: 8px; }
.form-status.is-success { padding: 14px 16px; background: rgba(23,228,194,.14); color: var(--x-accent); }
.form-status.is-error   { padding: 14px 16px; background: rgba(214,69,69,.10); color: #b33636; }

/* Honeypot – für Menschen unsichtbar */
.x-hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }

/* ---------------- Checkbox im Markendesign ---------------- */
.x-consent {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: 15px;
  line-height: 1.55;
  /* Dieselbe Trennung wie bei --form-link-color weiter oben: der Einwilligungstext
     steht im Footer auf einer weissen Karte, auf der Kontaktseite dagegen auf
     dunklem Grund. Mit dem einheitlichen #5d666f kam er dort auf 2,56:1 und war
     kaum lesbar. Der helle Wert erreicht auf rgb(32,40,45) 7,38:1. */
  color: var(--form-text-color, var(--x-slate));
  cursor: pointer;
  font-weight: 400;
}

.x-consent input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  flex: 0 0 auto;
  /* Das Template setzt "form input { width:100%; padding:0 15px; min-height:54px }".
     min-height gewinnt gegen height – ohne die drei Zeilen darunter wird die
     Checkbox 34x54 statt quadratisch. */
  box-sizing: border-box;
  padding: 0;
  width: 18px;
  height: 18px;
  min-height: 18px;
  max-height: 18px;
  min-width: 18px;
  max-width: 18px;
  margin: 2px 0 0;
  /* 0,35 ergab auf der weissen Karte nur 1,65:1. Die Umrandung ist bei einer
     weissen Checkbox auf weissem Grund das einzige Erkennungsmerkmal des
     Bedienelements – WCAG 1.4.11 verlangt dafuer 3:1. Voll deckend: 5,65:1. */
  border: 2px solid var(--x-slate, #5d666f);
  /* bewusst ohne Rundung – exakt quadratisch */
  border-radius: 0;
  background: #fff;
  cursor: pointer;
  position: relative;
  transition: background-color .18s ease, border-color .18s ease, box-shadow .18s ease;
}

.x-consent input[type="checkbox"]:hover {
  border-color: var(--x-accent-light);
}

.x-consent input[type="checkbox"]::after {
  content: "";
  position: absolute;
  inset: 0;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%231c2539' stroke-width='3.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center / 11px no-repeat;
  opacity: 0;
  transform: scale(.6);
  transition: opacity .18s ease, transform .18s ease;
}

.x-consent input[type="checkbox"]:checked {
  background: var(--x-accent-light);
  border-color: var(--x-accent-light);
}

.x-consent input[type="checkbox"]:checked::after {
  opacity: 1;
  transform: scale(1);
}

.x-consent input[type="checkbox"]:focus-visible {
  outline: none;
  box-shadow: 0 0 0 3px rgba(23, 228, 194, 0.3);
}

/* ---------------- Textlinks in Akzentfarbe, ohne Unterstrich ----------------
   Gilt auch fuer die Produktseite (Produktseiten-Link in den Produktinformationen)
   und die Rechtstexte – sonst greift dort das blaue Bootstrap-Standardlink. */
.x-consent a,
.rte a,
.accordion-content-inner a,
.info-data a,
.blog-description a,
.project-info-item a {
  color: var(--x-accent);
  text-decoration: none;
  font-weight: 500;
  transition: color .2s ease-in-out;
}
.x-consent a:hover,
.x-consent a:focus-visible,
.rte a:hover,
.rte a:focus-visible,
.accordion-content-inner a:hover,
.accordion-content-inner a:focus-visible,
.info-data a:hover,
.info-data a:focus-visible,
.blog-description a:hover,
.blog-description a:focus-visible,
.project-info-item a:hover,
.project-info-item a:focus-visible {
  color: var(--x-navy);
  text-decoration: none;
}

/* Footer liegt auf dunklem Grund -> hellerer Akzent */
footer .footer-widget a.link,
footer .footer-menu a,
footer .x-tagcloud-heading {
  text-decoration: none;
}
footer .footer-widget-brand a.link {
  color: var(--x-accent-light);
  text-decoration: none;
}
footer .footer-widget-brand a.link:hover {
  color: #fff;
}

/* ---------------- Tag-Cloud (Footer) ---------------- */
.x-tagcloud {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  /* gleicher Abstand zur Ueberschrift wie bei den anderen Footer-Spalten (.widget-heading + *) */
  margin: 28px 0 0;
  padding: 0;
  list-style: none;
}
.x-tagcloud li {
  font-size: 13px;
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.72);
  background: rgba(255, 255, 255, 0.07);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 40px;
  padding: 7px 13px;
  transition: background-color .2s ease, color .2s ease, border-color .2s ease;
}
.x-tagcloud li:hover {
  color: #fff;
  background: rgba(23, 228, 194, 0.16);
  border-color: rgba(23, 228, 194, 0.45);
}

/* ---------------- Technologie-Flipkarten ----------------
   Gemeinsames Bauteil fuer die Sektion "Unsere Technologien" auf /software/
   (Variante "brand") und das Laufband unter dem Hero auf /webdesign/
   (Variante "marquee"). Vorderseite Logo, Rueckseite Name; der Wechsel ist
   eine 3D-Drehung um die Y-Achse.

   Die Karte sitzt jeweils innerhalb des Original-Wrappers des Templates
   (.brand-logo .content-link bzw. .running-content .content-link), damit
   Raster, Abstaende und Animationen des Templates unangetastet bleiben. */
.x-flip {
  position: relative;
  perspective: 800px;
}

.x-flip__inner {
  position: relative;
  width: 100%;
  height: 100%;
  -webkit-transform-style: preserve-3d;
  transform-style: preserve-3d;
  -webkit-transition: -webkit-transform .6s cubic-bezier(.4, 0, .2, 1);
  transition: transform .6s cubic-bezier(.4, 0, .2, 1);
}

.x-flip:hover .x-flip__inner,
.x-flip:focus-visible .x-flip__inner,
.x-flip:focus-within .x-flip__inner,
.x-flip.is-flipped .x-flip__inner {
  transform: rotateY(180deg);
}

.x-flip__face {
  display: flex;
  align-items: center;
  justify-content: center;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
}

/* Die Vorderseite steht im Fluss und bestimmt damit die Breite der Karte –
   ein schmales Zeichen bekommt eine schmale Kachel, ein breites Wortzeichen
   eine breite. Die Rueckseite liegt deckungsgleich darueber. */
.x-flip__face--front {
  position: relative;
  width: 100%;
  height: 100%;
}

.x-flip__face--back {
  position: absolute;
  inset: 0;
  transform: rotateY(180deg);
}

.x-flip__face--front img {
  width: auto;
  max-width: 100%;
  object-fit: contain;
}

.x-flip__name {
  color: var(--color-foreground-heading, #1c2539);
  font-size: 18px;
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: .01em;
  text-align: center;
  white-space: nowrap;
}

/* Tastaturbedienung: die Karte ist fokussierbar, damit der Wechsel auch ohne
   Maus ausgeloest wird. Der Fokus muss sichtbar sein. */
.x-flip:focus-visible {
  outline: 2px solid var(--x-accent-light, #17e4c2);
  outline-offset: 6px;
  border-radius: 4px;
}

.x-flip:focus:not(:focus-visible) {
  outline: none;
}

/* Variante /software/: volle Spaltenbreite, Hoehe wie ein Logoplatz im
   Original (60 px). Der Wrapper des Templates ist ein Flex-Kind ohne eigene
   Breite und wuerde sonst auf 0 schrumpfen. */
.brand .brand-logo,
.brand .brand-logo .content-link {
  width: 100%;
}

.x-flip--brand {
  width: 100%;
  height: 60px;
}

.x-flip--brand .x-flip__face--front img {
  max-height: 60px;
}

/* Variante /webdesign/: feste Kachelgroesse, damit alle Logos im Laufband
   gleich viel Raum einnehmen und die Rueckseite exakt darueber liegt. Die
   Kachelhoehe bleibt bei der Bandhoehe des Originals (64 px), Abstaende,
   Geschwindigkeit und Richtung der Laufanimation bleiben unveraendert. Die
   Logos selbst sind hier bewusst groesser als auf /software/; wo eine hoeher
   aufgeloeste Fassung vorliegt, wird sie ausgeliefert. */
.x-flip--marquee {
  height: 64px;
  min-width: 64px;
}

.x-flip--marquee .x-flip__face--front {
  width: auto;
}

.x-flip--marquee .x-flip__face--front img {
  height: 64px;
  max-height: 64px;
}

.x-flip--marquee .x-flip__name {
  font-size: 20px;
}

/* Auf kleinen Schirmen faellt nur das Logo kleiner aus. Die Kachelhoehe bleibt
   bei 64 px, damit die Bandhoehe des Originals (160 px) erhalten bleibt. */
@media (max-width: 575px) {
  .x-flip--marquee .x-flip__face--front img {
    height: 48px;
    max-height: 48px;
  }

  .x-flip--marquee .x-flip__name {
    font-size: 17px;
  }
}

/* Laufband anhalten, sobald eine Karte per Maus oder Tastatur angesteuert
   wird – sonst laeuft die gerade gedrehte Karte aus dem Bild. Der Hover-Fall
   kommt bereits aus dem Template (.running-content .content-lists:hover). */
.running-content .content-lists:focus-within {
  animation-play-state: paused;
}

/* Ruecksichtnahme auf reduzierte Bewegung: keine Drehung, stattdessen ein
   ruhiges Ueberblenden. Der Name bleibt damit auch dann erreichbar. */
@media (prefers-reduced-motion: reduce) {
  .x-flip__inner {
    transform: none;
    transition: none;
  }

  .x-flip:hover .x-flip__inner,
  .x-flip:focus-visible .x-flip__inner,
  .x-flip:focus-within .x-flip__inner,
  .x-flip.is-flipped .x-flip__inner {
    transform: none;
  }

  .x-flip__face {
    backface-visibility: visible;
    -webkit-backface-visibility: visible;
    transition: opacity .3s ease;
  }

  .x-flip__face--back {
    transform: none;
    opacity: 0;
  }

  .x-flip:hover .x-flip__face--front,
  .x-flip:focus-within .x-flip__face--front,
  .x-flip.is-flipped .x-flip__face--front {
    opacity: 0;
  }

  .x-flip:hover .x-flip__face--back,
  .x-flip:focus-within .x-flip__face--back,
  .x-flip.is-flipped .x-flip__face--back {
    opacity: 1;
  }
}

/* Notfallanzeige: fehlt eine Logodatei tatsaechlich, steht im
   Original-Wrapper der Name der Technologie statt eines kaputten Bildes.
   Gleiche Flaeche wie ein Logo, dezent und zentriert. */
.brand-logo .content-link .x-tech-name,
.running-content .content-link .x-tech-name {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 60px;
  color: var(--color-foreground);
  opacity: .55;
  font-size: 18px;
  font-weight: 500;
  letter-spacing: .01em;
  text-align: center;
}

.running-content .content-link .x-tech-name {
  min-width: 200px;
  min-height: 64px;
}

/* Produktkarten ohne eigene Seite: statt eines Knopfes eine nicht verlinkte
   Statusanzeige. Gleiche Zeilenhoehe wie der Knopf, damit die Karten gleich
   hoch bleiben. */
.service-button .x-status {
  display: inline-flex;
  align-items: center;
  min-height: 58px;
  opacity: .7;
}

/* Platzhalterprodukte duerfen zurueckhaltender wirken, behalten aber das
   Originalkartenlayout. */
.x-produkt--planned .accordion-content .service-content-inner {
  opacity: .75;
}

/* Bild im informativen Bereich: das Template zeigt dort ein Motiv im Verhaeltnis
   1000x742 und fuellt die Spalte per object-fit: cover (gemessen 526x390). Unsere
   Programmbilder sind breiter; ohne diese Regel bestimmte das Bild die Spaltenhoehe
   und stand als schmaler Streifen neben der Textspalte. */
.image-text-video .image.height-100 img {
  width: 100%;
  height: 100%;
  min-height: 390px;
  object-fit: cover;
  object-position: left top;
}

/* Produktakkordeon auf /software/ (Sektion "Our Services" aus index-2.html).

   Das Template faerbt diese Sektion ueber Variablen ein, die es auf
   .our-services .service-list setzt. Unsere globalen Werte sind fuer helle
   Flaechen ausgelegt und waren hier falsch – gemessen gegen index-2.html:

     --color-border                      Template rgba(255,255,255,.2)
                                         vorher  rgba(14,21,40,.15)   -> Trenner fast unsichtbar
     --color-primary-button-text         Template rgba(255,255,255,1)
                                         vorher  rgba(14,21,40,1)     -> "Mehr erfahren" dunkel auf dunkel
     --color-primary-button-hover-*      Template Text rgb(32,40,45) auf weisser Flaeche

   Dieselbe Machart wie beim Footer: Variablen im Kontext setzen, keine
   Einzelregeln, kein !important. Gilt nur fuer diese Komponente. */
.our-services .service-list {
  --color-border: rgba(255, 255, 255, .2);
  --color-primary-button-text: rgba(255, 255, 255, 1);
  --color-primary-button-hover-text: rgba(32, 40, 45, 1);
  --color-primary-button-hover-background: rgba(255, 255, 255, 1);
  --color-primary-button-hover-border: rgba(32, 40, 45, 1);
}

/* Produktlogo im Symbolfeld: das Template gibt SVGs dort 70x70 vor
   (.service-list .accordion-li svg). Fuer unser <img> gilt dasselbe Mass –
   inklusive min-width, sonst quetscht der Flex-Container es im
   zusammengeklappten Zustand auf 44px.
   Bewusst OHNE Hintergrund, Innenabstand und Rundung: das Logo soll in seiner
   Originaldarstellung erscheinen. */
.service-list .x-produkt-logo {
  --size: 70px;
  width: var(--size);
  min-width: var(--size);
  height: var(--size);
  flex: 0 0 auto;
  object-fit: contain;
}
@media (max-width: 991px) {
  .service-list .x-produkt-logo { --size: 60px; }
}

/* Referenzbilder auf /webdesign/ (Sektion "Text Image" aus index-3.html).
   Das Template zeichnet die Motive dort mit width=1000 height=707 aus – das
   Verhaeltnis 1,414:1 bestimmt die Hoehe des .media-wrap, eine feste Hoehe
   gibt es nicht. Unsere Website-Screenshots sind mit rund 2,1:1 deutlich
   breiter und haetten die Kachel flacher gemacht als im Original.
   Deshalb hier dasselbe Verhaeltnis erzwingen und den Ueberschuss
   beschneiden; die Position steht je Bild im style-Attribut. */
.text-image-sticky .media-wrap img {
  width: 100%;
  height: auto;
  aspect-ratio: 1000 / 707;
  object-fit: cover;
}

/* Sichtbarer Fokus fuer die per Tastatur bedienbaren Akkordeon-Titel auf
   /software/. Das Template macht sie nur per Maus bedienbar und blendet den
   Umriss aus; mit Tastaturbedienung braucht es eine sichtbare Markierung. */
.service-list .accordion-title:focus-visible {
  outline: 2px solid var(--x-accent-light);
  outline-offset: -4px;
}

/* ---------------- Startseiten-Hero: Ueberschriften zweizeilig ----------------
   Die drei Folien tragen einen festen Umbruch (<br>), damit sie genau zwei
   Zeilen hoch stehen. Die zweite Zeile ist jeweils laenger als die erste
   ("Fuer effizientere Ablaeufe" braucht bei 90px rund 1070px) – die
   Template-Box ist aber auf 840px begrenzt. Ohne die beiden Regeln unten brach
   die zweite Zeile deshalb erneut um und die Ueberschrift wurde drei- bis
   vierzeilig. Gemessen wurde beides, nicht geschaetzt.

   Gilt nur fuer den Startseiten-Hero: .text-90 im Hero-Slider gibt es sonst
   nirgends (/webdesign/ nutzt .text-80, /software/ einen anderen Hero). */
@media (min-width: 1200px) {
  .hero-slider .swiper-slide .content-box.section-headings { max-width: 1180px; }
}

/* Unter 768px ist die Box schmaler als die zweite Zeile bei der
   Template-Groesse von 50px. Die Schrift skaliert dort mit der Breite; der
   Hoechstwert bleibt unter der Template-Groesse, der Mindestwert haelt sie
   auf kleinen Geraeten lesbar. */
/* Die Zeichenbegrenzung .hero-slider .content-box .heading { max-width: 17ch }
   stammt aus der Zeit ohne feste Umbrueche und war jetzt der Grund, warum die
   zweite Zeile trotzdem noch einmal umbrach. Sie wird nur fuer die
   Startseiten-Ueberschriften (.text-90) aufgehoben – /webdesign/ nutzt .text-80
   und behaelt seine bisherige Umbruchsteuerung. */
.hero-slider .content-box .heading.text-90 { max-width: none; }

/* Unter 992px ist die Spalte schmaler als die zweite Zeile bei den
   Template-Groessen (50px bzw. 60px). Der Wert 7vw ist aus der gemessenen
   Breite der laengsten Zeile abgeleitet: "Fuer effizientere Ablaeufe" braucht
   rund das 11,9-fache der Schriftgroesse. */
@media (max-width: 991px) {
  .hero-slider .swiper-slide .heading.text-90 { font-size: clamp(22px, 7vw, 56px); }
}
/* ================= Kontaktformulare: Zustaende und Erfolgsmodal ================= */

/* Die Statuszeile steht jetzt ueber den Feldern. Der Abstand kommt aus dem
   row-gap des Formulars; ein eigener margin-top wuerde ihn verdoppeln. */
.contact-form .form-status { margin-top: 0; }

/* Fehlerzustand: roter Rahmen plus dezente Flaeche. Der Rahmen allein waere
   eine reine Farbcodierung – deshalb traegt die Meldung zusaetzlich ein
   Ausrufezeichen als Textzeichen. */
.field.has-error input,
.field.has-error textarea,
.form input.is-invalid,
.form textarea.is-invalid,
.contact-form input.is-invalid,
.contact-form textarea.is-invalid {
  border-color: #d64545;
  background-color: rgba(214, 69, 69, .04);
}

.field.has-error input:focus,
.field.has-error textarea:focus {
  border-color: #d64545;
  box-shadow: 0 0 0 3px rgba(214, 69, 69, .18);
}

.field-error::before {
  content: "!";
  display: inline-grid;
  place-items: center;
  width: 15px;
  height: 15px;
  margin-right: 6px;
  border-radius: 50%;
  background: #c0392b;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
  vertical-align: -2px;
}

/* Die Checkbox-Zeile ist kein Flex-Container mit Spalten – die Meldung braucht
   dort eine eigene Zeile, sonst rutscht sie neben den Text.

   WICHTIG: nur fuer gefuellte Container. Die frueher hier stehende Fassung ohne
   :not(:empty) hatte dieselbe Spezifitaet wie `.field-error:empty{display:none}`
   weiter oben und gewann als spaetere Regel – der leere Fehlercontainer der
   Einwilligung wurde dadurch sichtbar und zeigte allein das ::before-Ausrufezeichen. */
.field-consent .field-error:not(:empty),
.form-consent .field-error:not(:empty),
.x-consent-row .field-error:not(:empty) { display: block; margin-top: 8px; }

/* Zweite Absicherung: ohne Text auch kein Symbol, unabhaengig von der Anzeigeart. */
.field-error:empty { display: none; }
.field-error:empty::before { content: none; }

/* Absende-Button waehrend der Anfrage */
.button.is-loading { opacity: .72; cursor: progress; }
.button[disabled] { pointer-events: none; }

/* ---------------- Erfolgsmodal ---------------- */
body.x-modal-open { overflow: hidden; }

.x-modal {
  position: fixed;
  inset: 0;
  z-index: 1200;
  display: grid;
  place-items: center;
  padding: 20px;
}
.x-modal[hidden] { display: none; }

.x-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(14, 21, 40, .55);
  opacity: 0;
  transition: opacity .18s ease;
}
.x-modal.is-open .x-modal__backdrop { opacity: 1; }

.x-modal__dialog {
  position: relative;
  width: 100%;
  max-width: 460px;
  max-height: calc(100vh - 40px);
  overflow-y: auto;
  padding: 32px 28px 28px;
  text-align: center;
  background: #fff;
  border-radius: 18px;
  box-shadow: 0 24px 60px rgba(14, 21, 40, .22);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .18s ease, transform .18s ease;
}
.x-modal.is-open .x-modal__dialog { opacity: 1; transform: none; }
.x-modal__dialog:focus { outline: none; }

.x-modal__icon {
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  margin: 0 auto 18px;
  border-radius: 50%;
  background: rgba(23, 228, 194, .16);
  color: var(--x-accent, #0b7d6c);
}

.x-modal__title {
  margin: 0 0 10px;
  font-size: 24px;
  line-height: 1.25;
  color: var(--x-navy, #0e1528);
}

.x-modal__text {
  margin: 0 0 24px;
  font-size: 16px;
  line-height: 1.6;
  color: #5d666f;
}

.x-modal__actions { display: flex; justify-content: center; }
.x-modal__actions .button { min-height: 48px; padding-inline: 32px; }

@media (max-width: 575px) {
  .x-modal { padding: 16px; }
  .x-modal__dialog { padding: 28px 20px 24px; border-radius: 14px; }
  .x-modal__title { font-size: 21px; }
}

@media (prefers-reduced-motion: reduce) {
  .x-modal__backdrop,
  .x-modal__dialog { transition: none; }
  .x-modal__dialog { transform: none; }
}

/* ============ Formularkomponente: Datenschutzlink, Selects, Anker ============ */

/* Der Link in der Einwilligung wurde bisher je Seite unterschiedlich dargestellt:
   home.php brachte eine eigene Inline-Regel `.x-consent a{text-decoration:underline}`
   mit, die als spaeter im Dokument stehende <style>-Regel site.css ueberstimmte.
   Die Darstellung liegt jetzt ausschliesslich hier und wird ueber Variablen auf
   Komponentenebene gesteuert – der Hintergrund darf sich unterscheiden, das
   Interaktionsverhalten nicht. */
/* Der Akzent richtet sich nach der Flaeche, auf der das Formular tatsaechlich
   sitzt – am Bildschirmfoto der jeweiligen Karte geprueft, nicht aus der
   Elternkette abgeleitet (die ist bis zur Sektion transparent und fuehrt in die
   Irre):
     Kontaktseite  .contact-form-wrap  dunkel  rgb(32, 40, 45)  -> heller Akzent
     Footer        .contact-box        weiss   rgb(255,255,255) -> dunkler Akzent

   Voreinstellung ist der dunkle Grund (Kontaktseite). */
.contact-form {
  --form-link-color: var(--x-accent-on-dark);
  --form-link-hover-color: var(--x-accent-hover-on-dark);
  /* Fliesstext neben dem Link (Einwilligungssatz) auf dunklem Grund: 7,38:1. */
  --form-text-color: #b0b7be;
}

/* Die Footer-Kontaktbox ist eine weisse Karte. Dort war der helle Mint mit
   1,63:1 auf Weiss unlesbar. */
.footer-contact .contact-form,
.contact-form--light {
  --form-link-color: var(--x-accent-on-light);
  --form-link-hover-color: var(--x-accent-hover-on-light);
  /* Auf Weiss bleibt das dunkle Schiefergrau: 5,65:1. */
  --form-text-color: var(--x-slate);
}

/* Der Ausweichlink neben der Karte hatte als einziger Link im Projekt gar keine
   eigene Regel und lief deshalb im Browserblau #0d6efd mit Unterstreichung –
   2,65:1 auf der hellen Karte und optisch aus der Reihe. Jetzt dieselbe
   Linkfarbe wie im uebrigen hellen Kontext: 4,72:1. */
.x-map__link a {
  color: var(--x-accent-on-light);
  text-decoration: none;
  font-weight: 500;
}
.x-map__link a:hover { color: var(--x-accent-hover-on-light); }

.contact-form .x-consent a,
.contact-form .form-consent a {
  color: var(--form-link-color);
  font-weight: 600;
  text-decoration: none;
  text-underline-offset: 3px;
  border-radius: 3px;
  transition:
    color var(--x-transition) var(--x-transition-ease),
    text-decoration-color var(--x-transition) var(--x-transition-ease);
}

.contact-form .x-consent a:visited,
.contact-form .form-consent a:visited { color: var(--form-link-color); }

.contact-form .x-consent a:hover,
.contact-form .form-consent a:hover {
  color: var(--form-link-hover-color);
}

.contact-form .x-consent a:focus-visible,
.contact-form .form-consent a:focus-visible {
  outline: 2px solid var(--form-link-color);
  outline-offset: 2px;
  text-decoration: underline;
}


/* ---------------- Native Selects im Formularlook ---------------- */
.x-select { position: relative; display: block; }

.form .x-select select,
.contact-form .x-select select {
  width: 100%;
  padding: 14px 46px 14px 18px;
  font: inherit;
  color: var(--x-navy);
  background: #fff;
  border: 1px solid rgba(93, 102, 111, 0.75);
  border-radius: 8px;
  transition: border-color .2s ease, box-shadow .2s ease;
  appearance: none;
  cursor: pointer;
}

.form .x-select select:hover,
.contact-form .x-select select:hover { border-color: rgba(93, 102, 111, 0.9); }

.form .x-select select:focus,
.contact-form .x-select select:focus {
  outline: none;
  border-color: var(--x-accent-light);
  box-shadow: 0 0 0 3px rgba(23, 228, 194, 0.22);
}

/* Pfeil als reine Dekoration; das Auswahlfeld bleibt ein natives <select>. */
.x-select::after {
  content: "";
  position: absolute;
  top: 50%;
  right: 18px;
  width: 10px;
  height: 10px;
  margin-top: -6px;
  border-right: 2px solid var(--x-navy, #0e1528);
  border-bottom: 2px solid var(--x-navy, #0e1528);
  transform: rotate(45deg);
  pointer-events: none;
}

@media (max-width: 767px) {
  .form .x-select select,
  .contact-form .x-select select { min-height: 48px; }
}

/* ---------------- Sprungziele unter dem Sticky-Header ---------------- */
#anfrage,
#projekt-anfrage { scroll-margin-top: 128px; }

@media (max-width: 991px) {
  #anfrage,
  #projekt-anfrage { scroll-margin-top: 96px; }
}

/* ============ Leistungsseiten: Abstaende und Handlungsaufforderungen ============ */

/* "Ihr Nutzen" und "Leistungen im Detail" standen zu dicht am Folgeinhalt. */
.service-choose-us { margin-top: 48px; }
.service-choose-us > .heading { margin-bottom: 28px; }
/* Der Beschreibungstext bringt aus dem Template je Breakpoint einen eigenen
   oberen Rand mit. Zusammen mit der Zeile darueber ergab das doppelte Abstaende –
   der Abstand kommt jetzt ausschliesslich von der Ueberschrift. */
.service-choose-us > .heading + * { margin-top: 0; }

@media (max-width: 767px) {
  .service-choose-us { margin-top: 36px; }
  .service-choose-us > .heading { margin-bottom: 20px; }
}

/* CTA im Hauptinhalt */
/* Anfrage-Block im Fliesstext einer Leistungsseite.

   Vorher: heller Mintschleier (8 % Deckkraft) mit Mintrand. Das sah nach einer
   Hinweisbox eines Frameworks aus und nicht nach einer Handlungsaufforderung –
   die Flaeche trat kaum hervor und der Rand wirkte wie eine Warnung.

   Jetzt dieselbe volle Markenflaeche wie die uebrigen dunklen Bereiche der
   Seite (#1c2539 – Fusszeile, Sidebar-Kontaktkarte, dunkle Sektionen). Kein
   Rand mehr; die Flaeche traegt sich selbst. Breite und Abstaende bleiben
   unveraendert: der Block sitzt in der Inhaltsspalte und haelt oben wie unten
   denselben Abstand. */
.service-cta {
  margin: 40px 0;
  padding: 34px 36px;
  background: var(--x-navy, #1c2539);
  border-radius: 18px;
  color: #fff;
}
.service-cta__text {
  margin: 0 0 26px;
  font-size: 21px;
  line-height: 1.55;
  color: #fff;
  max-width: 58ch;
}

/* Umrissvariante des Buttons – ausschliesslich in diesem Block.
   Die Template-Komponente wird nicht angefasst: sie liest ihre Farben aus
   diesen Variablen, und das Template selbst setzt sie ebenfalls je Sektion
   (.video, .header-3, .our-services, .text-banner). Genau dieses Muster wird
   hier fortgesetzt, damit die Buttonparitaet an allen anderen Stellen bleibt.
   Ruhezustand: durchsichtig mit weissem Rand. Hover: gefuellt weiss – die
   Umkehrung, die die Komponente ohnehin vorsieht. */
.service-cta .button--secondary {
  --color-secondary-button-background: transparent;
  --color-secondary-button-border: rgba(255, 255, 255, .75);
  --color-secondary-button-text: rgba(255, 255, 255, 1);
  --color-secondary-button-hover-background: rgba(255, 255, 255, 1);
  --color-secondary-button-hover-border: rgba(255, 255, 255, 1);
  --color-secondary-button-hover-text: var(--x-navy, #1c2539);
}
.service-cta .button {
  min-height: 52px;
  font-size: 17px;
}

@media (max-width: 575px) {
  .service-cta { padding: 26px 22px; margin: 32px 0; }
  .service-cta__text { font-size: 19px; }
}

/* CTA-Karte in der Sidebar, direkt unter den Leistungsunterlagen */
.sidebar-cta__title { margin: 0 0 10px; }
.sidebar-cta__text {
  margin: 0 0 18px;
  font-size: 16px;
  line-height: 1.6;
}
.sidebar-cta .button {
  width: 100%;
  min-height: 48px;
  justify-content: center;
}

/* ================== Globale Link- und Schaltflaechen-Uebergaenge ================== */

/* Bewusst ueber :where() mit Spezifitaet 0 gesetzt: das sind Grundwerte, die
   jede vorhandene Komponentenregel ohne Zutun ueberschreibt. Dadurch behalten
   Spezialkomponenten (Navigation, Karten, Marquees) ihre eigenen Effekte, und
   es wird kein !important gebraucht.
   Keine `transition: all` – nur die Eigenschaften, die sich tatsaechlich aendern. */
:where(a) {
  text-decoration: none;
  transition:
    color var(--x-transition) var(--x-transition-ease),
    background-color var(--x-transition) var(--x-transition-ease),
    border-color var(--x-transition) var(--x-transition-ease),
    opacity var(--x-transition) var(--x-transition-ease);
}

:where(a:hover) { text-decoration: none; }

/* Sichtbarer Tastaturfokus fuer alles Interaktive – nicht nur ueber Farbe. */
:where(a, button, .button, [type="submit"], [type="button"]):focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Deaktivierte Schaltflaechen reagieren nicht auf Hover. */
.button[disabled],
button[disabled],
.button.is-loading { pointer-events: none; }

/* ---------------- Sanftes Scrollen ----------------
   `scroll-behavior: smooth` setzt bereits das Template auf <html>
   (style.css: html { scroll-behavior: smooth }). Hier steht deshalb nur die
   Ruecknahme fuer Nutzer, die Bewegung reduziert haben wollen – zusammen mit
   den Sprungzielen weiter oben ergibt das weiches Scrollen ohne eigenes
   JavaScript und ohne Scroll-Jacking. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  :where(a) { transition-duration: 1ms; }

  /* Projekteigene Komponente – die Template-Buttons bleiben bewusst bei ihren
     0,3 s, weil das Template selbst keine Ruecknahme vorsieht. */
  .contact-form .x-consent a,
  .contact-form .form-consent a { transition-duration: 1ms; }
}


/* ---------------- Abstand der Sidebar-Widgets auf Artikelseiten ----------------
   Das Template staffelt die Widgets ueber `.sidebar-filter .sidebar-widget +
   .sidebar-widget` (40px, unter 768px 30px). `.sidebar-filter` ist unter 992px
   aber ein `position: fixed` Off-Canvas-Panel und braucht einen Oeffner.
   Die Uebersichtsseite /aktuelles/ hat einen (Themenfilter), die Artikelseite
   nicht – dort gibt es nichts zu filtern. Der Wrapper wuerde die Sidebar auf
   Mobilgeraeten unerreichbar machen, deshalb stehen hier dieselben Werte direkt
   auf der Sidebar. Wo beide Regeln greifen, liefern sie denselben Abstand. */
.blog-sidebar > .sidebar-widget + .sidebar-widget { margin-block-start: 40px; }

@media (max-width: 767px) {
  .blog-sidebar > .sidebar-widget + .sidebar-widget { margin-block-start: 30px; }
}

/* ---------------- Zugaenglichkeit: Tastaturbedienung ----------------

   1) Megamenue per Tastatur.
   Das Template klappt das Untermenue ausschliesslich bei :hover auf
   (style.css:1980 – .nav-item:hover > .menu-absolute). Mit der Tastatur war
   es dadurch nicht erreichbar: opacity 0 und visibility hidden nehmen die
   Links aus der Tabreihenfolge. :focus-within ergaenzt denselben Zustand,
   sobald der Fokus in den Menuepunkt wandert – ohne das Hoververhalten oder
   das Aussehen zu veraendern. Die Regel steht hier statt in style.css, damit
   die Templatedatei byteidentisch bleibt. */
.nav-item:focus-within > .menu-absolute {
  opacity: 1;
  visibility: visible;
}

/* 2) Sichtbarer Fokus auf Buttons.
   Die Template-Buttonkomponente setzt outline: none und zeigt Fokus nur
   ueber denselben Farbwechsel wie :hover (style.css:467). Auf Flaechen, wo
   der Wechsel schwach ausfaellt, ist damit nicht erkennbar, wo der Fokus
   steht. :focus-visible greift ausschliesslich bei Tastaturbedienung –
   Hover, Klickoptik und Buttonparitaet bleiben unberuehrt. */
.button:focus-visible,
button:focus-visible,
a:focus-visible {
  outline: 3px solid var(--x-accent-light, #17e4c2);
  outline-offset: 3px;
  border-radius: inherit;
}

/* Auf hellen Flaechen ist das helle Mint zu schwach – dort der dunkle Ton. */
.footer-contact .button:focus-visible,
.contact-form--light .button:focus-visible,
main .x-sec--light .button:focus-visible {
  outline-color: var(--x-navy, #1c2539);
}

/* ---------------- Skip-Link ----------------
   Stand zuvor in brand.css. Die Startseite laedt brand.css nicht (sie bringt
   ihre Tokens inline mit) – der Link erschien dort deshalb ungestylt und
   sichtbar am Seitenanfang. site.css laedt dagegen jede Seite. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 2000;
  background: var(--x-navy, #1c2539);
  color: #fff;
  padding: 12px 20px;
  border-radius: 0 0 8px 0;
  text-decoration: none;
}
.skip-link:focus {
  left: 0;
}

/* ---------------- Bildausschnitt der Hero-Motive ----------------

   Die Motive sind breite Businessfotos; die Personen stehen im oberen
   Bilddrittel. Der Seitenkopf ist dagegen ein flacher Streifen: mit
   object-position "center" nimmt der Browser die vertikale Mitte und
   schneidet genau die Gesichter oben ab – auf 1920 px waren nur noch
   Y 26–74 % des Motivs sichtbar.

   Gemessen liegen die Gesichter bei Y 8–42 %. 25 % verschiebt das
   Sichtfenster so weit nach oben, dass sie auf allen Breiten drin sind:
     1920  Sichtfenster 13–61 %
     1440  Sichtfenster  9–73 %
     1024  Sichtfenster  2–92 %
   Unter 1024 begrenzt ohnehin die Breite, nicht die Hoehe.

   Eine zweite Bilddatei fuer Mobil ist dafuer nicht noetig. */
.page-banner .media-bg img {
  object-fit: cover;
  object-position: center 25%;
}

/* Der Online-Marketing-Hero ist hoeher; dort reicht eine leichte
   Verschiebung, damit die Koepfe des Meetings nicht oben anstossen. */
.hero-banner-2 .banner-wrapper .media-bg img {
  object-fit: cover;
  object-position: center 35%;
}

/* ---------------- Ziehbarer Leistungsslider (/webdesign/) ----------------

   Swiper zieht die Karten bereits selbst (simulateTouch, threshold 5 px,
   preventClicks gegen versehentliche Navigation). Nur der Zeiger blieb auf
   "auto": die Option grabCursor ist gesetzt, dieser Build wertet sie aber
   nicht aus. Die beiden Zustaende deshalb hier – reine Darstellung, keine
   zweite Drag-Logik.

   :active greift, solange die Maustaste gedrueckt ist, und braucht dafuer
   kein JavaScript. */
expert-slider .swiper {
  cursor: grab;
}
expert-slider .swiper:active {
  cursor: grabbing;
}

/* Innerhalb der Karten bleibt es beim Zeigefinger: dort wird geklickt,
   nicht gezogen. Ohne diese Zeile erbt der Link den grab-Zeiger. */
expert-slider .swiper a,
expert-slider .swiper button {
  cursor: pointer;
}

/* ---------------- Bildausschnitt "Was Sie bei uns erwarten koennen" ----------

   Der Bildslot ist auf dem Desktop hochformatig (er fuellt die Hoehe der
   Textspalte), das Motiv ist quer. Gemessen sichtbar bleibt bei zentriertem
   Ausschnitt:

     375 / 768   das ganze Bild        beide Personen sichtbar
     1440        X 30-70 %             beide Personen sichtbar
     1920        X 23-77 %             beide Personen sichtbar
     1024        X 37-63 %             die rechte Person faellt heraus

   Nur in diesem schmalen Band ist die Spalte so hoch und schmal, dass der
   Ausschnitt knapp wird. Deshalb dort um fuenf Prozent nach rechts – das
   verschiebt das Fenster auf X 42-68 % und haelt beide Gesichter drin,
   ohne die uebrigen Breiten anzufassen. Eine zweite Bilddatei braucht es
   dafuer nicht. */
@media (min-width: 992px) and (max-width: 1199px) {
  .our-services .service-content-image img {
    object-position: 55% 50%;
  }
}

/* ---------------- Bildausschnitt Leistungskarte "Website-Relaunch" ----------

   Dasselbe schmale Band trifft die Karten des Leistungssliders noch haerter:
   dort ist der Bildslot nur rund 292 px breit, aber 639 px hoch, sodass bei
   zentriertem Ausschnitt lediglich X 35-65 % des Motivs sichtbar bleiben.

   Fuer zwei der drei Motive geht das auf – Karte 1 behaelt das Gesicht, Karte 3
   den Wasserfall-Graph auf dem Monitor. Beim Relaunch-Motiv liegt die
   Designerin aber links (X 5-35 %) und die beiden Vergleichsmonitore rechts
   (X 47-98 %); die Bildmitte zeigt genau dazwischen den unbeteiligten
   Kollegen im Hintergrund. Verschoben auf 72 % faellt das Fenster auf
   X 50-80 % und damit auf die beiden Bildschirme, um die es in der Leistung
   geht. Bewusst ueber den Dateinamen adressiert statt ueber nth-child: die
   Regel gilt dem Motiv, nicht der Position im Slider.

   Alle uebrigen Breiten bleiben unangetastet, bei 768 px ist ohnehin das
   ganze Bild sichtbar. */
@media (min-width: 992px) and (max-width: 1199px) {
  expert-slider .swiper-slide img[src*="webdesign-relaunch-alt-neu-vergleich"] {
    object-position: 72% 50%;
  }
}
