/* ==========================================================================
   Webmanufaktur Donau
   Gesamtes Design der Website. Kein Framework, kein Build-Werkzeug.

   STAND: 12.09.2026
   Diese Zeile ist zum Nachsehen da. Rufen Sie nach dem Hochladen
   ihre-domain.de/assets/css/site.css auf: steht dort ein aelteres Datum,
   ist die Datei nicht angekommen -- dann liegt es am Hochladen, nicht am
   Zwischenspeicher.

   Aufbau
     1  Farben, Schriftgroessen, Abstaende
     2  Grundlagen und Typografie
     3  Raster und Sektionen
     4  Knoepfe
     5  Kopfzeile und Menue
     6  Startbereich
     7  Laufband
     8  Geraeterahmen
     9  Das Angebot
    10  Leistungen
    11  Warum
    12  Ablauf
    13  Preise
    14  Fragen
    15  Kontakt und Formular
    16  Fusszeile
    17  Aktionsleiste fuers Handy
    18  Bewegung
   ========================================================================== */

/* ---- 1  Farben, Schriftgroessen, Abstaende ------------------------------- */

:root {
  color-scheme: dark;

  /* Grundflaechen. Die Seite ist bewusst durchgehend dunkel: die Marke lebt
     auf dem Marineblau des Logos. Es gibt keinen hellen Abschnitt. */
  --grund:        #0B1822;
  --grund-tief:   #071119;
  --flaeche:      #12222E;
  --flaeche-hoch: #172B39;

  --linie:        rgb(242 247 250 / .10);
  --linie-stark:  rgb(242 247 250 / .20);

  --text:         #F2F7FA;
  --text-mittel:  #AEC2D0;
  --text-leise:   #7F97A8;

  /* Die Markenfarbe steht zweimal da, und das ist Absicht.
     "marke" ist fuer Flaechen gedacht, "marke-text" fuer Schrift und Symbole
     auf dunklem Grund. Ein einziger Wert reicht nicht: das Flaechenblau
     erreicht als Text den noetigen Kontrast nicht, das Textblau wirkt als
     grosse Flaeche billig. */
  --marke:        #1C6FA8;
  --marke-tief:   #12496F;
  --marke-text:   #6FBCEE;
  --marke-schein: rgb(79 166 220 / .32);

  --welle: linear-gradient(105deg, #FFFFFF 0%, #DCEDFA 34%, #4FA6DC 68%, #12496F 100%);
  /* Fuer Schrift eigener Verlauf: der Flaechenverlauf endet in dunklem Blau und
     erreicht als Text auf dem dunklen Grund nur Kontrast 2. Dieser hier bleibt
     ueber die ganze Laenge hell, dunkelster Punkt 9,1 zu 1. */
  --welle-schrift: linear-gradient(100deg, #FFFFFF 0%, #DCEDFA 45%, #6FBCEE 100%);

  /* Ein Radius-System, ueberall gleich angewendet:
     Aussenschale 26, Innenkern 20, Eingabefelder 12, alles Bedienbare rund. */
  --r-schale: 1.625rem;
  --r-kern:   1.25rem;
  --r-feld:   .75rem;

  /* Eine einzige Abstandsskala. Jeder senkrechte Abstand auf der Seite kommt
     aus dieser Leiter, nichts wird frei Hand gesetzt. Vorher standen hier vier
     verschiedene Rhythmen nebeneinander: 140,8 Polster je Sektion (also 281,6
     zwischen zweien), 120/64 im Startbereich, 56 im Laufband, 76,8 unter den
     Sektionsueberschriften. Das war der Grund, warum die Seite unruhig wirkte. */
  --raum-1: .25rem;    /*   4 */
  --raum-2: .5rem;     /*   8 */
  --raum-3: .75rem;    /*  12 */
  --raum-4: 1rem;      /*  16 */
  --raum-5: 1.5rem;    /*  24 */
  --raum-6: 2rem;      /*  32 */
  --raum-7: 2.5rem;    /*  40 */
  --raum-8: 3.5rem;    /*  56 */
  --raum-9: 5rem;      /*  80 */

  --wrap: 1280px;
  --rand: clamp(1.25rem, 5vw, 3rem);
  --kopfhoehe: 4.5rem;

  /* Polster je Sektion. Zwei benachbarte Sektionen ergeben damit immer
     denselben Abstand, egal welche. */
  --sektion: clamp(4.25rem, 7.5vw, 7rem);

  --kurve: cubic-bezier(.16, 1, .3, 1);
  --kurve-weich: cubic-bezier(.32, .72, 0, 1);

  /* Dauern nach Bauteilart. Alles, was auf eine Eingabe antwortet, bleibt
     unter 300 ms: darueber wirkt eine Oberflaeche traege, egal wie schoen
     die Kurve ist. Laenger darf nur, was erklaert statt zu antworten. */
  --zeit-druck:  160ms;   /* Knopfdruck */
  --zeit-zeig:   200ms;   /* Farbe und Rand beim Zeigen */
  --zeit-klapp:  220ms;   /* Auf- und Zuklappen */
  --zeit-blende: 250ms;   /* Kopfzeile, Flaechenwechsel */
  --zeit-schub:  350ms;   /* Leisten, die hereinfahren */
  --zeit-hueben: 450ms;   /* Vollbildmenue */
  --zeit-auf:    600ms;   /* Auftritt beim Scrollen */
  --zeit-erklaer: 1100ms; /* erklaerende Bewegung, antwortet auf nichts */

  --schrift-display: 'Archivo', 'Segoe UI', system-ui, sans-serif;
  --schrift-text:    'Manrope', 'Segoe UI', system-ui, sans-serif;
  --schrift-mono:    'IBM Plex Mono', ui-monospace, SFMono-Regular, monospace;
}

/* ---- 2  Grundlagen und Typografie ---------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Muss groesser sein als die Kopfzeile (4,5rem), sonst verschwindet das
     Sprungziel beim Klick auf einen Ankerlink dahinter. */
  scroll-padding-top: calc(var(--kopfhoehe) + var(--raum-6));
}

/* Ohne diese beiden Zeilen wartet der Browser auf Beruehrungsgeraeten rund
   300 ms auf einen moeglichen Doppeltipp, bevor er den Tipp weitergibt. Die
   Seite fuehlt sich dadurch traege an. Die Antipp-Hervorhebung setzen wir
   selbst, statt sie dem Geraet zu ueberlassen. */
a, button, summary, label, input, select, textarea {
  touch-action: manipulation;
  -webkit-tap-highlight-color: rgb(111 188 238 / .18);
}

body {
  margin: 0;
  background: var(--grund);
  color: var(--text);
  font-family: var(--schrift-text);
  font-size: 1.0625rem;
  line-height: 1.65;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;

  /* clip, nicht hidden. Beides schneidet waagerecht ab, aber hidden wuerde den
     body zu einem Scroll-Container machen, und darauf bezoege sich dann jedes
     position:sticky im Dokument statt auf das Fenster. clip erzeugt keinen
     Scroll-Container und ist deshalb hier die sichere Wahl.
     Ueberlaufen tut ohnehin nur das Laufband, und das schneidet sich selbst
     ab. Diese Zeile ist also nur ein Sicherheitsnetz. */
  overflow-x: clip;
}

body.menue-offen { overflow: hidden; }

/* Groesse und Luft tragen die Ueberschrift, nicht das Schriftgewicht. Apple
   setzt seine 64-Pixel-Zeilen in Halbfett, nicht in Schwarz, und kommt mit
   knapp einem Prozent negativer Laufweite aus. Vorher stand hier Gewicht 900
   bei 3,5 Prozent, was gedrungen und laut wirkte. */
h1, h2, h3, h4 {
  font-family: var(--schrift-display);
  font-weight: 700;
  letter-spacing: -.026em;
  line-height: 1.02;
  margin: 0;
  text-wrap: balance;
}

h1 { font-size: clamp(2.5rem, 5.4vw, 4.5rem); letter-spacing: -.03em; line-height: 1; }
h2 { font-size: clamp(2rem, 4.4vw, 3.375rem); }
h3 { font-size: clamp(1.1875rem, 1.9vw, 1.4375rem); letter-spacing: -.018em; line-height: 1.28; }
h4 { font-size: 1.0625rem; letter-spacing: -.012em; line-height: 1.3; }

/* Ein Absatz direkt hinter einer Ueberschrift bekommt seinen Abstand von
   selbst. Das ersetzt neun verschiedene margin-top-Werte im Markup. */
h1 + p, h2 + p, h3 + p,
h1 + .leitung, h2 + .leitung,
h1 + .fliess, h2 + .fliess { margin-top: var(--raum-5); }

p { margin: 0; }

a { color: inherit; }

.leitung {
  color: var(--text-mittel);
  font-size: clamp(1.125rem, 1.6vw, 1.375rem);
  line-height: 1.5;
  letter-spacing: -.012em;
  max-width: 36rem;
}

.fliess {
  color: var(--text-mittel);
  font-size: clamp(1.0625rem, 1.2vw, 1.125rem);
  line-height: 1.65;
  max-width: 60ch;
}

/* Kleinlabel. Bewusst sparsam eingesetzt, nicht ueber jeder Sektion. */
.label {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--marke-text);
  display: block;
  margin-bottom: 1.25rem;
}

.zahl {
  font-family: var(--schrift-mono);
  font-size: .8125rem;
  letter-spacing: .08em;
  color: var(--text-leise);
}

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

::selection { background: var(--marke); color: #fff; }

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

.springen {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--text);
  color: var(--grund);
  padding: .85rem 1.35rem;
  border-radius: 0 0 var(--r-feld) 0;
  font-weight: 700;
  z-index: 200;
}
.springen:focus { left: 0; }

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

/* ---- 3  Raster und Sektionen --------------------------------------------- */

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

section { padding-block: var(--sektion); position: relative; }

.kopfzeile-block { max-width: 46rem; margin-bottom: var(--raum-9); }

/* Sektionen werden ueber die Flaeche getrennt, nicht ueber Linien. Vorher lief
   beides nebeneinander: an manchen Kanten eine Haarlinie, an anderen ein
   Farbwechsel. Zwei Mechanismen fuer dieselbe Aufgabe sehen aus wie ein
   Versehen. Geblieben ist der Farbwechsel. */
.flaeche-tief { background: var(--grund-tief); }

/* Hilfsklassen fuer die immer gleichen Abstaende. Sie ersetzen die frei Hand
   gesetzten style-Angaben im Markup. */
.abstand-s  { margin-top: var(--raum-5); }
.abstand-m  { margin-top: var(--raum-6); }
.abstand-l  { margin-top: var(--raum-8); }
.schmal     { max-width: 46rem; }
.schmaler   { max-width: 40rem; }
.voll       { width: 100%; }

/* Oberer Rand der Unterseiten: Kopfzeilenhoehe plus ein volles Sektionspolster. */
.seitenkopf { padding-top: calc(var(--kopfhoehe) + var(--sektion)); }

