/* =========================================================================
   LTS Transport, Website
   Ein Stylesheet, keine Build-Schritte. Aufbau von oben nach unten:
   Schriften, Tokens, Grundlagen, Bausteine, Kopf, Hero, Abschnitte, Bewegung.
   ========================================================================= */

/* Beide Schriften liegen im Projekt. Kein Request an Google, das ist die
   DSGVO-taugliche Variante. Lizenz: SIL Open Font License, siehe CREDITS.md */
@font-face {
  font-family: "Inter var";
  src: url("../fonts/inter-latin-wght-normal.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193,
    U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Archivo var";
  src: url("../fonts/archivo-latin-wght-normal.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  /* Monochrom, dunkel. Der Bau liefert die Farbe über die Fotos, das
     Interface bleibt schwarzweiß. Deshalb gibt es keinen Akzentton: jedes
     bunte Element würde in dieser Anordnung sofort wie ein Fremdkörper wirken. */
  --grund: #111319;
  --grund-tief: #0c0e12;

  --text: #eef0f3;
  --text-ruhig: #aeb3bb;
  --text-leise: #8b919b;

  /* Linien tragen dieses Design. Deshalb drei Stufen statt einer: --linie für
     Trenner, --linie-mittel für Kästen im Fließtext, --linie-stark für die
     Rahmen, die als Gestaltungselement gemeint sind. */
  --linie: rgb(255 255 255 / 0.12);
  --linie-mittel: rgb(255 255 255 / 0.22);
  --linie-stark: rgb(255 255 255 / 0.45);

  --breite: 100rem;
  --rand: clamp(1.25rem, 4vw, 6rem);

  --schrift-sans: "Inter var", -apple-system, BlinkMacSystemFont, "Segoe UI",
    Roboto, "Helvetica Neue", Arial, sans-serif;
  --schrift-display: "Archivo var", "Helvetica Neue", Arial, sans-serif;

  /* Gesperrte Versalien sind das Erkennungsmerkmal dieser Gestaltung. Die
     Werte stehen hier zentral, damit Sperrung und Größe nicht in dreißig
     Regeln einzeln driften. */
  /* Die Vorlage setzt ihre Beschriftungen auf neun Pixel. Auf einer Seite, die
     Angebote einsammelt, ist das zu klein: Formularbeschriftungen und Meta-
     Zeilen sind dann auf dem Handy kaum zu treffen. Eine Stufe hoeher wirkt
     genauso zierlich und bleibt bedienbar. */
  --schrift-klein: 0.6875rem;

  /* Wird von haupt.js gelesen, siehe MENUE_GRENZE. Die Media Query weiter
     unten traegt denselben Zahlenwert in px, damit beide Stellen beim Suchen
     nach "1200" gefunden werden. */
  --menue-grenze: 1200px;

  /* Breite der Spalte, in der die senkrechten Abschnittswoerter stehen. Als
     Variable, weil sie im Tablet-Bereich schmaler ist: dort geht jeder
     Zentimeter, den sie frisst, dem Inhalt ab. */
  --markerspalte: 3.5rem;

  /* Die Spalte gibt es erst ab 48rem. Darunter steht der Inhalt auf --rand,
     und diese Variable ist null, damit dieselbe Rechnung überall stimmt. */
  --markerversatz: 0px;

  /* Die eine Kante, auf der alles steht: Kopfzeile, jeder Abschnitt, der Fuß.
     Der Behälter ist auf --breite zentriert, deshalb reicht --rand allein
     nicht: sobald das Fenster breiter ist als --breite, wandert die Kante mit
     der halben Differenz nach innen. max() fängt den schmalen Fall ab, wo die
     Differenz negativ wäre. Elemente, die nicht im Behälter stehen (Kopfzeile,
     Fuß), rechnen damit dieselbe Kante aus. */
  --kante-links: max(
    calc(var(--rand) + var(--markerversatz)),
    calc((100% - var(--breite)) / 2 + var(--rand) + var(--markerversatz))
  );
  --kante-rechts: max(var(--rand), calc((100% - var(--breite)) / 2 + var(--rand)));

  /* Höhe der festen Kopfzeile. Steht hier und nicht am Hero, weil auch
     andere Abschnitte oben Platz für sie lassen müssen. */
  --kopfhoehe: 6rem;

  /* Takt für das Zusammenrücken der Kopfzeile. Der Wechsel hängt an einer
     Klasse, die bei 24 Pixeln Scrollweg umspringt, also muss die Kurve an
     beiden Enden weich sein. Kein `expo out` (`0.16, 1, 0.3, 1`): das schießt
     im ersten Zehntel los, und genau dieser Start liest sich als Ruck. Diese
     Kurve fährt an und läuft aus. */
  --kopf-zeit: 1.2s;
  --kopf-kurve: cubic-bezier(0.65, 0, 0.35, 1);

  --sperrung-weit: 0.28em;
  --sperrung-mittel: 0.16em;
  --sperrung-eng: 0.08em;
}

/* ---------- Grundlagen ---------- */

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

html {
  scroll-behavior: smooth;
  /* Der Kopf steht fest oben. Ohne diesen Abstand scrollt der Browser ein
     Sprungziel genau unter den Kopf und verdeckt es. WCAG 2.2 nennt das
     "Focus Not Obscured" (2.4.11). */
  scroll-padding-top: 6rem;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--grund);
  color: var(--text);
  font-family: var(--schrift-sans);
  font-size: 0.9375rem;
  line-height: 1.75;
  font-synthesis-weight: none;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
}

img,
picture,
svg,
video {
  display: block;
  max-width: 100%;
}

/* Muss nach den display-Regeln stehen und sie schlagen: sonst zeigt jedes
   Element mit eigenem display trotz hidden-Attribut seinen Inhalt. */
[hidden] {
  display: none !important;
}

img {
  height: auto;
}

/* Deutsche Zusammensetzungen werden in gesperrten Versalien schnell breiter als
   ein Telefon. break-word greift erst, wenn ein Wort sonst überliefe, ändert
   also nichts an Umbrüchen, die heute schon passen. */
h1,
h2,
h3,
h4 {
  margin: 0;
  font-weight: 400;
  overflow-wrap: break-word;
}

p,
ul,
ol,
dl,
figure {
  margin: 0;
}

a {
  color: inherit;
  text-decoration-color: var(--linie-stark);
  text-underline-offset: 0.25em;
}

a:hover {
  text-decoration-color: currentColor;
}

:focus-visible {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

::selection {
  background: var(--text);
  color: var(--grund);
}

.sprungmarke {
  position: absolute;
  left: 0.5rem;
  top: -100%;
  z-index: 100;
  padding: 0.75rem 1.25rem;
  background: var(--text);
  color: var(--grund);
  font-size: 0.7rem;
  letter-spacing: var(--sperrung-mittel);
  text-transform: uppercase;
  text-decoration: none;
}

.sprungmarke:focus-visible {
  top: 0.5rem;
}

.behaelter {
  width: 100%;
  max-width: var(--breite);
  margin-inline: auto;
  padding-inline: var(--rand);
}

/* ---------- Typografische Bausteine ---------- */

/* Die Display-Klasse bringt Familie, Sperrung und Versalien mit. Neue
   Überschriften bekommen sie und sonst nichts, damit der Satz einheitlich
   bleibt. */
.display {
  font-family: var(--schrift-display);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  line-height: 1.35;
}

.augenbraue {
  font-family: var(--schrift-display);
  font-size: 0.625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-weit);
  color: var(--text-leise);
}

/* Das gedrehte Wort am linken Rand. Kein rotiertes Textfeld, sondern echte
   aufrechte Buchstaben untereinander: rotierte Schrift wird von
   Sprachausgaben und beim Zoomen unbrauchbar. */
.marker {
  position: absolute;
  left: 0;
  top: 0;
  writing-mode: vertical-rl;
  text-orientation: upright;
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 500;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--text-leise);
  user-select: none;
}

/* Der Zahlenkasten. Zahl groß und dünn, Beschriftung klein und gesperrt,
   dazwischen nichts. Das Verhältnis trägt die Wirkung, nicht die Rahmenstärke. */
.zahlkasten {
  border: 1px solid var(--linie-mittel);
  padding: clamp(1.5rem, 3vw, 2.5rem);
  display: flex;
  flex-direction: column;
  gap: 1.25rem;
}

.zahlkasten__zahl {
  font-family: var(--schrift-display);
  font-size: clamp(3.5rem, 7vw, 5.5rem);
  font-weight: 200;
  line-height: 0.9;
  letter-spacing: -0.02em;
}

.zahlkasten__text {
  font-family: var(--schrift-display);
  font-size: 0.625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  line-height: 1.9;
  color: var(--text-ruhig);
}

/* Ein Zahlenkasten, der sich beim Hereinscrollen selbst aufbaut: der Rahmen
   wird von oben nach unten aufgedeckt, danach kommen Zahl und Beschriftung
   gestaffelt nach. Dieselben Keyframes wie im Hero.

   Der Rahmen liegt dafür im ::before und nicht am Kasten. Der clip-path würde
   sonst die Ziffern mitschneiden, und man sähe mitten im Auftritt nur Streifen
   der Zahl. */
.zahlkasten--auftritt {
  position: relative;
  border: 0;
  container-type: inline-size;
}

.zahlkasten--auftritt::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--linie-mittel);
  opacity: 0;
  pointer-events: none;
  transition: border-color 0.3s ease;
}

/* Wie bei jedem anderen gerahmten Kasten. Der Rahmen liegt hier im
   Pseudo-Element, deshalb greift der Zeigezustand auch dort. */
.zahlkasten--auftritt.ist-sichtbar:hover::before {
  border-color: var(--linie-stark);
}

/* Die Zahl ist in cqw bemessen, nicht in vw: der Kasten ist schmaler als das
   Fenster und wächst anders. Wer eine längere Zahl einsetzt, prüft die Breite
   im schmalsten Fall nach. */
