/* Anneli Laufenberg - Stadtfuehrungen in Wiesbaden
   Ein Stylesheet. Reihenfolge: Schrift, Tokens, Grundlagen, Typografie,
   Bilder, Knoepfe, Header, Fuss, Startseite, Fuehrungen, Tourenseite,
   Ueber mich, Kontakt, Bewegung. */

/* ----------------------------------------------------------------- Schrift
   Eine Familie, lokal, variabel. Latin-Subset, erzeugt von npm run schriften. */

@font-face {
  font-family: 'Schibsted Grotesk';
  src: url('/schriften/schibsted-grotesk-latin.woff2') format('woff2');
  font-weight: 400 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;
}

/* Display-Schrift: das Wort Wiesbaden im Hero, das Wortzeichen und die
   Ueberschrift "Wiesbaden at its finest" (aufrecht); Tourentitel,
   Stationsnamen und die Zwischentitel der Lesestrecke (kursiv, Nachtrag
   12.9). Zwei Schnitte, zwei Dateien, je genau eine Anfrage. */
@font-face {
  font-family: 'Instrument Serif';
  src: url('/schriften/instrument-serif-latin.woff2') format('woff2');
  font-weight: 400;
  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: 'Instrument Serif';
  src: url('/schriften/instrument-serif-italic-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: italic;
  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;
}

/* ------------------------------------------------------------------ Tokens */

:root {
  --weiss: #fafaf7;
  --flaeche: #f1efea;
  --linie: #ddd9d1;
  --text: #161616;
  --text-2: #5b5b57;
  --patina: #5e7f6b;
  --patina-tief: #3f5c4c;

  --schrift: 'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI',
    Roboto, 'Helvetica Neue', Arial, sans-serif;
  --schrift-display: 'Instrument Serif', Georgia, 'Times New Roman', serif;

  --gr-h1: clamp(2.75rem, 6vw, 5.5rem);
  --gr-h2: clamp(1.75rem, 3.5vw, 2.75rem);
  --gr-h3: 1.375rem;
  --gr-text: 1.125rem;
  --gr-meta: 0.875rem;
  --gr-nav: 0.9375rem;

  --breite: 1280px;
  --rand: clamp(1.25rem, 4vw, 3.5rem);
  --sektion: clamp(4rem, 10vw, 9rem);
  --spalte: clamp(1.25rem, 2.5vw, 2.5rem);

  --tempo: 600ms;
  --kurve: cubic-bezier(0.2, 0.7, 0.2, 1);
}

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

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

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--weiss);
  color: var(--text);
  font-family: var(--schrift);
  font-size: var(--gr-text);
  font-weight: 400;
  line-height: 1.6;
  overflow-x: hidden;
}

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

a {
  color: var(--patina-tief);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.18em;
  transition: color var(--tempo) var(--kurve), text-decoration-color var(--tempo) var(--kurve);
}

a:hover {
  color: var(--text);
  text-decoration-color: var(--patina);
}

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

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

.zum-inhalt {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  background: var(--patina-tief);
  color: var(--weiss);
  padding: 0.75rem 1.25rem;
}

.zum-inhalt:focus {
  left: var(--rand);
  top: 0.5rem;
}

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

.sektion {
  margin-top: var(--sektion);
}

.seitenkopf {
  padding-top: clamp(2.5rem, 6vw, 5rem);
}

/* -------------------------------------------------------------- Typografie */

h1,
h2,
h3 {
  font-weight: 500;
  margin: 0 0 0.5em;
  color: var(--text);
  text-wrap: balance;
}

h1 {
  font-size: var(--gr-h1);
  letter-spacing: -0.02em;
  line-height: 1;
}

h2 {
  font-size: var(--gr-h2);
  letter-spacing: -0.01em;
  line-height: 1.1;
}

h3 {
  font-size: var(--gr-h3);
  line-height: 1.25;
}

p {
  margin: 0 0 1.2em;
  max-width: 62ch;
}

.meta,
figcaption {
  font-size: var(--gr-meta);
  font-weight: 400;
  color: var(--text-2);
  line-height: 1.5;
}

/* Eine Zeile in Meta-Schrift ueber einem Block, als Ueberschrift ausgezeichnet. */
.zeile-meta {
  font-size: var(--gr-meta);
  font-weight: 400;
  color: var(--text-2);
  line-height: 1.5;
  letter-spacing: 0;
  margin: 0 0 0.75rem;
}

.einleitung {
  font-size: 1.25rem;
  line-height: 1.5;
}

.sektion-link {
  margin-top: 2rem;
}

.sektion-link a {
  font-weight: 500;
}

/* Gestapelte Fakten: Liste mit Haarlinien, kein Zeichen. */
.fakten {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  max-width: 62ch;
}

.fakten li {
  padding: 0.7rem 0;
  border-top: 1px solid var(--linie);
}

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

.hinweise {
  margin: 0;
  padding-left: 1.1em;
}

/* Bildnachweis: Motiv in Textgroesse, darunter Urheber, Fundstelle, Lizenz. */
.nachweis li > span {
  display: block;
}