/* Reihe aus Knoepfen, ueberall mit demselben Abstand nach oben. */
.knopfreihe {
  display: flex;
  flex-wrap: wrap;
  gap: var(--raum-3);
  margin-top: var(--raum-7);
}

/* Doppelrand: Aussenschale mit eigenem Grund, Innenkern mit eigenem Licht.
   Karten liegen dadurch nicht flach auf der Seite, sondern sitzen in einer
   Fassung, so wie eine Glasplatte in einem Rahmen. */
.schale {
  background: rgb(242 247 250 / .035);
  border: 1px solid var(--linie);
  border-radius: var(--r-schale);
  padding: .4375rem;
}

.kern {
  background: var(--flaeche);
  border-radius: var(--r-kern);
  box-shadow: inset 0 1px 0 rgb(242 247 250 / .07);
  height: 100%;
}

/* ---- 4  Knoepfe ----------------------------------------------------------- */

.knopf {
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  padding: .6875rem .6875rem .6875rem 1.375rem;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--schrift-text);
  font-size: .96875rem;
  font-weight: 700;
  letter-spacing: -.01em;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: transform var(--zeit-druck) var(--kurve),
              background-color var(--zeit-zeig) ease,
              border-color var(--zeit-zeig) ease,
              color var(--zeit-zeig) ease;
}

/* Der Pfeil sitzt nie nackt neben der Schrift, sondern in einem eigenen
   runden Feld, buendig am inneren Rand. */
.knopf__icon {
  width: 2rem; height: 2rem;
  flex: 0 0 2rem;
  border-radius: 999px;
  display: grid;
  place-items: center;
  transition: transform var(--zeit-zeig) var(--kurve),
              background-color var(--zeit-zeig) ease;
}
.knopf__icon svg { width: 1.0625rem; height: 1.0625rem; }

/* Zeigezustaende gehoeren hinter diese Abfrage. Ein Fingertipp loest sonst
   einen Zeigezustand aus, der haengen bleibt, bis woanders hingetippt wird. */
@media (hover: hover) and (pointer: fine) {
  .knopf:hover .knopf__icon { transform: translate(3px, -1px); }
}
.knopf:active { transform: scale(.975); }