.zahlkasten--auftritt .zahlkasten__zahl {
  font-size: 54cqw;
}

/* Dreistellig fuellt die Zahl den Kasten bei 54cqw fast ganz aus und die
   Aufteilung der Vorlage ist weg. Eine Stufe kleiner, damit Zahl und
   Beschriftung dasselbe Verhaeltnis behalten wie in den anderen Kaesten.
   Zwei Klassen im Selektor, sonst gewinnt die Regel darueber. */
.zahlkasten--auftritt .zahlkasten__zahl--drei {
  font-size: 38cqw;
}

.zahlkasten--auftritt .zahlkasten__zahl,
.zahlkasten--auftritt .zahlkasten__text {
  opacity: 0;
}

/* .einblenden sitzt am Kasten nur als Haken für den Beobachter und ist hier
   ausgeschaltet: sonst verblasst der ganze Kasten zusätzlich zu Rahmen, Zahl
   und Beschriftung. */
.zahlkasten--auftritt.einblenden {
  opacity: 1;
  transform: none;
  transition: none;
}

.zahlkasten--auftritt.ist-sichtbar::before {
  animation:
    hero-rahmen 2.4s cubic-bezier(0.4, 0.05, 0.15, 1) both,
    hero-rahmen-blende 0.6s ease-out both;
}

.zahlkasten--auftritt.ist-sichtbar .zahlkasten__zahl {
  animation: hero-auf 1.4s 0.75s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

.zahlkasten--auftritt.ist-sichtbar .zahlkasten__text {
  animation: hero-auf 1.4s 0.95s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

/* Ohne JavaScript kommt .ist-sichtbar nie, dann steht der Kasten fertig da. */
html:not(.js) .zahlkasten--auftritt::before,
html:not(.js) .zahlkasten--auftritt .zahlkasten__zahl,
html:not(.js) .zahlkasten--auftritt .zahlkasten__text {
  opacity: 1;
}

/* Der schräge Strich über den Servicespalten und unter dem Hero. Ein
   gedrehtes Pseudo-Element, kein Bild. */
.schraege {
  width: 3.25rem;
  height: 1px;
  background: var(--linie-stark);
  transform: rotate(-45deg);
  transform-origin: left center;
}

/* ---------- Knöpfe ---------- */

.knopf {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 3rem;
  padding: 0 2.25rem;
  border: 1px solid var(--linie-stark);
  background: none;
  color: var(--text);
  font-family: var(--schrift-display);
  font-size: 0.625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.25s ease, color 0.25s ease,
    border-color 0.25s ease;
}

.knopf:hover {
  background: var(--text);
  border-color: var(--text);
  color: var(--grund);
}

.knopf--voll {
  background: var(--text);
  border-color: var(--text);
  color: var(--grund);
}

.knopf--voll:hover {
  background: none;
  border-color: var(--linie-stark);
  color: var(--text);
}

/* Ein zweiter Rahmen, nach rechts unten versetzt. Nur die beiden Kanten, die
   man sieht: mit allen vieren lägen zwei Linien quer über der Schrift. */
/* Der zweite Rahmen ragt nach rechts unten aus dem Knopf heraus. Der Platz
   dafür gehört zum Knopf, sonst schiebt sich der Rahmen über das nächste
   Element, etwa den zweiten Knopf in einer Zeile. */
.knopf--versetzt {
  position: relative;
  margin-right: 0.875rem;
  margin-bottom: 0.875rem;
}

.knopf--versetzt::after {
  content: "";
  position: absolute;
  left: 0.875rem;
  top: 0.875rem;
  right: -0.875rem;
  bottom: -0.875rem;
  border-right: 1px solid var(--linie-mittel);
  border-bottom: 1px solid var(--linie-mittel);
  pointer-events: none;
}

/* ---------- Kopf ---------- */

.seitenkopf {
  position: fixed;
  inset: 0 0 auto;
  z-index: 50;
  animation: hero-auf 1.2s cubic-bezier(0.22, 0.61, 0.36, 1) both;
  transition: background-color var(--kopf-zeit) var(--kopf-kurve),
    border-color var(--kopf-zeit) var(--kopf-kurve);
  border-bottom: 1px solid transparent;
}

/* Über dem Hero bleibt der Kopf durchsichtig, ab dem ersten Scrollen legt er
   sich auf den Grund. Die Klasse setzt haupt.js. */
.seitenkopf.ist-fest {
  background: rgb(17 19 25 / 0.94);
  backdrop-filter: blur(10px);
  border-bottom-color: var(--linie);
}

/* Volle Breite wie das Hero-Bild darunter, siehe .hero__rahmen. */
.navi {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  width: 100%;
  padding: 1.5rem var(--rand);
  transition: padding var(--kopf-zeit) var(--kopf-kurve);
}

/* Die Leiste selbst bleibt, wie sie ist: volle Breite, gleiche Höhe. Nur ihr
   Inhalt rückt beim Scrollen auf die Kante, auf der auch Formular, Fotos und
   Fuß stehen. Wortmarke und Navigation wandern dabei aufeinander zu. */
.seitenkopf.ist-fest .navi {
  padding-inline: var(--kante-links) var(--kante-rechts);
}

/* Solange das Mobilmenü offen ist, bleibt der Inhalt auf --rand: das Menü
   darunter steht dort auch, und zwei verschiedene Kanten übereinander sehen
   nach Fehler aus. Die Klasse setzt haupt.js beim Öffnen. */
.seitenkopf.ist-menue-offen .navi {
  padding-inline: var(--rand);
}

/* Wortmarke fett und gross, der Zusatz klein daneben statt darunter. Die
   Grundlinien liegen dabei nicht buendig, sondern der Zusatz sitzt an der
   Oberkante der Versalien. */
.marke {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  text-decoration: none;
}

.marke__wort {
  display: flex;
  align-items: flex-start;
  gap: 0.625rem;
  font-family: var(--schrift-display);
  font-size: clamp(1.375rem, 2.2vw, 2rem);
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  line-height: 1;
}

.marke__wort span {
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.22em;
  line-height: 1.5;
  color: var(--text-ruhig);
  max-width: 5.5rem;
  padding-top: 0.15em;
}

.navi__liste {
  display: flex;
  align-items: center;
  gap: clamp(1.25rem, 2.2vw, 2.5rem);
  list-style: none;
  margin: 0;
  padding: 0;
}

.navi__liste a {
  font-family: var(--schrift-display);
  font-size: 0.8125rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  text-decoration: none;
  color: var(--text-ruhig);
  transition: color 0.2s ease;
}

.navi__liste a:hover,
.navi__liste a[aria-current="page"] {
  color: var(--text);
}

/* Der Menüknopf ist nur auf schmalen Geräten da. Drei Striche, die sich zum
   Kreuz drehen. */
.menueknopf {
  display: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  border: 1px solid var(--linie-mittel);
  background: none;
  color: var(--text);
  cursor: pointer;
}


.menueknopf__balken {
  display: block;
  width: 1.125rem;
  height: 1px;
  margin: 0.3125rem auto;
  background: currentColor;
  transition: transform 0.25s ease, opacity 0.2s ease;
}

.menueknopf[aria-expanded="true"] .menueknopf__balken:nth-child(1) {
  transform: translateY(0.375rem) rotate(45deg);
}

.menueknopf[aria-expanded="true"] .menueknopf__balken:nth-child(2) {
  opacity: 0;
}

.menueknopf[aria-expanded="true"] .menueknopf__balken:nth-child(3) {
  transform: translateY(-0.375rem) rotate(-45deg);
}

/* Die Liste steht oben unter der Kopfzeile, der Fuss unten. Nicht mit
   justify-content: center: sobald der Inhalt hoeher ist als das Fenster,
   schneidet ein zentrierter Flexbehaelter oben und unten ab, und der letzte
   Knopf ist nicht mehr erreichbar. Der Abstand kommt deshalb aus margin-top
   am Fuss, den kann das Scrollen zurueckholen. */
.mobilmenue {
  position: fixed;
  inset: 0;
  z-index: 45;
  display: flex;
  flex-direction: column;
  padding: calc(var(--kopfhoehe) + 1.5rem) var(--rand) 2.5rem;
  background: var(--grund);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.mobilmenue__liste {
  display: flex;
  flex-direction: column;
  counter-reset: menuepunkt;
}

/* Wie die Ueberschriften der Seite: gesperrte Versalien in der Displayschrift,
   linksbuendig auf der Kante. Die Linie sitzt oben, nicht unten, sonst haengt
   unter dem letzten Punkt eine Linie ohne Inhalt darunter. */
.mobilmenue__liste a {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 1rem;
  font-family: var(--schrift-display);
  font-size: clamp(1.375rem, 6.5vw, 1.75rem);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  text-decoration: none;
  padding: 0.875rem 0;
  border-top: 1px solid var(--linie);
  counter-increment: menuepunkt;
}

.mobilmenue__liste a:last-child {
  border-bottom: 1px solid var(--linie);
}

/* Die Nummer greift die Zahlenkaesten der Seite auf. Als CSS-Zaehler und nicht
   im Markup: sie ist Schmuck, und im Markup stuende sie in zwoelf Dateien.
   Der leere Alternativtext haelt sie aus der Vorlesereihenfolge heraus. */
.mobilmenue__liste a::before {
  content: counter(menuepunkt, decimal-leading-zero) / "";
  font-size: var(--schrift-klein);
  font-weight: 600;
  letter-spacing: var(--sperrung-mittel);
  color: var(--text-leise);
}

.mobilmenue__liste a:hover,
.mobilmenue__liste a[aria-current="page"] {
  color: var(--text);
}

.mobilmenue__fuss {
  margin-top: auto;
  padding-top: 2.5rem;
}

/* So gross wie im Hero: die Nummer ist auf dem Telefon der kuerzeste Weg zu
   einem Auftrag, nicht das Formular. */
.mobilmenue__tel {
  display: inline-block;
  font-family: var(--schrift-display);
  font-size: clamp(1.5rem, 7vw, 2rem);
  font-weight: 700;
  letter-spacing: 0.02em;
  text-decoration: none;
}

.mobilmenue__zeiten {
  margin: 0.5rem 0 0;
  font-size: var(--schrift-klein);
  font-family: var(--schrift-display);
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  color: var(--text-leise);
}

/* Rand rechts und unten fuer den zweiten Rahmen, sonst schiebt er sich ueber
   die Kante des Menuebereichs. */
.mobilmenue__knopf {
  margin: 2rem 0.875rem 0.875rem 0;
}

/* Die Punkte fahren gestaffelt ein, sobald das Menue sichtbar wird: das hidden
   faellt weg, damit startet die Animation von selbst neu. Dieselbe Bewegung
   wie bei den Auftritten auf der Seite. */
.mobilmenue__liste a,
.mobilmenue__fuss > * {
  animation: menue-auf 0.5s cubic-bezier(0.22, 0.61, 0.36, 1) backwards;
}

.mobilmenue__liste a:nth-child(1) { animation-delay: 0.04s; }
.mobilmenue__liste a:nth-child(2) { animation-delay: 0.08s; }
.mobilmenue__liste a:nth-child(3) { animation-delay: 0.12s; }
.mobilmenue__liste a:nth-child(4) { animation-delay: 0.16s; }
.mobilmenue__liste a:nth-child(5) { animation-delay: 0.2s; }
.mobilmenue__liste a:nth-child(6) { animation-delay: 0.24s; }
.mobilmenue__fuss > * { animation-delay: 0.3s; }

@keyframes menue-auf {
  from {
    opacity: 0;
    transform: translateY(0.75rem);
  }
}

/* ---------- Hero ---------- */

/* Der Hero fuellt genau eine Ansichtshoehe: Kopfzeile, Bild, unten derselbe
   Abstand wie an den Seiten. Ohne den unteren Abstand klebt das Bild an der
   Fensterkante und der Rahmen wirkt an drei Seiten aufgelegt, an einer nicht.
   Das Bild bekommt den Rest ueber flex statt ueber eine Rechnung mit vh:
   so bleibt der schraege Strich darunter aussen vor. */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100svh;
  min-height: 34rem;
  padding: var(--kopfhoehe) 0 var(--rand);
}

/* Bild und Kopfzeile laufen ueber die volle Fensterbreite, nur der aeussere
   Abstand bleibt. Eine Begrenzung auf die Inhaltsbreite laesst das Bild auf
   grossen Bildschirmen als Block in der Mitte stehen: bei 2560 Pixeln waren
   es 57 Prozent der Breite und links und rechts je ein halber Meter schwarz.
   Beide muessen dieselbe Regel haben, sonst steht die Wortmarke gegenueber
   der Bildkante versetzt. */
.hero__rahmen {
  position: relative;
  flex: 1;
  min-height: 0;
  width: 100%;
  padding-inline: var(--rand);
}

/* Die Fotos tragen in dieser Gestaltung keine Farbe bei, sie liefern Struktur.
   Entsaettigt und abgedunkelt fuegen sie sich in den monochromen Satz ein,
   und der helle Himmel frisst den Text darueber nicht mehr auf. */
/* Beschneidet das Bild. Der Auftritt faehrt es aus 1,06 herunter; ohne diesen
   Rahmen ragt es waehrenddessen ueber alle vier Kanten und der gleichmaessige
   schwarze Rand ist genau dann weg, wenn man am meisten hinsieht. */
.hero__bildfeld {
  position: relative;
  height: 100%;
  overflow: hidden;
  /* Traegt die Hoehe, seit die Videoebenen absolut liegen. */
  background: var(--grund-tief);
}

/* Zwei Ebenen uebereinander: waehrend die eine auslaeuft, faengt die andere
   von vorn an, und dazwischen wird ueberblendet. Deshalb absolut positioniert
   und nicht im Fluss. */
.hero__bild {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: opacity 1.4s linear;
  filter: grayscale(0.72) brightness(0.62) contrast(1.12);
}

/* Zwei Verläufe übereinander: einer legt sich von links über das Bild, damit
   der Rahmen mit der Jahreszahl steht, der zweite dunkelt die untere Kante ab,
   wo die Telefonnummer sitzt. Ein einzelner flächiger Schleier würde das Foto
   platt machen. */
/* Die Vorlage laesst das Foto weitgehend offen und dunkelt nur die linke
   Flanke hinter dem Rahmen und die untere rechte Ecke hinter der Telefon-
   nummer. Ein flaechiger Schleier ueber allem macht das Motiv platt. */
.hero__schleier {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(95deg, rgb(10 12 16 / 0.9) 0%, rgb(10 12 16 / 0.68) 30%,
      rgb(10 12 16 / 0.4) 62%, rgb(10 12 16 / 0.3) 100%),
    radial-gradient(ellipse 62% 58% at 88% 92%, rgb(10 12 16 / 0.8),
      rgb(10 12 16 / 0) 70%);
}

.hero__inhalt {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(1.5rem, 7vw, 11rem) clamp(1.5rem, 8vw, 13rem);
}

/* Ein geschlossenes Rechteck, rund ein Drittel der Bildbreite. Zahl und
   Beschriftung sitzen darin unten, nicht mittig: oben bleibt bewusst Luft,
   die den Rahmen als Gestaltungselement statt als Textkasten lesen laesst.

   Der Rahmen liegt in einem eigenen Pseudo-Element, weil ihn der Auftritt per
   clip-path aufdeckt. Steht der Rand am Kasten selbst, schneidet derselbe
   clip-path die Zahl darin mit durch, und man sieht mitten im Auftritt nur
   Streifen der Ziffern. */
.hero__kasten {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  padding: clamp(3rem, 8vw, 7rem) clamp(1.75rem, 3vw, 2.75rem)
    clamp(2rem, 3.5vw, 3rem);
  align-self: flex-start;
  /* 38 Prozent, nicht 32: die Angabe bezieht sich auf .hero__inhalt abzueglich
     dessen Polsterung, nicht auf die Bildbreite. Am Bild gemessen sind das die
     31 Prozent der Vorlage. */
  width: min(38%, 46rem);
  min-width: 16rem;
  /* Seitenverhaeltnis statt min-height in Prozent: die Prozentangabe bezieht
     sich auf die Innenhoehe des Elternteils und schrumpft damit mit dessen
     Polsterung mit. Bei mehr Inhalt darf der Rahmen ueber das Verhaeltnis
     hinauswachsen. */
  aspect-ratio: 12 / 11;

  /* Das Video hinter dem Kasten wird weichgezeichnet. Das gibt Tiefe und
     nimmt der Zahl die Unruhe aus dem laufenden Bild. Der Endwert steht hier
     als normaler Stil, die Animation weiter unten faehrt ihn nur an: mit
     animation-fill-mode both bliebe der Animationswert liegen und der
     Zeigen-Zustand kaeme nie zum Zug. */
  background: rgb(10 12 16 / 0.16);
  backdrop-filter: blur(7px) saturate(0.85);
  transition: backdrop-filter 0.6s ease, background-color 0.6s ease;
}

@supports (backdrop-filter: blur(1px)) {
  .hero__kasten {
    background: rgb(10 12 16 / 0.1);
  }
}

/* Beim Zeigen wird die Scheibe dichter und der Rahmen heller. Reine Zugabe,
   der Kasten ist nicht anklickbar. */
.hero__kasten:hover {
  background: rgb(10 12 16 / 0.3);
  backdrop-filter: blur(14px) saturate(0.75);
}

.hero__kasten:hover::before {
  border-color: var(--text);
}

.hero__kasten::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--linie-stark);
  pointer-events: none;
  transition: border-color 0.6s ease;
}