.nachweis .meta {
  margin-top: 0.15rem;
}

.textseite h2 {
  font-size: var(--gr-h3);
  margin-top: 2.5rem;
}

/* ------------------------------------------------------------------ Bilder
   Gerade beschnittene Rechtecke ohne Radius, ohne Rahmen. Unterschrift
   links unter dem Bild. Bilder sind ohne Skript immer sichtbar. Nur ein
   Bild, das beim Start des Skripts noch nicht geladen ist, bekommt von
   skript.js die Klasse .laedt (unsichtbar) und nach dem Laden .geladen;
   Bilder aus dem Cache werden nie angefasst. */

.bild {
  margin: 0;
}

.bild-rahmen {
  overflow: hidden;
  background: var(--flaeche);
}

.bild img {
  display: block;
  width: 100%;
  height: auto;
  transition: opacity 400ms ease, transform var(--tempo) var(--kurve);
}

.bild img.laedt {
  opacity: 0;
}

.bild img.geladen {
  opacity: 1;
}

.bild figcaption {
  margin-top: 0.6rem;
}

/* Bildnachweis als zweite Zeile der Unterschrift: "Foto: Name", bei
   CC BY-SA mit verlinkter Lizenz. */
.bild-nachweis {
  display: block;
  margin-top: 0.15rem;
}

.portraet {
  max-width: 320px;
}

/* Passbild auf /ueber-mich: die Quelle ist nur 364 px breit, darum
   hoechstens 300 px Anzeige (Nachtrag 12.14). */
.portraet.passbild {
  max-width: 300px;
}

/* ------------------------------------------------------------------ Knoepfe
   Rechteckig, kein Radius. Primaer in Patina-tief, damit der Text auf der
   Flaeche 7:1 erreicht (Patina selbst liegt mit Weiss bei 4,3:1). */

.knopf {
  display: inline-block;
  padding: 1rem 1.25rem;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.2;
  text-decoration: none;
  border: 1px solid transparent;
  transition: background-color var(--tempo) var(--kurve), color var(--tempo) var(--kurve),
    border-color var(--tempo) var(--kurve);
}

.knopf-primaer {
  background: var(--patina-tief);
  border-color: var(--patina-tief);
  color: var(--weiss);
}

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

.knopf-sekundaer {
  background: transparent;
  border-color: var(--text);
  color: var(--text);
}

.knopf-sekundaer:hover {
  border-color: var(--patina-tief);
  color: var(--patina-tief);
}

/* ------------------------------------------------------------------ Header */

.kopf {
  position: relative;
  background: var(--weiss);
  border-bottom: 1px solid var(--linie);
  z-index: 20;
}

@media (min-width: 900px) {
  .kopf {
    position: sticky;
    top: 0;
  }
}

.kopf-bahn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  padding-block: 1.1rem;
}

/* Wortzeichen: der Name in Instrument Serif, darunter die Rolle in
   Meta-Schrift, buendig unter dem Namen (Briefing 12.8). Kein Zeichen. */
.wortzeichen {
  display: inline-block;
  text-decoration: none;
  color: var(--text);
}

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

.wortzeichen-name {
  display: block;
  font-family: var(--schrift-display);
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.01em;
}

.wortzeichen-rolle {
  display: block;
  margin-top: 0.15rem;
}

.haupt-navigation ul {
  list-style: none;
  display: flex;
  gap: clamp(1.25rem, 2.5vw, 2.25rem);
  margin: 0;
  padding: 0;
}

.haupt-navigation a {
  display: inline-block;
  font-size: var(--gr-nav);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  padding-block: 0.3rem;
  border-bottom: 2px solid transparent;
  transition: border-color var(--tempo) var(--kurve);
}

.haupt-navigation a:hover,
.haupt-navigation a[aria-current='page'] {
  border-bottom-color: var(--patina);
}

/* Menue-Knopf und Schliessen-Knopf: zwei Linien von 22 px und 1,5 px in
   einer Tap-Flaeche von 44 x 44 px, ohne Rahmen. Der negative rechte Rand
   setzt die Linien buendig an den Inhaltsrand. Im offenen Overlay morphen
   die Linien des Schliessen-Knopfs in 300 ms zum X. */