.knopf--haupt {
  background: var(--text);
  color: var(--grund);
}
.knopf--haupt .knopf__icon { background: rgb(11 24 34 / .10); }
@media (hover: hover) and (pointer: fine) {
  .knopf--haupt:hover { background: #fff; }
  .knopf--haupt:hover .knopf__icon { background: rgb(11 24 34 / .16); }
}

.knopf--leise {
  background: transparent;
  color: var(--text);
  border-color: var(--linie-stark);
}
.knopf--leise .knopf__icon { background: rgb(242 247 250 / .08); }
@media (hover: hover) and (pointer: fine) {
  .knopf--leise:hover { border-color: var(--text-leise); background: rgb(242 247 250 / .04); }
}

.knopf--voll { width: 100%; justify-content: space-between; }

/* Textlink mit Unterstrich, der beim Zeigen von links durchlaeuft. */
.textlink {
  display: inline-flex;
  align-items: center;
  gap: .5rem;
  font-weight: 700;
  text-decoration: none;
  color: var(--marke-text);
  position: relative;
  padding-bottom: 2px;
}

/* Der Unterstrich laeuft ueber scaleX statt ueber background-size. Letzteres
   zwingt den Browser bei jedem Bild zum Neuzeichnen; eine Transformation
   erledigt die Grafikkarte allein. Die Lage haengt an der Textmitte, nicht am
   Kasten, weil der auf dem Handy 44 Pixel hoch ist. */
.textlink::after {
  content: "";
  position: absolute;
  left: 0;
  width: 100%;
  top: 50%;
  margin-top: .62em;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 240ms var(--kurve);
}
@media (hover: hover) and (pointer: fine) {
  .textlink:hover::after { transform: scaleX(1); }
}
.textlink svg { width: 1rem; height: 1rem; }

/* ---- 5  Kopfzeile und Menue ----------------------------------------------- */

.kopf {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 100;
  /* backdrop-filter steht bewusst nicht in dieser Liste: einen Weichzeichner
     ueber eine halbe Sekunde zu interpolieren kostet viel und ruckelt. Er
     schaltet hart, der Farbwechsel traegt den Uebergang. */
  transition: background-color var(--zeit-blende) ease,
              border-color var(--zeit-blende) ease;
  border-bottom: 1px solid transparent;
}
.kopf.gescrollt {
  background: rgb(11 24 34 / .78);
  backdrop-filter: blur(18px) saturate(150%);
  -webkit-backdrop-filter: blur(18px) saturate(150%);
  border-bottom-color: var(--linie);
}

.kopf__innen {
  height: var(--kopfhoehe);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
}

.marke {
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  text-decoration: none;
  color: var(--text);
  flex: 0 0 auto;
}
.marke__zeichen { width: 2.25rem; height: 1.85rem; color: var(--text); }
.marke__wort {
  font-family: var(--schrift-display);
  font-weight: 800;
  letter-spacing: -.03em;
  font-size: 1.0625rem;
  line-height: 1.05;
}
.marke__wort span { display: block; font-weight: 500; color: var(--text-leise); font-size: .8125rem; letter-spacing: -.01em; }

/* Reihenfolge beachten: erst alle Grundzustaende, dann ganz am Ende dieses
   Abschnitts die Abfrage fuer breite Fenster. Stuende eine Grundregel dahinter,
   wuerde sie die Abfrage bei gleicher Spezifitaet ueberschreiben. Genau so ist
   hier zwischenzeitlich der Knopf in der Kopfzeile verschwunden. */
.nav { display: none; }
.kopf__aktion { display: none; }

/* Hamburger, der sich beim Oeffnen zum Kreuz dreht. */
.menue-knopf {
  width: 2.75rem; height: 2.75rem;
  display: grid;
  place-items: center;
  background: transparent;
  border: 1px solid var(--linie-stark);
  border-radius: 999px;
  cursor: pointer;
  margin-left: auto;
  padding: 0;
}
.menue-knopf span {
  display: block;
  width: 1.125rem; height: 1.5px;
  background: var(--text);
  border-radius: 2px;
  transition: transform .55s var(--kurve), opacity .3s var(--kurve);
}
.menue-knopf span + span { margin-top: 5px; }
.menue-knopf[aria-expanded="true"] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.menue-knopf[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menue-knopf[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (min-width: 62rem) {
  .nav {
    display: flex;
    align-items: center;
    gap: 2rem;
    margin-left: auto;
  }
  .nav a {
    text-decoration: none;
    font-size: .9375rem;
    font-weight: 500;
    color: var(--text-mittel);
    transition: color var(--zeit-zeig) ease;
  }
  @media (hover: hover) and (pointer: fine) { .nav a:hover { color: var(--text); } }
  .kopf__aktion { display: inline-flex; }
  .menue-knopf { display: none; }
}

/* Das hidden-Attribut muss ausdruecklich gewinnen. Ohne diese Zeile schlaegt
   das display:flex darunter die Regel des Browsers, das Menue bliebe im DOM
   bedienbar und Tastaturnutzer landeten in einem unsichtbaren Overlay.
   Deshalb steuert hier display den Zustand und nicht visibility: auf einem
   Element mit visibility:hidden greift focus() naemlich nicht. */
.menue[hidden] { display: none; }

.menue {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: rgb(7 17 25 / .94);
  backdrop-filter: blur(28px);
  -webkit-backdrop-filter: blur(28px);
  padding: calc(var(--kopfhoehe) + var(--raum-7)) var(--rand) var(--raum-8);
  display: flex;
  flex-direction: column;
  gap: var(--raum-7);
  opacity: 0;
  transition: opacity var(--zeit-hueben) var(--kurve);

  /* Ohne diese beiden Zeilen scrollt bei offenem Menue die Seite dahinter
     weiter, sobald man am Ende der Liste angekommen ist. */
  overflow-y: auto;
  overscroll-behavior: contain;
}
.menue.offen { opacity: 1; }

.menue nav { display: flex; flex-direction: column; gap: .25rem; }
.menue nav a {
  font-family: var(--schrift-display);
  font-size: clamp(1.75rem, 8vw, 2.5rem);
  font-weight: 800;
  letter-spacing: -.035em;
  text-decoration: none;
  padding: .35rem 0;
  border-bottom: 1px solid var(--linie);
  /* Auftritt aus einer unsichtbaren Kiste, gestaffelt. */
  opacity: 0;
  transform: translateY(1.5rem);
  transition: opacity var(--zeit-hueben) var(--kurve),
              transform var(--zeit-hueben) var(--kurve);
}
/* Die Staffel gilt nur beim Oeffnen. Beim Schliessen wuerde sie das Menue
   nachhaengen lassen, obwohl der Nutzer es gerade wegwischen will:
   bewusste Geste langsam, Systemantwort schnappt. */
.menue.offen nav a {
  opacity: 1;
  transform: none;
  transition-delay: calc(var(--i) * 60ms);
}

.menue__fuss { margin-top: auto; display: grid; gap: 1rem; }
.menue__fuss a[href^="tel"] {
  font-family: var(--schrift-display);
  font-size: 1.375rem;
  font-weight: 800;
  letter-spacing: -.03em;
  text-decoration: none;
}

/* ---- 6  Startbereich ------------------------------------------------------ */

.start {
  min-height: 100dvh;
  display: flex;
  align-items: center;
  padding-top: calc(var(--kopfhoehe) + var(--raum-8));
  padding-bottom: var(--sektion);
  position: relative;
  overflow: hidden;
}

/* Ruhiger Lichtschein hinter dem Text, aus der Markenfarbe. Kein Neon. */
.start::before {
  content: "";
  position: absolute;
  top: -22vw; left: -14vw;
  width: 68vw; height: 68vw;
  background: radial-gradient(circle, rgb(28 111 168 / .30) 0%, transparent 62%);
  pointer-events: none;
  z-index: 0;
}

.start__raster {
  position: relative;
  z-index: 1;
  display: grid;
  gap: clamp(3rem, 7vw, 5rem);
  width: 100%;
}

@media (min-width: 60rem) {
  .start__raster {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, .75fr);
    align-items: center;
  }
}

.start h1 span { display: block; }
.start h1 .zeile-2 {
  font-weight: 500;
  font-size: .72em;
  color: var(--text-mittel);
  margin-top: .12em;
}

.start .leitung { margin-top: var(--raum-6); }



/* ---- 7  Laufband ---------------------------------------------------------- */

/* Zeigt das Einzugsgebiet. Fuer einen regionalen Betrieb ist das keine
   Dekoration, sondern die Antwort auf "kommen Sie auch zu mir". */
.laufband {
  position: relative;
  padding-block: var(--raum-8);
  border-block: 1px solid var(--linie);
  /* Die Dauer gehoert zur Laenge der Spur. Bei 18 Orten ist sie rund 9000
     Pixel breit; mit den urspruenglichen 46 Sekunden liefe das Band fast
     doppelt so schnell wie gedacht und wirkte hektisch. */
  --dauer: 76s;
}
.laufband__inhalt { overflow: hidden; }

.laufband__spur {
  display: flex;
  width: max-content;
  animation: laufband var(--dauer) linear infinite;
}
.laufband__satz {
  display: flex;
  align-items: center;
  gap: 2.25rem;
  padding-right: 2.25rem;
}
.laufband__wort {
  font-family: var(--schrift-display);
  font-size: clamp(1.125rem, 2.4vw, 1.75rem);
  font-weight: 700;
  letter-spacing: -.02em;
  color: var(--text-mittel);
  white-space: nowrap;
}
.laufband__welle {
  width: 2.25rem;
  height: 1.125rem;
  flex: 0 0 auto;
  color: var(--marke-text);
  opacity: .75;
}

@keyframes laufband { to { transform: translateX(-50%); } }

/* Ohne die Abfrage friert das Band auf dem Handy nach einer Beruehrung
   dauerhaft ein, weil der Zeigezustand dort haengen bleibt. */
@media (hover: hover) and (pointer: fine) {
  .laufband:hover .laufband__spur { animation-play-state: paused; }
}

/* ---- 8  Geraeterahmen ------------------------------------------------------ */

/* In den Rahmen steckt die echte Beispielseite als eigenes Dokument, kein
   nachgebautes Fenster aus leeren Kaesten. Sie wird in Originalbreite geladen
   und heruntergerechnet, damit sie auf jedem Bildschirm gestochen scharf
   bleibt und beim Scrollen wirklich laeuft.

   Die Breite und der Verkleinerungsfaktor gehoeren zusammen: der Faktor ist
   immer Rahmenbreite geteilt durch Ladebreite. Dadurch ist die sichtbare
   Hoehe des Dokuments auf jedem Bildschirm gleich, und der Scrollweg in den
   Keyframes muss nur einmal gesetzt werden. */

/* Telefon. Ladebreite 390, sichtbar 758 Zeilenpixel. */
.geraet {
  --b: 250px; --s: .641;
  position: relative;
  width: max-content;
  margin-inline: auto;
  border-radius: 2.25rem;
  padding: .5rem;
  background: linear-gradient(160deg, #2A3E4E, #101E29 45%, #253848);
  box-shadow: 0 2.5rem 5rem -1.5rem rgb(0 0 0 / .75),
              0 0 0 1px rgb(242 247 250 / .09);
}
@media (min-width: 30rem) { .geraet { --b: 290px; --s: .7436; } }
@media (min-width: 60rem) { .geraet { --b: 320px; --s: .8205; } }

.geraet__schirm {
  position: relative;
  width: var(--b);
  aspect-ratio: 9 / 17.5;
  border-radius: 1.85rem;
  overflow: hidden;
  background: #F6F5F2;
}

.geraet__steg {
  position: absolute;
  top: .5rem; left: 50%;
  transform: translateX(-50%);
  width: 4.5rem; height: .3125rem;
  border-radius: 999px;
  background: rgb(11 24 34 / .22);
  z-index: 2;
}

.geraet__lauf {
  width: 390px;
  height: 1560px;
  transform-origin: top left;
  scale: var(--s);
}

/* ---- Der Laptop -----------------------------------------------------------

   Drei Flaechen, die im Raum stehen: der Deckel mit dem Bildschirm, seine
   Rueckseite und die Bodenplatte. Das Scharnier ist die Unterkante des
   Deckels. Dort sitzt sein Drehpunkt, und genau dort beginnt die Bodenplatte
   im Textfluss -- deshalb sitzt die Naht immer passgenau, ohne gerechnete
   Hoehen.

   Beim Hereinscrollen klappt der Deckel von -90 Grad auf null. Null ist dabei
   kein gerundeter Wert, sondern der Punkt: im Bildschirm laeuft ein echtes
   Dokument, und jede Restdrehung wuerde die Schrift darin unscharf machen. Die
   Tiefe traegt danach allein die Bodenplatte, die liegt und bleibt liegen.

   Breite und Verkleinerungsfaktor gehoeren zusammen: der Faktor ist immer
   Rahmenbreite geteilt durch Ladebreite. Dadurch bleibt die sichtbare
   Dokumenthoehe auf jedem Bildschirm gleich (688 Zeilenpixel), und der
   Scrollweg in den Keyframes muss nur einmal gesetzt werden. */

/* Feste Stufen als Rueckfall. Sie sind so gewaehlt, dass der Laptop samt
   perspektivischem Ueberstand der Bodenplatte in seine Spalte passt -- die
   Spalte ist zwischen 960 und 1200 Pixeln Fensterbreite deutlich schmaler als
   das Fenster selbst.

   Bemessen ist die Breite nicht nach dem offenen Laptop, sondern nach dem
   halb aufgeklappten: der Deckel liegt dann schraeg nach vorn und kommt der
   Kamera naeher, dadurch waechst er in der Anzeige um gut ein Siebtel. Nach
   dem Ruhezustand bemessen wuerde er waehrend des Aufklappens in die
   Nachbarspalte greifen. */
.laptop { --b: 280px; --s: .2545; }
@media (min-width: 26rem) { .laptop { --b: 320px; --s: .2909; } }
@media (min-width: 34rem) { .laptop { --b: 410px; --s: .3727; } }
@media (min-width: 48rem) { .laptop { --b: 480px; --s: .4364; } }
@media (min-width: 60rem) { .laptop { --b: 300px; --s: .2727; } }
@media (min-width: 80rem) { .laptop { --b: 420px; --s: .3818; } }

/* Moderne Browser rechnen die Breite aus der Spalte, in der das Geraet
   tatsaechlich steht, statt aus der Fensterbreite. Die Stufen darueber
   greifen dann nicht mehr. Geprueft wird auf die Division zweier Laengen,
   denn genau daran haengt der Verkleinerungsfaktor. */
@supports (scale: calc(100px / 10px)) {
  .laptop {
    --b: min(82cqw, 480px);
    --s: calc(var(--b) / 1100px);
  }
}

.laptop {
  --rand: 8px;     /* Blende oben und seitlich */
  --kinn: 15px;    /* Blende unten, sie verdeckt das Scharnier */
  --winkel: 81deg; /* Neigung der Bodenplatte */
  position: relative;
  width: calc(var(--b) + var(--rand) * 2);
  /* Die Bodenplatte nimmt sich unten ihre volle Hoehe wieder heraus (siehe
     dort), liegend braucht sie nur rund ein Viertel davon. Diesen Rest gibt
     der Innenabstand zurueck. Getrennt gerechnet, weil sonst der
     Randzusammenfall das Ergebnis bestimmt und nicht die Geometrie. */
  padding-bottom: calc(var(--b) * .18);
  margin-inline: auto;
  transform-style: preserve-3d;
}

.laptop__deckel {
  position: relative;
  transform-style: preserve-3d;
  transform-origin: bottom center;
}

/* Dunkle Blende, helles Gehaeuse -- dieser Kontrast ist das, woran man einen
   Rechner von Apple auf einem Foto sofort erkennt. */
.laptop__schirm {
  position: relative;
  padding: var(--rand) var(--rand) var(--kinn);
  border-radius: .875rem .875rem .3125rem .3125rem;
  background: linear-gradient(165deg, #1D2A35, #0C151C 45%, #16222C);
  backface-visibility: hidden;
}
/* Kamera im oberen Rand. */
.laptop__schirm::before {
  content: "";
  position: absolute;
  top: calc(var(--rand) / 2 - 1.5px); left: 50%;
  width: 3px; height: 3px;
  margin-left: -1.5px;
  border-radius: 50%;
  background: rgb(242 247 250 / .22);
}
/* Scharnierschatten am Fuss des Deckels. */
.laptop__schirm::after {
  content: "";
  position: absolute;
  left: 12%; right: 12%; bottom: 0;
  height: 3px;
  border-radius: 3px 3px 0 0;
  background: linear-gradient(180deg, rgb(7 17 25 / .55), rgb(7 17 25 / .85));
}

.laptop__sicht {
  position: relative;
  width: var(--b);
  aspect-ratio: 16 / 10;
  overflow: hidden;
  border-radius: .1875rem;
  background: #F6F5F2;
  box-shadow: inset 0 0 0 1px rgb(7 17 25 / .45);
}
/* Der Rahmen muss hoeher sein als Laufweg plus Ausschnitt (1200 + 688), sonst
   endet der Lauf unterhalb dessen, was der eingebettete Rahmen ueberhaupt
   noch zeichnet, und die Anzeige laeuft leer.

   Der Laufweg selbst endet bei 1200, weil dort auf der Beispielseite ein
   Abschnitt zu Ende geht. Das letzte Bild, das stehen bleibt, ist damit ein
   vollstaendiges -- und nicht ein angeschnittenes. */
.laptop .geraet__lauf { width: 1100px; height: 2000px; }

/* Die Rueckseite des Deckels. Sie ist die einzige Flaeche, die man waehrend
   des Aufklappens sieht -- ohne sie verschwindet der Deckel, solange er von
   der Kamera weg zeigt. */
.laptop__ruecken {
  position: absolute;
  inset: 0;
  border-radius: .875rem .875rem .375rem .375rem;
  background: linear-gradient(195deg, #2E4152, #16252F 55%, #203140);
  box-shadow: inset 0 0 0 1px rgb(242 247 250 / .07);
  backface-visibility: hidden;
  transform: rotateY(180deg) translateZ(1px);
}

/* Die Bodenplatte liegt. Sie dreht sich um ihre Oberkante -- also um dieselbe
   Linie, an der der Deckel haengt -- und kippt nach vorn zum Betrachter.
   Im Textfluss belegt sie trotzdem ihre volle, aufrechte Hoehe -- sichtbar
   ist davon nach der Drehung nur rund ein Sechstel. Der negative Aussenabstand
   nimmt die ganze Hoehe wieder zurueck, sodass der Laptop im Textfluss genau
   bis zum Scharnier reicht; den sichtbaren Rest gibt der Innenabstand oben
   wieder dazu.

   Die Masse sind die eines MacBook Pro: Das Gehaeuse ist genau so breit wie
   der Deckel (jede Verschmaelerung erzeugt eine Stufe am Scharnier, die es an
   keinem echten Geraet gibt) und ungefaehr so tief, wie der Deckel hoch ist. */
.laptop__boden {
  position: relative;
  width: 100%;
  height: calc(var(--b) * .64);
  margin-bottom: calc(var(--b) * -.64);
  transform-origin: top center;
  transform: rotateX(var(--winkel));
  border-radius: 0 0 .625rem .625rem;
  background: linear-gradient(180deg,
      #0A1620 0%, #1C2C38 5%, #2E4351 45%, #445F74 93%, #16242F 100%);
  box-shadow: 0 3rem 4rem rgb(0 0 0 / .5);
}
/* Die Mulde, in der die Tasten sitzen. Einzelne Tasten waeren bei dieser
   Verkuerzung schmaler als ein Bildpunkt -- was bleibt, sind die sechs
   Tastenreihen als Streifen. Genau das sieht man auf einem Foto aus diesem
   Winkel auch. */
.laptop__boden::before {
  content: "";
  position: absolute;
  left: 7%; right: 7%; top: 11%;
  height: 48%;
  border-radius: .1875rem;
  background:
    repeating-linear-gradient(180deg,
      rgb(242 247 250 / .10) 0 3px,
      rgb(7 17 25 / .34) 3px 23px),
    linear-gradient(180deg, rgb(7 17 25 / .5), rgb(7 17 25 / .2));
  box-shadow: inset 0 1px 0 rgb(7 17 25 / .5),
              inset 0 -1px 0 rgb(242 247 250 / .07);
}
/* Griffmulde an der Vorderkante. */
.laptop__boden::after {
  content: "";
  position: absolute;
  left: 38%; right: 38%; bottom: 0;
  height: 4%;
  border-radius: 50% 50% 0 0 / 100% 100% 0 0;
  background: rgb(7 17 25 / .5);
}
/* Beim MacBook ist das Trackpad auffallend gross: rund die halbe Gehaeusebreite.
   Genau daran erkennt man es. */
.laptop__feld {
  position: absolute;
  left: 50%; bottom: 9%;
  width: 50%; height: 26%;
  transform: translateX(-50%);
  border-radius: .1875rem;
  background: linear-gradient(180deg, #1B2B37, #273C4D);
  box-shadow: inset 0 1px 0 rgb(242 247 250 / .12),
              0 1px 0 rgb(242 247 250 / .05);
}

/* Das eingebettete Dokument selbst. */
.geraet__seite {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
  background: #F6F5F2;
}

.geraet__hinweis {
  margin-top: var(--raum-5);
  text-align: center;
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-leise);
  display: flex;
  flex-wrap: wrap;
  gap: .5rem .75rem;
  align-items: center;
  justify-content: center;
}
.geraet__hinweis .textlink { font-size: .6875rem; letter-spacing: .1em; }

/* ---- 9  Das Angebot -------------------------------------------------------- */

.angebot__raster { display: grid; gap: clamp(3rem, 6vw, 4.5rem); }

@media (min-width: 60rem) {
  /* Spiegelverkehrt zum Startbereich: dort steht das Geraet rechts, hier
     links. Beide Sektionen sind sonst dieselbe Komposition aus Text und
     Objekt, und zwei gleich gebaute Abschnitte hintereinander liest der
     Besucher als Wiederholung, auch wenn der Inhalt ein anderer ist.

     Die Reihenfolge im Quelltext bleibt unangetastet, der Text steht dort
     weiterhin zuerst. Getauscht wird nur die Anzeige. Sonst wuerde ein
     Screenreader mit dem Geraet anfangen, und das ist eine leere Huelle. */
  .angebot__raster {
    grid-template-columns: minmax(0, .82fr) minmax(0, 1fr);
    align-items: start;
  }
  .angebot__raster > :first-child { order: 2; }
  .angebot__geraet { order: 1; position: sticky; top: 7rem; }
}

.schritte { display: grid; gap: 0; margin-top: var(--raum-8); }

.schritt {
  display: grid;
  grid-template-columns: 2.75rem minmax(0, 1fr);
  gap: 1.25rem;
  padding-block: 1.75rem;
  border-top: 1px solid var(--linie);
}
.schritt:last-child { border-bottom: 1px solid var(--linie); }

.schritt__marke {
  width: 2.75rem; height: 2.75rem;
  border-radius: 999px;
  display: grid;
  place-items: center;
  background: rgb(28 111 168 / .16);
  color: var(--marke-text);
  border: 1px solid rgb(111 188 238 / .26);
}
.schritt__marke svg { width: 1.25rem; height: 1.25rem; }
.schritt h2, .schritt h3 {
  font-size: clamp(1.1875rem, 1.9vw, 1.4375rem);
  letter-spacing: -.018em;
  line-height: 1.28;
  margin-bottom: var(--raum-2);
}
.schritt p { color: var(--text-mittel); font-size: 1rem; }

.zusicherung {
  margin-top: var(--raum-8);
  padding: var(--raum-5) var(--raum-6);
  border-radius: var(--r-kern);
  background: rgb(28 111 168 / .12);
  border: 1px solid rgb(111 188 238 / .22);
  font-size: 1.0625rem;
  color: var(--text);
}
.zusicherung strong { font-weight: 800; }

/* ---- 10  Leistungen -------------------------------------------------------- */

/* Bewusst kein Raster aus vier gleichen Kacheln: die erste Karte ist breit
   und traegt ein Bild, die drei anderen sind schmal und rein typografisch. */
.leistungen__raster { display: grid; gap: 1rem; }

@media (min-width: 48rem) {
  .leistungen__raster { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .leistung--breit { grid-column: span 2; }
}
@media (min-width: 68rem) {
  .leistungen__raster { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .leistung--breit { grid-column: span 3; }
}

.leistung .kern { padding: clamp(1.75rem, 3vw, 2.5rem); display: flex; flex-direction: column; gap: 1rem; }
.leistung__icon { width: 1.75rem; height: 1.75rem; color: var(--marke-text); }
.leistung p { color: var(--text-mittel); font-size: 1rem; }

.leistung--breit .kern {
  display: grid;
  gap: clamp(1.75rem, 4vw, 3rem);
  align-items: center;
  background: linear-gradient(120deg, var(--flaeche-hoch), var(--flaeche) 62%);
}
@media (min-width: 48rem) {
  .leistung--breit .kern { grid-template-columns: minmax(0, 1fr) minmax(0, .9fr); }
}
.leistung--breit h3 { font-size: clamp(1.5rem, 2.8vw, 2.125rem); }

.merkmale {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: .75rem;
}
@media (min-width: 30rem) { .merkmale { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 48rem) { .merkmale { grid-template-columns: minmax(0, 1fr); } }
@media (min-width: 68rem) { .merkmale { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.merkmal {
  display: grid;
  grid-template-columns: 1.125rem minmax(0, 1fr);
  gap: .6875rem;
  align-items: start;
  font-size: .9375rem;
  color: var(--text-mittel);
}
.merkmal svg { width: 1.125rem; height: 1.125rem; color: var(--marke-text); margin-top: .16rem; }

.merkmale__titel {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-leise);
  margin-bottom: 1.125rem;
}

/* ---- 11  Warum ------------------------------------------------------------- */



.warum__aussage {
  font-family: var(--schrift-display);
  font-size: clamp(1.75rem, 4.4vw, 3.25rem);
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1.06;
  max-width: 22ch;
  text-wrap: balance;
}
.warum__aussage em {
  font-style: normal;
  background: var(--welle-schrift);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.warum__text { margin-top: var(--raum-6); max-width: 44ch; color: var(--text-mittel); }



/* ---- 12  Ablauf ------------------------------------------------------------ */

.ablauf__raster { display: grid; gap: clamp(2.5rem, 6vw, 5rem); }
@media (min-width: 60rem) {
  .ablauf__raster { grid-template-columns: minmax(0, .8fr) minmax(0, 1.2fr); }
  .ablauf__kopf { position: sticky; top: 8rem; align-self: start; }
}

.etappen { position: relative; padding-left: 2.5rem; }

/* Die Linie fuellt sich beim Scrollen. Sie zeigt, wie weit man im Ablauf ist. */
.etappen__spur {
  position: absolute;
  left: .4375rem; top: .75rem; bottom: .75rem;
  width: 2px;
  background: var(--linie);
  border-radius: 2px;
  overflow: hidden;
}
.etappen__fuell {
  position: absolute;
  inset: 0;
  background: var(--welle);
  transform-origin: top center;
  transform: scaleY(0);
}

.etappe { position: relative; padding-bottom: clamp(2.5rem, 5vw, 3.5rem); }
.etappe:last-child { padding-bottom: 0; }
.etappe::before {
  content: "";
  position: absolute;
  left: -2.5rem; top: .55rem;
  width: 1rem; height: 1rem;
  border-radius: 999px;
  background: var(--grund);
  border: 2px solid var(--linie-stark);
}
.etappe h3 { margin-bottom: .625rem; }
.etappe p { color: var(--text-mittel); }
.etappe__dauer {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--marke-text);
  display: block;
  margin-bottom: .5rem;
}

/* ---- 13  Preise ------------------------------------------------------------ */



.pakete { display: grid; gap: 1rem; }
@media (min-width: 56rem) {
  .pakete { grid-template-columns: repeat(3, minmax(0, 1fr)); align-items: center; }
}

.paket .kern {
  padding: clamp(1.75rem, 3vw, 2.25rem);
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

/* Das mittlere Paket ist hoeher und traegt einen Rand aus der Markenfarbe.
   Damit sind die drei Karten nicht gleichwertig, sondern haben eine Mitte. */
.paket--empfohlen .schale {
  background: linear-gradient(150deg, rgb(79 166 220 / .30), rgb(18 73 111 / .12) 55%);
  border-color: rgb(111 188 238 / .34);
  box-shadow: 0 1.75rem 4rem -1.5rem rgb(28 111 168 / .55);
}
@media (min-width: 56rem) {
  .paket--empfohlen .kern { padding-block: var(--raum-9); }
}

.paket__stempel {
  font-family: var(--schrift-mono);
  font-size: .625rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--grund);
  background: var(--marke-text);
  border-radius: 999px;
  padding: .3125rem .75rem;
  align-self: flex-start;
}

.paket__preis {
  font-family: var(--schrift-display);
  font-variant-numeric: tabular-nums;
  font-size: clamp(2.25rem, 5vw, 3rem);
  font-weight: 900;
  letter-spacing: -.04em;
  line-height: 1;
}
.paket__preis small {
  display: block;
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-leise);
  margin-top: .625rem;
}

.paket__liste { list-style: none; margin: 0; padding: 0; display: grid; gap: .75rem; }
.paket__liste li {
  display: grid;
  grid-template-columns: 1.125rem minmax(0, 1fr);
  gap: .75rem;
  align-items: start;
  font-size: .96875rem;
  color: var(--text-mittel);
}
.paket__liste svg { width: 1.125rem; height: 1.125rem; color: var(--marke-text); margin-top: .18rem; }

.paket .knopf { margin-top: auto; }

.betreuung {
  margin-top: 1.5rem;
  display: grid;
  gap: 1.5rem;
  align-items: center;
}
@media (min-width: 52rem) {
  .betreuung { grid-template-columns: minmax(0, 1fr) auto; }
}
.betreuung .kern { padding: clamp(1.5rem, 3vw, 2rem); display: grid; gap: 1.25rem; }
@media (min-width: 52rem) {
  .betreuung .kern { grid-template-columns: minmax(0, 1fr) auto; align-items: center; }
}
.betreuung p { color: var(--text-mittel); font-size: 1rem; }

.steuerhinweis {
  margin-top: 1.75rem;
  font-size: .875rem;
  color: var(--text-leise);
}

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

.fragen__raster { display: grid; gap: clamp(2.5rem, 5vw, 4rem); }
@media (min-width: 60rem) {
  .fragen__raster { grid-template-columns: minmax(0, .7fr) minmax(0, 1.3fr); }
  .fragen__kopf { position: sticky; top: 8rem; align-self: start; }
}

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

.frage summary {
  list-style: none;
  cursor: pointer;
  padding: 1.5rem 3rem 1.5rem 0;
  position: relative;
  font-family: var(--schrift-display);
  font-size: clamp(1.0625rem, 1.8vw, 1.25rem);
  font-weight: 700;
  letter-spacing: -.02em;
  line-height: 1.3;
  transition: color var(--zeit-zeig) ease;
}
.frage summary::-webkit-details-marker { display: none; }
@media (hover: hover) and (pointer: fine) {
  .frage summary:hover { color: var(--marke-text); }
}

.frage summary::after {
  content: "";
  position: absolute;
  right: .25rem; top: 1.85rem;
  width: .875rem; height: .875rem;
  background: currentColor;
  transition: transform var(--zeit-klapp) var(--kurve);
  clip-path: polygon(43% 0, 57% 0, 57% 43%, 100% 43%, 100% 57%, 57% 57%, 57% 100%, 43% 100%, 43% 57%, 0 57%, 0 43%, 43% 43%);
}
.frage[open] summary::after { transform: rotate(135deg); }

.frage__text {
  padding: 0 2.5rem 1.75rem 0;
  color: var(--text-mittel);
  max-width: 60ch;
}
.frage__text p + p { margin-top: 1rem; }

/* ---- 15  Kontakt und Formular ---------------------------------------------- */

.kontakt__raster { display: grid; gap: clamp(3rem, 6vw, 4.5rem); }
@media (min-width: 62rem) {
  .kontakt__raster { grid-template-columns: minmax(0, .85fr) minmax(0, 1.15fr); }
}

.direktweg { display: grid; gap: var(--raum-6); margin-top: var(--raum-8); }
.direktweg__zeile { display: grid; gap: .375rem; }
.direktweg__zeile a {
  font-family: var(--schrift-display);
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  font-weight: 800;
  letter-spacing: -.03em;
  text-decoration: none;
  color: var(--text);
  transition: color var(--zeit-zeig) ease;
  word-break: break-word;
}
@media (hover: hover) and (pointer: fine) { .direktweg__zeile a:hover { color: var(--marke-text); } }

.formular .kern { padding: clamp(1.75rem, 4vw, 2.75rem); }

.feldpaar { display: grid; gap: 1.25rem; }
@media (min-width: 40rem) { .feldpaar { grid-template-columns: repeat(2, minmax(0, 1fr)); } }

.feld { display: grid; gap: .5rem; margin-bottom: 1.25rem; }
.feld label {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-mittel);
}
.feld input, .feld textarea, .feld select {
  width: 100%;
  font-family: var(--schrift-text);
  font-size: 1rem;
  color: var(--text);
  background: rgb(7 17 25 / .55);
  border: 1px solid var(--linie-stark);
  border-radius: var(--r-feld);
  padding: .875rem 1rem;
  min-height: 3rem;
  transition: border-color var(--zeit-zeig) ease, background-color var(--zeit-zeig) ease;
}
.feld textarea { min-height: 8.5rem; resize: vertical; line-height: 1.55; }
.feld select {
  appearance: none;
  background-image: linear-gradient(45deg, transparent 50%, var(--text-mittel) 50%),
                    linear-gradient(135deg, var(--text-mittel) 50%, transparent 50%);
  background-position: right 1.15rem center, right .8rem center;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}
.feld option { background: var(--flaeche); color: var(--text); }
@media (hover: hover) and (pointer: fine) {
  .feld input:hover, .feld textarea:hover, .feld select:hover { border-color: var(--text-leise); }
}
.feld input:focus, .feld textarea:focus, .feld select:focus {
  border-color: var(--marke-text);
  background: rgb(7 17 25 / .85);
  outline: none;
  box-shadow: 0 0 0 3px rgb(111 188 238 / .18);
}
.feld input::placeholder, .feld textarea::placeholder { color: var(--text-leise); }

.feld__hinweis { font-size: .8125rem; color: var(--text-leise); }
.feld__fehler {
  font-size: .8125rem;
  color: #FFB4A8;
  display: none;
}
.feld.hat-fehler .feld__fehler { display: block; }
.feld.hat-fehler input, .feld.hat-fehler textarea, .feld.hat-fehler select { border-color: #FF8A73; }

.einwilligung {
  display: grid;
  grid-template-columns: 1.25rem minmax(0, 1fr);
  gap: .875rem;
  align-items: start;
  margin-block: 1.5rem;
  font-size: .875rem;
  color: var(--text-mittel);
}
.einwilligung input {
  width: 1.25rem; height: 1.25rem;
  margin: .18rem 0 0;
  accent-color: var(--marke-text);
  min-height: 0;
}
.einwilligung a { color: var(--marke-text); }

/* Falle fuer Formularroboter. Fuer Menschen unsichtbar, aber nicht display:none,
   sonst fuellen manche Roboter sie trotzdem aus. */
.falle {
  position: absolute;
  left: -9999px;
  width: 1px; height: 1px;
  overflow: hidden;
}

.formular__melder {
  display: none;
  margin-top: 1.25rem;
  padding: 1rem 1.25rem;
  border-radius: var(--r-feld);
  font-size: .9375rem;
}
.formular__melder.zeigt { display: block; }
.formular__melder.gut { background: rgb(28 111 168 / .18); border: 1px solid rgb(111 188 238 / .3); }
.formular__melder.schlecht { background: rgb(255 138 115 / .12); border: 1px solid rgb(255 138 115 / .35); color: #FFD3C9; }

/* ---- 15b  Rechtsseiten und Fliesstextseiten -------------------------------- */

/* Impressum, Datenschutz und die Regionalseiten teilen sich diesen Satz.
   Eine schmale Spalte, damit Zeilen nicht laenger als etwa 70 Zeichen werden. */
.rechtstext { max-width: 46rem; }
.rechtstext h1 { margin-bottom: 2.5rem; }
.rechtstext h2 {
  font-size: clamp(1.25rem, 2.4vw, 1.625rem);
  margin-top: 3rem;
  margin-bottom: .875rem;
  padding-top: 1.75rem;
  border-top: 1px solid var(--linie);
}
.rechtstext h1 + h2 { margin-top: 0; border-top: 0; padding-top: 0; }
.rechtstext h3 { margin-top: 2rem; margin-bottom: .625rem; }
.rechtstext p { color: var(--text-mittel); }
.rechtstext p + p { margin-top: 1rem; }
.rechtstext a { color: var(--marke-text); }
.rechtstext ul { color: var(--text-mittel); margin: 1rem 0 0; padding-left: 1.25rem; }
.rechtstext li + li { margin-top: .5rem; }
.rechtstext li::marker { color: var(--marke-text); }

/* Einleitung der Regionalseiten. Wer ueber Google hier landet, soll ohne
   Scrollen sehen, was er bekommt. Deshalb steht rechts dasselbe Geraet wie auf
   der Startseite, mit der echten Beispielseite darin. */
.gebiet__raster { display: grid; gap: var(--raum-9); }
@media (min-width: 62rem) {
  .gebiet__raster {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, .8fr);
    align-items: center;
  }
}
.gebiet__kopf { max-width: 46rem; }
.gebiet__orte {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  margin-top: 2rem;
  list-style: none;
  padding: 0;
}
.gebiet__orte li {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--text-mittel);
  border: 1px solid var(--linie);
  border-radius: 999px;
  padding: .4375rem .875rem;
}

/* ---- 16  Fusszeile --------------------------------------------------------- */

.fuss {
  background: var(--grund-tief);
  border-top: 1px solid var(--linie);
  padding-block: var(--sektion) var(--raum-7);
}
.fuss__oben { display: grid; gap: 2.5rem; }
@media (min-width: 52rem) {
  .fuss__oben { grid-template-columns: minmax(0, 1.4fr) repeat(2, minmax(0, 1fr)); gap: 3rem; }
}
.fuss__text { color: var(--text-leise); font-size: .9375rem; margin-top: 1.25rem; max-width: 32ch; }
.fuss h3 {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-leise);
  margin-bottom: 1.25rem;
}
.fuss ul { list-style: none; margin: 0; padding: 0; display: grid; gap: .75rem; }
.fuss ul a { text-decoration: none; color: var(--text-mittel); font-size: .9375rem; transition: color var(--zeit-zeig) ease; }
@media (hover: hover) and (pointer: fine) { .fuss ul a:hover { color: var(--text); } }

.fuss__unten {
  margin-top: var(--raum-9);
  padding-top: 1.75rem;
  border-top: 1px solid var(--linie);
  display: flex;
  flex-wrap: wrap;
  gap: 1rem 2rem;
  justify-content: space-between;
  font-size: .8125rem;
  color: var(--text-leise);
}

/* ---- 16b  Trefferflaechen auf Beruehrungsgeraeten -------------------------- */

/* Kleine Textlinks sind mit der Maus gut zu treffen, mit dem Daumen nicht.
   Statt sie optisch groesser zu machen, bekommen sie auf Beruehrungsgeraeten
   eine unsichtbar vergroesserte Trefferflaeche. Das Layout bleibt dadurch
   unveraendert, die Ziele erreichen aber die geforderten 44 Bildpunkte. */
.marke,
.textlink,
.direktweg__zeile a,
.menue__fuss a[href^="tel"],
.fragen__kopf .textlink,
.fuss ul a,
.fuss__unten a { position: relative; }

@media (pointer: coarse) {
  .marke::after,
  .textlink::after,
  .direktweg__zeile a::after,
  .menue__fuss a[href^="tel"]::after,
  .fuss ul a::after,
  .fuss__unten a::after {
    content: "";
    position: absolute;
    inset: -14px -10px;
  }
}

/* ---- 17  Aktionsleiste fuers Handy ----------------------------------------- */

/* Erscheint erst, wenn der Startbereich vorbei ist. Im Startbereich stehen die
   Knoepfe ohnehin gross auf dem Schirm. */
.handyleiste {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 80;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: .5rem;
  padding: .625rem .75rem calc(.625rem + env(safe-area-inset-bottom));
  background: rgb(7 17 25 / .9);
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  border-top: 1px solid var(--linie);
  transform: translateY(110%);
  transition: transform var(--zeit-schub) var(--kurve-weich);
}
.handyleiste.zeigt { transform: none; }

.handyleiste a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .5rem;
  min-height: 3rem;
  border-radius: 999px;
  text-decoration: none;
  font-weight: 700;
  font-size: .9375rem;
}
.handyleiste svg { width: 1.0625rem; height: 1.0625rem; }
.handyleiste .h-anruf { background: rgb(242 247 250 / .08); color: var(--text); border: 1px solid var(--linie-stark); }
.handyleiste .h-haupt { background: var(--text); color: var(--grund); }

@media (min-width: 62rem) { .handyleiste { display: none; } }

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

/* Grundzustand nur setzen, wenn JavaScript laeuft. Ohne JavaScript ist alles
   sofort sichtbar, die Seite bleibt vollstaendig lesbar. */
html.js .auf { opacity: 0; transform: translateY(1.75rem); }
html.js .auf.sichtbar {
  opacity: 1;
  transform: none;
  transition: opacity var(--zeit-auf) var(--kurve),
              transform var(--zeit-auf) var(--kurve);
}

@keyframes aufblenden {
  from { opacity: 0; transform: translateY(2rem); }
  to   { opacity: 1; transform: none; }
}
@keyframes linieFuellen { from { transform: scaleY(0); } to { transform: scaleY(1); } }
@keyframes seitenlauf       { from { transform: translateY(0); } to { transform: translateY(-780px); } }
@keyframes seitenlauf-start { from { transform: translateY(0); } to { transform: translateY(-430px); } }
@keyframes seitenlauf-weit { from { transform: translateY(0); } to { transform: translateY(-1200px); } }
@keyframes zeileAuf { from { opacity: 0; transform: translateY(105%); } to { opacity: 1; transform: none; } }
@keyframes welleZeichnen { from { stroke-dashoffset: 340; } to { stroke-dashoffset: 0; } }

/* Auftritt der Ueberschrift beim Laden: die Zeilen steigen aus einer Maske auf. */
.maske { display: block; overflow: hidden; padding-bottom: .06em; }
/* Der Startbereich hatte sich erst nach 1,48 Sekunden gesetzt. So lange war
   der Aktionsknopf nicht zu sehen, und das auf der Seite, die verkaufen soll.
   Jetzt sind es 0,9 Sekunden, mit 70 statt 140 Millisekunden Versatz. */
html.js .maske > span {
  display: block;
  opacity: 0;
  transform: translateY(105%);
  animation: zeileAuf 600ms var(--kurve) forwards;
}
html.js .maske:nth-of-type(1) > span { animation-delay: 60ms; }
html.js .maske:nth-of-type(2) > span { animation-delay: 130ms; }
html.js .start .leitung,
html.js .start .knopfreihe {
  opacity: 0;
  animation: aufblenden 520ms var(--kurve) forwards;
}
html.js .start .leitung { animation-delay: 200ms; }
html.js .start .knopfreihe { animation-delay: 270ms; }

/* Scrollgebundene Fassung. Wo der Browser sie kann, laeuft die Bewegung am
   Scrollbalken statt an einem Zeitgeber: sie folgt der Hand des Nutzers. */
@supports (animation-timeline: view()) {
  html.js .auf {
    opacity: 1;
    transform: none;
    animation: aufblenden linear both;
    animation-timeline: view();
    /* Ein Verzoegern ueber animation-delay wirkt hier nicht. Der Bereich
       wird ueber animation-range gesetzt, sonst passiert schlicht nichts. */
    animation-range: entry 6% cover 30%;
  }
  html.js .auf.sichtbar { transition: none; }

  /* Karten, die in derselben Zeile stehen, treten sonst alle im selben
     Augenblick auf. Das liest sich wie ein Umschalter, nicht wie Bewegung.
     Ein Versatz muss hier ueber den Bereich laufen: bei einer
     Scroll-Zeitleiste bleibt animation-delay wirkungslos. */
  html.js .leistungen__raster > .auf:nth-child(2),
  html.js .pakete > .auf:nth-child(2),
  html.js .stuetzen > .auf:nth-child(2),
  html.js .schritte > .auf:nth-child(2) { animation-range: entry 9% cover 33%; }

  html.js .leistungen__raster > .auf:nth-child(3),
  html.js .pakete > .auf:nth-child(3),
  html.js .stuetzen > .auf:nth-child(3),
  html.js .schritte > .auf:nth-child(3) { animation-range: entry 12% cover 36%; }

  html.js .leistungen__raster > .auf:nth-child(4),
  html.js .pakete > .auf:nth-child(4) { animation-range: entry 15% cover 39%; }

  .etappen__fuell {
    animation: linieFuellen linear both;
    animation-timeline: view();
    animation-range: entry 55% exit 45%;
  }

  html.js .start .geraet__seite,
  html.js .gebiet__geraet .geraet__seite {
    animation: seitenlauf-start linear both;
    animation-timeline: scroll(root);
    animation-range: 0 100vh;
  }
  /* Die Seite im Bildschirm des Laptops.

     Sie haengt bewusst nicht an der Zeitachse des Geraets: ab 60rem steht der
     Laptop fest (`position: sticky`), und eine view()-Zeitachse misst genau
     die Bewegung ihres eigenen Elements. Steht das Element, steht die
     Animation -- die Seite im Rahmen lief dann gar nicht mehr mit, und im
     Ausschnitt blieb das helle Wandfoto aus dem Kopfbereich stehen.

     Angetrieben wird sie darum vom Abschnitt selbst, der weiterlaeuft. Der
     Bereich `entry 100% exit 0%` ist genau die Strecke, auf welcher der
     Abschnitt den Bildschirm fuellt -- also genau die Strecke, auf welcher
     der Laptop steht. */
  html.js .laptop .geraet__seite {
    animation: seitenlauf-weit linear both;
    animation-timeline: --laptop;
    animation-range: cover 15% cover 95%;
  }
  @media (min-width: 60rem) {
    #angebot { view-timeline-name: --angebot; }
    html.js .laptop .geraet__seite {
      animation-timeline: --angebot;
      /* Nicht die ganze Deckung: am Anfang klappt der Deckel noch auf, am
         Ende ist der Laptop schon fast oben raus. Die mittleren 55 Prozent
         sind die Strecke, auf der er offen dasteht -- und sie sind ungefaehr
         so lang wie der Laufweg selbst, sodass die Seite im Rahmen etwa im
         Takt der Seite darunter laeuft. */
      animation-range: cover 35% cover 90%;
    }
  }
}

/* Ohne scrollgebundene Animation fuellt sich die Linie beim Eintreten. */
@supports not (animation-timeline: view()) {
  html.js .etappen__fuell { transition: transform var(--zeit-erklaer) var(--kurve); }

  /* Derselbe Versatz fuer Browser ohne Scroll-Zeitleiste, dort ueber die
     Verzoegerung. 60 Millisekunden je Karte, innerhalb der ueblichen
     Spanne von 30 bis 80. */
  html.js .leistungen__raster > .auf.sichtbar:nth-child(2),
  html.js .pakete > .auf.sichtbar:nth-child(2),
  html.js .stuetzen > .auf.sichtbar:nth-child(2),
  html.js .schritte > .auf.sichtbar:nth-child(2) { transition-delay: 60ms; }

  html.js .leistungen__raster > .auf.sichtbar:nth-child(3),
  html.js .pakete > .auf.sichtbar:nth-child(3),
  html.js .stuetzen > .auf.sichtbar:nth-child(3),
  html.js .schritte > .auf.sichtbar:nth-child(3) { transition-delay: 120ms; }

  html.js .leistungen__raster > .auf.sichtbar:nth-child(4),
  html.js .pakete > .auf.sichtbar:nth-child(4) { transition-delay: 180ms; }
  html.js .etappen.sichtbar .etappen__fuell { transform: scaleY(1); }
}

.welle-zeichnen {
  stroke-dasharray: 340;
  stroke-dashoffset: 340;
}
/* stroke-dashoffset laeuft ueber Paint, nicht ueber die Grafikkarte, und das
   Zeichen steht in der festen Kopfzeile jeder Seite. 1,6 Sekunden bei jedem
   Aufruf sind dafuer zu viel Aufwand fuer zu wenig Wirkung. */
html.js .welle-zeichnen { animation: welleZeichnen 800ms var(--kurve) 120ms forwards; }

/* Vollstaendiger Abschaltweg. Wer im Betriebssystem weniger Bewegung
   eingestellt hat, bekommt die Seite ruhig und sofort vollstaendig. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.js .auf,
  html.js .maske > span,
  html.js .start .leitung,
  html.js .start .knopfreihe {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
    transition: none !important;
  }
  .laufband__spur { animation: none; }
  .etappen__fuell { transform: scaleY(1); animation: none; }
  html.js .geraet__seite { animation: none; transform: none; }
  .welle-zeichnen, html.js .welle-zeichnen { stroke-dashoffset: 0; animation: none; }
  /* Weniger und sanfter, nicht gar nichts. Farbwechsel bleiben weich, nur die
     Bewegung faellt weg: ein hart umspringender Knopf ist kein Zugewinn an
     Barrierefreiheit. */
  .knopf { transition: background-color var(--zeit-zeig) ease, border-color var(--zeit-zeig) ease, color var(--zeit-zeig) ease; }
  .knopf__icon { transition: background-color var(--zeit-zeig) ease; transform: none !important; }
  .textlink::after { transition: none; }
  .frage summary { transition: color var(--zeit-zeig) ease; }
  .frage summary::after { transition: none; }
  .handyleiste { transition: none; }
}

/* ---- 19  Oberflaeche ------------------------------------------------------- */

/* Eine sehr feine Koernung ueber der ganzen Seite. Grosse dunkle Flaechen wirken
   sonst wie leeres Schwarz, besonders auf guten Bildschirmen, wo man die
   Streifen im Farbverlauf sieht. Die Schicht liegt fest, nimmt keine Klicks an
   und scrollt nicht mit, sonst muesste die Grafikkarte sie dauernd neu
   zeichnen. */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  opacity: .05;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='k'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23k)'/%3E%3C/svg%3E");
}

@media (prefers-reduced-motion: reduce) { body::after { opacity: .035; } }

/* Der Inhalt liegt ueber der Koernung. */
/* Ebenen-Stapel. Die Reihenfolge steht hier vollstaendig an einer Stelle,
   damit sie nachvollziehbar bleibt:
     200  Sprunglink zum Inhalt
     100  Kopfzeile
      90  Vollbildmenue
      80  Aktionsleiste auf dem Handy
       2  Seiteninhalt
       1  Koernung ueber der Flaeche */
.kopf, main, .fuss, .handyleiste, .menue { position: relative; z-index: 2; }
.kopf        { z-index: 100; }
.menue       { z-index: 90; }
.handyleiste { z-index: 80; }

/* ---- 20  Preisbuehne -------------------------------------------------------- */

/* Die Preissektion ist der Hoehepunkt der Seite. Sie bekommt deshalb als
   einzige eine eigene Buehne: tieferer Grund, ein ruhiger Lichtschein aus der
   Markenfarbe und eine mittig gesetzte Ueberschrift. Alle anderen Sektionen
   sind linksbuendig, dadurch faellt diese heraus, ohne laut zu sein. */
.preise {
  background: var(--grund-tief);
  overflow: hidden;
}
.preise::before {
  content: "";
  position: absolute;
  top: -30%;
  left: 50%;
  transform: translateX(-50%);
  width: min(70rem, 120%);
  aspect-ratio: 1;
  background: radial-gradient(circle, rgb(28 111 168 / .20) 0%, transparent 62%);
  pointer-events: none;
}
.preise .wrap { position: relative; z-index: 1; }

.buehne {
  text-align: center;
  max-width: 44rem;
  margin-inline: auto;
  margin-bottom: var(--raum-9);
}
.buehne .leitung { margin-inline: auto; }
.buehne .label { color: var(--marke-text); }

/* ---- 21  Kostenvergleich ----------------------------------------------------- */

/* Der Anker vor den Paketen. Bewusst keine Karten, sondern drei Spalten mit
   Haarlinien: der Vergleich soll sachlich wirken, nicht wie ein Angebot. */
.vergleich {
  display: grid;
  gap: 0;
  margin-bottom: var(--raum-8);
  border-top: 1px solid var(--linie);
  border-bottom: 1px solid var(--linie);
}
/* Dieselbe Schwelle wie bei den Paketen darunter: beide Preisblöcke wechseln
   gemeinsam auf drei Spalten. Bei 48rem waeren die Spalten nur 230 Pixel breit
   und der Text darin sechszeilig. */
@media (min-width: 56rem) {
  .vergleich { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .vergleich__weg + .vergleich__weg { border-left: 1px solid var(--linie); border-top: 0; }
}
.vergleich__weg { padding: var(--raum-7) 0; }
@media (min-width: 56rem) { .vergleich__weg { padding: var(--raum-7) var(--raum-6); } }
.vergleich__weg + .vergleich__weg { border-top: 1px solid var(--linie); }
.vergleich__weg:first-child { padding-left: 0; }
.vergleich__weg:last-child { padding-right: 0; }

.vergleich__was {
  font-family: var(--schrift-mono);
  font-size: .6875rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--text-leise);
  display: block;
  margin-bottom: var(--raum-4);
}
.vergleich__preis {
  font-family: var(--schrift-display);
  font-size: clamp(1.625rem, 3vw, 2.125rem);
  font-weight: 700;
  letter-spacing: -.03em;
  line-height: 1.05;
  color: var(--text-mittel);
}
.vergleich__weg p:not(.vergleich__preis) {
  margin-top: var(--raum-3);
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--text-leise);
}

/* Die eigene Spalte ist die einzige in voller Helligkeit. Der Unterschied
   entsteht durch Kontrast, nicht durch einen Rahmen. */
.vergleich__weg--wir .vergleich__was { color: var(--marke-text); }
.vergleich__weg--wir .vergleich__preis { color: var(--text); }
.vergleich__weg--wir p:not(.vergleich__preis) { color: var(--text-mittel); }

.fussnote {
  font-size: .8125rem;
  line-height: 1.6;
  color: var(--text-leise);
  max-width: 48rem;
  margin-top: var(--raum-5);
}

/* ---- 22  Kleinteile ---------------------------------------------------------- */

.zahl--zeile { display: block; margin-bottom: var(--raum-2); }

/* ---- 23  Knopfreihe auf schmalen Schirmen ------------------------------------ */

/* Nebeneinander gesetzte Knoepfe brechen auf dem Handy untereinander um und
   stehen dann verschieden breit da, was zufaellig aussieht. Untereinander und
   auf volle Breite ist beides besser: ruhiger und leichter zu treffen. */
@media (max-width: 29.99rem) {
  .knopfreihe { flex-direction: column; align-items: stretch; }
  .knopfreihe .knopf { width: 100%; justify-content: space-between; }
}

/* Auf dem Handy darf der Startbereich etwas frueher anfangen. */
@media (max-width: 47.99rem) {
  .start { padding-top: calc(var(--kopfhoehe) + var(--raum-6)); }
}

/* ---- 24  Tippziele ----------------------------------------------------------- */

/* Ein Finger trifft zuverlaessig ab etwa 44 Pixel Kantenlaenge. Reine Textzeilen
   sind rund 20 Pixel hoch, also bekommen die Links, die keine Knoepfe sind,
   Polster statt einer groesseren Schrift. Das aendert am Aussehen nichts und
   macht die Seite auf dem Handy deutlich verlaesslicher.
   Linien im Fliesstext sind ausgenommen: dort ist ein kleines Ziel zulaessig,
   weil die Umgebung den Sinn traegt. */

.marke { padding-block: var(--raum-3); }



.direktweg__zeile a { display: inline-block; padding-block: var(--raum-2); }

.fuss ul { gap: 0; }
.fuss ul a {
  display: block;
  padding-block: var(--raum-3);
  min-height: 2.75rem;
}

.einwilligung input { width: 1.5rem; height: 1.5rem; }
.einwilligung { gap: var(--raum-4); grid-template-columns: 1.5rem minmax(0, 1fr); }

/* Auf dem Zeigegeraet darf es wieder kompakter sein. */
@media (min-width: 62rem) {
  .fuss ul { gap: var(--raum-3); }
  .fuss ul a { padding-block: 0; min-height: 0; }
}

/* Freistehende Textlinks sind auf dem Handy und auf Tablets ebenfalls
   Tippziele, nicht nur Schmuck. Ab Zeigegeraet-Breite darf es wieder eng
   werden, dort trifft eine Maus jede Zeile. */
@media (max-width: 61.99rem) {
  .textlink { min-height: 2.75rem; }
}

/* ---- 25  Preiszeile auf den Regionalseiten ----------------------------------- */

/* Kein zweiter Preisblock, nur eine Zeile. Ein vollstaendig wiederholter Block
   auf vier Seiten waere fuer Google eine Dublette. */
.preiszeile {
  margin-top: var(--raum-7);
  padding: var(--raum-5) var(--raum-6);
  border-radius: var(--r-kern);
  background: rgb(28 111 168 / .12);
  border: 1px solid rgb(111 188 238 / .22);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--text-mittel);
}
.preiszeile strong { color: var(--text); font-weight: 800; }

/* ---- 26  Geraete als Koerper im Raum ----------------------------------------- */

/* Die Geraete sind die einzigen Dinge auf dieser Seite mit Tiefe, und das ist
   Absicht. Ein Gedanke, konsequent auf ein Bauteil angewandt, wirkt teuer.
   Zehn kleine Effekte nebeneinander wirken unruhig.

   Die Drehung haengt am Scrollbalken, nicht an der Maus. Eine mausgefuehrte
   Kippung laeuft im Haupt-Thread, hat keine Traegheit und wirkt deshalb
   kuenstlich. Apple dreht seine Produkte am Scroll, aus demselben Grund.

   Der Winkel bleibt klein. Im Bildschirm steckt ein echtes Dokument, und ein
   dauerhaft stark gedrehter Bildschirm wird unscharf. Bei sieben Grad ist die
   Verzerrung unterhalb eines Bildpunkts, und sobald das Geraet mittig steht,
   liegt es exakt flach und damit gestochen scharf. */

.start__geraet,
.gebiet__geraet {
  perspective: 1500px;
  perspective-origin: 50% 40%;
}

/* Beim Laptop steht die Kamera weiter weg und hoeher. Weiter weg, weil die
   liegende Bodenplatte sonst stark auseinanderlaeuft und breiter wird als ihre
   Spalte; hoeher, weil man sonst genau auf ihre Kante schaut und von der
   Flaeche nichts sieht. Der Bildschirm selbst bleibt davon unberuehrt: er
   steht am Ende bei null Grad und damit parallel zur Bildebene, und eine
   Flaeche in der Bildebene verzerrt keine Perspektive. */
.angebot__geraet {
  perspective: 2800px;
  perspective-origin: 50% 26%;
  container-type: inline-size;
}

.geraet, .laptop {
  transform-style: preserve-3d;
}
.geraet { backface-visibility: hidden; }

/* Erst die Kante macht aus dem Rechteck einen Koerper: Licht faengt sich oben
   auf dem Rahmen, die Unterseite liegt im Schatten, und links steht die
   sichtbare Schmalseite. Auf dunklem Grund traegt das die Tiefe, ein
   Aufsetzschatten waere dort ohnehin unsichtbar. */
.geraet {
  box-shadow:
    0 0 0 1px rgb(242 247 250 / .10),
    inset 0 1.5px 0 rgb(242 247 250 / .20),
    inset 0 -2px 3px rgb(11 24 34 / .65),
    -2px 1px 0 rgb(8 18 26 / .8),
    -4px 2px 0 rgb(8 18 26 / .45),
    0 2.5rem 5rem -1.5rem rgb(0 0 0 / .8);
}

.laptop__schirm {
  box-shadow:
    0 0 0 1px rgb(242 247 250 / .10),
    inset 0 1.5px 0 rgb(242 247 250 / .16),
    0 1.5rem 3.5rem -1rem rgb(0 0 0 / .7);
}

@keyframes geraetStellen {
  from { transform: rotateY(-7deg) rotateX(3deg); }
  to   { transform: rotateY(0deg) rotateX(0deg); }
}
@keyframes laptopStellen {
  from { transform: rotateY(5deg); }
  to   { transform: rotateY(0deg); }
}
@keyframes deckelOeffnen {
  from { transform: rotateX(-90deg); }
  to   { transform: rotateX(0deg); }
}

/* Ohne scrollgebundene Animation stehen die Geraete leicht angedreht still.
   Das ist der Ruhezustand, kein Notbehelf: auch ohne Bewegung bleibt die
   Tiefe erhalten. */
.geraet { transform: rotateY(-7deg) rotateX(3deg); }
.laptop { transform: rotateY(5deg); }
/* Ohne Scrollbindung steht der Laptop offen da. Zugeklappt waere er ein
   Geraet, das nichts zeigt -- und zeigen ist seine ganze Aufgabe. */
.laptop__deckel { transform: rotateX(0deg); }

@supports (animation-timeline: view()) {
  html.js .start__geraet .geraet,
  html.js .gebiet__geraet .geraet {
    animation: geraetStellen linear both;
    animation-timeline: scroll(root);
    animation-range: 0 45vh;
  }
  html.js .angebot__geraet .laptop {
    animation: laptopStellen linear both;
    animation-timeline: view();
    animation-range: entry 25% cover 45%;
  }

  /* Der Deckel haengt an einer benannten Zeitleiste des Laptops, nicht an
     seiner eigenen. Er ist waehrend des Aufklappens um bis zu 90 Grad
     gedreht, und eine Zeitleiste, die ihre eigene Bewegung misst, kann sich
     aufschaukeln. Der Laptop darunter steht ruhig. */
  html.js .angebot__geraet .laptop { view-timeline-name: --laptop; }
  html.js .angebot__geraet .laptop__deckel {
    animation: deckelOeffnen linear both;
    animation-timeline: --laptop;
    animation-range: entry 10% cover 38%;
  }
}

/* Bei reduzierter Bewegung liegen die Geraete flach. Eine feste Schraeglage
   waere zwar unbewegt, aber sie kaeme vom selben Effekt, den jemand gerade
   abbestellt hat. */
@media (prefers-reduced-motion: reduce) {
  .geraet,
  .laptop,
  .laptop__deckel { transform: none !important; animation: none !important; }
  /* Die Bodenplatte behaelt ihre Neigung. Sie bewegt sich nicht, sie liegt --
     das ist Bauform, nicht Effekt. Flach gelegt waere der Laptop kein Laptop
     mehr, sondern zwei Rechtecke uebereinander. */
}

/* ---- 27  Ansprechpartner mit Gebietskarte ------------------------------------ */

/* Der Abschnitt bestand vorher aus einer Ueberschrift und drei gleich breiten
   Textspalten. Drei gleiche Spalten sind das Standardmuster, das in den
   eigenen Designregeln als Fehler gefuehrt wird, und der ganze Abschnitt hatte
   nichts zum Ansehen.

   Jetzt traegt ihn eine echte Karte des Einzugsgebiets. Sie ist kein Schmuck:
   die Ueberschrift behauptet "aus der Gegend", und die Karte belegt es. Die
   Geometrie von Donau und Iller kommt aus OpenStreetMap, sie ist also richtig.
   Und die Donau, die mitten hindurchlaeuft, ist derselbe Fluss wie im Namen
   und dieselbe Linie wie im Logo. */

.warum__raster { display: grid; gap: var(--raum-9); align-items: start; }
@media (min-width: 62rem) {
  .warum__raster {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.02fr);
    gap: clamp(3rem, 6vw, 5.5rem);
    /* Die Karte ist naturgemaess quadratisch, die Textspalte doppelt so hoch.
       Oben buendig wuerde die Karte oben kleben und darunter ein Loch lassen.
       Mittig gesetzt liegt die Leere gleichmaessig ueber und unter ihr und
       liest sich als Absicht. */
    align-items: center;
  }
}

