:root {
  --ink: #102f46;
  --muted: #61717e;
  --paper: #f8f1e5;
  --sand: #ead9bc;
  --water: #c7e4e5;
  --teal: #14777c;
  --gold: #c98624;
  --coral: #de6246;
  --navy: #102f46;
  --night: #071b28;
  --card: #fffaf0;
  --line: rgba(16, 47, 70, 0.16);

  /* Seitenrand aller Inhaltsbereiche, je Seite. Eine Stellschraube für
     Reiseseiten und Startseite; auf schmalen Fenstern weiter unten kleiner. */
  --gutter: 2.5rem;

  /* Höhe von Topnav plus Tagesleiste. Beide liegen über dem Inhalt, deshalb
     braucht jedes Sprungziel denselben Abstand nach oben (scroll-margin-top). */
  --stick: 8.6rem;

  /* Wo die Tagesleiste hängen bleibt. Solange die Topnav sichtbar ist, unter
     ihrer Unterkante; sobald sie beim Herunterscrollen verschwindet, rückt die
     Leiste in die frei gewordene Höhe nach – sonst schwebt sie mitten im Bild
     über einer leeren Stelle. Den Zustand setzt bindNavAutoHide in app.js. */
  --tabs-top: 4.6rem;

  /* Innenabstand der Karten. Als Variable, weil der zugeklappte und der
     aufgeklappte Teil einer Karte denselben Wert brauchen – sonst springt
     der Text beim Öffnen um ein paar Pixel. */
  --day-pad: 1.6rem;
  /* Seitliches Polster im Aufklapper. Der Wert entspricht dem, was vorher hart
     in .stop-details stand; die Lesebahn weiter unten rechnet damit. */
  --stop-pad: 1rem;

  /* Geometrie der Zeitachse: Breite der Achsenspalte und Abstand zum Text.
     Als Variablen, weil die Lesebahn genau auf der Mitte der Achslinie enden
     muss – eine hart geschriebene Zahl würde beim nächsten Feinschliff der
     Achse still auseinanderlaufen. */
  --rail: 3.6rem;
  --rail-gap: 0.9rem;

  /* Farbe des randlosen Einleitungsbands. Kühl getönt, damit es sich vom warmen
     Seitenverlauf und von den hellen Karten darunter absetzt. */
  --band: rgba(199, 228, 229, 0.42);
}

/* Nur die Position der Tagesleiste hängt am Scrollzustand. Die drei Variablen
   darüber standen versehentlich hier drin: Da das Attribut erst beim ersten
   Scrollen gesetzt wird und beim Hochscrollen auf "visible" wechselt, waren
   --day-pad, --stop-pad und --band auf Desktopbreiten beim Laden undefiniert.
   Eine undefinierte Variable macht die ganze Deklaration ungültig – Kartenpolster
   fiel auf 0, das Einleitungsband wurde durchsichtig, und beides flackerte beim
   Scrollen. Auf schmalen Fenstern fiel es nicht auf, weil die Medienabfrage
   weiter unten alle drei in :root neu setzt. */
:root[data-nav="hidden"] {
  --tabs-top: 0.5rem;
}

* {
  box-sizing: border-box;
}

/* Das hidden-Attribut muss gewinnen. Die Regel dafür steht nur im Stylesheet des
   Browsers, und jede eigene display-Angabe schlägt sie – unabhängig von der
   Spezifität, weil Autorenregeln vor Browserregeln kommen. Genau dadurch waren
   beide Wetterzeilen gleichzeitig sichtbar: `.weather-line` setzt display: flex,
   also blieb das gesetzte hidden ohne Wirkung.

   Die Regel gilt absichtlich für alles, was hidden benutzt – Wetterzeilen,
   Tageskarten und Aufklapper –, damit derselbe Fehler nicht wiederkehrt. */
[hidden] {
  display: none !important;
}

/* Beim Antippen legen mobile Browser eine blaue Fläche über das getroffene
   Element – beim Aufklappen eines Stops blitzte dadurch der ganze zugeklappte
   Bereich kurz blau auf. Die Rückmeldung übernimmt stattdessen die :active-Regel
   weiter unten, die nur den Titel kurz eindrückt. */
a,
button {
  -webkit-tap-highlight-color: transparent;
}

/* Hinweis bei gesetztem ?heute= oder ?jetzt=. Fest am unteren Rand, damit er
   weder die Navigationsleiste noch die Sprungziele stört – und auffällig genug,
   dass eine Testansicht nicht mit der Wirklichkeit verwechselt wird. */
.test-hint {
  position: fixed;
  left: 50%;
  bottom: 0.7rem;
  transform: translateX(-50%);
  z-index: 30;
  margin: 0;
  max-width: calc(100% - 1.4rem);
  padding: 0.5rem 0.9rem;
  border-radius: 999px;
  background: var(--coral);
  color: white;
  font-size: 0.72rem;
  font-weight: 900;
  letter-spacing: 0.04em;
  text-align: center;
  box-shadow: 0 0.6rem 1.6rem rgba(7, 27, 40, 0.3);
}

.test-hint a {
  text-decoration: underline;
}

/* scroll-behavior steht hier absichtlich nicht mehr: global gesetzt galt es auch
   für jedes scrollIntoView nach dem Aufklappen. Es wird jetzt pro Aufruf gesetzt. */
html {
  background: var(--paper);
}