.linien-knopf {
  position: relative;
  flex: none;
  width: 44px;
  height: 44px;
  margin-right: -11px;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.linien-knopf-linie {
  position: absolute;
  left: 11px;
  top: 21.25px;
  width: 22px;
  height: 1.5px;
  background: currentColor;
  transition: transform 300ms var(--kurve);
}

.linien-knopf-linie:first-child {
  transform: translateY(-3.5px);
}

.linien-knopf-linie:last-child {
  transform: translateY(3.5px);
}

.menue-overlay.offen .menue-zu .linien-knopf-linie:first-child {
  transform: rotate(45deg);
}

.menue-overlay.offen .menue-zu .linien-knopf-linie:last-child {
  transform: rotate(-45deg);
}

/* Scroll-Sperre bei offenem Menue. --scrollbalken setzt skript.js auf die
   Breite eines klassischen Scrollbalkens, damit die Seite nicht springt. */
html.menue-offen {
  overflow: hidden;
  padding-right: var(--scrollbalken, 0px);
}

/* Mobilmenue: deckt das ganze Fenster. Drei Zonen: Kopfzeile wie der
   Header, Navigation, Kontaktblock am unteren Rand. Einblenden 250 ms,
   Ausblenden 200 ms (.schliesst), beides nur ueber opacity. */
.menue-overlay {
  position: fixed;
  inset: 0;
  height: 100dvh;
  z-index: 50;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
  background: var(--weiss);
  color: var(--text);
  opacity: 0;
  transition: opacity 200ms ease;
}

.menue-overlay[hidden] {
  display: none;
}

.menue-overlay.offen {
  opacity: 1;
  transition-duration: 250ms;
}

.menue-overlay.offen.schliesst {
  opacity: 0;
  transition-duration: 200ms;
}

.menue-kopf {
  flex: none;
  border-bottom: 1px solid var(--linie);
}

.menue-navigation {
  margin-top: 2rem;
}

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

.menue-navigation li + li {
  border-top: 1px solid var(--linie);
}

.menue-punkt {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  padding-block: 1rem;
  font-family: var(--schrift-display);
  font-size: clamp(2rem, 9vw, 2.75rem);
  font-weight: 400;
  line-height: 1.1;
  color: var(--text);
  text-decoration: none;
}

.menue-punkt:hover {
  color: var(--text);
}

.menue-wort {
  flex: 1;
}

.menue-pfeil {
  flex: none;
  width: 16px;
  height: 16px;
  color: var(--text-2);
  transition: transform 180ms var(--kurve);
}

.menue-punkt:hover .menue-pfeil,
.menue-punkt:focus-visible .menue-pfeil {
  transform: translateX(4px);
}

/* Aktuelle Seite: kursiv, davor ein Punkt von 6 px in Patina. */
.menue-punkt[aria-current='page'] .menue-wort {
  font-style: italic;
}

.menue-punkt[aria-current='page']::before {
  content: '';
  flex: none;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--patina);
}

/* Kontaktblock: klebt am unteren Rand, mindestens 2rem unter der
   Navigation. Anrufen liegt auf --patina-tief wie jeder Primaerknopf. */
.menue-kontakt {
  flex: none;
  margin-top: auto;
  padding-top: 2rem;
}

.menue-kontakt .meta {
  margin: 0 0 0.75rem;
}

.menue-knoepfe {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
}

.menue-knoepfe .knopf {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 52px;
  padding-block: 0;
  text-align: center;
}

.menue-email {
  display: inline-block;
  margin-top: 1rem;
  font-size: var(--gr-text);
}

/* Auftritt: die Menuepunkte folgen von 12 px unten mit 40 ms Versatz,
   der Kontaktblock zuletzt. Die Animation haengt an .offen und laeuft bei
   jedem Oeffnen neu; beim Schliessen bleibt .offen bis zum Ende stehen,
   deshalb blendet dann nur die Flaeche aus, ohne Versatz. */
@keyframes menue-einlauf {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
}

.menue-overlay.offen .menue-navigation li,
.menue-overlay.offen .menue-kontakt {
  animation: menue-einlauf 450ms var(--kurve) both;
}

.menue-overlay.offen .menue-navigation li:nth-child(1) {
  animation-delay: 50ms;
}

.menue-overlay.offen .menue-navigation li:nth-child(2) {
  animation-delay: 90ms;
}

.menue-overlay.offen .menue-navigation li:nth-child(3) {
  animation-delay: 130ms;
}

.menue-overlay.offen .menue-navigation li:nth-child(4) {
  animation-delay: 170ms;
}

.menue-overlay.offen .menue-kontakt {
  animation-delay: 210ms;
}

/* Reduzierte Bewegung: nur Ein- und Ausblenden der Flaeche. Die Dauer
   muss die allgemeine Abschaltung am Dateiende uebertrumpfen. */
@media (prefers-reduced-motion: reduce) {
  .menue-overlay {
    transition-duration: 200ms !important;
  }

  .menue-overlay.offen:not(.schliesst) {
    transition-duration: 250ms !important;
  }

  .menue-overlay.offen .menue-navigation li,
  .menue-overlay.offen .menue-kontakt {
    animation: none;
  }

  .menue-punkt:hover .menue-pfeil,
  .menue-punkt:focus-visible .menue-pfeil {
    transform: none;
  }
}

@media (min-width: 900px) {
  .menue-auf {
    display: none;
  }
}

@media (max-width: 899px) {
  .haupt-navigation {
    display: none;
  }
}

/* -------------------------------------------------------------------- Fuss */

.fuss {
  margin-top: var(--sektion);
  background: var(--flaeche);
  border-top: 1px solid var(--linie);
}

.fuss-spalten {
  display: grid;
  gap: 2.5rem;
  grid-template-columns: 1fr;
  padding-block: 3rem;
}

@media (min-width: 720px) {
  .fuss-spalten {
    grid-template-columns: 1.5fr 1fr 1fr;
  }
}