.warum__text { margin-top: var(--raum-6); max-width: 44ch; color: var(--text-mittel); }

/* Die drei Zusagen stehen jetzt untereinander in der Textspalte, nicht mehr
   als eigene Reihe. Dadurch faellt das Dreispalten-Muster weg und die linke
   Spalte traegt genug Gewicht, um der Karte standzuhalten. */
.zusagen { margin: var(--raum-9) 0 0; padding: 0; }
.zusage {
  display: grid;
  gap: var(--raum-2);
  padding-block: var(--raum-5);
  border-top: 1px solid var(--linie);
}
.zusage:last-child { border-bottom: 1px solid var(--linie); }
.zusage dt {
  font-family: var(--schrift-display);
  font-size: 1.0625rem;
  font-weight: 700;
  letter-spacing: -.018em;
}
.zusage dd {
  margin: 0;
  color: var(--text-mittel);
  font-size: .96875rem;
  line-height: 1.6;
  max-width: 52ch;
}

/* ---- Die Karte selbst -------------------------------------------------------- */

.warum__karte { margin: 0; }
.warum__karte .kern { padding: clamp(.75rem, 2vw, 1.25rem); }

.karte { width: 100%; height: auto; display: block; overflow: visible; }

/* Elf Ortsnamen auf einer 300 Pixel breiten Karte sind unlesbarer Pfeffer.
   Auf schmalen Schirmen bleiben deshalb nur die fuenf, die das Gebiet
   aufspannen; die uebrigen kommen erst ab mittlerer Breite dazu. */