.hero__aussage {
  display: flex;
  flex-direction: column;
  gap: 0.875rem;
  font-weight: 400;
}

/* Der schwerste Satz der Seite. Ausser hier und in der Ueberschrift von
   "Ueber uns" steht Archivo ueberall leicht bis mittel. */
.hero__zahl {
  font-family: var(--schrift-display);
  font-size: clamp(4.5rem, 8.9vw, 17rem);
  font-weight: 800;
  line-height: 0.85;
  letter-spacing: -0.04em;
}

.hero__zeile {
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  line-height: 1.85;
  color: var(--text);
}

.hero__kontakt {
  position: absolute;
  right: clamp(2rem, 5vw, 4.5rem);
  bottom: clamp(2rem, 5vw, 3.5rem);
  text-align: right;
  max-width: 22rem;
}

.hero__kontakt p {
  font-size: var(--schrift-klein);
  line-height: 1.7;
  color: var(--text);
  margin-bottom: 0.625rem;
}

.hero__telefon {
  font-family: var(--schrift-display);
  font-size: clamp(1.125rem, 1.9vw, 1.5rem);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  text-decoration: none;
  white-space: nowrap;
}

.hero__telefon:hover {
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

/* Der schräge Strich, der den Hero vom ersten Abschnitt trennt. Er sitzt
   rechts, genau wie in der Vorlage, und ist rein dekorativ. */
.hero__strich {
  width: 100%;
  padding: clamp(1.5rem, 3vw, 2.5rem) var(--rand) 0;
  display: flex;
  justify-content: flex-end;
}

.hero__strich span {
  display: block;
  width: 5rem;
  height: 1px;
  background: var(--linie-mittel);
  transform: rotate(-45deg);
}

/* ---------- Unterseiten-Hero ---------- */

/* Das Bild liegt im Markup vor dem Inhalt und wird hier hinter ihn gelegt.
   Ohne die absolute Positionierung steht erst ein grosses Foto im Fluss und
   der Text darunter. Gilt genauso fuer das Zitatband weiter unten. */
.unterseite-hero {
  position: relative;
  padding: 11rem 0 clamp(3rem, 6vw, 5rem);
  border-bottom: 1px solid var(--linie);
  isolation: isolate;
}

.unterseite-hero > picture {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.unterseite-hero > picture img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.unterseite-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background:
    linear-gradient(95deg, rgb(10 12 16 / 0.92) 0%, rgb(10 12 16 / 0.72) 45%,
      rgb(10 12 16 / 0.55) 100%);
}

.unterseite-hero__titel {
  font-size: clamp(1.625rem, 3.4vw, 2.75rem);
  max-width: 30ch;
  margin-top: 2rem;
  margin-bottom: 1.75rem;
}

.unterseite-hero__text {
  max-width: 42rem;
  color: var(--text-ruhig);
}

/* Die Klasse sitzt am nav, die Punkte stehen in einem ol darin. Ohne die
   eigene Regel fuer das ol bleiben Nummerierung und Standardeinzug stehen. */
.krumen {
  margin-bottom: 2rem;
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-weit);
  color: var(--text-leise);
}