body {
  margin: 0;
  color: var(--ink);
  background:
    radial-gradient(circle at top left, rgba(20, 119, 124, 0.2), transparent 32rem),
    linear-gradient(180deg, #fff8eb 0%, #f2e2c6 48%, #dcecee 100%);
  font-family: "Bahnschrift", "Aptos", "Trebuchet MS", sans-serif;
}

a {
  color: inherit;
}

/* Früher stand hier `main { overflow: hidden }`. Das machte `position: sticky`
   in jedem Kind unwirksam – eine mitlaufende Tagesleiste war damit unmöglich.
   Beschnitten wird jetzt nur dort, wo wirklich ein Bild übersteht. */
.hero {
  min-height: 100svh;
  position: relative;
  display: grid;
  align-items: end;
  padding: 1rem;
  overflow: clip;
  color: white;
  isolation: isolate;
}

.hero-bg,
.hero-shade {
  position: absolute;
  inset: 0;
  z-index: -2;
}

.hero-bg {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero-shade {
  z-index: -1;
  background:
    linear-gradient(180deg, rgba(7, 27, 40, 0.18), rgba(7, 27, 40, 0.82)),
    radial-gradient(circle at 80% 20%, rgba(222, 98, 70, 0.42), transparent 18rem);
}

.topnav {
  position: fixed;
  top: 0.7rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 20;
  display: flex;
  gap: 0.35rem;
  padding: 0.38rem;
  border: 1px solid rgba(255, 255, 255, 0.25);
  border-radius: 999px;
  background: rgba(7, 27, 40, 0.76);
  backdrop-filter: blur(16px);
  box-shadow: 0 0.8rem 2rem rgba(7, 27, 40, 0.28);
  transition: transform 240ms ease, opacity 240ms ease;
}

/* Beim Herunterscrollen weggeschoben (siehe bindNavAutoHide in app.js).
   translateX(-50%) muss erhalten bleiben, es zentriert die Leiste. */
.topnav[data-hidden="true"] {
  transform: translateX(-50%) translateY(calc(-100% - 1.4rem));
  opacity: 0;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .topnav,
  .day-tabs {
    transition: none;
  }
}

/* 44 px Mindesthöhe: drei Ziele liegen hier direkt nebeneinander. */
.topnav a {
  display: flex;
  min-width: 3.9rem;
  min-height: 44px;
  align-items: center;
  justify-content: center;
  padding: 0.3rem 0.7rem;
  border-radius: 999px;
  color: white;
  font-size: 0.76rem;
  font-weight: 800;
  text-align: center;
  text-decoration: none;
}

.topnav a:active,
.topnav a:hover {
  background: rgba(255, 255, 255, 0.18);
}

.hero-copy {
  max-width: 45rem;
  margin: 0 auto;
  padding: 8rem 1rem 3.4rem;
  animation: rise 0.8s ease-out both;
}

.eyebrow {
  margin: 0 0 0.8rem;
  color: var(--teal);
  font-size: 0.78rem;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.hero .eyebrow {
  color: #ffde9c;
}

h1,
h2,
h3 {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  letter-spacing: -0.055em;
  line-height: 0.94;
  overflow-wrap: break-word;
}

h1 {
  max-width: 12ch;
  font-size: clamp(3.9rem, 18vw, 7.5rem);
}

h2 {
  font-size: clamp(2.5rem, 12vw, 4.8rem);
}

h3 {
  font-size: clamp(1.65rem, 7vw, 3.1rem);
}

p {
  line-height: 1.55;
}

.hero-copy > p:not(.eyebrow) {
  max-width: 34rem;
  font-size: 1.08rem;
  color: rgba(255, 255, 255, 0.88);
}

.hero-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.65rem;
  margin-top: 1.4rem;
}

.hero-stats span {
  padding: 0.9rem 0.8rem;
  border: 1px solid rgba(255, 255, 255, 0.2);
  border-radius: 1.15rem;
  background: rgba(255, 255, 255, 0.13);
  backdrop-filter: blur(12px);
  font-size: 0.72rem;
  font-weight: 800;
}

.hero-stats b {
  display: block;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 2.1rem;
  line-height: 1;
}

.section {
  width: min(72rem, calc(100% - 2 * var(--gutter)));
  margin: 0 auto;
  padding: 4.2rem 0;
  scroll-margin-top: var(--stick);
}

/* Der Einleitungsblock ist ein durchgehendes Farbband statt eines Kastens: Der
   Text behält die Inhaltsbreite der Seite, die Fläche läuft bis an beide
   Bildschirmränder. Vorher stand hier ein 1px-Rahmen – zusammen mit
   `padding: 4.2rem 0` in `.section` lag der Text ohne Abstand auf der Linie.

   Umgesetzt über einen sehr weiten Schattenrand statt über 100vw: Das verändert
   die Breite des Elements nicht und erzeugt deshalb keine waagrechte
   Bildlaufleiste. clip-path beschneidet oben und unten, damit das Band genau an
   der Ober- und Unterkante endet. */
.intro {
  padding-top: 4.8rem;
  background: var(--band);
  box-shadow: 0 0 0 100vmax var(--band);
  clip-path: inset(0 -100vmax);
}

.intro p:last-child,
.section-head p {
  max-width: 42rem;
  color: var(--muted);
  font-size: 1.02rem;
}

.weather-grid {
  display: grid;
  /* auto-fit statt fester Spaltenzahl: die Reisen haben unterschiedlich viele Tage.
     Die Kartenbreite ist begrenzt, damit zwei Tage keine 570-Pixel-Kacheln ergeben. */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 0.8rem;
  margin-top: 1.4rem;
}

.weather-card,
.day-card {
  border: 1px solid var(--line);
  box-shadow: 0 1.1rem 2.8rem rgba(16, 47, 70, 0.09);
}

/* Die Stops eines Tages sind eine durchgehende Zeitachse: links Uhrzeit und
   Bildmarke auf der Linie, rechts Titel, Kurztext und die Fakten im Aufklapper.
   Deshalb hat der einzelne Stop keine eigene Kartenkontur mehr - die Tageskarte
   ist der Rahmen, die Linie hält die Reihenfolge zusammen. */
.stops {
  display: grid;
  gap: 0;
  margin-top: 1.4rem;
  /* Bezugsrahmen für die Containerabfrage der Lesebahn: Sie soll auf die Breite
     der Stop-Spalte reagieren, nicht auf die des Fensters. Sonst bräuchte es
     eine dritte Bruchstelle in der Fensterskala, und bei starkem Zoom griffe
     die Regel nicht. */
  container-type: inline-size;
  container-name: stops;
}

.stop-card {
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  gap: 0 var(--rail-gap);
  scroll-margin-top: var(--stick);
}

.stop-rail {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
}

.stop-time {
  padding-top: 0.15rem;
  color: var(--teal);
  font-size: 0.85rem;
  font-variant-numeric: tabular-nums;
  font-weight: 900;
  line-height: 1;
}

.stop-mark {
  position: relative;
  z-index: 1;
  display: block;
  flex: none;
  width: 2.6rem;
  height: 2.6rem;
  border: 2px solid var(--card);
  border-radius: 50%;
  box-shadow: 0 0 0 2px rgba(20, 119, 124, 0.55);
  object-fit: cover;
  /* box-shadow mit, damit der Ring des offenen Stops mitwächst statt zu springen. */
  transition: transform 220ms ease, box-shadow 220ms ease;
}

.stop-card:hover .stop-mark {
  transform: scale(1.06);
}

/* flex: 1 lässt die Linie bis zum unteren Rand des Stops laufen - dadurch
   schließt sie ohne Lücke an die Bildmarke des nächsten Stops an. */
/* Achslinie und Bildmarke liegen eine Stapelebene höher als der Inhalt: Die
   Lesebahn steht im Dokument nach der Achse und hat eine deckende Fläche, würde
   die Linie also überdecken. Mit z-index läuft sie sichtbar über die Bahn, und
   der Lesetext hängt an ihr. */
.stop-line {
  position: relative;
  z-index: 1;
  flex: 1;
  width: 2px;
  min-height: 0.9rem;
  border-radius: 1px;
  background: rgba(20, 119, 124, 0.22);
}

/* Am letzten Stop läuft die Achse aus, statt ins Leere zu stoßen. */
.stop-card:last-child .stop-line {
  background: linear-gradient(rgba(20, 119, 124, 0.22), rgba(20, 119, 124, 0));
}

.stop-main {
  min-width: 0;
  padding-bottom: 1.5rem;
}

.stop-toggle {
  display: block;
  width: 100%;
  min-height: 2.75rem;
  padding: 0;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  background: transparent;
  cursor: pointer;
}

.stop-toggle:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 4px;
  border-radius: 0.6rem;
}

.stop-toggle:hover .stop-title {
  color: var(--teal);
}

/* Kurztext direkt in der Liste: der Tag ist damit lesbar, ohne etwas zu öffnen. */
.stop-lead {
  display: block;
  margin-top: 0.35rem;
  color: var(--muted);
  font-size: 0.95rem;
  line-height: 1.45;
  text-wrap: pretty;
}

.stop-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.stop-chips span {
  padding: 0.25rem 0.5rem;
  border-radius: 0.4rem;
  background: rgba(16, 47, 70, 0.07);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 900;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Die UID ist die Klammer zum Kalendereintrag, aber keine Reiseinformation.
   Sie steht deshalb ganz unten in der geöffneten Karte, nicht in der Übersicht. */
/* .stop-details .uid statt .uid: sonst gewinnt die allgemeine `.stop-details p`-Regel. */
.stop-details .uid {
  margin-top: 1rem;
  padding-top: 0.7rem;
  border-top: 1px dashed var(--line);
  color: var(--muted);
  font-size: 0.7rem;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-align: right;
  text-transform: uppercase;
}

.stop-heading {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 0.55rem;
}

.stop-title {
  display: block;
  min-width: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 1.35rem;
  line-height: 1.08;
  overflow-wrap: anywhere;
  transition: color 160ms ease;
}

.stop-chevron {
  flex: 0 0 auto;
  color: var(--teal);
  font-size: 1.45rem;
  font-weight: 900;
  line-height: 0.9;
  transition: transform 220ms ease;
}

.stop-toggle[aria-expanded="true"] .stop-chevron {
  transform: rotate(180deg);
}

.stop-details {
  margin-top: 0.85rem;
  padding: var(--stop-pad);
  border-radius: 0.9rem;
  background: rgba(199, 228, 229, 0.34);
}

/* Das Foto des Ortes, erst im aufgeklappten Zustand. Die Bildmarke auf der
   Zeitachse ist nur 2,6rem groß und zeigt kaum etwas – hier bekommt der Ort ein
   Gesicht. Es lädt erst beim Öffnen, weil der Aufklapper bis dahin `hidden` ist. */
.stop-photo {
  display: block;
  width: 100%;
  height: clamp(9rem, 24vw, 15rem);
  border-radius: 0.55rem;
  object-fit: cover;
  background: rgba(16, 47, 70, 0.06);
}

.stop-description,
.stop-details p {
  margin: 0.8rem 0 0;
}

/* Kurzer Aufhänger über der ausführlichen Beschreibung. */
.stop-description {
  color: var(--ink);
  font-size: 1.02rem;
  font-weight: 800;
  line-height: 1.4;
}

.stop-body p {
  max-width: 44rem;
  color: var(--muted);
  font-size: 0.97rem;
  line-height: 1.62;
}

/* ── Lesebahn ──────────────────────────────────────────────────────────────
   Auf schmalen Fenstern bleiben dem Aufklapper nur rund 196px Inhaltsbreite,
   also etwa 22 Zeichen je Zeile. Drei Absätze werden dadurch so hoch, dass ein
   geöffneter Stop über zwei Bildschirme reicht.

   Der ganze Aufklapper verlässt deshalb die Textspalte: nach links bis genau auf
   die Mitte der Achslinie, nach rechts bis an die Innenkante der Tageskarte.
   Eine Fläche, eine Breite, ein Ton – Foto, Beschreibung, Fakten, Anfahrt,
   Karte und UID sitzen alle auf demselben Grund und an derselben Satzkante.
   Vorher brach nur der Prosablock aus, und das ergab drei Breiten und zwei
   Tönungen übereinander.

   Warum die Verschiebung über negative Außenmaße läuft und nicht über das
   Raster: Ein Aufklapper, der als eigene Rasterzeile über beide Spalten geht,
   nimmt der Achse ihre Zeile – die Linie wäre unterbrochen. So bleibt sie
   unangetastet und bekommt eine zweite Aufgabe: Sie ist ab hier auch der linke
   Satzrand des Aufklappers.

   Geschaltet über die Breite der Stop-Spalte, nicht die des Fensters: aktiv
   unter 26rem Spaltenbreite, also von 320px bis rund 495px Fensterbreite und
   ebenso bei starkem Zoom. */
@container stops (max-width: 26rem) {
  .stop-details {
    /* Links bis zur Linienmitte: Spalt + halbe Achsenbreite. Rechts bis zur
       Kartenkante: Kartenpolster. Ohne --stop-pad in der Rechnung – anders als
       ein Kind des Aufklappers ist der Aufklapper selbst nicht eingerückt. */
    margin-inline-start: calc(-1 * (var(--rail-gap) + var(--rail) / 2));
    margin-inline-end: calc(-1 * var(--day-pad));
    /* Links mehr Polster, damit der Satz nicht an der Achslinie klebt. */
    padding-inline: 0.95rem var(--stop-pad);
    /* Deckend, nicht getönt: Eine durchscheinende Fläche über der Achslinie
       würde die Linie durchscheinen lassen und an der linken Kante eine Naht
       zeigen. Der Wert ist derselbe Ton über Kartenpapier gerechnet – die
       Erscheinung bleibt gleich, nur läuft die Linie jetzt sichtbar darüber. */
    background: #ecf3ec;
    background: color-mix(in srgb, var(--water) 34%, var(--card));
    border-radius: 0.55rem 0 0 0.55rem;
  }

  /* Zeilenhöhe und Schriftgröße sind der stärkere Hebel als die Breite: 1,62
     ist ein Wert für lange Zeilen, nicht für 36 Zeichen. */
  .stop-body p {
    font-size: 0.94rem;
    line-height: 1.5;
  }
}

.stop-facts {
  display: grid;
  gap: 0.55rem 1.4rem;
  /* min(13rem, 100%) statt 13rem: Die Zeitachse verengt die Spalte auf dem Handy
     auf rund 165px. Eine feste Mindestbreite von 13rem (208px) kann dort nicht
     schrumpfen – der Kasten wurde 27px breiter als sein Platz und der Text lief
     über den Rand. Mit min() fällt die Spalte auf die verfügbare Breite zurück. */
  grid-template-columns: repeat(auto-fit, minmax(min(13rem, 100%), 1fr));
  /* Kein eigener Kasten mehr: Der Aufklapper ist eine Fläche, und ein zweiter
     getönter Kasten darin ergab drei Breiten und zwei Töne übereinander.
     Getrennt wird jetzt mit einer Haarlinie – dieselbe Sprache wie bei der UID
     am Fuß der Karte. */
  margin: 1.1rem 0 0;
  padding: 1.1rem 0 0;
  border-top: 1px solid rgba(16, 47, 70, 0.12);
}

.stop-facts dt {
  color: var(--teal);
  font-size: 0.68rem;
  font-weight: 900;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.stop-facts dd {
  margin: 0.15rem 0 0;
  font-size: 0.9rem;
  line-height: 1.45;
}

.route {
  color: var(--muted);
  font-size: 0.78rem;
}

.stop-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.8rem;
  margin-top: 0.8rem;
}

.ticket {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  font-size: 0.78rem;
}

.ticket a {
  color: var(--teal);
  font-weight: 800;
}

.load-error {
  max-width: 40rem;
  margin: 5rem auto;
  padding: 2rem;
  color: var(--muted);
}

.weather-status {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  margin-top: 1rem;
  padding: 0.52rem 0.72rem;
  border: 1px solid rgba(16, 47, 70, 0.12);
  border-radius: 999px;
  background: rgba(255, 250, 240, 0.72);
  color: var(--muted);
  font-size: 0.82rem;
  font-weight: 800;
}

.weather-status span {
  display: inline-flex;
  align-items: center;
  min-height: 1.45rem;
  padding: 0 0.55rem;
  border-radius: 999px;
  background: var(--gold);
  color: white;
}

.weather-status[data-live="true"] span {
  background: var(--teal);
}

.weather-card {
  /* begrenzt, damit eine Reise mit nur zwei Tagen keine überbreiten Kacheln bekommt */
  max-width: 24rem;
  min-height: 12rem;
  padding: 1rem;
  border-radius: 1.5rem;
  background: linear-gradient(160deg, #fffdf5, #dceff1);
}

.weather-card span {
  display: inline-grid;
  width: 2.6rem;
  height: 2.6rem;
  place-items: center;
  border-radius: 50%;
  background: var(--night);
  color: white;
  font-weight: 900;
}

.weather-card strong {
  display: block;
  margin-top: 1.15rem;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 2.1rem;
  letter-spacing: -0.05em;
  /* Sicherheitsnetz: kein Wert darf über die Kachel hinauslaufen. */
  overflow-wrap: anywhere;
}

/* Der Platzhalter steht im selben Element wie sonst „17/13 °C“. Dessen 2,1rem
   Georgia sind für 14 Zeichen zu groß: Auf dem Handy war das Wort „Prognose“
   allein breiter als die Kachel (152px Inhalt in 129px Platz) und lief über den
   Rand. Als Statustext gehört er ohnehin in die Grundschrift, nicht in die
   Zahlentypografie. */
.weather-card strong.weather-empty {
  font-family: inherit;
  font-size: 1.02rem;
  letter-spacing: 0;
  line-height: 1.3;
}

.weather-card b {
  display: block;
  color: var(--coral);
}

.weather-card p {
  margin-bottom: 0;
  color: var(--muted);
  font-size: 0.92rem;
}

.days {
  display: grid;
  gap: 1.4rem;
  margin-top: 1.5rem;
  /* Jede Tageskarte behält ihre eigene Höhe. Ohne "start" streckt das Grid
     die zugeklappte Nachbarkarte auf die Höhe der aufgeklappten Karte. */
  align-items: start;
}

.day-card {
  overflow: hidden;
  border-radius: 2rem;
  background: var(--card);
  scroll-margin-top: var(--stick);
}

/* Tagesleiste: sie ersetzt die vier Aufklapper. Ein Tag ist immer offen,
   ein Tap wechselt ihn – statt erst einmal Inhalt sichtbar zu machen. */
.day-tabs {
  position: sticky;
  /* Ohne Topnav 4,6rem = deren Unterkante plus Luft, mit ausgeblendeter Topnav
     dicht am oberen Rand. Der Übergang ist animiert, damit die Leiste nachrückt
     statt zu springen. */
  top: var(--tabs-top);
  transition: top 240ms ease;
  z-index: 15;
  margin-top: 1.4rem;
  padding: 0.35rem;
  border: 1px solid var(--line);
  border-radius: 1.15rem;
  background: rgba(255, 250, 240, 0.88);
  backdrop-filter: blur(12px);
  box-shadow: 0 0.6rem 1.6rem rgba(16, 47, 70, 0.1);
}

.day-tabs-inner {
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(4.4rem, 1fr);
  gap: 0.35rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;   /* kein Zurückblättern der Seite beim Wischen */
  scroll-snap-type: x proximity;
  scrollbar-width: none;            /* eigener Hinweis statt Systembalken */
}

.day-tabs-inner::-webkit-scrollbar { display: none; }

/* Hinweis, dass es seitlich weitergeht. Ein angeschnittener Tag allein reicht
   nicht — auf dem Handy sieht das aus wie ein Anschnitt des Rahmens. Deshalb ein
   Verlauf plus Pfeil, und zwar nur auf der Seite, auf der wirklich mehr kommt.
   Das Attribut setzt bindWischhinweis in app.js. */
.day-tabs::before,
.day-tabs::after {
  content: "";
  position: absolute;
  top: 0.35rem;
  bottom: 0.35rem;
  width: 2.4rem;
  pointer-events: none;
  opacity: 0;
  transition: opacity 180ms ease;
  background-repeat: no-repeat;
  background-size: 0.6rem, auto;
}

.day-tabs::before {
  left: 0.35rem;
  border-radius: 0.85rem 0 0 0.85rem;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 14'%3E%3Cpath d='M7 1 1 7l6 6' fill='none' stroke='%23102f46' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"),
    linear-gradient(90deg, rgba(255, 250, 240, 0.98) 45%, rgba(255, 250, 240, 0));
  background-position: left 0.1rem center, center;
}

.day-tabs::after {
  right: 0.35rem;
  border-radius: 0 0.85rem 0.85rem 0;
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 14'%3E%3Cpath d='M1 1l6 6-6 6' fill='none' stroke='%23102f46' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E"),
    linear-gradient(270deg, rgba(255, 250, 240, 0.98) 45%, rgba(255, 250, 240, 0));
  background-position: right 0.1rem center, center;
}

.day-tabs[data-mehr~="links"]::before,
.day-tabs[data-mehr~="rechts"]::after { opacity: 1; }

/* Seit die Leiste springt statt zu filtern, sind das Links und keine Knoepfe –
   deshalb text-decoration und color ausdruecklich setzen. */
.day-tab {
  display: grid;
  gap: 0.1rem;
  min-height: 44px;
  align-content: center;
  padding: 0.3rem 0.4rem;
  border: 0;
  border-radius: 0.85rem;
  background: transparent;
  color: #586672;
  font-family: inherit;
  font-weight: 900;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  scroll-snap-align: start;
}

.day-tab b {
  font-size: 0.95rem;
}

.day-tab small {
  font-size: 0.68rem;
  font-weight: 800;
  opacity: 0.75;
}

/* Der Tag, der gerade im Bild ist. Fruehers war das der einzige sichtbare Tag;
   jetzt sind alle da und die Marke sagt nur noch, wo man steht. */
.day-tab[aria-current="true"] {
  background: var(--navy);
  color: white;
}

.day-tab:focus-visible {
  outline: 3px solid var(--teal);
  outline-offset: 2px;
}

/* Der Einstieg unterwegs: was jetzt ansteht, ohne Tap und ohne Scrollen. */
.today-card {
  display: grid;
  gap: 0.3rem;
  margin-top: 1rem;
  padding: 1.1rem 1.2rem;
  border-radius: 1.4rem;
  background: var(--teal);
  color: white;
  box-shadow: 0 0.9rem 2.2rem rgba(20, 119, 124, 0.26);
}

.today-card[data-status="bevorstehend"] {
  background: var(--navy);
}

.today-card[data-status="vergangen"] {
  border: 1px solid var(--line);
  background: rgba(255, 250, 240, 0.8);
  color: var(--ink);
  box-shadow: none;
}

.today-eyebrow {
  margin: 0;
  font-size: 0.7rem;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  opacity: 0.92;
}

.today-title {
  margin: 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 1.6rem;
  line-height: 1.06;
  letter-spacing: -0.03em;
}

.today-meta {
  margin: 0;
  font-size: 0.9rem;
  opacity: 0.9;
}

.today-jump {
  display: inline-flex;
  justify-self: start;
  min-height: 44px;
  align-items: center;
  margin-top: 0.45rem;
  padding: 0 1rem;
  border-radius: 0.9rem;
  background: white;
  color: var(--ink);
  font-size: 0.85rem;
  font-weight: 900;
  text-decoration: none;
}

.day-hero {
  width: 100%;
  height: 16rem;
  object-fit: cover;
}

.day-body {
  /* display: block ist zwingend – als <span> bliebe das Element inline, und die
     Polsterung würde die Blockelemente darin nicht einrücken. Genau deshalb
     klebten Titel und Notiz vorher am Kartenrand. */
  display: block;
  padding: var(--day-pad);
}

.day-title {
  display: block;
  margin: 0.5rem 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: 1.6rem;
  font-weight: 900;
  line-height: 1.05;
}

.day-note {
  display: block;
  margin-top: 0.8rem;
  color: var(--muted);
}

.day-details {
  padding: 0 var(--day-pad) var(--day-pad);
  /* Sicherheitsnetz für die Lesebahn: Sie rechnet auf den Pixel an die
     Kartenkante. Bei krummen Gerätepixelverhältnissen darf ein halbes Pixel
     Überstand keine waagrechte Bildlaufleiste erzeugen. */
  overflow-x: clip;
}

.day-label,
.weather-pill {
  display: inline-flex;
  align-items: center;
  min-height: 2rem;
  margin: 0 0 0.7rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  color: white;
  background: var(--teal);
  font-size: 0.78rem;
  font-weight: 900;
}

.weather-pill {
  margin-top: 0.9rem;
  color: var(--ink);
  background: #e8f3f1;
}

/* Gefüllt aus der Live-Prognose statt aus dem statischen Planungshinweis. */
.weather-pill[data-live="true"] {
  color: white;
  background: var(--teal);
}

/* Platzhalter, solange keine echte Prognose vorliegt – nie erfundene Zahlen. */
.weather-empty {
  color: var(--muted);
  font-style: italic;
  font-weight: 600;
}

.day-card.gold .day-label {
  background: var(--gold);
}

.day-card.coral .day-label {
  background: var(--coral);
}

.day-card.navy .day-label {
  background: var(--navy);
}

.day-body > p:not(.day-label):not(.weather-pill) {
  color: var(--muted);
}

/* Hier standen `ol` und `li` als nackte Elementselektoren: ein dreispaltiges
   Grid für die Stop-Liste aus dem Design-Entwurf. Die Umsetzung rendert Stops
   längst als `.stop-card`-Divs — im ganzen Projekt gibt es kein einziges `<ol>`
   und kein `<li>` außer auf der Testseite.

   Damit hatten die beiden Regeln keine Aufgabe mehr, richteten aber Schaden an:
   jedes `<li>` der Testseite wurde zum Grid, und der Link landete in der ersten
   Spalte — auf dem Handy 3,05 rem breit. Jeder Linktitel brach dort auf drei bis
   vier Zeilen um, Zeilen wurden 177 px hoch, die Seite fast 7000 px lang.
   Deshalb gelöscht statt überschrieben: ein nackter Elementselektor für ein
   Bauteil erwischt irgendwann eine Stelle, für die er nie gedacht war. */

time {
  padding-top: 0.18rem;
  color: var(--coral);
  font-size: 0.82rem;
  font-weight: 900;
}

.maps-link {
  display: flex;
  justify-self: end;
  width: 5.9rem;
  min-height: 3rem;
  align-items: center;
  gap: 0.45rem;
  padding: 0.35rem 0.55rem 0.35rem 0.35rem;
  border: 1px solid rgba(20, 119, 124, 0.18);
  border-radius: 0.9rem;
  background: linear-gradient(135deg, rgba(255, 250, 240, 0.98), rgba(220, 239, 241, 0.94));
  color: var(--ink);
  font-size: 0.78rem;
  font-weight: 900;
  text-decoration: none;
  box-shadow: 0 0.45rem 1.1rem rgba(16, 47, 70, 0.08);
}

.maps-link:active,
.maps-link:hover {
  transform: translateY(-1px);
  border-color: rgba(20, 119, 124, 0.42);
}

.maps-link small {
  display: block;
  color: var(--teal);
  font-size: 0.55rem;
  line-height: 1.05;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.maps-mark {
  position: relative;
  display: inline-grid;
  flex: 0 0 auto;
  width: 2.18rem;
  height: 2.18rem;
  place-items: center;
  border-radius: 50% 50% 50% 0;
  background: var(--coral);
  transform: rotate(-45deg);
  box-shadow: inset 0 0 0 0.25rem rgba(255, 255, 255, 0.28);
}

.maps-mark::after {
  content: "";
  width: 0.64rem;
  height: 0.64rem;
  border-radius: 50%;
  background: white;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(1.6rem);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ══ Bewegung ══════════════════════════════════════════════════════════════
   Grundsatz: Bewegung beantwortet eine Frage – woher kam das, wohin ist es
   gegangen, was hat sich geändert. Alles hier bewegt ausschließlich transform
   und opacity, beide werden nach dem Layout aufgetragen und lösen keinen
   Neuumbruch aus. Das ist bei 30 Zeichen je Zeile keine Feinheit: ein
   animiertes Höhen- oder Breitenmaß würde den Text in jedem Bild neu brechen.

   Ausgelöst wird fast alles ohne JavaScript. `[hidden]` bedeutet
   `display: none`; taucht ein Element daraus auf, startet der Browser seine
   Animationen von selbst neu. Tageswechsel und Aufklappen brauchen deshalb
   keinen Zeitgeber – nur die Position im Tag kommt als --i aus app.js. */

@keyframes stop-auftritt {
  from {
    opacity: 0;
    transform: translateY(0.5rem);
  }
}

@keyframes linie-waechst {
  from {
    transform: scaleY(0);
  }
}

@keyframes flaeche-setzt-sich {
  from {
    opacity: 0;
    transform: translateY(-0.4rem);
  }
}

@keyframes marke-nickt {
  50% {
    transform: scale(0.88);
  }
}

/* Die Stops eines Tages ziehen von oben nach unten auf, 45ms auseinander.
   Zusammen mit der wachsenden Linie liest sich das Betreten eines Tages als
   Aufziehen der Zeitachse – das tragende Motiv erklärt sich dadurch selbst. */
.stop-main {
  animation: stop-auftritt 380ms ease-out backwards;
  animation-delay: calc(var(--i, 0) * 45ms);
}

/* scaleY ist hier besonders sauber: flex: 1 legt die Höhe der Linie vor der
   Animation fest, das Skalieren ändert daran nichts. transform-origin oben,
   damit sie von der eigenen Bildmarke nach unten wächst. */
.stop-line {
  animation: linie-waechst 420ms ease-out backwards;
  animation-delay: calc(var(--i, 0) * 45ms + 120ms);
  transform-origin: top center;
}

/* Der Inhalt des Aufklappers setzt sich von oben hinein. Die Höhe springt
   dabei bewusst: dass mehr da ist, ist die eigentliche Auskunft – bewegt wird
   nur, was schon Platz hat. */
.stop-details > * {
  animation: flaeche-setzt-sich 300ms ease-out backwards;
}

.stop-details > :nth-child(2) { animation-delay: 40ms; }
.stop-details > :nth-child(3) { animation-delay: 80ms; }
.stop-details > :nth-child(n + 4) { animation-delay: 120ms; }

/* Ein offener Stop markiert sich auf der Achse. Mehrere Stops dürfen offen
   sein – dann sieht man an der Achse, was man schon gelesen hat. */
.stop-card:has([aria-expanded="true"]) .stop-mark {
  transform: scale(1.14);
  box-shadow: 0 0 0 3px rgba(20, 119, 124, 0.75);
}

/* Der Stop, dessen Zeit gerade abgelaufen ist, tritt weich zurück und hakt sich
   ab. markProgress läuft im Minutentakt – ohne Übergang wäre das ein Flackern
   mitten im Lesen. */
.stop-card .stop-main,
.stop-card .stop-time {
  transition: opacity 600ms ease;
}

.stop-card[data-past="true"] .stop-mark {
  animation: marke-nickt 520ms ease-in-out;
}

/* Antwort im Moment der Berührung, bevor irgendetwas lädt oder aufklappt.
   Unterwegs am Handy die wichtigste Bewegung der Liste, obwohl die kleinste. */
.stop-toggle:active .stop-title,
.day-tab:active,
.maps-link:active,
.today-jump:active,
.today-more:active,
.topnav a:active {
  transform: scale(0.96);
}

.stop-title,
.day-tab,
.maps-link,
.today-jump,
.today-more {
  transition: transform 120ms ease;
}

/* Die gewählte Tagespille rastet ein, statt hart umzuschalten. */
.day-tab[aria-current="true"] {
  animation: marke-nickt 260ms ease-out reverse;
}

/* Das Foto ist der einzige Inhalt, der nach dem Layout eintrifft: es lädt mit
   loading="lazy" erst beim Öffnen. Es blendet auf, statt zu erscheinen. */
@keyframes foto-auf {
  from {
    opacity: 0;
    transform: scale(1.015);
  }
}

.stop-photo {
  animation: foto-auf 520ms ease-out backwards;
  animation-delay: 60ms;
}

/* Die Live-Prognose ersetzt heute stillschweigend „keine Prognose“ durch Zahlen.
   Mit dem Attribut, das loadWeather ohnehin setzt, trifft sie sichtbar ein. */
.weather-pill[data-live="true"] {
  animation: flaeche-setzt-sich 420ms ease-out;
}

/* Die Heute-Karte ist unterwegs die Antwort auf „was jetzt?“ und steht an einer
   Stelle, an die das Auge nicht von sich aus zuerst geht. */
.today-card {
  animation: rise 520ms ease-out both;
  animation-delay: 80ms;
}

/* Das Titelbild kommt eine Spur zu groß herein und setzt sich – ein
   Ankunftsbild, das ankommt. Einmalig, keine Dauerbewegung. */
@keyframes hero-setzt-sich {
  from {
    transform: scale(1.06);
  }
}

.hero-bg {
  animation: hero-setzt-sich 1600ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
}

/* Wer keine Bewegung will, bekommt keine – jede Animation endet sofort in ihrem
   Zielzustand, statt abgeschaltet zu werden. Sonst blieben Elemente mit
   `backwards` in ihrem Anfangszustand stehen und wären unsichtbar. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-delay: 0ms !important;
    transition-duration: 1ms !important;
  }
}

/* Eine Skala statt vier Bruchstellen in zwei Einheiten: 48rem und 64rem.
   Vorher lagen 40rem, 760px, 900px und 60rem nebeneinander – zwischen 640 und
   760 px galt eine Mischform, die niemand entworfen hatte. */
@media (max-width: 48rem) {
  /* Auf schmalen Fenstern kleinere Abstände – aber nicht so klein, dass der
     Text am Rand klebt. Die Lesebreite ist reichlich bemessen, damit sie nicht
     den Seitenrand bestimmt. */
  :root {
    --gutter: 1.25rem;
    --day-pad: 1.15rem;
    /* 0.8rem, nicht 1.05rem: Dieser Wert stand vorher hart in .stop-details und
       ist jetzt die Variable. 1.05rem würde den Aufklapper enger machen und der
       Lesebahn Breite nehmen. */
    --stop-pad: 0.8rem;
    /* Die Achse rückt zusammen. Als Variablen, damit die Lesebahn mitrechnet –
       vorher stand die Geometrie in .stop-card hart und nur zufällig passend. */
    --rail: 3rem;
    --rail-gap: 0.7rem;
  }

  .section {
    width: min(100% - 2 * var(--gutter), 44rem);
    padding: 3.2rem 0;
  }

  .topnav {
    width: calc(100% - 1rem);
    justify-content: space-between;
  }

  .topnav a {
    min-width: auto;
    flex: 1;
    padding-inline: 0.35rem;
  }

  /* Knapp unter Fensterhöhe: die Tagesleiste ist am unteren Rand angeschnitten,
     damit unterwegs sichtbar ist, dass darunter der Plan beginnt. */
  .hero {
    min-height: 78svh;
    padding: 0.55rem;
  }

  .hero-copy {
    padding-inline: 0.35rem;
    padding-bottom: 2rem;
  }

  h1 {
    max-width: 100%;
    font-size: clamp(2.9rem, 14vw, 4.1rem);
  }

  h2 {
    font-size: clamp(2.1rem, 9.5vw, 3.5rem);
  }

  .hero-stats {
    gap: 0.45rem;
  }

  .hero-stats span {
    padding: 0.75rem 0.6rem;
  }

  .weather-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .weather-card {
    min-height: 11rem;
  }

  .day-card {
    border-radius: 1.55rem;
  }

  .day-hero {
    height: 10.5rem;
  }

  .day-body {
    min-width: 0;
  }

  .day-title {
    font-size: clamp(1.3rem, 5.5vw, 1.7rem);
    line-height: 1.03;
  }

  .day-label,
  .weather-pill {
    max-width: 100%;
    min-height: 1.75rem;
    padding: 0.28rem 0.52rem;
    font-size: 0.67rem;
    line-height: 1.25;
    white-space: normal;
  }

  .weather-pill {
    margin-top: 0.55rem;
    align-items: flex-start;
  }

  .day-note {
    margin-top: 0.55rem;
    font-size: 0.84rem;
    line-height: 1.4;
  }

  /* Schmale Fenster: die Bildmarke wird kleiner, die Achsenbreite steht oben. */
  .stop-mark {
    width: 2.2rem;
    height: 2.2rem;
  }

  .stop-time {
    font-size: 0.8rem;
  }

  .stop-title {
    font-size: 1.18rem;
  }

  .stop-lead {
    font-size: 0.9rem;
  }

  /* Die `li`-Regel, die hier die Spalten für schmale Fenster verengte, ist mit
     dem nackten `li`-Selektor entfallen — siehe die Erklärung dort. */

  .maps-link {
    width: 5.6rem;
    min-height: 2.8rem;
    padding-right: 0.42rem;
  }

  .maps-mark {
    width: 1.95rem;
    height: 1.95rem;
  }

}

/* Zweite und letzte Stufe der Skala. Zwei Tage nebeneinander gibt es nicht mehr:
   es ist immer genau ein Tag geöffnet, den die Leiste wechselt. */
@media (min-width: 64rem) {
  .day-hero {
    height: 20rem;
  }
}


/* ---------------------------------------------- Unterwegs: "Direkt im Tag" */

/* Der Vollbild-Hero ist ein Ankunftsbild. Läuft die Reise, reicht ein Kopf:
   Bild, Tagesnummer, Titel - der Rest waere Weg zum Plan. Vor und nach der
   Reise bleibt `.hero` unveraendert, deshalb steht hier nur die Abweichung. */
.hero-compact {
  min-height: 13.25rem;
  align-items: end;
  padding: 0;
}

.hero-compact .hero-copy {
  padding: 0 var(--gutter) 1rem;
  animation-duration: 0.5s;
}

.hero-compact h1 {
  max-width: 14ch;
  font-size: clamp(2.1rem, 9vw, 3rem);
  line-height: 0.98;
}

.hero-compact .eyebrow {
  margin-bottom: 0.4rem;
  font-size: 0.72rem;
}

/* Wetter unterwegs: eine Zeile mit Zahl und Konsequenz. Die volle Sektion mit
   allen Reisetagen bleibt erhalten, steht aber unter dem Plan. */
.weather-line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  padding: 0.65rem var(--gutter);
  border-bottom: 1px solid rgba(16, 47, 70, 0.1);
  background: rgba(199, 228, 229, 0.55);
}

.weather-line .weather-pill {
  margin: 0;
  min-height: 1.4rem;
  padding: 0.15rem 0.5rem;
  font-size: 0.67rem;
}

.weather-line b {
  font-size: 0.78rem;
  line-height: 1.35;
}

/* Ohne Sektionskopf beginnt der Plan direkt unter der Wetterzeile. */
.day-section.is-running {
  padding-top: 1rem;
}

.day-section.is-running .day-tabs {
  margin-top: 0;
}

/* Erledigte Stops bleiben lesbar, treten aber zurueck - die Achse zeigt damit
   den Tagesfortschritt, ohne dass etwas verschwindet. Gesetzt wird das
   Attribut in markProgress(), hier steht nur das Aussehen. */
.stop-card[data-past="true"] .stop-main {
  opacity: 0.5;
}

.stop-card[data-past="true"] .stop-time {
  color: var(--muted);
}

.stop-card[data-past="true"] .stop-mark {
  filter: saturate(0.4);
  box-shadow: 0 0 0 2px rgba(16, 47, 70, 0.2);
}

/* Innen oder aussen entscheidet unterwegs ueber die Reihenfolge - deshalb steht
   es als zweiter Chip in der Zeile und nicht erst in den Fakten. */
.stop-chips [data-weather="aussen"] {
  background: rgba(222, 98, 70, 0.12);
  color: #a8442c;
}

.stop-chips [data-weather="innen"] {
  background: rgba(20, 119, 124, 0.12);
  color: #0f5b5f;
}

.stop-chips [data-weather="beides"] {
  background: rgba(16, 47, 70, 0.07);
  color: var(--muted);
}

/* Route und Details nebeneinander statt nur Route. */
.today-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 0.45rem;
}

.today-actions .today-jump {
  margin-top: 0;
}

.today-more {
  display: inline-flex;
  min-height: 44px;
  align-items: center;
  padding: 0 1rem;
  border: 1px solid rgba(255, 255, 255, 0.45);
  border-radius: 0.9rem;
  color: white;
  font-size: 0.85rem;
  font-weight: 900;
  text-decoration: none;
}

/* Bildnachweis. Lizenzpflicht, kein Inhalt der Reise: auffindbar und lesbar,
   aber so klein wie vertretbar. 10px ist die Untergrenze — darunter wird es auf
   dem Handy unlesbar, und eine unlesbare Namensnennung erfüllt die Pflicht nicht.
   Zeilenhöhe bewusst großzügig, weil der Text bei dieser Größe sonst verklumpt. */
.credits {
  margin: 0 auto;
  padding: 0 var(--gutter) 2.5rem;
  max-width: 70rem;
  /* Nicht --muted (#61717e): das ergibt auf --paper nur 4,48:1 und verfehlt die
     4,5:1, die WCAG AA für Kleintext fordert. Dieser Ton liegt bei 5,26:1 und
     bleibt trotzdem deutlich zurückgenommen. Kleine Schrift braucht mehr
     Kontrast, nicht weniger. */
  color: #586672;
  text-wrap: pretty;
  hyphens: auto;
}

/* Die Beschriftung des zugeklappten Nachweises. Sie ist der einzige Weg zur
   Nennung und darf deshalb nicht so klein sein wie der Nachweis selbst — was man
   finden soll, muss man lesen können. 12px, und die ganze Zeile ist 44px hoch. */
.credits > summary {
  display: flex;
  align-items: center;
  min-height: 44px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  cursor: pointer;
  list-style: none;          /* eigenes Zeichen, siehe ::after */
}

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

/* Ein Zeichen, das den Zustand zeigt. Ohne das sieht der zugeklappte Nachweis
   wie eine gewöhnliche Zeile aus, und niemand tippt darauf. */
.credits > summary::after {
  content: "＋";
  margin-left: 0.45rem;
  font-size: 1.1em;
  line-height: 1;
}

.credits[open] > summary::after { content: "－"; }

.credits > summary:hover,
.credits > summary:focus-visible { color: var(--ink); }

/* Der Nachweis selbst bleibt sehr klein — er ist eine Fußnote, kein Inhalt. */
.credits > p {
  margin: 0;
  padding-bottom: 0.4rem;
  font-size: 10px;
  line-height: 1.7;
}

.credits a {
  color: inherit;
  text-decoration-color: rgba(88, 102, 114, 0.45);
  text-underline-offset: 2px;
}

.credits a:hover,
.credits a:focus-visible {
  color: var(--ink);
  text-decoration-color: currentColor;
}

/* Fußzeile ganz unten: nur der Weg zu den Testparametern. Bewusst noch
   zurückhaltender als der Bildnachweis — sie interessiert im Alltag niemanden,
   muss aber unterwegs vom Handy aus erreichbar sein. Kein display:none und
   keine 0.01-Deckkraft: was man antippen soll, muss man sehen können. */
.pagefoot {
  margin: 0 auto;
  padding: 0 var(--gutter) 1.5rem;
  max-width: 70rem;
  font-size: 10px;
  line-height: 1.6;
  text-align: right;
}

/* Unauffällig heißt nicht untreffbar: der Text bleibt 10 px, die Tippfläche
   wächst durch Polster auf 44 px. Ohne das war das Ziel genau 10 px hoch.
   Farbe wie beim Bildnachweis (5,26:1) – #6b7783 lag bei 4,07:1 und damit unter
   den 4,5:1, die WCAG AA für Kleintext fordert. */
.pagefoot a {
  display: inline-block;
  padding: 1.05rem 0;
  color: #586672;
  text-decoration-color: rgba(88, 102, 114, 0.35);
  text-underline-offset: 2px;
}

.pagefoot a:hover,
.pagefoot a:focus-visible {
  color: var(--ink);
  text-decoration-color: currentColor;
}

/* Testparameter-Seite. Reine Werkzeugseite, deshalb schmucklos und dicht. */
.testseite {
  max-width: 52rem;
  margin: 0 auto;
  padding: 3rem var(--gutter) 4rem;
}

.testseite h1 { margin: 0.25rem 0 1rem; }

/* Anker unter die Sprungleiste statt dahinter. */
.testseite section { scroll-margin-top: 1.5rem; }

.testseite h2 {
  margin: 2.75rem 0 0.35rem;
  padding-bottom: 0.35rem;
  /* Vorher 2px in --ink: eine schwarze Linie quer über die Seite, schwerer als
     die Überschrift darüber. Ein Strich soll gliedern, nicht dominieren. */
  border-bottom: 1px solid var(--line);
}
.testseite h3 { margin: 1.5rem 0 0.5rem; font-size: 1rem; }
.testseite p { margin: 0 0 0.9rem; max-width: 62ch; }
.testseite .vorwort { font-size: 1.05rem; }

/* Datum und Umfang unter dem Reisetitel. Vorher stand das als `0.7em` im h2 und
   wurde damit 25px groß — fast so groß wie der Ortsname daneben. Eine
   Nebenangabe in Titelgröße liest sich wie eine zweite Überschrift. */
.testseite .sub {
  margin: 0 0 1rem;
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #586672;
}

/* Sprungleiste. Die Seite ist mit zwei Reisen über 4000px lang; ohne sie
   scrollt man auf dem Handy an allem vorbei. Waagrecht rollbar, damit sie bei
   vielen Reisen nicht umbricht und die Seite nicht breiter macht. */
.testseite .sprung {
  display: flex;
  gap: 0.4rem;
  margin: 0 0 2rem;
  padding-bottom: 0.4rem;
  overflow-x: auto;
  scrollbar-width: thin;
}

.testseite .sprung a {
  flex: none;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 0.9rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.testseite .sprung a:hover,
.testseite .sprung a:focus-visible {
  border-color: var(--teal);
  color: var(--teal);
}
.testseite code {
  padding: 0.1em 0.35em;
  border-radius: 4px;
  background: var(--sand);
  font-size: 0.9em;
}

.testseite ul { margin: 0 0 1rem; padding: 0; list-style: none; }
.testseite li { border-bottom: 1px solid var(--line); }

/* Die **ganze** Zeile ist die Tippfläche, Titel und Hinweis zusammen. Vorher lag
   der Hinweis neben dem Link statt darin: antippbar war nur die erste Zeile, die
   Erklärung darunter war toter Text. Auf dem Handy trifft man aber die Zeile. */
.testseite li a {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 0.1rem;
  min-height: 3rem;
  padding: 0.4rem 0;
  color: var(--ink);
  text-decoration: none;
}

.testseite li a .was {
  font-weight: 600;
  text-decoration: underline;
  text-decoration-color: rgba(16, 47, 70, 0.3);
  text-underline-offset: 2px;
}

/* Nicht --muted (#61717e): das sind auf --paper nur 4,48:1 und verfehlt die
   4,5:1, die WCAG AA unter 24px fordert — hier bei 13,6px. 5,26:1 statt dessen. */
.testseite li a .wie {
  font-size: 0.85rem;
  color: #586672;
}

.testseite li a:hover .was,
.testseite li a:focus-visible .was {
  color: var(--teal);
  text-decoration-color: currentColor;
}

.testseite table { width: 100%; border-collapse: collapse; margin: 0 0 1.5rem; }
.testseite th, .testseite td {
  padding: 0.5rem 0.75rem 0.5rem 0;
  border-bottom: 1px solid var(--line);
  text-align: left;
  vertical-align: top;
}
.testseite th { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.06em; }

.testseite .hinweis {
  padding: 0.9rem 1.1rem;
  border-left: 3px solid var(--gold);
  background: var(--card);
  border-radius: 0 8px 8px 0;
}
/* 44px Tippfläche statt 16px Textzeile — der Rückweg wird unterwegs benutzt. */
.testseite .zurueck { margin-top: 3rem; }
.testseite .zurueck a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 1rem 0 0;
  font-weight: 700;
}

/* ─────────────────────────────────────────────────────────── Start-Intro
 *
 * Zwei Sekunden Vorspann, nach der Entwurfsfassung „Reiseplan Intro" aus
 * Claude Design. Übernommen sind Komposition, Farben, Zeiten und Bewegung;
 * das Laufzeitgerüst des Entwurfs und die Symbolschrift vom Google-CDN nicht —
 * siehe den Kopf von assets/intro.js.
 *
 * Alle Zeiten sind Anteile von 2 s, damit die Szenengrenzen des Entwurfs
 * ablesbar bleiben:  Aufschlag 0–22,5 % · Route 22,5–47,5 % · Titel 47,5–85 % ·
 * Übergabe 85–100 %.
 *
 * Der Hintergrund ist **derselbe** wie der von `body`. Dadurch blendet das Intro
 * am Ende auf exakt die Fläche, die darunter schon steht — die Übergabe ist
 * nicht zu sehen, nur das Verschwinden der Zeichnung.
 */
.intro {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  place-items: center;
  /* Rein dekorativ: Tippen geht durch. Ein Vorspann, der sich festfrisst, darf
     die App nicht blockieren. */
  pointer-events: none;
  overflow: hidden;
  background:
    radial-gradient(circle at top left, rgba(20, 119, 124, 0.2), transparent 32rem),
    linear-gradient(180deg, #fff8eb 0%, #f2e2c6 48%, #dcecee 100%);
  animation: intro-uebergabe 2s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}

/* Größe der Stop-Marke. Alles andere rechnet daran, damit die Komposition auf
   jedem Gerät dieselbe bleibt — der Entwurf war auf 1080 × 1920 gezeichnet. */
.intro-buehne {
  --m: clamp(3.2rem, 15vw, 5rem);
  display: grid;
  justify-items: center;
  animation: intro-kamera 2s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}

/* ── Zeitachse ───────────────────────────────────────────────────────── */

.intro-achse {
  position: relative;
  display: grid;
  row-gap: calc(var(--m) * 0.52);
}

/* Wächst von der ersten zur letzten Marke nach unten (Szene „Route"). */
.intro-linie {
  position: absolute;
  left: 50%;
  top: calc(var(--m) / 2);
  bottom: calc(var(--m) / 2);
  width: clamp(3px, 0.6vw, 6px);
  margin-left: calc(clamp(3px, 0.6vw, 6px) / -2);
  border-radius: 999px;
  background: rgba(20, 119, 124, 0.26);
  transform-origin: top center;
  transform: scaleY(0);
  animation: intro-linie 0.46s cubic-bezier(0.25, 1, 0.5, 1) 0.41s forwards;
}

/* Der Ring, der beim Aufschlag der ersten Marke ausläuft. */
.intro-ring {
  position: absolute;
  left: 50%;
  top: calc(var(--m) / 2);
  width: var(--m);
  height: var(--m);
  margin: calc(var(--m) / -2);
  border: clamp(3px, 0.5vw, 5px) solid var(--teal);
  border-radius: 50%;
  opacity: 0;
  animation: intro-ring 0.38s cubic-bezier(0.33, 1, 0.68, 1) 0.16s forwards;
}

.intro-stop {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  column-gap: calc(var(--m) * 0.22);
}

.intro-zeit {
  grid-column: 1;
  justify-self: end;
  font-size: clamp(0.85rem, 3.7vw, 1.3rem);
  font-weight: 900;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  color: var(--teal);
  opacity: 0;
  animation: intro-zeit 0.3s cubic-bezier(0.33, 1, 0.68, 1) forwards;
}

.intro-marke {
  grid-column: 2;
  display: grid;
  place-items: center;
  width: var(--m);
  height: var(--m);
  border: clamp(4px, 0.9vw, 8px) solid var(--card);
  border-radius: 50%;
  color: var(--card);
  box-shadow:
    0 0 0 clamp(3px, 0.6vw, 6px) rgba(20, 119, 124, 0.45),
    0 1.4rem 2.8rem rgba(16, 47, 70, 0.18);
  opacity: 0;
  transform: scale(0.55);
  animation: intro-marke 0.34s cubic-bezier(0.34, 1.56, 0.64, 1) forwards;
}

.intro-marke svg {
  width: 52%;
  height: 52%;
}

/* Nur die Marken tragen den Tagesfarbton. Die Uhrzeiten bleiben durchgehend in
   der Akzentfarbe — so hat es der Entwurf, und es hält die linke Spalte ruhig. */
.intro-stop[data-ton="teal"] .intro-marke { background: var(--teal); }
.intro-stop[data-ton="gold"] .intro-marke { background: var(--gold); }
.intro-stop[data-ton="coral"] .intro-marke { background: var(--coral); }

/* Die drei Einsätze stehen einzeln, weil sie im Entwurf nicht gleichmäßig
   verteilt sind: der erste fällt sofort, die beiden anderen rasten in der
   Szene „Route" ein. */
.intro-stop:nth-child(3) .intro-marke { animation-delay: 0.02s; animation-name: intro-marke-fall; }
.intro-stop:nth-child(4) .intro-marke { animation-delay: 0.59s; }
.intro-stop:nth-child(5) .intro-marke { animation-delay: 0.77s; }
.intro-stop:nth-child(3) .intro-zeit { animation-delay: 0.14s; }
.intro-stop:nth-child(4) .intro-zeit { animation-delay: 0.71s; }
.intro-stop:nth-child(5) .intro-zeit { animation-delay: 0.89s; }

/* ── Wortmarke ───────────────────────────────────────────────────────── */

.intro-eyebrow {
  margin: calc(var(--m) * 0.7) 0 0;
  font-size: clamp(0.7rem, 3.2vw, 1.05rem);
  font-weight: 900;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--teal);
  opacity: 0;
  animation: intro-auf 0.34s cubic-bezier(0.33, 1, 0.68, 1) 0.89s forwards;
}

.intro-wort {
  margin: calc(var(--m) * 0.16) 0 0;
  font-family: Georgia, "Times New Roman", serif;
  font-size: clamp(2.6rem, 13vw, 4.6rem);
  line-height: 0.94;
  letter-spacing: -0.055em;
  color: var(--ink);
  opacity: 0;
  animation: intro-auf-weit 0.42s cubic-bezier(0.33, 1, 0.68, 1) 1.01s forwards;
}

.intro-strich {
  margin-top: calc(var(--m) * 0.28);
  width: clamp(7rem, 28vw, 10rem);
  height: clamp(4px, 0.75vw, 8px);
  border-radius: 999px;
  background: var(--teal);
  opacity: 0.9;
  transform: scaleX(0);
  animation: intro-strich 0.36s cubic-bezier(0.25, 1, 0.5, 1) 1.09s forwards;
}

/* ── Bewegung ────────────────────────────────────────────────────────── */

/* Eine durchgehende Kamera: langsames Setzen, dann das Abheben zum Titel. */
@keyframes intro-kamera {
  0%   { transform: translateY(0) scale(1.03); }
  42%  { transform: translateY(0) scale(1.005); }
  72%  { transform: translateY(calc(var(--m) * -0.22)) scale(1); }
  100% { transform: translateY(calc(var(--m) * -0.22)) scale(1); }
}

@keyframes intro-uebergabe {
  0%, 85% { opacity: 1; transform: scale(1); }
  100%    { opacity: 0; transform: scale(1.05); }
}

@keyframes intro-marke {
  from { opacity: 0; transform: scale(0.55); }
  to   { opacity: 1; transform: scale(1); }
}

/* Der erste Stop fällt von oben ein statt nur aufzupoppen. */
@keyframes intro-marke-fall {
  from { opacity: 0; transform: translateY(calc(var(--m) * -1.5)) scale(0.55); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes intro-linie { to { transform: scaleY(1); } }

@keyframes intro-ring {
  from { opacity: 0.5; transform: scale(0.7); }
  to   { opacity: 0; transform: scale(2.6); }
}

@keyframes intro-zeit {
  from { opacity: 0; transform: translateX(-1.6rem); }
  to   { opacity: 1; transform: translateX(0); }
}

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

@keyframes intro-auf-weit {
  from { opacity: 0; transform: translateY(2.9rem); }
  to   { opacity: 1; transform: translateY(0); }
}

@keyframes intro-strich { to { transform: scaleX(1); } }

/* Wer reduzierte Bewegung verlangt, bekommt gar kein Intro — intro.js legt es
   dann nicht an. Diese Regel ist die zweite Sicherung, falls es doch im
   Dokument steht. */
@media (prefers-reduced-motion: reduce) {
  .intro { display: none; }
}