/* Schriftgroessen in SVG-Einheiten skalieren mit der Anzeigebreite mit. Die
   Karte ist 420 Einheiten breit und wird je nach Schirm zwischen rund 295 und
   440 Pixeln dargestellt. Ein fester Wert waere also entweder auf dem Handy
   unlesbar oder auf dem Rechner plakativ. Deshalb zwei Stufen, so gewaehlt,
   dass die Beschriftung in beiden Faellen bei rund elf Pixeln landet. */
.karte__ort {
  font-family: var(--schrift-mono);
  font-size: 15px;
  letter-spacing: .04em;
  fill: var(--text-leise);
}
.karte__ort--mitte { font-size: 20px; }
.karte__quelle { font-size: 11px; }

@media (min-width: 62rem) {
  .karte__ort { font-size: 11px; letter-spacing: .05em; }
  .karte__ort--mitte { font-size: 15px; }
  .karte__quelle { font-size: 8.5px; }
}

/* Elf Namen auf einer 300 Pixel breiten Karte sind unlesbarer Pfeffer. Auf
   schmalen Schirmen bleiben nur die fuenf, die das Gebiet aufspannen. */
.karte__rang2 { display: none; }
@media (min-width: 34rem) { .karte__rang2 { display: block; } }
.karte__ort--mitte {
  font-family: var(--schrift-display);
  font-weight: 700;
  letter-spacing: -.02em;
  fill: var(--text);
}
.karte__quelle {
  font-family: var(--schrift-mono);
  letter-spacing: .04em;
  fill: var(--text-leise);
  opacity: .55;
}