.krumen ol {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  list-style: none;
  margin: 0;
  padding: 0;
}

.krumen li + li::before {
  content: "/";
  margin-right: 0.5rem;
  color: var(--linie-mittel);
}

.krumen a {
  text-decoration: none;
}

.krumen a:hover {
  color: var(--text);
}

/* ---------- Hero: Auftritt beim Laden ---------- */

/* Der Rahmen kommt zuerst, dann die Zahl, zuletzt die Nummer rechts unten.
   Die Staffelung ist der Unterschied zwischen "alles ist da" und einem
   Auftritt. Bei reduzierter Bewegung schaltet die globale Regel weiter
   unten alles ab. */
/* Der Rahmen wird von oben nach unten aufgedeckt. Das Aufschlagen der unteren
   Linie kam nicht vom clip-path selbst, sondern vom Ende der Bewegung: die
   letzten Prozent liefen zu schnell. Deshalb ist der Schluss jetzt gedehnt,
   die letzten zwoelf Prozent brauchen ein Drittel der Zeit. */
/* Zwei Bilder, kein Zwischenschritt. Jeder zusaetzliche Keyframe setzt die
   Zeitkurve neu an: die Bewegung bremst dort ab und beschleunigt wieder, und
   genau das sieht man als Ruck. Die Weichheit kommt allein aus der Kurve.

   Die Deckkraft laeuft als zweite, kurze Animation nebenher, damit sie keinen
   Keyframe in dieser hier braucht. */
@keyframes hero-rahmen {
  from {
    clip-path: inset(0 0 100% 0);
  }
  to {
    clip-path: inset(0 0 0 0);
  }
}