.fuss .meta {
  margin: 0 0 0.5rem;
}

.fuss-liste {
  list-style: none;
  margin: 0 0 1.75rem;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.fuss-liste a {
  color: var(--text);
  text-decoration: none;
}

.fuss-liste a:hover {
  color: var(--patina-tief);
  text-decoration: underline;
}

/* --------------------------------------------------------------- Startseite */

/* Der Hero: das Kurhaus als Standbild, darin der Textblock unten links.
   Zwei Ebenen, kein Canvas und kein Skript: das Foto als <img> (LCP) und
   darueber die Typografie. Die Hoehe ist so gewaehlt, dass die naechste
   Sektion immer angeschnitten stehen bleibt.

   Beim Scrollen bleibt der Hero stehen, in voller Breite und ohne jede
   Formaenderung. Er steht vor dem Hauptteil; Hauptteil und Fuss liegen
   darueber (.nach-hero, deckendes Weiss) und schieben sich von unten ueber
   das Bild wie ein Vorhang, bis zum Seitenende. Das ist reines Layout und
   gilt in jedem Browser.

   Bewegung darauf, nur ohne prefers-reduced-motion und nur mit CSS
   scroll-driven animations; kennt der Browser sie nicht, entfallen sie
   ersatzlos, der Hero bleibt aber stehen:
   - Zoomfahrt: das Foto faehrt in 24 s von 1,00 auf 1,06 und leicht nach
     unten, dann in 24 s zurueck, endlos alternierend. Laeuft unabhaengig.
   - Tiefe: der Textblock wandert mit 0,75 der Scrollgeschwindigkeit nach
     oben und blendet ueber die ersten 50 % der Herohoehe aus.
   - Schleier: ueber die letzten 30 % legt sich Schwarz von 0 auf 45 %, das
     Bild tritt zurueck, statt hart verdeckt zu werden. */

.hero {
  --hero-hoehe: min(88svh, 900px);
  position: sticky;
  top: 0;
  z-index: 0;
  height: var(--hero-hoehe);
  overflow: hidden;
  background: var(--flaeche);
  color: var(--weiss);
}

/* Alles nach dem Hero ist der Vorhang: eine geschlossene weisse Flaeche
   ueber dem Hero, die Hauptteil und Fuss enthaelt und bis zum Seitenende
   reicht. Der Sektionsabstand steckt im Polster des Vorhangs, nicht im
   Aussenabstand der ersten Sektion - sonst bliebe dort ein Streifen
   durchsichtig und das Bild schiene hindurch. Der Fuss liegt mit seinem
   Aussenabstand ebenfalls im Vorhang. */
.nach-hero {
  position: relative;
  z-index: 1;
  background: var(--weiss);
  padding-top: var(--sektion);
}

.nach-hero > main > .sektion:first-child {
  margin-top: 0;
}

.hero-buehne {
  position: absolute;
  inset: 0;
  margin: 0;
}

.hero-foto {
  position: absolute;
  inset: 0;
  display: block;
}

.hero-foto img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 50% 0%;
}

@media (aspect-ratio <= 1) {
  .hero-foto img {
    object-position: 60% 50%;
  }
}

/* Weicher Verlauf von unten, damit Weiss auf dem Foto traegt. Dazu ein
   zweiter, flacher Verlauf von links: der Textblock steht links, das Kurhaus
   in der Bildmitte bleibt so frei. Die Werte sind nachgemessen, nicht
   geschaetzt; erst mit ihnen liegt jedes Textpixel ueber 4,5:1 (Briefing 8).
   Der seitliche Verlauf endet nach 1200 px, damit er auf breiten Schirmen
   nicht ueber das ganze Bild laeuft, auf Mobil aber die volle Breite deckt. */
.hero-buehne::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to top, rgba(0, 0, 0, 0.85), rgba(0, 0, 0, 0) 72%),
    linear-gradient(to right, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0) min(100%, 1200px));
  pointer-events: none;
}

/* Der Schleier liegt ueber allem im Hero, auch ueber Typografie und
   Bildunterschrift: der ganze Hero tritt zurueck, nicht nur das Foto.
   Ohne scroll-driven animations bleibt er unsichtbar. */
.hero::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 2;
  background: #000;
  opacity: 0;
  pointer-events: none;
}

/* Bildunterschrift und Giebelinschrift unten rechts am Inhaltsrand. Sie
   gehoert zum Bild, liegt aber ueber dem Verlauf: sonst dunkelt der Verlauf
   die Schrift mit ab. */
.hero-fuss {
  position: absolute;
  z-index: 1;
  right: max(var(--rand), calc((100% - var(--breite)) / 2 + var(--rand)));
  bottom: 1rem;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.1rem 1.25rem;
  text-align: right;
  color: rgba(255, 255, 255, 0.75);
}

/* Der Textblock steht unten links am Inhaltsrand: Zeile, Wort, Name, Knoepfe. */
.hero-typo {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  pointer-events: none;
}

.hero-block {
  padding-bottom: clamp(3.5rem, 8vh, 5rem);
}