.warum__karte figcaption {
  /* Die Groesse der Zahl steht hier, weil der optische Ausgleich am Text sie
     kennen muss. Sonst stimmt die Ausrichtung nur bei einer Fensterbreite. */
  --zahl-groesse: clamp(1.75rem, 3vw, 2.25rem);
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--raum-6);
  align-items: start;
  margin-top: var(--raum-6);
  padding-top: var(--raum-5);
  border-top: 1px solid var(--linie);
}

/* Die Zahl braucht ihre eigene Zeilenhoehe. Vorher erbte sie die 1,55 des
   Elternteils: bei 36 Pixel Schrift ergab das eine Zeilenbox von 56 Pixeln,
   also zwanzig Pixel Luft, die niemand gesetzt hatte. Genau daran lag es,
   dass der Block verschoben aussah. */
.karte__mass { display: block; }

.karte__weite {
  display: block;
  font-family: var(--schrift-display);
  font-size: var(--zahl-groesse);
  font-weight: 800;
  letter-spacing: -.035em;
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.karte__weite-label {
  display: block;
  margin-top: var(--raum-2);
  font-family: var(--schrift-mono);
  font-size: .625rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--text-leise);
  white-space: nowrap;
}

/* Optischer Ausgleich. Oben buendig heisst nicht gleich aussehend: ueber der
   Versalhoehe jeder Zeile sitzt noch der halbe Durchschuss, und der ist bei
   der grossen Zahl und beim kleinen Text verschieden hoch.

   Der Ausgleich muss mit der Zahl mitwachsen. Ein fester Wert stimmt nur bei
   einer einzigen Fensterbreite: bei 36 Pixel Zahl braucht es 2,6 Pixel, bei
   28 Pixel praktisch keine. Beide Werte im Browser ausgemessen, die Gerade
   dazwischen steht in der Rechnung. max() faengt ab, dass der Wert negativ
   wird. */