@keyframes hero-rahmen-blende {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* Die Scheibe zieht sich mit dem Rahmen auf. Ohne das steht sie von der ersten
   Millisekunde an als Rechteck im Bild, bevor irgendein Rahmen da ist. */
@keyframes hero-scheibe {
  from {
    backdrop-filter: blur(0) saturate(1);
  }
  to {
    backdrop-filter: blur(7px) saturate(0.85);
  }
}

@keyframes hero-auf {
  from {
    opacity: 0;
    transform: translateY(1rem);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes hero-bild {
  from {
    transform: scale(1.06);
  }
  to {
    transform: none;
  }
}

.hero__bild {
  animation: hero-bild 3.6s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

/* Sanft an, gleichmaessig durch, kriechend aus. Nachgerechnet steht der Rahmen
   nach der Haelfte der Zeit bei 81 Prozent, nach drei Vierteln bei 97, und die
   letzten drei Prozent brauchen das ganze letzte Viertel. Damit kommt die
   untere Linie langsam zusammen, statt anzuschlagen.

   Die Deckkraft laeuft als eigene, kurze Animation, damit sie keinen Keyframe
   in der Aufdeckung braucht: jeder zusaetzliche Keyframe setzt die Zeitkurve
   neu an und erzeugt genau dort einen Ruck. */
.hero__kasten::before {
  animation:
    hero-rahmen 2.4s 0.2s cubic-bezier(0.4, 0.05, 0.15, 1) both,
    hero-rahmen-blende 0.6s 0.2s ease-out both;
}

/* backwards, nicht both: nach dem Auftritt gilt wieder der Stil oben, und
   damit greift der Zeigen-Zustand. */
.hero__kasten {
  animation: hero-scheibe 2.4s 0.2s cubic-bezier(0.4, 0.05, 0.15, 1) backwards;
}

.hero__zahl {
  animation: hero-auf 1.4s 0.95s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

.hero__zeile {
  animation: hero-auf 1.4s 1.15s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

.hero__kontakt {
  animation: hero-auf 1.4s 1.4s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

.hero__strich span {
  animation: hero-auf 1.4s 1.7s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

/* ---------- Abschnitte ---------- */

.abschnitt {
  position: relative;
  padding-block: clamp(4.5rem, 10vw, 9rem);
  /* Faengt das randlose Laufband ab. clip statt hidden: hidden macht den
     Abschnitt zu einem Scrollcontainer und bricht damit das klebende Bild
     in der Haltung. */
  overflow-x: clip;
}

/* Eine einzige Abstufung, und die nur am Schluss jeder Seite. Der Rhythmus
   entsteht über Weißraum und Linien, nicht über Flächenfarben. Die hellere
   Stufe darüber gab es einmal, sie stand als grauer Block zwischen zwei
   schwarzen Abschnitten und passte zu keinem von beiden. */
.abschnitt--tinte {
  background: var(--grund-tief);
}

/* Der letzte Abschnitt stoesst an den Fuss. Beide volle Polster ergeben eine
   leere Bahn von 200 Pixeln zwischen dem letzten Satz und der Wortmarke. */
main > .abschnitt:last-child {
  padding-bottom: clamp(2.5rem, 5vw, 4.5rem);
}

.behaelter {
  position: relative;
}

/* Der Marker braucht eine eigene Spalte. Sie entsteht ueber zusaetzliches
   Innenpolster am Behaelter, nicht ueber einen negativen Rand: sonst schiebt
   sich der Marker aus dem Fenster, sobald das Fenster schmaler ist als die
   Inhaltsbreite. Unter 48rem faellt beides weg.

   Die Spalte steht an JEDEM Behaelter, nicht nur an denen mit Marker: sonst
   beginnt der eine Abschnitt auf der Markerkante und der naechste eine Spalte
   weiter links, und die Seite hat zwei Fluchten statt einer. */
@media (min-width: 48rem) {
  :root {
    --markerversatz: var(--markerspalte);
  }

  .behaelter {
    padding-inline-start: calc(var(--rand) + var(--markerspalte));
  }
}

.marker {
  left: var(--rand);
  top: 0.25rem;
}

.kopf {
  max-width: 46rem;
  margin-bottom: clamp(2.5rem, 5vw, 4.5rem);
}

.kopf--mitte {
  margin-inline: auto;
  text-align: center;
}

.kopf .augenbraue {
  display: block;
  margin-bottom: 1.5rem;
}

.kopf__titel {
  font-size: clamp(1.375rem, 2.8vw, 2.125rem);
  margin-bottom: 1.5rem;
  max-width: 26ch;
}

.kopf--mitte .kopf__titel {
  margin-inline: auto;
}

.kopf__text {
  color: var(--text-ruhig);
  max-width: 38rem;
}

.kopf--mitte .kopf__text {
  margin-inline: auto;
}

.fliesstext {
  max-width: 42rem;
}

.fliesstext > * + * {
  margin-top: 1.5rem;
}

.fliesstext h2 {
  font-family: var(--schrift-display);
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  margin-top: 3rem;
}

.fliesstext h3 {
  font-family: var(--schrift-display);
  font-size: 1rem;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  margin-top: 2.5rem;
}

.fliesstext p,
.fliesstext li {
  color: var(--text-ruhig);
}

.fliesstext ul,
.fliesstext ol {
  padding-left: 1.25rem;
}

.fliesstext li + li {
  margin-top: 0.75rem;
}

.raster {
  display: grid;
  gap: clamp(1.75rem, 3.5vw, 3.5rem);
}

.raster--zwei {
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
}

.raster--drei {
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.raster--vier {
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
}

/* ---------- Über uns: Aussage, Zahlenkasten, Collage ---------- */

/* Der Abschnitt füllt wie der Hero genau eine Ansichtshöhe. Deshalb ist er
   eine Flexspalte: Kopf und Kasten nehmen ihre Höhe aus dem Inhalt, die
   Collage bekommt den Rest. Der obere Rand entspricht der Kopfhöhe, sonst
   liegt die Überschrift unter der Kopfzeile, wenn der Abschnitt oben steht. */
/* Vier Spalten wie in der Vorlage. Ohne die feste Zahl setzt auto-fit knapp
   ueber dem Umbruchpunkt drei nebeneinander, und die vierte steht allein in
   der zweiten Zeile. Zwischen 48rem und 68rem sind es zwei, siehe dort. */
@media (min-width: 68rem) {
  .wir__dienste .raster {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (min-width: 68rem) {
  .ueber {
    display: flex;
    flex-direction: column;
    min-height: 100svh;
    padding-block: var(--kopfhoehe) clamp(2rem, 5vh, 3.5rem);
  }

  .ueber > .behaelter {
    display: flex;
    flex-direction: column;
    flex: 1;
  }
}

.ueber__kopf {
  margin-bottom: clamp(2.5rem, 5vh, 4rem);
}

/* Größer und schwerer als die übrigen Abschnittstitel. Das ist die Aussage
   der Seite, nicht eine Überschrift unter vielen. */
.ueber__titel {
  font-size: clamp(1.5rem, 2.4vw, 2.25rem);
  font-weight: 700;
  line-height: 1.3;
  margin-bottom: 1.75rem;
  max-width: 34ch;
}

.ueber__satz {
  color: var(--text-ruhig);
  line-height: 1.9;
  max-width: 34rem;
  margin-bottom: clamp(2rem, 4vh, 2.75rem);
}

/* Die Collage. Die Bilder liegen in der Vorlage nicht in einem Raster,
   sondern frei versetzt übereinander, und genau das trägt die Wirkung: kein
   Bild teilt eine Kante mit einem anderen. Deshalb absolute Prozentwerte in
   einem Kasten, dessen Höhe aus der übrigen Ansichtshöhe kommt. Die Werte
   sind an der Vorlage abgemessen. Wer ein Bild verschiebt, verschiebt auch
   die zugehörige Scheibe. */
.ueber__collage {
  position: relative;
  display: grid;
  gap: clamp(1rem, 3vw, 2rem);
}

.ueber__bild {
  overflow: hidden;
}

/* picture steht zwischen Kasten und Bild und hat von sich aus keine Höhe.
   Ohne diese Regel greift `height: 100%` am img ins Leere, das Bild fällt auf
   sein Seitenverhältnis zurück und füllt den Kasten nicht. Die Scheibe darüber
   steht dann zur Hälfte auf dem Grund und liest sich als grauer Klotz. */
.ueber__bild picture {
  width: 100%;
  height: 100%;
}

.ueber__bild img {
  width: 100%;
  height: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
}

/* Unter 48rem stehen Kasten und Bilder untereinander. Die Scheiben und der
   schräge Strich entfallen dort: übereinandergelegte Flächen brauchen Platz,
   den ein Telefon nicht hat. */
.ueber__schraege,
.ueber__scheibe {
  display: none;
}

/* ---------- Über uns: Zahlenkasten ---------- */

/* Der Kasten ist dieselbe Milchglasscheibe wie im Hero und steht deshalb auf
   dem mittleren Bild, nicht daneben: ohne Motiv dahinter hat das Weichzeichnen
   nichts zu tun. Der Rahmen liegt im Pseudo-Element, weil ihn der Auftritt per
   clip-path aufdeckt. Steht er am Kasten selbst, schneidet derselbe clip-path
   die Zahl darin mit durch.

   Anders als im Hero ist der Ruhezustand hier der leere Rahmen: der Auftritt
   startet erst beim Hereinscrollen, nicht beim Laden. Mit dem Hero-Ansatz
   (Endwert als normaler Stil, Animation mit backwards) stünde die Scheibe
   schon vorher im Bild.

   Ausgelöst wird er über .ist-sichtbar an der Collage, nicht am Kasten selbst.
   Der Kasten ragt oben über die Collage hinaus und käme mit eigenem
   .einblenden früher in den Blick des Beobachters: sein Auftritt liefe dann
   hinter der noch unsichtbaren Collage ab, und wenn die Bilder einblenden,
   stünde er schon fertig da. */
.ueber__zahlkasten {
  position: relative;
  container-type: inline-size;
  border: 0;
  margin: 0;
  gap: 1.5rem;
  width: clamp(13.5rem, 60vw, 21rem);
  background: transparent;
  backdrop-filter: blur(0) saturate(1);
  transition: backdrop-filter 2.2s cubic-bezier(0.4, 0.05, 0.15, 1),
    background-color 2.2s cubic-bezier(0.4, 0.05, 0.15, 1);
}

.ueber__zahlkasten::before {
  content: "";
  position: absolute;
  inset: 0;
  border: 1px solid var(--linie-stark);
  opacity: 0;
  pointer-events: none;
  transition: border-color 0.6s ease;
}

.ueber__zahlkasten .zahlkasten__zahl {
  font-size: 54cqw;
  opacity: 0;
}

.ueber__zahlkasten .zahlkasten__text {
  opacity: 0;
}

.ueber__collage.ist-sichtbar .ueber__zahlkasten {
  background: rgb(10 12 16 / 0.16);
  backdrop-filter: blur(7px) saturate(0.85);
}

@supports (backdrop-filter: blur(1px)) {
  .ueber__collage.ist-sichtbar .ueber__zahlkasten {
    background: rgb(10 12 16 / 0.1);
  }
}

/* Beim Zeigen wird die Scheibe dichter und der Rahmen heller, wie im Hero.
   Reine Zugabe, der Kasten ist nicht anklickbar. */
.ueber__collage.ist-sichtbar .ueber__zahlkasten:hover {
  background: rgb(10 12 16 / 0.3);
  backdrop-filter: blur(14px) saturate(0.75);
  transition-duration: 0.6s;
}

.ueber__collage.ist-sichtbar .ueber__zahlkasten:hover::before {
  border-color: var(--text);
}

/* Dieselben Keyframes wie im Hero: Rahmen von oben nach unten aufdecken, die
   Deckkraft als eigene kurze Animation daneben, damit die Aufdeckung ohne
   Zwischenschritt auskommt. Danach Zahl und Beschriftung gestaffelt. */
.ueber__collage.ist-sichtbar .ueber__zahlkasten::before {
  animation:
    hero-rahmen 2.4s cubic-bezier(0.4, 0.05, 0.15, 1) both,
    hero-rahmen-blende 0.6s ease-out both;
}

.ueber__collage.ist-sichtbar .ueber__zahlkasten .zahlkasten__zahl {
  animation: hero-auf 1.4s 0.75s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

.ueber__collage.ist-sichtbar .ueber__zahlkasten .zahlkasten__text {
  animation: hero-auf 1.4s 0.95s cubic-bezier(0.33, 0.7, 0.2, 1) both;
}

/* Ohne JavaScript kommt .ist-sichtbar nie, dann steht der Kasten fertig da. */
html:not(.js) .ueber__zahlkasten {
  background: rgb(10 12 16 / 0.16);
  backdrop-filter: blur(7px) saturate(0.85);
}

html:not(.js) .ueber__zahlkasten::before,
html:not(.js) .ueber__zahlkasten .zahlkasten__zahl,
html:not(.js) .ueber__zahlkasten .zahlkasten__text {
  opacity: 1;
}

/* ---------- Über uns: Anordnung ab 48rem ---------- */

@media (min-width: 48rem) {
  .ueber__collage {
    display: block;
    flex: 1;
    min-height: 17rem;
  }

  .ueber__bild,
  .ueber__scheibe,
  .ueber__schraege {
    position: absolute;
    display: block;
  }

  .ueber__bild img {
    aspect-ratio: auto;
  }

  /* Die Reihenfolge ist Teil der Vorlage: links liegt über der Mitte, die
     Mitte über rechts. Legt man rechts nach oben, schiebt sich das untere
     Bild vor das mittlere und die Staffelung kippt. */
  .ueber__bild--rechts {
    left: 59%;
    top: 46.5%;
    width: 41%;
    height: 53.5%;
    z-index: 1;
  }

  .ueber__bild--mitte {
    left: 26%;
    top: 0;
    width: 39.2%;
    height: 65%;
    z-index: 2;
  }

  .ueber__bild--links {
    left: 0;
    top: 34%;
    width: 40.7%;
    height: 65%;
    z-index: 3;
  }

  /* Eine aufgehellte Scheibe über dem Teil des Bildes, den kein anderes Bild
     überlappt. Sie bindet die drei Fotos zu einer Fläche zusammen, ohne die
     zerfällt die Collage in drei nebeneinanderliegende Rechtecke. Bewusst nur
     ein Schleier und kein backdrop-filter: das Weichzeichnen frisst hier das
     Motiv, und der Schleier allein reicht für die Trennung. */
  .ueber__scheibe {
    z-index: 4;
    background: rgb(255 255 255 / 0.1);
  }

  .ueber__scheibe--a {
    left: 41.2%;
    top: 0;
    width: 24.1%;
    height: 65%;
  }

  .ueber__scheibe--b {
    left: 59%;
    top: 62.7%;
    width: 22.3%;
    height: 37.3%;
  }

  .ueber__schraege {
    left: 11.5%;
    top: 29%;
    z-index: 5;
  }

  /* Der Kasten sitzt mit der unteren linken Ecke auf dem mittleren Bild und
     ragt oben über die Collage hinaus, in die freie Spalte neben dem Text.
     Deshalb bottom statt top: die Höhe kommt aus dem Inhalt, festgelegt ist
     nur, wie tief die Ecke im Bild liegt.

     Die 59 Prozent sind dieselben wie am rechten Bild und an der Scheibe
     darunter: die drei stehen auf einer Kante. Mit 60 lag der Kasten 15 Pixel
     daneben, zu wenig für eine Staffelung und zu viel für eine Flucht. */
  .ueber__zahlkasten {
    position: absolute;
    left: 59%;
    bottom: 87%;
    width: 24%;
    z-index: 6;
  }
}

/* ---------- Wer wir sind: Aussage über dem Leistungsüberblick ---------- */

/* Der Abschnitt trägt zwei Marker, einen am Text und einen an der
   Leistungsreihe. Deshalb steht hier keiner als direktes Kind des Behälters:
   die Regel weiter oben würde sonst den ganzen Abschnitt einrücken, und der
   Zahlenkasten stünde nicht mehr wie in der Vorlage ganz außen. */
.wir__kopf {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
}

.wir__zahlkasten {
  justify-self: start;
  align-self: start;
  width: min(100%, 21rem);
}

.wir__titel {
  font-size: clamp(1.375rem, 2.8vw, 2.125rem);
  margin-bottom: 1.75rem;
  max-width: 24ch;
}

.wir__text p {
  color: var(--text-ruhig);
  max-width: 44ch;
}

.wir__text p + p {
  margin-top: 1.5rem;
}

.wir__dienste {
  position: relative;
  margin-top: clamp(4rem, 10vw, 8rem);
}

@media (min-width: 48rem) {
  /* Kasten, Marker und Text nebeneinander wie in der Vorlage. Die dritte
     Spalte ist gedeckelt und füllt die Zeile bewusst nicht aus: die freie
     Fläche rechts gehört zum Aufbau. */
  .wir__kopf {
    grid-template-columns: minmax(13rem, 22%) auto minmax(0, 40rem);
    column-gap: clamp(2rem, 6vw, 6rem);
    align-items: start;
    /* Ohne start zieht das Raster den freien Platz in die auto-Spalte des
       Markers. Der steht dann nicht neben dem Kasten, sondern in der Mitte
       der Zeile: vertical-rl setzt seine Zeile an den rechten Rand. */
    justify-content: start;
  }

  /* Dieser Marker steht zwischen Kasten und Text, nicht am linken Rand. Als
     Rasterzelle statt als absolute Marke, sonst müsste seine Spalte doppelt
     gepflegt werden. */
  .wir__marker {
    position: static;
  }

  /* Der zweite Marker steht in derselben Spalte wie alle anderen. Die haelt
     der Behaelter frei, deshalb ein negativer Wert: der Marker greift aus dem
     Inhalt heraus in die Spalte davor. Der Strich oben ragt durch seine
     Drehung ueber die Spalte hinaus, daher die negative Hoehe. */
  .wir__dienste > .marker {
    left: calc(-1 * var(--markerspalte));
    top: -1.25rem;
  }
}

/* ---------- Technik: Bild, Zahlenkasten, Aussage darunter ---------- */

.technik__kopf {
  display: grid;
  gap: clamp(2.5rem, 6vw, 4rem);
}

/* Das Bild hat das Seitenverhältnis der Vorlage. Höhe kommt vom Verhältnis,
   deshalb brauchen picture und img eine volle Höhe: sonst fällt das img auf
   das Verhältnis der Datei zurück und füllt seinen Kasten nicht. */
.technik__bild {
  aspect-ratio: 5 / 3;
}

.technik__bild picture,
.technik__bild img {
  height: 100%;
}

.technik__bild img {
  width: 100%;
  object-fit: cover;
}

.technik__zahlkasten {
  align-self: start;
  width: min(100%, 24rem);
}

.technik__text {
  position: relative;
  margin-top: clamp(3rem, 7vw, 6rem);
}

.technik__inhalt {
  max-width: 32rem;
}

@media (min-width: 48rem) {
  /* Bild links auf der Kante, Kasten rechts auf der Gegenkante, oben bündig.
     Die freie Fläche der Vorlage liegt zwischen beiden statt hinter dem
     Kasten: so bleibt der luftige Aufbau, und die Zeile endet trotzdem auf
     derselben Kante wie jeder andere Abschnitt. Die mittlere Spalte nimmt den
     Rest, deshalb stehen Bild und Kasten explizit in ihrer Spalte. */
  .technik__kopf {
    grid-template-columns: minmax(0, 50%) 1fr minmax(0, 28%);
    column-gap: clamp(2rem, 6vw, 6rem);
    align-items: start;
  }

  .technik__bild {
    grid-column: 1;
  }

  .technik__zahlkasten {
    grid-column: 3;
    justify-self: end;
  }

  /* Der Textblock beginnt bei einem Drittel, der Marker ein Stück davor. Beide
     Werte beziehen sich auf die Breite des Behälters, nicht auf das Fenster. */
  .technik__text {
    padding-inline-start: 33%;
  }

  .technik__marker {
    left: 25%;
    top: 0.25rem;
  }
}

/* ---------- Projekte: zwei versetzte Reihen ---------- */

.projekte__liste {
  position: relative;
  display: grid;
  gap: clamp(3rem, 7vw, 6rem);
}

.projekt {
  display: grid;
  gap: clamp(1.5rem, 4vw, 2.5rem);
}

.projekt__bild {
  aspect-ratio: 4 / 3;
}

.projekt__bild picture,
.projekt__bild img {
  height: 100%;
}

.projekt__bild img {
  width: 100%;
  object-fit: cover;
}

.projekt__titel {
  font-size: clamp(1.125rem, 2vw, 1.5rem);
  margin-bottom: 1.5rem;
}

/* Der Strich liegt am Absatz und nicht am Textblock: in der zweiten Reihe ist
   die Überschrift zweizeilig, ein fester Abstand von oben säße dort falsch. */
.projekt__satz {
  position: relative;
  color: var(--text-ruhig);
  max-width: 34rem;
}

/* Der Strich ragt nach links über den Absatz hinaus. Solange Bild und Text
   nebeneinander stehen, liegt er im Zwischenraum; gestapelt zeigt er aus dem
   Behälter heraus. Deshalb erscheint er erst ab 48rem, wie die Scheiben in der
   Collage. */
.projekt__strich {
  display: none;
}

.projekt__knopf {
  margin-top: clamp(2rem, 4vw, 3rem);
}

@media (min-width: 48rem) {
  /* Bild und Text nebeneinander, die zweite Reihe weiter eingerückt als die
     erste. Die Staffelung der Vorlage bleibt, sie sitzt jetzt aber zwischen
     den beiden Kanten der Seite: Reihe eins beginnt links auf der Kante,
     Reihe zwei endet rechts auf der Gegenkante. Die 17 Prozent Versatz sind
     der Abstand der Vorlage zwischen beiden Reihen.

     Einrückung und Abstand sind eigene Rasterspalten und kein Außenrand: als
     Rand würde die Reihe schmaler, und die Prozentwerte für Bild und Text
     bezögen sich dann in jeder Reihe auf eine andere Breite. */
  .projekt {
    grid-template-columns: 0 44.4% 3.3% 35.3%;
    column-gap: 0;
    align-items: start;
  }

  .projekt--versetzt {
    grid-template-columns: 17% 44.4% 3.3% 35.3%;
  }

  .projekt__bild {
    grid-column: 2;
  }

  .projekt__text {
    grid-column: 4;
  }

  .projekt__strich {
    display: block;
    position: absolute;
    left: -1.75rem;
    top: 1.5rem;
  }

  .projekte__liste > .marker {
    left: calc(-1 * var(--markerspalte));
    top: 0.25rem;
  }
}

/* ---------- Schluss: Aufruf mit Zahlenkasten ---------- */

/* Steht am Ende jeder Unterseite. Aussage links, Zahlenkasten daneben, damit
   der Abschluss denselben Aufbau hat wie der Kontaktabschnitt der Startseite. */
.schluss {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
}

.schluss__titel {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  margin-bottom: 1.5rem;
}

.schluss__satz {
  color: var(--text-ruhig);
  max-width: 40rem;
}

.schluss__knopf {
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

.schluss__kasten {
  align-self: start;
  justify-self: start;
  width: min(100%, 20rem);
}

@media (min-width: 48rem) {
  .schluss {
    grid-template-columns: minmax(0, 46%) minmax(0, 26%);
    column-gap: clamp(2rem, 6vw, 6rem);
    align-items: start;
  }
}

/* ---------- Hinweisseiten: 404 und Danke ---------- */

/* Beide Seiten haben genau einen Abschnitt. Er fuellt die Ansicht, sonst steht
   der Fuss auf halber Hoehe und darunter bleibt eine leere Flaeche. Oben
   bleibt Kopfhoehe Platz, die Leiste ist auf diesen Seiten von Anfang an
   gefuellt. */
.hinweisseite {
  display: flex;
  align-items: center;
  min-height: 100svh;
  padding-block: var(--kopfhoehe) clamp(3rem, 8vh, 6rem);
}

.hinweisseite .behaelter {
  width: 100%;
}

/* Zwei Klassen im Selektor, nicht eine: .haken setzt margin auf null und steht
   weiter unten in der Datei. Mit nur .hinweisseite__schritte gewinnt die
   spaetere Regel, und der erste Punkt klebt am Absatz darueber. */
.hinweisseite .hinweisseite__schritte {
  margin-top: clamp(2rem, 4vw, 2.75rem);
  margin-bottom: 0;
}

.hinweisseite__knoepfe {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.75rem;
  margin-top: clamp(2rem, 4vw, 2.75rem);
}

/* Steht unter den Knoepfen und nicht oben wie bei den Rechtstexten: dort ist
   der Kasten die Warnung vor dem Text darunter, hier die Auskunft darueber,
   dass die Bestaetigung ueber ihm gerade nicht stimmt. */
.hinweisseite__platzhalter {
  margin-top: clamp(2.5rem, 5vw, 3.5rem);
  max-width: 40rem;
}

/* ---------- Karten ---------- */

/* Die Spalte im Vorlagenstil: schraeger Strich, Titel in gesperrten
   Versalien, kleiner Text. Kein Rahmen, keine Flaeche, der Strich traegt. */
.karte {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding-top: 2.5rem;
  position: relative;
}

.karte::before {
  content: "";
  position: absolute;
  top: 0.75rem;
  left: 0;
  width: 3rem;
  height: 1px;
  background: var(--linie-stark);
  transform: rotate(-45deg);
  transform-origin: left center;
}

.karte__nummer {
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 500;
  letter-spacing: var(--sperrung-weit);
  text-transform: uppercase;
  color: var(--text-leise);
}

.karte__titel {
  font-family: var(--schrift-display);
  font-size: 0.9375rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  line-height: 1.7;
}

/* Ist der Titel zugleich der Link auf die Unterseite: ohne Unterstreichung im
   Ruhezustand, wie bei den Kacheln weiter unten. In gesperrten Versalien läuft
   die Linie sonst quer durch die Sperrung. */
.karte__link {
  text-decoration: none;
}

.karte__link:hover {
  text-decoration: underline;
  text-decoration-color: var(--linie-stark);
}

.karte__text,
.karte p:not(.karte__nummer) {
  color: var(--text-ruhig);
  font-size: 0.875rem;
}

/* ---------- Haltung ---------- */

.haltung__liste {
  list-style: none;
  margin: 0;
  padding: 0;
  counter-reset: haltung;
}

.haltung__liste li {
  padding-block: 2rem;
  border-top: 1px solid var(--linie);
}

.haltung__liste li:first-child {
  padding-top: 0;
  border-top: none;
}

.haltung__titel {
  display: grid;
  grid-template-columns: 3rem 1fr;
  gap: 0.5rem;
  align-items: baseline;
  font-family: var(--schrift-display);
  font-size: 0.9375rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  line-height: 1.7;
  margin-bottom: 0.875rem;
}

.haltung__titel b {
  font-weight: 200;
  font-size: 1.5rem;
  color: var(--text-leise);
  letter-spacing: 0;
}

.haltung__text {
  color: var(--text-ruhig);
  font-size: 0.875rem;
  padding-left: 3.5rem;
}

/* ---------- Preis ---------- */

.preis {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: clamp(1.75rem, 3vw, 2.5rem);
  border: 1px solid var(--linie-mittel);
  transition: border-color 0.3s ease;
}

.preis:hover {
  border-color: var(--linie-stark);
}

.preis__wert {
  font-family: var(--schrift-display);
  font-size: clamp(1.75rem, 3.5vw, 2.5rem);
  font-weight: 200;
  line-height: 1;
}

.preis__text {
  font-size: 0.875rem;
  color: var(--text-ruhig);
}

/* Der Pfeil-Link: gesperrte Versalien mit einem Strich dahinter, der beim
   Zeigen wächst. Wird auf den Ratgeberseiten genutzt. */
.pfeil-link {
  font-family: var(--schrift-display);
  font-size: 0.625rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  white-space: nowrap;
}

.pfeil-link::after {
  content: "";
  display: inline-block;
  width: 1.5rem;
  height: 1px;
  margin-left: 0.625rem;
  vertical-align: middle;
  background: currentColor;
  transition: width 0.3s ease;
}

a:hover .pfeil-link::after,
.pfeil-link:hover::after {
  width: 2.25rem;
}

/* ---------- Fragen ---------- */

/* Die Liste richtet sich nach ihrem Kopf: mittig nur dort, wo der Kopf mittig
   steht. Auf den Unterseiten ist er linksbündig, dort stand die Liste sonst
   quer darunter. Der Marker bleibt in beiden Fällen am Rand, er gehört zum
   Abschnitt und nicht zum Inhalt. */
.fragen {
  max-width: 52rem;
  border-top: 1px solid var(--linie);
}

.kopf--mitte + .fragen {
  margin-inline: auto;
}

/* Auf den Unterseiten steht die Fragenliste neben ihrem Kopf, nicht darunter.
   Darunter endete sie bei 52rem mitten in der Seite, während jeder andere
   Abschnitt bis an die rechte Kante läuft. */
.fragenblock .fragen {
  max-width: none;
}

@media (min-width: 68rem) {
  .fragenblock {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 2fr);
    column-gap: clamp(3rem, 6vw, 7rem);
    align-items: start;
  }

  .fragenblock .kopf {
    margin-bottom: 0;
  }
}

.fragen__mehr {
  max-width: 52rem;
  margin-inline: auto;
  margin-top: clamp(2rem, 4vw, 3rem);
  text-align: center;
  font-size: 0.875rem;
  color: var(--text-leise);
}

.fragen__mehr a {
  color: var(--text-ruhig);
  text-decoration-color: var(--linie-mittel);
}

.fragen__mehr a:hover {
  color: var(--text);
}

.frage {
  border-bottom: 1px solid var(--linie);
}

.frage summary {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1.5rem;
  padding-block: 1.5rem;
  cursor: pointer;
  list-style: none;
  font-family: var(--schrift-display);
  font-size: 0.9375rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-eng);
  line-height: 1.6;
}

.frage summary::-webkit-details-marker {
  display: none;
}

/* Plus, das beim Oeffnen zum Minus wird. Ein gedrehter Strich, damit kein
   Icon-Font noetig ist. */
.frage summary::after {
  content: "";
  flex: none;
  width: 0.875rem;
  height: 0.875rem;
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat,
    linear-gradient(currentColor, currentColor) center / 1px 100% no-repeat;
  transition: transform 0.3s ease;
}

.frage[open] summary::after {
  transform: rotate(90deg);
  background:
    linear-gradient(currentColor, currentColor) center / 100% 1px no-repeat;
}

.frage__antwort {
  padding-bottom: 1.75rem;
  max-width: 44rem;
}

.frage__antwort p {
  color: var(--text-ruhig);
  font-size: 0.875rem;
}

/* ---------- Kontakt ---------- */

.kontakt {
  position: relative;
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
}

.kontakt__titel {
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  margin-bottom: 1.5rem;
}

.kontakt__satz {
  color: var(--text-ruhig);
  max-width: 40rem;
}

/* Wie in der Vorlage: Aussage und Absatz links, direkt darunter das Formular
   über die volle Breite. Kein zweiter Block daneben, die Fläche rechts bleibt
   frei. Telefon und E-Mail stehen im Absatz, damit sie nicht verloren gehen. */
.kontakt__kopf {
  max-width: 44rem;
}

.kontakt__satz a {
  color: var(--text);
  text-decoration-color: var(--linie-stark);
}

@media (min-width: 48rem) {
  /* Der Marker greift in die Spalte, die der Behaelter freihaelt. Ueberschrift
     und Formular beginnen dadurch auf derselben Kante wie jeder andere
     Abschnitt. */
  .kontakt > .marker {
    left: calc(-1 * var(--markerspalte));
    top: 0.25rem;
  }
}

/* ---------- Formular ---------- */

.formular {
  display: grid;
  gap: 1.75rem;
}

@media (min-width: 44rem) {
  .formular {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .feld:has(textarea),
  /* Die Klasse sitzt am label im Feld, nicht am Feld selbst. Ohne :has bliebe
     die Einwilligung auf einer Spalte stehen. */
  .feld:has(.feld--wahl),
  .formular > .knopf,
  .formular__fussnote,
  .hinweis {
    grid-column: 1 / -1;
  }
}

/* Der Knopf steht links und füllt die Zeile nicht, wie in der Vorlage. */
.formular__senden {
  justify-self: start;
}

/* Der Rahmen liegt am Feld und nicht am Eingabekasten: in der Vorlage steht die
   Beschriftung mit im Rahmen. Die Fehlermeldung bleibt ebenfalls im Rahmen,
   direkt unter der Eingabe. */
.feld {
  position: relative;
  /* Nicht auf --linie-mittel: das sind 2:1 gegen den Grund, ein Feldrahmen
     braucht als einzige Begrenzung 3:1 (WCAG 1.4.11). */
  border: 1px solid var(--linie-stark);
  transition: border-color 0.2s ease;
}

.feld:hover {
  border-color: var(--text-ruhig);
}

.feld:focus-within {
  border-color: var(--text);
}

.feld:has([aria-invalid="true"]) {
  border-color: #e8836a;
}

/* Die Einwilligung ist eine Zeile mit Kästchen und Satz, kein Eingabefeld. Ein
   Rahmen darum wäre ein zweiter Kasten neben dem Kästchen. */
.feld:has(.feld--wahl) {
  position: static;
  border: 0;
}

/* Die Beschriftung liegt wie in der Vorlage im Kasten, bei leerem Feld auf der
   Eingabezeile. Sobald etwas drinsteht oder der Fokus da ist, rutscht sie nach
   oben und macht Platz. Sie verschwindet dabei nicht: ein Platzhalter anstelle
   einer Beschriftung ist keine Beschriftung. */
.feld > label:not(.feld--wahl) {
  position: absolute;
  left: 1rem;
  top: 1.625rem;
  transform: translateY(-50%);
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-weit);
  color: var(--text-leise);
  pointer-events: none;
  transition: top 0.25s ease;
}

/* Beim Nachrichtenfeld steht sie immer oben, der Kasten ist hoch genug. */
/* Die Beschriftung steht im Markup HINTER der Eingabe. Nur so lässt sie sich
   über den Geschwister-Selektor ansprechen. Der Weg über :has war fragil: der
   Browser rechnet den Stil bei einer Wertänderung im :has-Argument nicht
   zuverlässig neu. Am Kasten ändert die Reihenfolge nichts, die Beschriftung
   liegt absolut, und for/id verbindet sie unabhängig von der Position. */
.feld input:not(:placeholder-shown) ~ label:not(.feld--wahl),
.feld input:focus ~ label:not(.feld--wahl),
.feld textarea ~ label:not(.feld--wahl) {
  top: 0.8rem;
}

.feld input:not([type="checkbox"]),
.feld textarea,
.feld select {
  width: 100%;
  padding: 1.25rem 1rem 0.5rem;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 0.9375rem;
  line-height: 1.5;
}

/* Der Fokusring wandert vom Eingabefeld an den Rahmen des Feldes, sonst läge er
   innen an dessen Kante und wäre kaum zu sehen. Das Kästchen der Einwilligung
   behält seinen eigenen Ring, es steht in keinem Rahmen. */
.feld input:not([type="checkbox"]):focus-visible,
.feld textarea:focus-visible,
.feld select:focus-visible {
  outline: none;
}

.feld:has(input:not([type="checkbox"]):focus-visible),
.feld:has(textarea:focus-visible),
.feld:has(select:focus-visible) {
  outline: 2px solid var(--text);
  outline-offset: 3px;
}

.feld textarea {
  min-height: 11rem;
  padding-top: 2rem;
  resize: vertical;
}

.feld input::placeholder,
.feld textarea::placeholder {
  color: var(--text-leise);
  opacity: 1;
}

/* Der Fehler steht am Feld, nicht als Sammelmeldung oben. So findet ihn auch,
   wer mit der Tastatur durch das Formular geht. */
.feld__fehler {
  display: block;
  padding: 0 1rem 0.625rem;
  font-size: 0.8125rem;
  color: #f0a58f;
}

.feld__fehler:empty {
  padding: 0;
}

.feld:has(.feld--wahl) .feld__fehler {
  padding-inline: 0;
}

/* Die Klasse sitzt am label selbst, das Kaestchen und Text umschliesst. Ein
   eigener display-Wert ist deshalb noetig: .feld daneben ist ein anderer
   Baustein und vererbt hier nichts. */
.feld--wahl {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: 0.75rem;
  font-family: var(--schrift-sans);
  font-size: 0.8125rem;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-ruhig);
  line-height: 1.7;
  cursor: pointer;
}

.feld--wahl input {
  width: 1.125rem;
  height: 1.125rem;
  margin-top: 0.2rem;
  flex: none;
  accent-color: var(--text);
}

.feld--wahl a {
  color: var(--text);
}

/* Honigtopf gegen einfache Formular-Bots. Muss unsichtbar bleiben, darf aber
   nicht display:none sein, sonst fuellen ihn manche Bots gar nicht erst aus. */
.honigtopf {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.formular__fussnote {
  font-size: 0.8125rem;
  color: var(--text-leise);
  /* Ueber die volle Zeile gelesen sind das 1400 Pixel in einer Zeile. Dieselbe
     Spaltenbreite wie der Satz im Kontaktkopf. */
  max-width: 44rem;
}

.hinweis {
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--linie-mittel);
  font-size: 0.875rem;
  color: var(--text-ruhig);
}

.hinweis--info {
  border-left: 2px solid var(--text);
}

/* ---------- Platzhalter-Banner auf den Rechtstexten ---------- */

.platzhalter-banner {
  margin-bottom: 2.5rem;
  padding: 1.25rem 1.5rem;
  border: 1px dashed var(--linie-stark);
  font-size: 0.875rem;
  color: var(--text-ruhig);
}

.platzhalter-banner b {
  color: var(--text);
}

/* ---------- Haken-Liste ---------- */

.haken {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1rem;
}

.haken li {
  display: grid;
  grid-template-columns: 1.5rem 1fr;
  gap: 0.75rem;
  align-items: baseline;
  color: var(--text-ruhig);
  font-size: 0.875rem;
}

.haken li::before {
  content: "";
  width: 0.75rem;
  height: 1px;
  background: var(--linie-stark);
  align-self: center;
}

/* ---------- Fuß ---------- */

/* Der Fuß steht linksbündig auf derselben Kante wie die Wortmarke im Kopf.
   Rechtsbündig wie in der Vorlage stand er quer zum übrigen Satz, der von der
   ersten bis zur letzten Zeile links ausgerichtet ist. */
/* Keine Linie nach oben. Der Kontaktabschnitt darüber steht auf demselben Ton,
   beide bilden zusammen den Abschluss der Seite. */
/* Gleiches Polster oben und unten: der Abbinder steht in seiner Bahn mittig,
   nicht an deren Oberkante. */
.seitenfuss {
  padding-block: clamp(2.25rem, 3.5vw, 3rem);
  background: var(--grund-tief);
}

/* Wortmarke links, Rechtstexte rechts auf derselben Kante, auf der auch der
   Inhalt darueber endet. Bei zu wenig Platz bricht die Zeile um, und dann
   steht der kleine Satz wieder links unter der Wortmarke: rechtsbuendig ergibt
   er nur neben ihr einen Sinn. */
.seitenfuss__zeile {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem 1.75rem;
}

@media (min-width: 48rem) {
  .seitenfuss__zeile > .seitenfuss__klein {
    text-align: right;
  }
}

/* Kleiner als im Kopf. Im Fuß ist die Wortmarke Abbinder, nicht Navigation. */
.seitenfuss .marke__wort {
  font-size: clamp(1.125rem, 1.6vw, 1.5rem);
}

.seitenfuss__klein {
  font-family: var(--schrift-display);
  font-size: var(--schrift-klein);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--sperrung-mittel);
  color: var(--text-leise);
  line-height: 2;
}

.seitenfuss__klein a {
  color: var(--text-ruhig);
  text-decoration: none;
}

.seitenfuss__klein a:hover {
  color: var(--text);
  text-decoration: underline;
  text-underline-offset: 0.3em;
}

/* ---------- Fotos ---------- */

.foto {
  filter: grayscale(0.35) brightness(0.85) contrast(1.08);
  transition: filter 0.4s ease;
}

a:hover > picture .foto,
a:hover .foto {
  filter: grayscale(0.1) brightness(0.95) contrast(1.05);
}

/* ---------- Bewegung ---------- */

.einblenden {
  opacity: 0;
  transform: translateY(1.25rem);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

.einblenden.ist-sichtbar {
  opacity: 1;
  transform: none;
}

/* Ohne JavaScript darf nichts unsichtbar bleiben. */
html:not(.js) .einblenden {
  opacity: 1;
  transform: none;
}

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

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
    /* Muss mit. Die Dauer allein reicht nicht: gestaffelte Auftritte tragen
       ihre Staffelung in der Verzögerung, und mit fill-mode backwards steht
       dann sekundenlang der Anfangszustand im Bild. Zahl und Beschriftung im
       Zahlenkasten wären ohne diese Zeile knapp eine Sekunde unsichtbar. */
    animation-delay: 0.01ms !important;
  }
}

/* ---------- Tablet: 48rem bis 68rem ---------- */

/* Ein iPad quer ist 1024 Pixel breit und lag damit unter der alten Grenze von
   68rem: es bekam denselben gestapelten Satz wie ein Telefon, mit
   bildschirmbreiten Fotos untereinander. Die Anordnungen der Vorlage beginnen
   deshalb bei 48rem. Dieser Block zieht die Werte nach, die auf 768 Pixeln
   sonst zu knapp wuerden. */
@media (min-width: 48rem) and (max-width: 67.99rem) {
  :root {
    --markerspalte: 2.75rem;
  }

  /* Auf dem Desktop bekommt die Collage ihre Hoehe aus der Restflaeche der
     Ansicht. Ohne diese Rechnung haben die absolut liegenden Bilder keine
     Hoehe mehr, und der Kasten faellt auf sein min-height zusammen. Das
     Verhaeltnis tritt hier an die Stelle der Rechnung. */
  .ueber__collage {
    aspect-ratio: 16 / 10;
  }

  /* Die Textspalte des Desktops ist auf 40rem gedeckelt und stuende hier fast
     leer neben viel freier Flaeche. Sie nimmt stattdessen, was Kasten und
     Marker uebrig lassen. */
  .wir__kopf {
    grid-template-columns: minmax(9rem, 26%) auto minmax(0, 1fr);
    column-gap: 2rem;
  }

  /* Vier Spalten sind hier zu schmal, und auto-fit setzt drei nebeneinander
     und die vierte allein darunter. Zwei mal zwei bleibt aufgeraeumt. */
  .wir__dienste .raster {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  /* Mit den Werten der Vorlage blieben dem Absatz auf 768 Pixeln 164 Pixel
     Spalte. Beide Reihen ruecken deshalb weniger ein, und der Text bekommt
     mehr Breite als das Bild. Die zweite Reihe steht weiter rechts als die
     erste, das bleibt. Der Versatz ist hier 9 Prozent statt 17: auf 1024
     Pixeln fraesse der Desktop-Wert die halbe Textspalte der zweiten Reihe. */
  .projekt {
    grid-template-columns: 0 39.1% 3.9% 48%;
  }

  .projekt--versetzt {
    grid-template-columns: 9% 39.1% 3.9% 48%;
  }

  /* Die Spalte zwischen Bild und Text ist hier schmaler als auf dem Desktop,
     der Strich rueckt entsprechend nach. */
  .projekt__strich {
    left: -1.25rem;
  }
}

/* ---------- Schmale Geräte ---------- */

@media (max-width: 47.99rem) {
  .marker {
    display: none;
  }

  /* Auf dem Telefon nimmt der Kasten die Breite seines Inhalts, nicht die 38
     Prozent der Vorlage: 38 Prozent von 390 Pixeln sind 148 und zu wenig fuer
     die Zahl. Ab dem Tablet gilt wieder der Wert der Vorlage. */
  .hero__kasten {
    width: auto;
    min-height: 0;
    padding-top: clamp(2rem, 9vw, 3.5rem);
  }

  /* Auf dem Telefon sitzt die Telefonnummer unter dem Kasten statt in der
     Ecke. In der Ecke ueberlagert sie sonst das Bildmotiv und wird unlesbar.
     Auf dem Tablet ist das Bild breit genug fuer die Ecke der Vorlage. */
  .hero__inhalt {
    justify-content: flex-end;
    padding-bottom: 2rem;
  }

  .hero__kontakt {
    position: static;
    text-align: left;
    margin-top: 1.5rem;
  }
}

/* 1200px, nicht 768: sechs Punkte in 13 Pixeln plus die Wortmarke brauchen rund
   1160 Pixel. Darunter lief die Leiste ueber, waehrend der Menueknopf noch
   verborgen war. Derselbe Wert steht oben als --menue-grenze und wird von dort
   auch von haupt.js gelesen. */
@media (max-width: 1200px) {
  .navi__liste {
    display: none;
  }

  .menueknopf {
    display: block;
  }

  /* Der Menueknopf macht die Leiste hoeher als auf dem Desktop: 1,5rem Polster
     oben und unten plus 2,75rem Knopf sind 5,75rem. Mit der Desktop-Hoehe lag
     die Bildkante 20 Pixel unter der Leiste und der Knopf klebte darauf. Der
     Wert steht am :root, damit auch die uebrigen Abschnitte ihn sehen. */
  :root {
    --kopfhoehe: 6.75rem;
  }

  /* Weichzeichnen ueber laufendem Video kostet auf Geraeten ohne Netzstrom
     spuerbar Rechenzeit. Weniger Radius, dafuer eine dichtere Flaeche
     dahinter. Reine Leistungsfrage, an der Anordnung aendert sie nichts. */
  .hero__kasten {
    backdrop-filter: blur(4px) saturate(0.9);
    background: rgb(10 12 16 / 0.24);
  }

  .hero__kasten:hover {
    backdrop-filter: blur(4px) saturate(0.9);
    background: rgb(10 12 16 / 0.24);
  }

  /* Im Hochformat schneidet object-fit den mittleren Streifen heraus, und das
     ist beim Hero-Video der Himmel. Der Ausschnitt rutscht deshalb nach unten
     zu den Fassaden. */
  .hero__bild {
    object-position: center 72%;
  }

  .unterseite-hero {
    padding-top: 8.5rem;
  }

  .haltung__text {
    padding-left: 0;
  }

}

@media (max-width: 30rem) {
  .haltung__titel {
    grid-template-columns: 2.25rem 1fr;
  }
}