.hero-titel {
  margin: 0;
  color: var(--weiss);
  font-weight: 400;
  letter-spacing: 0;
  text-shadow: 0 2px 24px rgba(0, 0, 0, 0.28);
}

.hero-zeile {
  display: block;
  font-family: var(--schrift);
  font-size: clamp(0.875rem, 1.2vw, 1.125rem);
  font-weight: 500;
  letter-spacing: 0.18em;
  padding-left: 0.1em;
  text-transform: uppercase;
  line-height: 1.3;
  margin-bottom: clamp(0.5rem, 1.2vh, 0.9rem);
}

.hero-wort {
  display: block;
  font-family: var(--schrift-display);
  font-size: clamp(3.25rem, 9vw, 8.5rem);
  line-height: 0.92;
  text-wrap: nowrap;
}

/* Die Buchstaben der Animation sind leer; ihr Zeichen kommt aus
   data-zeichen. Der Text der Ueberschrift steht daneben einmal als
   Textknoten (.nur-fuer-screenreader), damit die h1 nicht doppelt liest. */
.hero-buchstabe {
  display: inline-block;
}

.hero-buchstabe::before {
  content: attr(data-zeichen);
}

.hero-unterzeile {
  margin: clamp(1rem, 2.4vh, 1.75rem) 0 clamp(1.25rem, 3vh, 2rem);
  font-size: 1.125rem;
  line-height: 1.5;
  max-width: 44ch;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}

.hero-knoepfe {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  pointer-events: auto;
}

/* Sekundaerer Knopf im Bild: weisser Rahmen auf durchsichtigem Grund,
   im Hover weisse Flaeche mit dunklem Text. */
.hero .knopf-sekundaer {
  background: transparent;
  border-color: var(--weiss);
  color: var(--weiss);
}

.hero .knopf-sekundaer:hover {
  background: var(--weiss);
  border-color: var(--weiss);
  color: var(--text);
}

.hero :focus-visible {
  outline-color: var(--weiss);
}

@media (max-width: 719px) {
  .hero-block {
    padding-bottom: 4.5rem;
  }

  .hero-knoepfe {
    flex-direction: column;
  }

  .hero-knoepfe .knopf {
    text-align: center;
  }
}

/* Auftritt beim Laden, einmalig: die Buchstaben von Wiesbaden je 40 ms
   versetzt aus 20 px und leichter Unschaerfe, Zeile, Name, Knoepfe und
   Bildunterschrift 200 ms danach. Ohne Auftritt steht alles sofort. */

@keyframes hero-buchstabe-ein {
  from {
    opacity: 0;
    transform: translateY(20px);
    filter: blur(8px);
  }
  to {
    opacity: 1;
    transform: none;
    filter: blur(0);
  }
}