.karte__weite-text {
  font-size: .9375rem;
  line-height: 1.6;
  color: var(--text-leise);
  max-width: 30ch;
  padding-top: max(0px, calc(var(--zahl-groesse) * .319 - .555rem));
}

/* Auf schmalen Schirmen untereinander, sonst wird der Text zweispaltig eng. */
@media (max-width: 33.99rem) {
  .warum__karte figcaption { grid-template-columns: minmax(0, 1fr); gap: var(--raum-4); }
  .karte__weite-text { padding-top: 0; max-width: none; }
}


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

/* Die Donau zeichnet sich beim Scrollen selbst, genau wie die Welle im Logo
   beim Laden. Das ist der Grund fuer die Animation: sie verbindet Zeichen,
   Name und Karte zu einer Sache. pathLength normiert jeden Zug auf 1, deshalb
   braucht keiner der drei Zuege eine gemessene Laenge. */
@keyframes flussZeichnen { from { stroke-dashoffset: 1; } to { stroke-dashoffset: 0; } }
@keyframes ringOeffnen   { from { transform: scale(.94); opacity: 0; } to { transform: none; opacity: 1; } }
@keyframes pulsEinmal    { from { transform: scale(1); opacity: .9; } to { transform: scale(3.4); opacity: 0; } }