@keyframes hero-zeile-ein {
  from {
    opacity: 0;
    transform: translateY(12px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* Die Zoomfahrt: nur transform, 24 s hin, 24 s zurueck, endlos. */
@keyframes hero-zoom {
  from {
    transform: scale(1) translateY(0);
  }
  to {
    transform: scale(1.06) translateY(1.2%);
  }
}

/* Der Textblock wandert schneller nach oben als der stehende Hero: ueber die
   volle Herohoehe um 0,75 davon. Daraus entsteht die Tiefe. */
@keyframes hero-block-wandern {
  from {
    transform: translateY(0);
  }
  to {
    transform: translateY(calc(-0.75 * var(--hero-hoehe)));
  }
}

@keyframes hero-block-aus {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes hero-schleier {
  from {
    opacity: 0;
  }
  to {
    opacity: 0.45;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .hero-buchstabe {
    animation: hero-buchstabe-ein 880ms cubic-bezier(0.2, 0.7, 0.2, 1) both;
  }

  .hero-buchstabe:nth-child(2) { animation-delay: 40ms; }
  .hero-buchstabe:nth-child(3) { animation-delay: 80ms; }
  .hero-buchstabe:nth-child(4) { animation-delay: 120ms; }
  .hero-buchstabe:nth-child(5) { animation-delay: 160ms; }
  .hero-buchstabe:nth-child(6) { animation-delay: 200ms; }
  .hero-buchstabe:nth-child(7) { animation-delay: 240ms; }
  .hero-buchstabe:nth-child(8) { animation-delay: 280ms; }
  .hero-buchstabe:nth-child(9) { animation-delay: 320ms; }
  .hero-buchstabe:nth-child(n + 10) { animation-delay: 360ms; }

  .hero-zeile,
  .hero-unterzeile,
  .hero-knoepfe,
  .hero-fuss {
    animation: hero-zeile-ein 800ms 200ms var(--kurve) both;
  }

  .hero-foto img {
    animation: hero-zoom 24s ease-in-out infinite alternate;
  }
}

/* Beides haengt am Scrollfortschritt des Dokuments, nicht an einer Uhr und
   nicht an einem Scroll-Handler. Ohne Unterstuetzung entfaellt es ersatzlos. */
@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .hero-block {
      animation-name: hero-block-wandern, hero-block-aus;
      animation-duration: auto, auto;
      animation-timing-function: linear, linear;
      animation-fill-mode: both, both;
      animation-timeline: scroll(root block), scroll(root block);
      animation-range: 0 var(--hero-hoehe), 0 calc(0.5 * var(--hero-hoehe));
    }

    .hero::after {
      animation-name: hero-schleier;
      animation-duration: auto;
      animation-timing-function: linear;
      animation-fill-mode: both;
      animation-timeline: scroll(root block);
      animation-range: calc(0.7 * var(--hero-hoehe)) var(--hero-hoehe);
    }
  }
}

/* Wiesbaden at its finest: die Lesestrecke unter dem Hero (Nachtrag 12.9).
   Ueberschrift in Instrument Serif, Zwischentitel kursiv, eine Haarlinie
   zwischen den Stationen mit gleichem Abstand darueber und darunter.
   Die Lesespalte ist 62 Zeichen Fliesstext breit (Ueberschrift, Vorspann,
   Stationen und Link teilen sie) und steht ab 1000 px mittig im Raster.
   Die Bilder stehen dort als Float rechts in ihrer Station, buendig zur
   Oberkante des Zwischentitels, und ragen um ein Drittel ihrer Breite ueber
   den rechten Rand der Spalte hinaus; Zwischentitel und Absatz laufen in der
   Spalte an ihnen entlang. Die Station schliesst den Float ein, die
   Haarlinie liegt unter Text und Bild. Unter 1000 px stehen die Bilder in
   voller Breite zwischen Zwischentitel und Absatz, ohne Parallax; weil das
   Bild im Markup vor dem Zwischentitel steht, stellt ein Flex-Container
   dort die Reihenfolge her. */

.finest {
  --finest-abstand: clamp(2.5rem, 5vw, 4rem);
  --finest-bildbreite: 20rem;
}

.finest-lese {
  max-width: 62ch;
}

.finest-titel {
  font-family: var(--schrift-display);
  font-size: clamp(2.75rem, 6vw, 5rem);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1;
  margin: 0 0 clamp(2rem, 4vw, 3.5rem);
}

.finest-vorspann {
  font-size: 1.25rem;
  line-height: 1.5;
  margin: 0 0 clamp(3rem, 6vw, 5rem);
}

.finest-station {
  margin-bottom: var(--finest-abstand);
}

.finest-station:last-child {
  margin-bottom: 0;
}

.finest-station-text {
  display: flex;
  flex-direction: column;
  padding-bottom: var(--finest-abstand);
  border-bottom: 1px solid var(--linie);
}

.finest-station:last-child .finest-station-text {
  padding-bottom: 0;
  border-bottom: 0;
}

.finest-station-titel {
  order: -1;
  font-family: var(--schrift-display);
  font-style: italic;
  font-size: 1.75rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.15;
  margin: 0 0 0.75rem;
}

.finest-station-text p {
  margin-bottom: 0;
}

/* Im Flex-Container fallen Raender nicht zusammen: 0,75 rem unter dem
   Zwischentitel plus 0,75 rem ueber dem Bild ergeben 1,5 rem. */
.finest-bild {
  margin: 0.75rem 0 1.75rem;
}

.finest-link {
  margin-top: var(--finest-abstand);
}

@media (min-width: 1000px) {
  .finest-lese {
    margin-inline: auto;
  }

  /* flow-root schliesst den Float ein: die Station ist so hoch wie Text
     oder Bild, die Haarlinie liegt unter beidem. */
  .finest-station-text {
    display: flow-root;
  }

  /* Float rechts, ein Drittel der Breite ragt ueber den Spaltenrand hinaus
     (negativer rechter Rand). Der obere Rand richtet die Bildkante auf die
     Versalhoehe des Zwischentitels aus. */
  .finest-bild {
    float: right;
    width: var(--finest-bildbreite);
    margin: 0.25rem calc(var(--finest-bildbreite) / -3) 1rem 2rem;
  }

  /* Leichter Parallax: die Bilder laufen mit 0,9 der Scrollgeschwindigkeit.
     Waehrend ein Bild das Fenster durchquert (Fensterhoehe plus eigene
     Hoehe), bleibt es um ein Zehntel davon zurueck: von -5 % oben nach +5 %
     unten, linear am Sichtfortschritt des Bildes. Nur transform, kein
     Scroll-Handler; ohne Unterstuetzung oder bei reduzierter Bewegung
     entfaellt es ersatzlos. */
  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .finest-bild {
        animation-name: finest-parallax;
        animation-duration: auto;
        animation-timing-function: linear;
        animation-fill-mode: both;
        animation-timeline: view(block);
      }
    }
  }
}

@keyframes finest-parallax {
  from {
    transform: translateY(calc(-5vh - 5%));
  }
  to {
    transform: translateY(calc(5vh + 5%));
  }
}

.ueber-raster {
  display: grid;
  gap: 2.5rem;
}

@media (min-width: 720px) {
  .ueber-raster {
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--spalte);
  }

  .ueber-raster .portraet {
    grid-column: 1 / 5;
  }

  .ueber-text {
    grid-column: 5 / 13;
  }
}

@media (min-width: 900px) {
  .ueber-raster .portraet {
    grid-column: 1 / 4;
  }

  .ueber-text {
    grid-column: 5 / 12;
  }
}

/* Persoenlicher Text auf /ueber-mich unter den Fakten, Lauftext in der
   Lesespalte, darunter der Name als Unterschrift in Instrument Serif
   kursiv, mit Abstand zum letzten Absatz. */
.persoenlich {
  margin-top: 2.5rem;
}

.unterschrift {
  font-family: var(--schrift-display);
  font-style: italic;
  font-size: 1.75rem;
  line-height: 1.2;
  margin: 2rem 0 0;
}

/* --------------------------------------------------------------- Fuehrungen
   Der Kasten ist Bild plus Text auf Weiss, ohne Rahmen. Hover: Bild
   skaliert im beschnittenen Container, der Titel bekommt eine
   Unterstreichung, die von links einlaeuft. */

.touren-raster {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 3.5rem var(--spalte);
}

@media (min-width: 640px) {
  .touren-raster {
    grid-template-columns: repeat(2, 1fr);
  }
}

/* Ab 1000 px drei Spalten: die sechs Fuehrungen stehen dann in zwei vollen
   Reihen, keine Reihe endet mit einer einzelnen Karte. */
@media (min-width: 1000px) {
  .touren-raster {
    grid-template-columns: repeat(3, 1fr);
  }
}

.tourenkasten-link {
  display: block;
  color: var(--text);
  text-decoration: none;
}

.tourenkasten-link:hover {
  color: var(--text);
}

.tourenkasten-link:hover img {
  transform: scale(1.03);
}

/* Titel in Instrument Serif Italic, dieselbe Sprache wie die H1 der
   Tourenseite (Nachtrag 12.9). */
.tourenkasten-titel {
  font-family: var(--schrift-display);
  font-style: italic;
  font-size: 1.5rem;
  font-weight: 400;
  letter-spacing: 0;
  line-height: 1.15;
  margin: 1.25rem 0 0.25rem;
}

.tourenkasten-titel span {
  background-image: linear-gradient(var(--patina), var(--patina));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 2px;
  padding-bottom: 2px;
  transition: background-size var(--tempo) var(--kurve);
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

.tourenkasten-link:hover .tourenkasten-titel span {
  background-size: 100% 2px;
}

.tourenkasten-untertitel {
  margin: 0 0 0.75rem;
}

.tourenkasten-kurz {
  margin: 0 0 0.75rem;
}

.tourenkasten-eckdaten {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  margin: 0;
}

/* --------------------------------------------------------------- Tourenseite
   Nachtrag 12.9: Titel in Instrument Serif Italic; ab 1000 px links Text
   und Route (Spalten 1 bis 7), rechts Eckdaten und Anfrage (9 bis 12) in
   einer Spalte, die beim Lesen mitlaeuft. Unter 1000 px einspaltig in der
   Reihenfolge Titel, Eckdaten, Route, Anfrage: die Seitenspalte loest sich
   dafuer in ihre beiden Teile auf (display: contents), die Reihen sind
   ausdruecklich vergeben. */

.tour-kopf {
  padding-top: 1.5rem;
}

.tour-kopf > .meta {
  margin: 0 0 1.25rem;
}

.tour-raster {
  display: grid;
  gap: 3rem;
  padding-top: clamp(2rem, 5vw, 4rem);
}

@media (max-width: 999px) {
  .tour-seite {
    display: contents;
  }

  .tour-text {
    grid-row: 1;
  }

  /* Der Unterrand der Eckdaten gilt der Seitenspalte; mobil traegt der
     Rasterabstand. */
  .tour-seite .eckdaten {
    grid-row: 2;
    margin-bottom: 0;
  }

  .tour-route {
    grid-row: 3;
  }

  .tour-anfrage {
    grid-row: 4;
  }

  /* Ohne Route rueckt die Anfrage nach, sonst bliebe eine leere Reihe
     samt Rasterabstand. */
  .tour-raster-ohne-route .tour-anfrage {
    grid-row: 3;
  }
}

@media (min-width: 1000px) {
  .tour-raster {
    grid-template-columns: repeat(12, 1fr);
    column-gap: var(--spalte);
  }

  .tour-text {
    grid-column: 1 / 8;
    grid-row: 1;
  }

  .tour-route {
    grid-column: 1 / 8;
    grid-row: 2;
  }

  /* Sticky unter dem Kopf: Kopfhoehe rund 5,5 rem (Polster, Name, Rolle,
     Linie) plus 1,5 rem Luft. align-self: start, sonst fuellt die Spalte
     beide Reihen und kann nicht mitlaufen. */
  .tour-seite {
    grid-column: 9 / 13;
    grid-row: 1 / 3;
    align-self: start;
    position: sticky;
    top: 7rem;
  }

  .tour-raster-ohne-route .tour-seite {
    grid-row: 1;
  }
}

/* Die H1 der Tourenuebersicht spricht dieselbe Sprache wie die Tourentitel. */
.tour-titel,
.seitenkopf-titel {
  font-family: var(--schrift-display);
  font-style: italic;
  font-size: clamp(2.75rem, 6vw, 5rem);
  font-weight: 400;
  letter-spacing: -0.01em;
  line-height: 1;
  margin-bottom: 0.75rem;
}

.tour-untertitel {
  margin: 0 0 2rem;
}

.tour-route h2 {
  font-size: var(--gr-h3);
  margin: 0 0 1.25rem;
}

/* Touren ohne feste Route: normaler Absatz statt Zeitleiste, gleicher
   Unterrand wie die Route (Nachtrag 12.13). */
.tour-verlauf {
  margin-bottom: 1.5rem;
}

/* Die Route als Zeitleiste: 1-px-Linie in --linie, Punkte 8 px in
   --patina, Stationsnamen kursiv. Treffpunkt und Endpunkt in Meta-Schrift
   unter dem Namen. */
.route {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 0;
  max-width: 62ch;
}

.route li {
  position: relative;
  padding: 0 0 1.5rem 1.75rem;
  font-size: 1.25rem;
  line-height: 1.3;
}

.route li:last-child {
  padding-bottom: 0;
}

.route li::before {
  content: '';
  position: absolute;
  left: 0;
  top: calc(0.65em - 4px);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--patina);
}