html.js .karte__donau,
html.js .karte__iller { stroke-dasharray: 1; stroke-dashoffset: 1; }

html.js .karte__ring,
html.js .karte__puls,
html.js .karte__mitte { transform-box: fill-box; transform-origin: center; }

@supports (animation-timeline: view()) {
  html.js .karte__iller {
    animation: flussZeichnen linear both;
    animation-timeline: view();
    animation-range: entry 30% cover 40%;
  }
  html.js .karte__donau {
    animation: flussZeichnen linear both;
    animation-timeline: view();
    animation-range: entry 34% cover 52%;
  }
  html.js .karte__ring {
    animation: ringOeffnen linear both;
    animation-timeline: view();
    animation-range: entry 20% entry 70%;
  }
  html.js .karte__puls {
    animation: pulsEinmal linear both;
    animation-timeline: view();
    animation-range: entry 55% cover 25%;
  }
}

/* Ohne scrollgebundene Animation steht die Karte fertig gezeichnet da. */
@supports not (animation-timeline: view()) {
  html.js .karte__donau, html.js .karte__iller { stroke-dashoffset: 0; }
  html.js .karte__puls { opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  html.js .karte__donau, html.js .karte__iller {
    stroke-dashoffset: 0 !important; animation: none !important;
  }
  html.js .karte__ring { transform: none !important; opacity: 1 !important; animation: none !important; }
  html.js .karte__puls { opacity: 0 !important; animation: none !important; }
}

/* ---- 28  Halteknopf am Ortsband ---------------------------------------------- */

/* Bewegung, die laenger als fuenf Sekunden laeuft und von allein startet,
   braucht laut WCAG 2.2.2 eine Moeglichkeit, sie anzuhalten. Das Anhalten beim
   Zeigen reicht dafuer nicht: mit der Tastatur kommt man da nicht hin, und auf
   dem Handy gibt es kein Zeigen. Deshalb ein echter Knopf. Er sitzt am rechten
   Rand hinter einem weichen Verlauf, damit die Schrift nicht darunter
   durchlaeuft. */
.laufband__halt {
  position: absolute;
  top: 50%;
  right: var(--rand);
  transform: translateY(-50%);
  z-index: 2;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--linie-stark);
  border-radius: 999px;
  background: var(--grund);
  color: var(--text-mittel);
  cursor: pointer;
  padding: 0;
  transition: color var(--zeit-zeig) ease, border-color var(--zeit-zeig) ease;
}
@media (hover: hover) and (pointer: fine) {
  .laufband__halt:hover { color: var(--text); border-color: var(--text-leise); }
}
.laufband__halt svg { width: 1.0625rem; height: 1.0625rem; }
.laufband__halt .laufband__halt-aus { display: none; }
.laufband__halt[aria-pressed="true"] .laufband__halt-an { display: none; }
.laufband__halt[aria-pressed="true"] .laufband__halt-aus { display: block; }

/* Weicher Auslauf, damit die Ortsnamen nicht am Knopf kleben. */
.laufband::after {
  content: "";
  position: absolute;
  inset: 0 0 0 auto;
  width: clamp(6rem, 14vw, 10rem);
  background: linear-gradient(to right, transparent, var(--grund) 62%);
  pointer-events: none;
  z-index: 1;
}

.laufband.haelt .laufband__spur { animation-play-state: paused; }