.route li::after {
  content: '';
  position: absolute;
  left: 3.5px;
  top: calc(0.65em + 6px);
  bottom: -2px;
  width: 1px;
  background: var(--linie);
}

.route li:last-child::after {
  display: none;
}

.route-ort {
  display: block;
  font-family: var(--schrift-display);
  font-style: italic;
}

.route-rolle {
  display: block;
  margin-top: 0.1rem;
}

.eckdaten {
  margin: 0 0 2.5rem;
  border-top: 1px solid var(--linie);
}

.eckdaten dt {
  font-size: var(--gr-meta);
  color: var(--text-2);
  padding-top: 0.75rem;
}

.eckdaten dd {
  margin: 0.1rem 0 0.75rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px solid var(--linie);
}

/* Zweite Zeile unter einem Wert, etwa "Kinder bis 12 Jahre frei". */
.eckdaten-zusatz {
  display: block;
  margin-top: 0.15rem;
}

.kontakt-zeile {
  margin: 0 0 0.25rem;
  font-weight: 500;
}

.kontakt-zeile a {
  color: var(--text);
  text-decoration-color: var(--linie);
}

.kontakt-zeile a:hover {
  text-decoration-color: var(--patina);
}

/* Weitere Fuehrungen: drei Kaesten wie auf der Uebersicht, durch eine
   Haarlinie vom Artikel abgesetzt. Die Linie liegt als ::before im
   Inhaltsbereich, damit sie an der Inhaltskante endet, nicht am Bahnrand. */
.weitere-fuehrungen::before {
  content: '';
  display: block;
  border-top: 1px solid var(--linie);
  margin-bottom: clamp(2rem, 5vw, 3.5rem);
}

.weitere-fuehrungen h2 {
  margin-bottom: 2rem;
}

/* ----------------------------------------------------------------- Ueber mich */

/* Die beiden Zeichen nebeneinander, mittig, 56 px hoch, unveraendert:
   keine Einfaerbung, kein Rahmen, kein farbiger Grund. Mobil bricht die
   Zeile um, statt die Logos zu stauchen. */
.logos-liste {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: clamp(2rem, 6vw, 4rem);
  align-items: center;
  justify-content: center;
}

.logos-liste img {
  display: block;
  height: 56px;
  width: auto;
}

.logo-platzhalter {
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  width: min(100%, 220px);
  height: 88px;
  padding: 0.75rem;
  border: 1px solid var(--linie);
}

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

.kontakt-gross {
  margin: 0 0 0.3rem;
  font-size: clamp(1.5rem, 3.5vw, 2.75rem);
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.2;
  max-width: none;
  overflow-wrap: anywhere;
}

.kontakt-gross a {
  color: var(--text);
  text-decoration-thickness: 2px;
  text-decoration-color: var(--linie);
  text-underline-offset: 0.15em;
}

.kontakt-gross a:hover {
  text-decoration-color: var(--patina);
}

.kontakt-seite .kontaktzeilen {
  margin-block: clamp(2rem, 6vw, 5rem);
}

/* Der WhatsApp-Link unter den grossen Zeilen, in Lauftextgroesse. */
.kontakt-whatsapp {
  margin: 1rem 0 0;
}

/* -------------------------------------------------------------------- Bewegung
   Sektionen erscheinen beim Scrollen mit 12 px Versatz, 600 ms, einmalig.
   Ohne Skript und bei reduzierter Bewegung ist alles sofort sichtbar. */

.einblenden {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--tempo) var(--kurve), transform var(--tempo) var(--kurve);
}

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

@media (scripting: none) {
  .einblenden {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
  }

  .einblenden,
  .bild img.laedt {
    opacity: 1;
    transform: none;
  }

  .tourenkasten-link:hover img {
    transform: none;
  }
}
