/* ==========================================================================
   Schriften

   Raleway und Syne liegen im Ordner fonts, nicht bei Google. Der Aufruf
   von fonts.googleapis.com übertrug bei jedem Seitenaufruf die IP-Adresse
   des Besuchers in die USA, und genau darum drehen sich die Abmahnungen.
   Nebenbei fällt eine fremde Verbindung weg, die Seite startet schneller.

   Es liegen nur die vier Schnitte da, die das Design benutzt, gekürzt auf
   lateinische Zeichen samt Umlauten. Zusammen 112 KB statt der 300 KB, die
   Google ausliefert. Wer einen weiteren Schnitt braucht, muss ihn hier
   eintragen und die Datei dazulegen.

   font-display: swap — der Text steht sofort, die Schrift tauscht sich
   nach. Ohne das bleibt die Seite bis zum Laden der Schrift leer.
   ========================================================================== */

@font-face {
  font-family: 'Raleway';
  src: url('../fonts/raleway-200.woff2') format('woff2');
  font-weight: 200;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Raleway';
  src: url('../fonts/raleway-300.woff2') format('woff2');
  font-weight: 300;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Raleway';
  src: url('../fonts/raleway-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Raleway';
  src: url('../fonts/raleway-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Syne';
  src: url('../fonts/syne-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   ROTGLUT HOTELFOTOGRAFIE — rotglut.css

   Eigenes Stylesheet, geschrieben für diese Seite. Kein Bootstrap, kein
   Template, keine Icon-Fonts. Alles, was hier steht, wird auch benutzt.

   Aufbau
     1. Werte        Farben, Schriften, Abstände
     2. Grundlagen   Reset, Typografie
     3. Bausteine    Hülle, Kopfblock, Knöpfe, Bänder
     4. Kopf & Menü
     5. Fuß
     6. Bewegung, Druck

   Zwei Schriften: Raleway für alles, Syne ausschließlich für die
   Wortmarke ROTGLUT.
   ========================================================================== */


/* ==========================================================================
   1. Werte
   ========================================================================== */

:root {
  /* Farben. Die Seite steht auf Anthrazitblau — dunkler Grund, helle
     Schrift. Der Grund dafür ist nicht Mode, sondern das Motiv: ein
     Hotelfoto ist fast immer hell und warm. Gegen Weiß muss es sich
     behaupten und verliert dabei; auf Anthrazit leuchtet es. Eine
     Fotografenseite gehört in ein dunkles Passepartout, nicht auf ein
     Blatt Papier.

     Vier Materialien, nicht zwei:
       --grund    die Seite
       --tiefe    eingelassen: Kopfglas, Fuß, das Band in der Mitte
       --flaeche  erhoben: Eingabefelder, Karten
       --papier   die eine helle Platte je Seite, für die Aufforderung

     --grund und --tinte sind das Paar, das jede Umkehr vertauscht. Alles,
     was in beiden Umgebungen funktionieren muss, benutzt sie. */
  --grund:     #151c26;   /* Seitengrund */
  --tiefe:     #0f151d;   /* eingelassene Flächen */
  --flaeche:   #1e2733;   /* erhobene Flächen: Felder, Karten */
  --papier:    #f4f6f9;   /* helle Fläche, auch auf Dunkel hell */
  --tinte:     #eef1f6;   /* Fließtext, Überschriften — 15.13:1 */
  --grau:      #a9b2c0;   /* zweite Ebene — 8.01:1 */
  --leise:     #8b95a4;   /* Beschriftungen, Hinweise — 5.65:1 */
  --linie:     rgba(238, 241, 246, 0.13);
  --linie-2:   rgba(238, 241, 246, 0.28);
  --matt:      #222b38;   /* Platz, den ein Bild noch nicht füllt */
  /* Der Schleier über dem zugedeckten Abschnitt. Eigener Wert und nicht
     var(--grund): eine Fläche, die ihre Farbreihe umkehrt, hätte den
     Schleier sonst mit umgekehrt und die Fotos weiß gewaschen statt
     abgedunkelt. Genau das ist unter der hellen Platte passiert. */
  --schleier:  #151c26;

  /* Der Hauch hinter den Texten. Die Tinte bei fünf Prozent, nicht ein
     eigener Blauton: so hebt der Verlauf den Grund an, ohne ihn zu färben.
     Farbe kommt aus den Fotos, nicht aus dem Hintergrund. */
  --hauch:     rgba(238, 241, 246, 0.05);

  /* Korn gegen die Ringe. Ein weicher radialer Verlauf über eine große
     dunkle Fläche kann nur in ganzen Stufen laufen: gemessen wurde ein
     Sprung je 60 bis 100 Pixel, und weil jede Stufe eine große glatte
     Fläche mit harter Kante ist, liest man sie als konzentrische Ringe.

     Mehr Farbstopps helfen nicht, die Stufen stecken in den acht Bit.
     Feines Rauschen darüber verwischt die Kanten — dieselbe Dithering-
     Technik, mit der auch Bilder in kleine Farbtiefen gebracht werden.
     Es liegt bei drei Prozent und ist als Textur nicht zu sehen, nur
     als Abwesenheit der Ringe. */
  --korn: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='k'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/></filter><rect width='160' height='160' filter='url(%23k)' opacity='0.032'/></svg>");
  --dunkel:    #0f151d;   /* Alter Name der Tiefe, für die Menütafel */

  /* Die Glut stand einmal an drei Stellen je Seite: gezeichnete Kontur im
     Thesenband, markierter Text, Tastaturmarke der Menütafel. Alle drei
     sind gefallen — in einer Gestaltung aus Linien, Grau und Fotos war das
     bunte Wort jedes Mal lauter als die Stelle, an der es stand.

     Geblieben ist ein einziger Punkt: der Tropfen, der unter dem
     Einstiegshinweis am Faden herunterläuft. Zehn Pixel, einmal je 2,6
     Sekunden, sonst nirgends auf der Seite. Ein fallender Funke — und drei
     Zeilen darüber steht, wie die Marke heißt. Sparsamer geht ein Akzent
     nicht, und genau deshalb trägt er.

     Der Wert ist aus dem Favicon ausgelesen, nicht gewählt: #b32e22 füllt
     dort 47.461 von 65.536 Pixeln. Hier stand einmal #d94b35 mit der
     Begründung, das Favicon-Rot komme auf dunklem Grund nur auf 2,5:1 und
     wirke stumpf. Das gilt für Text. Ein Punkt von zehn Pixeln ist kein
     Text, und dass die Marke überall denselben Ton trägt, wiegt schwerer
     als ein Kontrastwert, der hier nichts zu entscheiden hat.

     Die Inseratsprüfung hat ihre eigene Glut in ihrem eigenen Stilblock.
     Dort ist Rot kein Akzent, sondern Signal: laufender Schritt,
     Fundstelle, Tastaturfokus. Das ist eine andere Sache. */
  --glut: #b32e22;

  /* Schrift */
  --ui:    'Raleway', 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --marke: 'Syne', var(--ui);

  /* Abstände. Eine Reihe, keine Zwischenwerte.

     Die beiden großen Stufen wachsen jetzt mit dem Fenster. Als feste
     Werte standen 64 und 112 Pixel auf dem Handy zu breit im Bild und
     auf einem 27-Zoll-Schirm zu eng unter einer 72-Pixel-Zeile. Die
     Untergrenze entspricht dem Handy, bei etwa 1440 Pixel Fensterbreite
     sind die alten Werte erreicht, darüber wird weiter aufgemacht. */
  --s:   8px;
  --m:   16px;
  --l:   32px;
  --xl:  clamp(44px, 4.4vw, 72px);
  --xxl: clamp(72px, 8vw, 140px);

  /* Seitenrand. Kopfleiste, Einstiegssatz, Bildreihen und Fuß saßen auf
     vier verschiedenen Kanten: 24, 32, 16 und 18 Pixel. Auf einem Schirm
     übereinander gesehen wirkt das unaufgeräumt, weil Wortmarke,
     Schlagzeile und Bildraster jeweils woanders anfangen. Alle vier
     benutzen jetzt diesen Wert und beginnen auf derselben senkrechten
     Linie. Die Hülle bleibt davon unberührt: sie ist ein zentrierter
     Satzspiegel, keine Kante. */
  --rand: clamp(16px, 2.2vw, 32px);

  /* Breiten */
  --huelle: 1200px;
  --lesen:  62ch;

  /* Kopfhöhe, wird an mehreren Stellen gebraucht */
  /* Reine Vorgabe. Die tatsächliche Höhe misst rotglut.js und schreibt sie
     hier hinein, weil sie von der Schriftgröße der Wortmarke abhängt. */
  --kopf: 60px;

  /* Formularelemente in der Farbe des Textes statt im Systemblau. */
  accent-color: var(--tinte);
}


/* ==========================================================================
   2. Grundlagen
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;

  /* HIER STAND EIN SICHERHEITSNETZ, UND ES WAR DAS PROBLEM.

     Gegen seitliches Aufschieben lag an html und body ein
     `overflow-x: hidden`, überschrieben von `overflow-x: clip`. Der
     Kommentar an dieser Stelle warnte selbst davor: hidden macht aus html
     und body Scrollbehälter und bricht damit jedes position: sticky darin.
     clip sollte das umgehen.

     Nur greift clip nicht überall. Wo es fehlt — oder wo der Browser trotz
     clip die Wurzel zum Scrollbehälter macht —, gilt die hidden-Zeile, und
     dann klebt nichts mehr: weder die Bildpaneele der Startseite noch der
     Querlauf der Einrichterseite. Nachgestellt und gemessen: mit hidden
     steht die Paneeloberkante bei −600 statt bei 60.

     Ein Sicherheitsnetz, das die halbe Gestaltung abschaltet, ist keines.
     Der Überlauf wird jetzt dort gefasst, wo er entsteht — der Querlauf
     bringt mit .querlauf__fenster seinen eigenen Scrollbehälter mit, und
     das Honigtopf-Feld steht bei -9999px links, wo gar kein scrollbarer
     Überlauf entsteht. Geprüft über alle Seiten und sechs Breiten. */
}

body {
  margin: 0;
  max-width: 100%;
  background: var(--grund);
  color: var(--tinte);
  font-family: var(--ui);
  font-weight: 300;
  font-size: 17px;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

img, video { max-width: 100%; height: auto; display: block; }

/* Fotos lassen sich aus der Seite ziehen und auf dem Schreibtisch ablegen.
   Bei einer Seite, die aus Fotos besteht, ist das die bequemste Art, sie
   mitzunehmen — also wird das Ziehen abgeschaltet.

   WAS DAS IST UND WAS NICHT: es ist eine geschlossene Tür, kein Schloss.
   Die Dateien liegen im Browser, jede Entwicklerkonsole und jeder Aufruf
   der Bildadresse kommt weiter an sie heran. Ein echter Schutz wäre ein
   Wasserzeichen oder kleinere Dateien, und beides kostet etwas.

   Die Kacheln der Inseratsprüfung müssen ziehbar bleiben, dort ordnet man
   Bilder damit um. Sie sind ohnehin Uploads des Besuchers, nicht meine
   Fotos. Gezogen wird dort die figure, nicht das img — deshalb genügt die
   Ausnahme darunter. */
img, video {
  -webkit-user-drag: none;
  user-drag: none;
}

.kachel img {
  -webkit-user-drag: element;
  user-drag: element;
}

/* pretty verhindert, dass ein einzelnes Wort allein in der letzten Zeile
   steht. Browser ohne die Angabe umbrechen wie bisher. */
p { margin: 0 0 var(--m); text-wrap: pretty; }
p:last-child { margin-bottom: 0; }

a { color: inherit; }

/* Die einzige Stelle, an der die Marke als Farbe auftritt. */
/* Markierter Text war das dritte Glut-Signal. Unbunt umgekehrt tut er
   dasselbe und passt sich jeder Fläche an: die Tokens lösen sich am
   markierten Element auf, auf der hellen Platte dreht sich das Verhältnis
   von allein mit. */
::selection { background: var(--tinte); color: var(--grund); }

/* Sprungziele lagen bisher unter der festen Kopfleiste, weil niemand ihr
   dem Browser die Höhe der Leiste genannt hat. Betrifft den Pfeil unter
   dem Einstiegssatz ebenso wie jeden Link mit Raute. */
[id] { scroll-margin-top: calc(var(--kopf) + var(--m)); }

/* Die Naht hinter dem Plakat ist eine Ausnahme. Überall sonst ist die
   Luft über dem Sprungziel richtig — eine Überschrift, die direkt unter
   der Leiste klebt, liest sich gedrängt. Hier ist das Ziel aber keine
   Überschrift, sondern eine Kante: darüber steht das Video des Plakats.
   Mit den sechzehn Pixeln Luft blieb genau dieser Streifen Video unter der
   Leiste stehen. Das Bildpaneel soll bündig an der Leiste anschlagen. */
#weiter { scroll-margin-top: var(--kopf); }

button { font: inherit; color: inherit; }

/* Zwei Pixel statt einem: ein Haarstrich war auf dem hellen Grund kaum
   zu sehen. currentColor bleibt, dadurch stimmt der Rahmen auf der
   dunklen Menütafel ohne eigene Regel. */
:focus-visible { outline: 2px solid currentColor; outline-offset: 4px; }

h1, h2, h3 { margin: 0; font-weight: 300; line-height: 1.15; }

/* Die eine große Überschrift pro Seite: Versalien, weit gesperrt. */
.titel {
  font-size: clamp(30px, 18px + 3.2vw, 60px);
  font-weight: 200;
  line-height: 1.2;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-wrap: balance;
}

/* Beschriftungen: klein, gesperrt, grau. */
.marker {
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--leise);
}


/* ==========================================================================
   3. Bausteine
   ========================================================================== */

.huelle {
  width: min(100% - var(--l), var(--huelle));
  margin-inline: auto;
}

.band { padding-block: var(--xxl); }
.band--eng { padding-block: var(--xl); }

/* Zwei Bildreihen hintereinander sollen als ein Feld lesen. Die folgende
   Reihe rückt so weit auf, dass zwischen den Reihen derselbe Abstand
   bleibt wie zwischen den Bildern einer Reihe. Luft entsteht nur um
   Textblöcke. */
.band--eng + .band--eng {
  padding-top: 0;
  margin-top: calc(var(--m) - var(--xl));
}

@media (max-width: 46rem) {
  .band--eng + .band--eng { margin-top: calc(var(--s) - var(--xl)); }
}

.band--dunkel {
  background: var(--dunkel);
  color: var(--papier);
}

.band--dunkel .marker { color: rgba(250, 250, 250, 0.55); }

/* Kopfblock einer Seite: Haarlinie, Titel, Haarlinie, Rolle. */
.aufschlag { text-align: center; }

.aufschlag .strich {
  width: 120px;
  height: 1px;
  background: var(--linie-2);
  margin-inline: auto;
}

.aufschlag .titel { margin-block: var(--l) var(--m); }
.aufschlag .marker { margin-bottom: var(--l); }

/* Zwei Spalten: Bild und Text. */
.zweispalt {
  display: grid;
  gap: var(--l);
  align-items: start;
}

@media (min-width: 62rem) {
  .zweispalt {
    grid-template-columns: 5fr 6fr;
    gap: var(--xl);
  }
}

.zweispalt__text { max-width: var(--lesen); }
.zweispalt__text p + p { margin-top: var(--m); }

/* Hochformat. Ohne Deckel würde das Bild in der einspaltigen Ansicht
   die volle Hüllenbreite einnehmen und alles erschlagen. */
.zweispalt__bild { margin: 0; }
.zweispalt__bild img { width: 100%; max-width: 420px; }

/* Rechtstexte: lange Fließtexte mit Zwischenüberschriften. Bewusst
   schmal gesetzt, damit die Zeilen lesbar bleiben. */
.rechtstext { max-width: 72ch; }

.rechtstext h2 {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--leise);
  margin: var(--xl) 0 var(--m);
  padding-top: var(--m);
  border-top: 1px solid var(--linie);
}

.rechtstext h3 {
  font-size: 17px;
  font-weight: 500;
  margin: var(--l) 0 var(--s);
}

.rechtstext p { color: var(--grau); }
.rechtstext strong { color: var(--tinte); font-weight: 500; }
.rechtstext a { color: var(--tinte); text-decoration: underline; text-underline-offset: 3px; }
.rechtstext a:hover { text-decoration: none; }

/* Vorher-Nachher: zwei Bilder übereinander, das obere wird beschnitten.
   Bedient wird über einen unsichtbaren Schieberegler, dadurch geht es mit
   Maus, Finger und Tastatur. Ohne JavaScript steht er in der Mitte. */
.vergleich {
  --pos: 50%;
  position: relative;
  overflow: hidden;
  background: var(--matt);
  touch-action: pan-y;
}

.vergleich img {
  display: block;
  width: 100%;
  user-select: none;
  -webkit-user-drag: none;
}

.vergleich__nachher {
  position: absolute;
  inset: 0;
  clip-path: inset(0 calc(100% - var(--pos)) 0 0);
}

.vergleich__griff {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--pos);
  width: 1px;
  background: rgba(250, 250, 250, 0.9);
  pointer-events: none;
}

.vergleich__griff::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 34px;
  height: 34px;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  background: rgba(250, 250, 250, 0.95);
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.25);
}

/* Der Regler liegt unsichtbar über dem ganzen Bild. */
.vergleich__regler {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  appearance: none;
  -webkit-appearance: none;
  background: none;
}

/* Auch auf dem Regler selbst, nicht nur auf dem Rahmen: die Berührung
   landet auf dem Eingabefeld, und ohne die Angabe schiebt der Browser
   dort die Seite, statt den Regler zu bewegen. */
.vergleich__regler { touch-action: pan-y; }

.vergleich__regler::-webkit-slider-thumb { -webkit-appearance: none; width: 60px; height: 100%; }
.vergleich__regler::-moz-range-thumb { width: 60px; height: 100%; border: 0; background: none; }
.vergleich__regler:focus-visible { outline: 2px solid var(--papier); outline-offset: -4px; }

.vergleich__hinweis {
  position: absolute;
  left: 50%;
  bottom: 18px;
  transform: translateX(-50%);
  margin: 0;
  padding: 10px 22px;
  border-radius: 999px;
  background: rgba(30, 30, 28, 0.55);
  backdrop-filter: blur(3px);
  font-size: 10px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(250, 250, 250, 0.95);
  pointer-events: none;
  transition: opacity .4s ease;
}

.vergleich.benutzt .vergleich__hinweis { opacity: 0; }

/* Textblock über einem Vergleich: schmal und zentriert. */
.einleitung { max-width: 62ch; margin-inline: auto; text-align: center; }

/* Linksbündige Variante für redaktionelle Seiten. */
.einleitung--links { margin-inline: 0; text-align: left; }
/* Abschnittsüberschrift: dieselbe Anmutung wie der Seitentitel, nur
   kleiner. Versalien, mager, weit gesperrt. */
.einleitung h2 {
  font-size: clamp(22px, 14px + 1.9vw, 38px);
  font-weight: 200;
  letter-spacing: 0.06em;
  line-height: 1.25;
  text-transform: uppercase;
  text-wrap: balance;
  margin-bottom: var(--l);
}
.einleitung p { color: var(--grau); }

/* Einzelbild zwischen zwei Textblöcken. Bewusst schmaler als die Hülle,
   damit es ruhig steht und die Bilder im Querlauf die größeren bleiben. */
.bildband { margin: 0 auto; max-width: 860px; }
.bildband img { width: 100%; }

/* --------------------------------------------------------------------------
   Redaktionelle Bausteine der Startseite

   Zwei Werkzeuge, die den Rhythmus machen:

   1. WUCHT — Aussagen in der Größe des Einstiegssatzes, nicht kleiner.
      Sie stehen links, rechts oder über die volle Breite, nie mittig.

   2. MOSAIK — ein Raster aus zwölf Spalten, in dem jedes Bild seine
      eigene Größe und Position bekommt. Leere Felder gehören dazu.
   -------------------------------------------------------------------------- */

/* --- Wucht ---------------------------------------------------------------- */

.wucht { padding-block: var(--xxl); }

.wucht h1,
.wucht h2 {
  /* Die Umbrüche stehen im Text als <br>. Damit der Browser nicht noch
     einmal zusätzlich umbricht, richtet sich die Schriftgröße nach der
     längsten Zeile: --zeichen steht am Element.

     ACHTUNG, --zeichen ist KEINE Zeichenzahl mehr. Es war einmal eine,
     zusammen mit dem Faktor 1.55 als angenommener mittlerer Zeichenbreite.
     Gemessen hat eine Versalie in Syne aber 0.825 em statt der
     unterstellten 0.645, und je nach Buchstaben schwankt es zwischen 1.25
     und 1.45. Auf breiten Schirmen fiel das nicht auf, weil die Obergrenze
     von 72px greift. Auf dem Handy lief die Zeile aus dem Bild.

     --zeichen ist jetzt die tatsächliche Breite der längsten Zeile in em,
     mal 1.55, aufgerundet, mit zwei Prozent Reserve. Der Faktor 1.55 kürzt
     sich damit aus der Rechnung heraus und die Zeile füllt die Spalte
     genau. Wer eine Überschrift ändert, misst den Wert nach, statt Zeichen
     zu zählen.

     UND BEIM NACHMESSEN ZWEI FALLEN. Ein Range über den Inhalt liefert mit
     getClientRects ein Rechteck je INLINE-KASTEN, nicht je Zeile: das
     ausgestellte Wort im <em> hat eigene Auszeichnung und zerlegt seine
     Zeile in mehrere Rechtecke. Wer davon das breiteste nimmt, misst ein
     Bruchstück — und zwar genau bei den Überschriften, deren längste Zeile
     das <em> enthält. Die Rechtecke gehören nach Oberkante gruppiert und je
     Gruppe von der linkesten zur rechtesten Kante gerechnet. Zweitens muss
     für die Messung white-space: nowrap gelten, sonst misst man bei einer
     umbrechenden Zeile ebenfalls nur ein Bruchstück. Mit beidem stimmen
     alle zwölf vorhandenen Überschriften auf den Punkt, ohne das vier
     nicht. */
  --zeichen: 24;

  font-family: var(--marke);
  font-size: min(72px, calc(min(1200px, 100vw - 64px) / var(--zeichen) * 1.55));
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: 0;
  text-transform: uppercase;
  hyphens: none;
  overflow-wrap: normal;
}

.wucht--rechts h1,
.wucht--rechts h2 { margin-left: auto; text-align: right; }

/* Beitext: eine Stufe größer als Fließtext, damit er neben der großen
   Überschrift nicht wie eine Fußnote wirkt. Im rechten Block steht er
   rechtsbündig, damit der Block als Ganzes an einer Kante sitzt. */
.wucht__rand {
  margin-top: var(--l);
  max-width: 46ch;
  font-size: clamp(17px, 15px + 0.4vw, 20px);
  line-height: 1.7;
  color: var(--grau);
}

.wucht__rand + .wucht__rand { margin-top: var(--m); }
.wucht--rechts .wucht__rand { margin-left: auto; text-align: right; }

.wucht__knopf { margin-top: var(--l); }
.wucht--rechts .wucht__knopf { display: flex; justify-content: flex-end; }

/* Eine Zeile darf auch mal absetzen, ohne dass Farbe nötig wird. */
/* Eine Zeile darf auch mal absetzen, ohne dass Farbe nötig wird.
   Die Kontur ist in em angegeben, nicht in Pixeln: ein fester Haarstrich
   von einem Pixel wirkte unter einer 72 Pixel hohen Versalie dünn und
   zerfranst, unter der halb so großen Zeile auf dem Handy dagegen fett.
   Mit 0.02em behält die Kontur bei jeder Größe dasselbe Gewicht. */
.wucht em { font-style: normal; -webkit-text-stroke: 0.02em var(--tinte); color: transparent; }

/* --- Bildreihen -----------------------------------------------------------
   Drei Spalten über die volle Fensterbreite, mit Abstand. Die Bilder
   laufen beim Erreichen des Sichtfelds nacheinander ein, kein Hovereffekt.
   -------------------------------------------------------------------------- */

/* Die Fuge ist die schmale Stufe, nicht die mittlere. Bei sechzehn Pixeln
   lag zwischen den Kacheln mehr Luft als nötig und die Fotos wurden kleiner
   als sie sein dürfen — ein Raster aus Fotos soll als Fläche lesen, nicht
   als neun Einzelbilder. Acht Pixel halten die Kacheln getrennt und geben
   jeder gut fünf Pixel mehr Breite. Dieselbe Fuge gilt auf dem Handy und
   in der randlosen ersten Reihe; sie ist damit überall dieselbe. */
.reihe {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--s);
  width: 100%;
  padding-inline: var(--rand);
}

@media (max-width: 46rem) { .reihe { grid-template-columns: repeat(2, 1fr); gap: var(--s); } }

/* Auf dem Handy im Hochformat wären zwei Spalten rund 170 px breit. Dann
   ist von einem Hotelzimmer nichts mehr zu erkennen. Deshalb dort ein Bild
   je Zeile, über die volle Breite. */
@media (max-width: 34rem) { .reihe { grid-template-columns: 1fr; } }

.reihe figure { margin: 0; }

.reihe img,
.reihe video {
  width: 100%;
  aspect-ratio: 3 / 2;
  object-fit: cover;
  display: block;
  background: var(--matt);
}

/* Oben steht, die Bilder laufen nacheinander ein. Getan haben sie das
   nie: alle neun Kacheln teilten sich dieselbe Übergangszeit und kippten
   im selben Augenblick herein. Jede Kachel bekommt jetzt ihre eigene
   kleine Verzögerung, sodass die Reihe von links oben nach rechts unten
   aufgeht. Neun Werte, weil eine Reihe neun Kacheln fasst. Kürzere
   Reihen lassen die hinteren Regeln einfach ungenutzt. */
.js .reihe figure {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity .9s cubic-bezier(.2, .6, .2, 1),
              transform .9s cubic-bezier(.2, .6, .2, 1);
}

.js .reihe figure:nth-child(1) { transition-delay:   0ms; }
.js .reihe figure:nth-child(2) { transition-delay:  70ms; }
.js .reihe figure:nth-child(3) { transition-delay: 140ms; }
.js .reihe figure:nth-child(4) { transition-delay: 190ms; }
.js .reihe figure:nth-child(5) { transition-delay: 260ms; }
.js .reihe figure:nth-child(6) { transition-delay: 330ms; }
.js .reihe figure:nth-child(7) { transition-delay: 380ms; }
.js .reihe figure:nth-child(8) { transition-delay: 450ms; }
.js .reihe figure:nth-child(9) { transition-delay: 520ms; }

.js .reihe.da figure { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  .js .reihe figure { opacity: 1; transform: none; transition-delay: 0s; }
}

/* --- Wer schon vor der Kamera stand ---------------------------------------
   Sechsunddreißig Häuser als Aufzählung wären ein Inventar gewesen. Als
   Fließtext mit Trennpunkten lesen sie sich als Masse — und Masse ist hier
   die Aussage. Der Kniff ist von der Schwesterseite übernommen.

   Auf der Schwesterseite sind einige Namen hervorgehoben. Hier nicht: dort
   sind es Auftraggeber verschiedenen Gewichts, hier sind es Häuser, und
   keines davon steht über dem anderen.

   Die Trennpunkte stehen in ::after, nicht im Text. So liest ein
   Screenreader die Namen und nicht zwischen jedem einen Punkt, und der
   letzte bekommt keinen.
   -------------------------------------------------------------------------- */

/* Der eine Satz über dem Strom. Er sagt, was die Namen sonst nur andeuten,
   und er hält die Ortsverankerung auch dann, wenn den Häusern selbst
   irgendwann die Ortsangaben fehlen. Jede der vier genannten Ecken steht
   wirklich in der Liste — Ostsee und Nordsee, Füssen, Mosel, Thüringen. */
.haeuser__spanne {
  margin: 0 0 var(--l);
  max-width: 64ch;
  color: var(--grau);
}

/* Sachlich heisst nicht unbearbeitet. Drei Mittel, alle aus der Sprache
   der Seite, keines davon Dekoration:

   Versalien mit Sperrung — dieselbe Auszeichnung, die auf der Seite die
   Marker und den Einstiegshinweis trägt. Sie macht aus einem Absatz eine
   Textur: man liest nicht mehr Satz für Satz, sondern sieht eine Fläche,
   in der Namen stehen. Die Sperrung ist enger als bei den Markern
   (0.08 statt 0.26em) — die sind drei Wörter lang, das hier sind
   siebenunddreissig.

   Blocksatz — er gibt der Fläche zwei gerade Kanten. Ein Flatterrand liest
   sich als Aufzählung, ein Block als Gegenstand.

   Ein Haarstrich darüber — die Linie, mit der sich auf dieser Seite jeder
   Abschnitt über die Bilder schiebt, hier als Auftakt. */
.haeuser {
  margin: 0;

  /* KEINE Breitenbegrenzung. Mit 72ch war der Block 552 Pixel schmal, es
     standen ein bis zwei Namen je Zeile, und damit hatte der Blocksatz
     nichts zu dehnen — der rechte Rand flatterte trotzdem. Über die ganze
     Hülle stehen vier bis fünf Namen nebeneinander: erst dadurch wird aus
     der Aufzählung eine Fläche, und erst dadurch greift der Blocksatz.

     Das ist zugleich der Aufbau: die Überschrift bleibt rechtsbündig, das
     Namensfeld läuft über die volle Breite. Der Gegensatz ist gewollt. */
  padding-top: var(--l);
  border-top: 1px solid var(--linie);

  font-size: 0.78rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  line-height: 2.1;
  text-align: justify;
  color: var(--leise);
}

/* Beim Überfahren tritt der einzelne Name hervor. Kein Verweis, keine
   Bedienung — nur ein Zeichen, dass dort einzelne Häuser stehen und nicht
   eine Tapete. */
.haeuser span { transition: color .25s ease; }
.haeuser span:hover { color: var(--tinte); }

/* inline-block, nicht nur nowrap. `nowrap` verhindert den Umbruch, aber
   nicht das Dehnen: der Blocksatz zog die Abstände INNERHALB der Namen
   auseinander, und „Restaurant Vino Sands Timmendorfer Strand" zerfiel in
   fünf Einzelwörter. Ein inline-block wird als ein Stück gesetzt — gedehnt
   wird dann nur der Raum zwischen den Namen, und genau das soll er. */
.haeuser span {
  display: inline-block;
  white-space: nowrap;
}

.haeuser span::after {
  content: " · ";
  color: var(--linie-2);
  white-space: normal;

  /* Der Punkt darf beim Überfahren nicht mit aufleuchten — er gehört
     nicht zum Namen, er trennt ihn vom nächsten. */
  transition: none;
}

.haeuser span:last-child::after { content: ""; }

/* Eine Liste ohne Hinweis liest sich als vollständig — sie ist aber eine
   Auswahl. Der Schluss sagt das, und er sagt es leiser als die Namen: er
   ist kein Haus und soll auch nicht wie eines aussehen. */
.haeuser__mehr {
  color: var(--linie-2);
  font-style: italic;
}

/* Rechtsbündige Abschnitte stellen den Block nach rechts, der Text darin
   bleibt linksbündig: eine Namenskolonne mit rechtem Flattersatz wäre
   nicht zu lesen. */
/* Der Spannen-Satz folgt der Ausrichtung des Abschnitts, das Namensfeld
   nicht — es nimmt die ganze Breite. */
.wucht--rechts .haeuser__spanne {
  margin-left: auto;
  text-align: left;
}

/* Auf dem Handy kein Blocksatz. Bei 390 Pixeln steht oft nur ein Name je
   Zeile — der Blocksatz hätte dann nichts zu dehnen ausser den Lücken
   zwischen zwei Namen, und die würden zu Löchern. Linksbündig und eine
   Spur kleiner. */
@media (max-width: 46rem) {
  .haeuser {
    text-align: left;
    font-size: 0.72rem;
    line-height: 2;
    letter-spacing: 0.06em;
  }

  /* Und der Umbruch innerhalb eines Namens muss erlaubt sein. „Strandgrün
     Golf- & Spa Resort Timmendorfer Strand" ist bei 390 Pixeln breiter als
     die Spalte; mit nowrap schob es die ganze Seite seitlich auf —
     gemessen. Ein umgebrochener Name ist das kleinere Übel als eine Seite,
     die quer scrollt. */
  .haeuser span { white-space: normal; }
}

/* --- Drei Wege ------------------------------------------------------------ */

.wege { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--l); }

@media (min-width: 56rem) { .wege { grid-template-columns: repeat(3, 1fr); gap: var(--xl); } }

/* Die Oberkante ist die einzige Linie, die eine Spalte hat. Beim
   Überfahren wird sie dunkel: die Spalte antwortet, ohne dass ein Kasten,
   ein Schatten oder eine Fläche dazukommt. */
.weg { border-top: 1px solid var(--linie); padding-top: var(--m); transition: border-top-color .3s ease; }
.weg:hover { border-top-color: var(--tinte); }

/* Ziffern auf gleicher Breite, sonst steht die 1 in 01 schmaler als die
   0 in 02 und die drei Spalten fangen minimal versetzt an. */
.weg__nr { font-size: 11px; letter-spacing: 0.15em; color: var(--leise); font-variant-numeric: tabular-nums; }

.weg__titel {
  margin: var(--s) 0 var(--m);
  font-size: clamp(20px, 16px + 0.8vw, 28px);
  font-weight: 300;
  letter-spacing: 0.02em;
  text-wrap: balance;
}

.weg__titel a { text-decoration: none; }
.weg__titel a:hover { text-decoration: underline; text-underline-offset: 4px; }
.weg p { color: var(--grau); font-size: 16px; }

/* --- Fragen ---------------------------------------------------------------
   Ausklapper ohne JavaScript, über das eingebaute details-Element.
   -------------------------------------------------------------------------- */

.fragen { max-width: 78ch; margin-inline: auto; }

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

.frage summary {
  list-style: none;
  cursor: pointer;
  padding: var(--m) 0;
  padding-right: var(--l);
  position: relative;
  font-size: clamp(17px, 15px + 0.4vw, 21px);
  font-weight: 400;
  text-wrap: balance;
  transition: color .2s ease;
}

.frage summary::-webkit-details-marker { display: none; }
.frage summary:hover { color: var(--tinte); }

/* Das Zeichen rechts war ein Pluszeichen aus der Schrift, das beim
   Öffnen gegen einen Halbgeviertstrich getauscht wurde. Zwei
   verschiedene Formen, verschieden breit, verschieden hoch sitzend: sie
   können nicht ineinander übergehen, und die angehängte Bewegung lief
   deshalb ins Leere. Es fing außerdem an einer festen Stelle von oben an
   und stand bei zweizeiligen Fragen zu hoch.

   Jetzt sind es zwei gezeichnete Striche, mittig zur Zeile. Der
   senkrechte dreht sich beim Öffnen auf den waagerechten, aus dem Plus
   wird ein Minus, und man sieht die Drehung. */
.frage summary::before,
.frage summary::after {
  content: "";
  position: absolute;
  right: 2px;
  top: 50%;
  width: 15px;
  height: 1px;
  background: var(--leise);
  transition: transform .35s cubic-bezier(.2, .6, .2, 1), background-color .25s ease;
}

.frage summary::before { transform: translateY(-50%) rotate(90deg); }
.frage summary::after  { transform: translateY(-50%); }

.frage[open] summary::before { transform: translateY(-50%) rotate(0deg); }

.frage summary:hover::before,
.frage summary:hover::after,
.frage[open] summary::before,
.frage[open] summary::after { background: var(--tinte); }

.frage p {
  margin: 0 0 var(--m);
  max-width: 68ch;
  color: var(--grau);
}

/* Der Antworttext sprang bisher hart ins Bild. Wo der Browser eine Höhe
   zwischen null und "auto" berechnen kann, wird daraus eine Bewegung.
   Alle anderen klappen weiter hart auf, es fehlt ihnen nichts. */
@supports (interpolate-size: allow-keywords) {
  :root { interpolate-size: allow-keywords; }

  .frage::details-content {
    block-size: 0;
    overflow: hidden;
    opacity: 0;
    transition: block-size .38s cubic-bezier(.2, .6, .2, 1),
                opacity .3s ease,
                content-visibility .38s;
    transition-behavior: allow-discrete;
  }

  .frage[open]::details-content { block-size: auto; opacity: 1; }
}

/* --------------------------------------------------------------------------
   Einstieg der Startseite: nur Schrift, ein Wort je Zeile, die Zeilen
   erscheinen nacheinander. Aufbau wie auf stephanpatzsch.de, dort in
   Gold, hier unbunt.
   -------------------------------------------------------------------------- */

.satz {
  /* Der Satz muss samt Unterzeile und Pfeil ohne Scrollen sichtbar sein.
     Deshalb begrenzt die Schriftgröße nicht nur die Breite (vw), sondern
     auch die Höhe (vh). Die Rechnung: sieben Zeilen mal 1.08 Zeilenhöhe,
     dazu der Abstand zur Unterzeile, die Unterzeile selbst mit ihren zwei
     Zeilen und die Polsterung oben und unten.

     dvh statt vh, weil auf Mobilgeräten die Adressleiste ein- und
     ausfährt. Mit vh rechnet der Browser dort mit der größeren Höhe und
     schneidet die erste Zeile ab. */
  height: calc(100vh - var(--kopf));
  height: calc(100dvh - var(--kopf));
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--m) var(--rand) var(--xl);
  position: relative;
  overflow: hidden;
}

.satz__inhalt { display: flex; flex-direction: column; width: fit-content; }

.satz__zeile {
  font-family: var(--marke);
  /* Die Höhe wird nicht mehr als Anteil des Fensters geschätzt, sondern
     ausgerechnet: vom Fenster gehen der Kopf und alles ab, was neben den
     sieben Zeilen noch Platz braucht (Polsterung, Abstand, die zweizeilige
     Unterzeile, etwas Reserve). Der Rest geteilt durch 7 mal 1.08. So passt
     der Satz auch in niedrige Fenster, statt oben abgeschnitten zu werden. */
  /* Rechnung im CSS, Feinschliff im Skript: --satzgroesse wird nur gesetzt,
     wenn der Satz trotz Rechnung nicht ins Fenster passt. */
  font-size: var(--satzgroesse, min(12vw, calc((100dvh - var(--kopf) - 200px) / 7.56)));
  font-weight: 700;
  /* Unter 1.0 ragen die Punkte von Ä, Ö und Ü in die Zeile darüber.
     Bei sieben Zeilen kostet das Höhe, deshalb ist die Schriftgröße
     entsprechend kleiner gerechnet. */
  line-height: 1.08;
  letter-spacing: 0;
  text-transform: uppercase;
  display: block;
  width: fit-content;
}

.satz h1 { display: flex; flex-direction: column; margin: 0; font-size: inherit; font-weight: inherit; }

.satz__unter {
  margin-top: var(--l);
  /* Keine Breitenbegrenzung: die Einheit ch rechnet ohne die Sperrung,
     dadurch bricht die Zeile viel zu früh um. Der Umbruch wird im Text
     mit <br> gesetzt. */
  max-width: none;
  font-size: clamp(11px, 0.4vw + 9px, 14px);
  font-weight: 500;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--grau);
}

/* --- Der Hinweis nach unten -----------------------------------------------
   Hier stand ein Pfeil, ein ↓ in der rechten unteren Ecke. Zwei Dinge
   sprachen dagegen: ein Schriftzeichen als Bedienhinweis ist kein
   gezeichnetes Zeichen, und vor einem laufenden Bild las es sich wie eine
   Schaltfläche aus einer anderen Anwendung.

   Jetzt steht ein Wort mittig auf der Unterkante, und darunter hängt ein
   Faden bis auf die Grundlinie des Einstiegs. Ein heller Tropfen läuft ihn
   hinunter — das ist die Richtungsangabe, ohne dass eine Pfeilspitze
   nötig wäre. Dieselbe Machart wie die Trennlinien im Menü: gezeichnet,
   nicht gesetzt. */

.satz__entdecken {
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: var(--l);
  z-index: 2;

  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;

  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--grau);
  text-decoration: none;
  white-space: nowrap;
  transition: color .3s ease;
}

/* Die Sperrung schiebt das Wort nach links aus der Mitte: der Zwischenraum
   hinter dem letzten Buchstaben zählt zur Breite. Ein halber Schritt nach
   rechts stellt es zurück auf die Achse des Fadens. */
.satz__entdecken__wort { margin-right: -0.26em; }

.satz__entdecken__faden {
  position: relative;
  width: 1px;
  height: 26px;
  background: var(--linie-2);
  overflow: hidden;
  transition: height .3s cubic-bezier(.2, .6, .2, 1);
}

/* Der einzige farbige Punkt der Seite. Er war weiß wie der Faden und ging
   darin unter; in Glut ist er das, was der Name verspricht.

   HIER LAG EINMAL EIN SCHEIN darum, zwei Stufen weich auslaufend. Dafür
   musste der Faden zu einem 24 Pixel breiten Kasten werden, weil sein
   overflow: hidden den Schein seitlich abgeschnitten hätte, und die Linie
   zog in ein eigenes ::before um. Viel Gerüst für einen Pixel — der Punkt
   allein sagt dasselbe. */
.satz__entdecken__faden::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 10px;
  background: var(--glut);
  animation: tropfen 2.6s cubic-bezier(.55, 0, .45, 1) infinite;
}

.satz__entdecken:hover { color: var(--tinte); }
.satz__entdecken:hover .satz__entdecken__faden { height: 34px; }

@keyframes tropfen {
  0%   { top: -10px; opacity: 0; }
  20%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { top: 100%; opacity: 0; }
}

/* Zeilen laufen nacheinander ein. */
.js .satz__zeile { opacity: 0; transform: translateY(20px); transition: opacity .7s ease, transform .7s ease; }
.js .satz.da .satz__zeile { opacity: 1; transform: none; }

@media (max-width: 46rem) {
  .satz__zeile { font-size: min(14vw, 9.5vh); }

  /* Auf dem Handy ist unter dem Plakat kein Platz mehr für einen Hinweis:
     das Wort lief mitten in die Unterzeile. Es wird dort auch nicht
     gebraucht — wer ein Telefon in der Hand hält, wischt ohnehin. Damit
     geht auf dem Handy auch der Funke, er hängt am Hinweis. */
  .satz__entdecken { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .satz__entdecken__faden::after { animation: none; opacity: 0; }
  .js .satz__zeile { opacity: 1; transform: none; }
}

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

.kontakt {
  display: grid;
  gap: var(--xl);
  align-items: start;
}

@media (min-width: 62rem) { .kontakt { grid-template-columns: 4fr 7fr; } }

.kontakt h2 {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--leise);
  margin-bottom: var(--m);
}

.kontakt address { font-style: normal; color: var(--grau); line-height: 2; }
.kontakt address strong { color: var(--tinte); font-weight: 500; }
.kontakt address a { color: var(--tinte); text-decoration: underline; text-underline-offset: 3px; }

.formular { display: grid; gap: var(--m); }

.feld { display: grid; gap: 6px; }

.feld label {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--leise);
}

.feld input,
.feld textarea {
  font: inherit;
  color: var(--tinte);
  background: var(--flaeche);
  border: 1px solid var(--linie-2);
  padding: 12px 14px;
  width: 100%;
}

.feld textarea { min-height: 200px; resize: vertical; }
.feld input:hover, .feld textarea:hover { border-color: var(--grau); }
.feld input:focus, .feld textarea:focus { outline: none; border-color: var(--tinte); }

/* Fehler erst zeigen, wenn abgeschickt wurde. */
.formular.geprueft .feld input:invalid,
.formular.geprueft .feld textarea:invalid { border-color: #a4402c; }

.feld__fehler { font-size: 13px; color: #a4402c; display: none; }
.formular.geprueft .feld input:invalid ~ .feld__fehler,
.formular.geprueft .feld textarea:invalid ~ .feld__fehler { display: block; }

/* Honigtöpfe: für Menschen unsichtbar, für Maschinen verlockend. */
.honig {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.melder { font-size: 15px; line-height: 1.7; }
.melder:empty { display: none; }
.melder strong { font-weight: 500; }
.melder--gut { color: var(--tinte); border-left: 2px solid var(--tinte); padding-left: var(--m); }
.melder--schlecht { color: #a4402c; border-left: 2px solid #a4402c; padding-left: var(--m); }
.melder a { color: inherit; }
.melder__grund { color: var(--leise); font-size: 13px; }

/* --------------------------------------------------------------------------
   Querlauf: Der Abschnitt bleibt stehen, während die Bilder seitlich
   durchlaufen. Ohne JavaScript ist es ein normaler Streifen, den man
   seitlich scrollt oder wischt. Das Skript hängt die Bewegung an den
   Scrollstand und setzt dafür die Höhe des Abschnitts.
   -------------------------------------------------------------------------- */

.querlauf__kopf { text-align: center; padding-bottom: var(--l); }

.querlauf__kopf h2 {
  font-size: clamp(22px, 14px + 1.9vw, 38px);
  font-weight: 200;
  letter-spacing: 0.06em;
  line-height: 1.25;
  text-transform: uppercase;
}

.querlauf__fenster {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}

.querlauf__bahn {
  display: flex;
  gap: var(--l);
  padding-inline: var(--m);
  width: max-content;
}

/* Alle Bilder laufen auf gleicher Höhe, die Breite ergibt sich aus dem
   Seitenverhältnis. So gibt es keine Höhensprünge und nichts wird
   beschnitten, auch wenn Hoch- und Querformat gemischt sind. */
.querlauf__bild {
  flex: 0 0 auto;
  margin: 0;
  max-width: 88vw;
  scroll-snap-align: center;
}

.querlauf__bild img {
  height: min(62vh, 600px);
  width: auto;
  max-width: 88vw;
  object-fit: contain;
}

/* Die Unterschrift bekommt eine feste Obergrenze. Ohne sie bestimmt die
   Textlänge die Breite der Zelle statt das Bild, und schmale Hochformate
   bekommen trotzdem eine lesbare Spalte. */
.querlauf__bild h3,
.querlauf__bild p { max-width: 46ch; }

.querlauf__bild h3 {
  margin-top: var(--m);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

.querlauf__bild p { margin-top: var(--s); font-size: 15px; color: var(--grau); }

/* Mit JavaScript wird daraus der klebende Ablauf. */
.js .querlauf { position: relative; }
.js .querlauf__klebe { position: sticky; top: var(--kopf); padding-block: var(--l); }
.js .querlauf__fenster { overflow: hidden; scroll-snap-type: none; }
.js .querlauf__bahn { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  .js .querlauf { height: auto !important; }
  .js .querlauf__klebe { position: static; }
  .js .querlauf__fenster { overflow-x: auto; }
  .js .querlauf__bahn { transform: none !important; }
}

/* Rundgang im Rahmen. */
.rundgang {
  position: relative;
  aspect-ratio: 16 / 9;
  background: var(--dunkel);
  overflow: hidden;
}

.rundgang iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Der Rundgang fängt das Mausrad ab, um zu zoomen. Fährt man beim Scrollen
   darüber, bleibt die Seite stehen. Deshalb liegt ein Schleier darauf, der
   alle Zeiger abfängt. Erst ein Klick übergibt die Bedienung an den
   Rundgang, ein Klick daneben oder Escape nimmt sie zurück. */
.rundgang__schleier {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: var(--m);
  background: transparent;
  border: 0;
  color: var(--papier);
  font: inherit;
  cursor: pointer;
}

.rundgang__schleier span {
  padding: 10px 20px;
  background: rgba(27, 36, 48, 0.74);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  transition: background-color .25s ease;
}

.rundgang__schleier:hover span,
.rundgang__schleier:focus-visible span { background: rgba(27, 36, 48, 0.9); }

.rundgang.aktiv .rundgang__schleier { display: none; }

@media (max-width: 46rem) { .rundgang { aspect-ratio: 4 / 3; } }

/* Knopf: Versalien, Rahmen, füllt sich beim Überfahren. */
.knopf {
  display: inline-block;
  background: transparent;
  border: 1px solid currentColor;
  padding: 14px 32px;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: background-color .3s cubic-bezier(.2, .6, .2, 1),
              border-color .3s cubic-bezier(.2, .6, .2, 1),
              color .3s cubic-bezier(.2, .6, .2, 1),
              transform .12s ease;
}

/* Beim Überfahren tauschen Schrift und Grund die Rolle. Beide Werte
   kommen aus der Umgebung, dadurch stimmt es auf hellem wie auf dunklem
   Grund ohne Sonderregel.

   Die Rahmenfarbe muss dabei ausdrücklich mitgesetzt werden. Über
   currentColor hätte der Rahmen die neue, helle Schriftfarbe angenommen
   und einen hellen Ring um die dunkle Fläche gelegt.

   Der Tastaturfokus füllt den Knopf nicht mehr mit. Der Fokusrahmen
   liegt außerhalb und übernimmt currentColor: das wäre nach dem Tausch
   die helle Schriftfarbe gewesen, also ein heller Rahmen auf hellem
   Grund. Ohne den Tausch bleibt er dunkel und damit sichtbar. */
.knopf:hover {
  background: var(--tinte);
  border-color: var(--tinte);
  color: var(--grund);
}

.knopf:active { transform: translateY(1px); }

.knopfreihe {
  display: flex;
  flex-wrap: wrap;
  gap: var(--m);
  justify-content: center;
}

/* Abschlussband mit Telefon und Anfrage. */
.abschluss { text-align: center; }
.abschluss .knopfreihe { margin-top: var(--l); }

.abschluss .titel {
  font-size: clamp(22px, 14px + 1.7vw, 34px);
  text-wrap: balance;
  font-weight: 200;
  letter-spacing: 0.3em;
  margin-right: -0.3em;
}

.abschluss p { max-width: 56ch; margin: var(--m) auto 0; color: var(--grau); }


/* ==========================================================================
   4. Kopf und Menü
   ========================================================================== */

.kopf {
  position: fixed;
  inset: 0 0 auto;
  z-index: 9990;
  background: var(--flaeche);
  border-bottom: 1px solid rgba(0, 0, 0, 0.10);
}

/* Unter der Leiste läuft die ganze Seite durch, meist ein Foto. Deckend
   weiß schneidet sie das hart ab. Durchscheinend mit Weichzeichner
   bleibt zu ahnen, dass dort etwas vorbeizieht, und die Wortmarke
   verliert dabei keinen Kontrast: 82 Prozent Weiß reichen dafür aus.
   Nur dort, wo der Browser den Weichzeichner beherrscht. Alle anderen
   behalten die deckende Fläche aus der Regel darüber.

   ACHTUNG, der Weichzeichner darf nicht an .kopf selbst hängen. Wie
   filter macht backdrop-filter das Element zum Bezugsrahmen für alles
   darin, was position: fixed ist. Die Menütafel steht in der Kopfleiste
   und maß sich dann nicht mehr am Fenster, sondern an der Leiste: sie
   schrumpfte auf Leistenhöhe zusammen. Der Weichzeichner liegt deshalb
   auf einer Ebene davor, die keine Vorfahrin der Tafel ist. */
@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .kopf { background: transparent; }

  .kopf::before {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(255, 255, 255, 0.82);
    -webkit-backdrop-filter: blur(14px) saturate(1.4);
    backdrop-filter: blur(14px) saturate(1.4);
  }

  /* Damit Wortmarke und Schalter über der Schicht liegen, nicht darunter. */
  .kopf__innen { position: relative; }
}

.kopf__innen {
  display: flex;
  align-items: center;
  padding: 10px var(--rand);
}

/* Platzhalter, damit der Inhalt nicht unter dem festen Kopf beginnt. */
.kopfplatz { height: var(--kopf); }

/* Wortmarke: ROTGLUT in Syne, darunter die Leistungszeile, auf exakt
   dieselbe Breite verteilt. Deshalb steht dort ein Buchstabe je span. */
.wortmarke {
  display: inline-flex;
  flex-direction: column;
  align-items: stretch;
  line-height: 1.1;
  text-decoration: none;
  color: var(--tinte);
}

.wortmarke__haupt {
  font-family: var(--marke);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 0.10em;
  margin-right: -0.10em;
  /* Dieselbe Regung wie bei der Marke im Fuß: die Sperrung öffnet sich
     leicht. Die Leistungszeile darunter verteilt sich über dieselbe
     Breite und geht deshalb von allein mit. */
  transition: letter-spacing .35s ease, margin-right .35s ease;
}

.wortmarke:hover .wortmarke__haupt,
.wortmarke:focus-visible .wortmarke__haupt {
  letter-spacing: 0.13em;
  margin-right: -0.13em;
}

.wortmarke__unter {
  display: flex;
  justify-content: space-between;
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0;
  /* War ein fester Wert und wäre auf der anthrazitblauen Kopfleiste
     unsichtbar geblieben — genau die Falle aus der Werkzeugtafel. */
  color: var(--grau);
  margin-top: 5px;
}

/* Schalter */
#menue-schalter { position: absolute; opacity: 0; pointer-events: none; }

.schalter {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-left: auto;
  position: relative;
  z-index: 10000;
  cursor: pointer;
  user-select: none;
  -webkit-user-select: none;
}

.schalter * { cursor: pointer; }

.schalter__wort {
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  line-height: 1;
  transition: color .3s ease;
}

.schalter__striche {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 24px;
  height: 17px;
}

.schalter__striche span {
  display: block;
  height: 2px;
  background: currentColor;
  transition: transform .3s ease, opacity .2s ease;
}

/* Tafel */
.tafel {
  position: fixed;
  inset: 0;
  z-index: 9995;
  /* Sehr dezent ein Foto hinter der Tafel: die Deckschicht lässt nur etwa
     zehn Prozent durch, mehr würde die Menüzeilen unruhig machen. Das Bild
     wird erst geladen, wenn die Tafel geöffnet wird, weil sie bis dahin
     unsichtbar ist. Fehlt es, bleibt die Tafel schlicht dunkel. */
  background:
    linear-gradient(rgba(10, 14, 20, 0.90), rgba(10, 14, 20, 0.90)),
    var(--dunkel) url('../images/leistungen/menue-kueche.webp') center 60% / cover no-repeat;
  color: var(--papier);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 112px 32px 48px;
  overflow-y: auto;
  opacity: 0;
  visibility: hidden;
  transition: opacity .4s ease, visibility .4s;
}

#menue-schalter:checked ~ .tafel { opacity: 1; visibility: visible; }

/* Die Tafel blendete als eine Fläche ein, alles darauf zugleich.

   Jetzt wird sie gezeichnet. Zuerst läuft der Trennstrich einer Zeile
   von links aus, kurz danach kommt die Zeile selbst nach: Linie, Wort,
   Linie, Wort, sechsmal von oben nach unten. Die Zeilen steigen dabei
   nur noch acht Pixel statt vierzehn. Die Striche tragen die Bewegung,
   der Text muss es nicht mehr auch noch tun, und dadurch wird es ruhiger
   statt lebhafter.

   --takt ist der Einsatz einer Zeile. Strich und Text lesen denselben
   Wert, der Text mit neunzig Millisekunden Vorsprung des Striches. Wer
   das Ganze schneller oder langsamer haben will, ändert die sechs Werte,
   nicht die Regeln darüber.

   Die Verzögerungen stehen nur im geöffneten Zustand. Beim Schließen
   fällt alles ohne Wartezeit zusammen, sonst hinge die Tafel nach.

   Wer Bewegung abbestellt hat, bekommt sie hier nicht: die Regel am Ende
   der Datei nimmt die Übergänge heraus, die Endwerte gelten trotzdem. */
.tafel__frage,
.tafel__zeile,
.tafel__fuss {
  opacity: 0;
  transform: translateY(8px);
  transition: opacity .5s ease, transform .5s cubic-bezier(.16, .84, .44, 1);
}

#menue-schalter:checked ~ .tafel .tafel__frage,
#menue-schalter:checked ~ .tafel .tafel__zeile,
#menue-schalter:checked ~ .tafel .tafel__fuss { opacity: 1; transform: none; }

#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(1) { --takt:  70ms; }
#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(2) { --takt: 135ms; }
#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(3) { --takt: 200ms; }
#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(4) { --takt: 265ms; }
#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(5) { --takt: 330ms; }
#menue-schalter:checked ~ .tafel .tafel__zeile:nth-child(6) { --takt: 395ms; }

#menue-schalter:checked ~ .tafel .tafel__zeile::before,
#menue-schalter:checked ~ .tafel .tafel__zeile:last-child::after { transition-delay: var(--takt, 0ms); }

#menue-schalter:checked ~ .tafel .tafel__zeile { transition-delay: calc(var(--takt, 0ms) + 90ms); }

#menue-schalter:checked ~ .tafel .tafel__frage { transition-delay:  40ms; }
#menue-schalter:checked ~ .tafel .tafel__fuss  { transition-delay: 520ms; }
#menue-schalter:checked ~ .schalter .schalter__wort { color: var(--papier); }
#menue-schalter:checked ~ .schalter .schalter__striche span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
#menue-schalter:checked ~ .schalter .schalter__striche span:nth-child(2) { opacity: 0; }
#menue-schalter:checked ~ .schalter .schalter__striche span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
#menue-schalter:checked ~ .schalter { color: var(--papier); }

/* Bisher verschwand die Wortmarke hinter der Tafel: die Marke war zwei
   Sekunden lang weg und die Seite verlor beim Öffnen ihren Anker. Sie
   liegt jetzt über der Tafel und dreht nur ihre Farbe um. Damit schiebt
   sich beim Öffnen ein Blatt über die Seite, statt dass die Kopfzeile
   ausgetauscht wird. Der Verweis führt weiter auf die Startseite, ein
   Klick schließt die Tafel also durch den Seitenwechsel.

   Die Wortmarke steht im Quelltext VOR dem Schalter, das Geschwister-
   zeichen ~ greift also nicht. Es geht über den Elternknoten, und zwar
   auf beiden Wegen: :has() für sich allein, die Körperklasse als
   Rückfall aus dem Skript. Dasselbe Paar sichert weiter unten schon das
   Festhalten der Seite. */
.kopf__innen:has(#menue-schalter:checked) .wortmarke,
body.menue-offen .wortmarke {
  position: relative;
  z-index: 10000;
  color: var(--papier);
}

.kopf__innen:has(#menue-schalter:checked) .wortmarke__unter,
body.menue-offen .wortmarke__unter { color: rgba(250, 250, 250, 0.62); }

/* Seite dahinter festhalten */
body:has(#menue-schalter:checked),
body.menue-offen { overflow: hidden; }

.tafel__innen { width: min(100% - 16px, 900px); margin-inline: auto; }

.tafel__frage {
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--leise);
  margin: 0 0 24px;
}

.tafel__liste { list-style: none; margin: 0; padding: 0; }

/* Die Trennlinien waren Rahmen. Ein Rahmen ist entweder da oder nicht,
   er lässt sich nicht ziehen. Als eigene Striche können sie beim Öffnen
   von links nach rechts auslaufen, und genau das trägt jetzt die
   Bewegung der Tafel. transform statt Breite: das läuft in der
   Bildebene, ohne dass für jedes Einzelbild neu umbrochen wird. */
.tafel__zeile { position: relative; }

.tafel__zeile::before,
.tafel__zeile:last-child::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  height: 1px;
  background: rgba(250, 250, 250, 0.14);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .75s cubic-bezier(.16, .84, .44, 1);
}

.tafel__zeile::before { top: 0; }
.tafel__zeile:last-child::after { bottom: 0; }

#menue-schalter:checked ~ .tafel .tafel__zeile::before,
#menue-schalter:checked ~ .tafel .tafel__zeile:last-child::after { transform: scaleX(1); }

.tafel__zeile a {
  display: flex;
  align-items: baseline;
  gap: 20px;
  padding: clamp(14px, 1.5vw, 24px) 0;
  text-decoration: none;
  color: var(--papier);
}

/* Verschoben wurde bisher über padding-left am Verweis. Das rechnet den
   Kasten bei jedem Einzelbild neu aus und schiebt die Randspalte mit,
   die eigentlich stehen bleiben soll. Jetzt wandern nur Ziffer und Titel,
   und zwar über transform: dieselben zwanzig Pixel, aber in der
   Bildebene und ohne Umbruch. */
.tafel__zeile a:hover .tafel__nr,
.tafel__zeile a:hover .tafel__titel,
.tafel__zeile a:focus-visible .tafel__nr,
.tafel__zeile a:focus-visible .tafel__titel { transform: translateX(20px); }

/* --------------------------------------------------------------------------
   Zeile lesen

   Hier standen kurzzeitig sechs Fotos, für jede Zeile eines, die beim
   Überfahren bildschirmfüllend aufkamen. Es war zu viel: bei jeder
   Zeigerbewegung wechselte die ganze Fläche, das Menü kam nicht zur
   Ruhe. Das eine Foto hinter der Tafel reicht, und es bleibt stehen.

   Was bleibt, ist ein einziger Gedanke: die Zeile, auf der der Zeiger
   steht, tritt vor, die anderen treten zurück. Nichts bewegt sich über
   die Zeile hinaus.
   -------------------------------------------------------------------------- */

@media (hover: hover) {
  /* Nicht zu stark: bei 0.45 sind die übrigen Zeilen noch gut zu lesen,
     die gelesene steht trotzdem klar davor.

     Gedimmt werden die drei Beschriftungen, nicht der Verweis, der sie
     enthält. Am Verweis hängt die Verschiebung, und eine Deckkraft unter
     eins macht aus einem Element einen eigenen Stapelzusammenhang. Die
     beiden sollen sich nicht ins Gehege kommen. */
  .tafel__liste:hover .tafel__nr,
  .tafel__liste:hover .tafel__titel,
  .tafel__liste:hover .tafel__rand,
  .tafel__liste:has(a:focus-visible) .tafel__nr,
  .tafel__liste:has(a:focus-visible) .tafel__titel,
  .tafel__liste:has(a:focus-visible) .tafel__rand { opacity: 0.45; }

  .tafel__liste .tafel__zeile a:hover .tafel__nr,
  .tafel__liste .tafel__zeile a:hover .tafel__titel,
  .tafel__liste .tafel__zeile a:hover .tafel__rand,
  .tafel__liste .tafel__zeile a:focus-visible .tafel__nr,
  .tafel__liste .tafel__zeile a:focus-visible .tafel__titel,
  .tafel__liste .tafel__zeile a:focus-visible .tafel__rand { opacity: 1; }
}

.tafel__nr {
  font-size: 11px;
  letter-spacing: 0.15em;
  color: var(--leise);
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  transition: color .3s ease, opacity .35s ease,
              transform .4s cubic-bezier(.16, .84, .44, 1);
}

.tafel__zeile a:hover .tafel__nr,
/* Die Tastaturmarke hellt die Ziffer auf, statt sie einzufärben. */
.tafel__zeile a:focus-visible .tafel__nr { color: var(--tinte); }

.tafel__titel {
  font-size: clamp(26px, 16px + 2.2vw, 48px);
  font-weight: 200;
  line-height: 1.15;
  letter-spacing: 0.02em;
  transition: opacity .35s ease,
              transform .4s cubic-bezier(.16, .84, .44, 1);
}

.tafel__zeile--hier .tafel__titel { color: var(--leise); }

.tafel__rand {
  margin-left: auto;
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--leise);
  flex: 0 0 auto;
  transition: opacity .35s ease;
}

.tafel__fuss {
  margin-top: 48px;
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  align-items: center;
  justify-content: space-between;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--leise);
}

.tafel__fuss a { color: var(--leise); text-decoration: none; transition: color .3s ease; }
.tafel__fuss a:hover, .tafel__fuss a.aktiv { color: var(--papier); }

.tafel__neben {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 22px;
  align-items: center;
}

.tafel__sprache span { opacity: 0.4; margin: 0 6px; }

@media (max-width: 640px) {
  .tafel { padding: 96px 20px 40px; justify-content: flex-start; }
  .tafel__rand { display: none; }
  .tafel__fuss { flex-direction: column; align-items: flex-start; gap: 14px; }
  .wortmarke__haupt { font-size: 19px; }
  .kopf__innen { padding: 9px var(--rand); }
}


/* ==========================================================================
   5. Fuß
   ========================================================================== */

.fuss {
  border-top: 1px solid var(--linie);
  padding: var(--xxl) var(--rand);
  text-align: center;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--grau);
}

.fuss__marke {
  display: inline-block;
  text-decoration: none;
  color: var(--tinte);
  transition: transform .35s ease;
}

.fuss__marke:hover { transform: translateY(-3px); }

.fuss__marke .haupt {
  display: block;
  font-family: var(--marke);
  font-size: 22px;
  font-weight: 700;
  letter-spacing: 2px;
  transition: letter-spacing .35s ease;
}

.fuss__marke:hover .haupt { letter-spacing: 4px; }

.fuss__marke .unter {
  display: block;
  font-size: 11px;
  letter-spacing: 2px;
  color: var(--leise);
  margin-top: 4px;
}

.fuss__zeile { margin-top: var(--m); line-height: 2; }

/* Längerer Hinweis im Fuß: nicht in Versalien, auf Lesebreite begrenzt. */
.fuss__hinweis {
  max-width: 64ch;
  margin: var(--m) auto 0;
  font-size: 11px;
  line-height: 1.9;
  text-transform: none;
  letter-spacing: 0.02em;
  color: var(--leise);
}
.fuss__zeile a { text-decoration: none; color: var(--tinte); }
.fuss__zeile a:hover { text-decoration: underline; }

.fuss__sozial {
  margin-top: var(--m);
  display: flex;
  justify-content: center;
  gap: 14px;
}

.fuss__sozial a { color: var(--tinte); opacity: 0.7; display: inline-flex; transition: opacity .3s ease, transform .3s ease; }
.fuss__sozial a:hover { opacity: 1; transform: translateY(-2px); }
.fuss__sozial svg { width: 22px; height: 22px; fill: currentColor; }


/* ==========================================================================
   6. Bewegung und Druck
   ========================================================================== */

/* Einblenden beim Scrollen. Ohne JavaScript bleibt alles sichtbar,
   die Klasse wird erst gesetzt, wenn das Skript läuft. */
/* `ease` ist die Vorgabe und hat keinen Charakter: die Bewegung gleitet
   gleichmäßig hinein und hört einfach auf. Diese Kurve bremst stark aus —
   der Block kommt schnell und legt sich hin, statt anzukommen. */
.js .auftritt {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .8s ease,
              transform .8s cubic-bezier(.16, .9, .2, 1);
}

.js .auftritt.da { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .js .auftritt { opacity: 1; transform: none; }
}

@media print {
  .kopf, .kopfplatz, .tafel, .fuss__sozial, .knopfreihe, .scrollstand { display: none; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .band { padding-block: 20px; }
  .band--dunkel { background: none; color: #000; }
}


/* ==========================================================================
   9. Vier Materialien

   Auf dunklem Grund kann eine Fläche nicht mehr dadurch auffallen, dass
   sie dunkel ist. Die Rollen drehen sich um: die Seite ist dunkel, und
   das Besondere ist hell.

   Je Seite gibt es deshalb genau eine helle Platte, und sie liegt auf der
   Aufforderung. Sie ist das Hellste auf der ganzen Seite und damit der
   Punkt, an dem der Blick landet. Alles andere arbeitet mit den drei
   dunklen Stufen: Tiefe, Grund, erhobene Fläche.
   ========================================================================== */

/* --- Eingelassen: Kopf, Fuß, das Band in der Mitte ------------------------ */

/* Der volle Satz Werte, nicht nur Grund und Schrift: diese Flächen können
   innerhalb einer hellen Umgebung liegen — der Fuß der Inseratsprüfung
   steht zum Beispiel im hellen Erklärblock. Ohne die eigenen Werte erbt er
   dort die dunkle Schrift und steht dunkel auf dunkel. Wieder dieselbe
   Lehre: die Umkehr gehört an das Element, das den Grund trägt. */
.kopf,
.fuss,
.band--dunkel,
.dunkelfeld {
  --grund:     #0f151d;
  --tiefe:     #0f151d;
  --flaeche:   #1e2733;
  --tinte:     #eef1f6;
  --grau:      #a9b2c0;
  --leise:     #8b95a4;
  --linie:     rgba(238, 241, 246, 0.13);
  --linie-2:   rgba(238, 241, 246, 0.28);

  background: var(--grund);
  color: var(--tinte);
}

/* Die Kopfleiste war weiß und durchscheinend, damit die Fotos darunter zu
   ahnen bleiben. Der Gedanke bleibt, nur ist das Glas jetzt dunkel: unter
   einer dunklen Scheibe wirkt ein helles Foto beleuchtet, unter einer
   weißen ausgewaschen.

   ACHTUNG, unverändert gültig: der Weichzeichner darf nicht an .kopf
   selbst hängen, sonst wird die Leiste zum Bezugsrahmen für die fest
   stehende Menütafel und diese schrumpft auf Leistenhöhe. */
.kopf { border-bottom: 1px solid var(--linie); }

@supports ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .kopf { background: transparent; }

  .kopf::before {
    background: rgba(15, 21, 29, 0.72);
    -webkit-backdrop-filter: blur(16px) saturate(1.25);
    backdrop-filter: blur(16px) saturate(1.25);
  }
}

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


/* --- Die helle Platte -----------------------------------------------------
   Jede Seite endet mit derselben Aufforderung. Sie bekommt als einzige
   Fläche der Seite den hellen Grund — und damit die ganze Aufmerksamkeit,
   ohne dass ein Pfeil, eine Farbe oder ein Ausrufezeichen nötig wäre.

   Die Umkehr hängt am Element, das auch den Grund trägt, nie an einzelnen
   Kindern. Dadurch stimmen Knopf, Beitext und Kontur von allein: .knopf
   tauscht im Hover --tinte und --grund, und beide stehen hier richtig
   herum. Das ist die Lehre aus der Werkzeugtafel, wo die Signatur weiß
   auf weiß stand.
   -------------------------------------------------------------------------- */

/* Die Aufforderung lag als einzige helle Platte der Seite hier. Das war
   richtig gedacht, solange die Abschnitte untereinander standen: auf
   dunklem Grund fällt eine Fläche dadurch auf, dass sie hell ist.

   Seit sich die Abschnitte übereinanderschieben, stimmt es nicht mehr. Eine
   weiße Platte, die sich über Fotos legt, liest sich nicht als Höhepunkt,
   sondern als Fehler — und der Schleier darüber wusch die Fotos weiß, statt
   sie abzudunkeln. Die Platte ist deshalb eingelassen wie Kopf und Fuß; ihr
   Gewicht holt sie aus dem engeren Satzspiegel, nicht aus der Helligkeit. */
.abschluss {
  /* Über den Token, nicht über background: die allgemeine Regel, die jedem
     zudeckenden Abschnitt seinen Grund gibt, hat höhere Spezifität und
     gewinnt sonst — die Platte lag dadurch exakt auf Grundfarbe und war
     als Fläche gar nicht mehr da. Wird --grund hier umgesetzt, folgt jede
     Regel von allein, gleich welche greift. */
  --grund: var(--tiefe);

  background: var(--feld, var(--grund));
  border-block: 1px solid var(--linie);

  /* Enger als jedes andere Band, und zwar deutlich. Mit der großzügigen
     Polsterung der übrigen Abschnitte war die Platte auf 1920 Pixeln 563
     hoch bei 199 Pixeln Inhalt — zwei Drittel leuchtende Leerfläche.

     Auf dunklem Grund darf Leerraum großzügig sein, er tritt zurück. Eine
     helle Fläche tut das nicht: sie blendet in dem Maß, in dem sie groß
     ist. Die Platte muss ihren Inhalt fassen, nicht ein Feld aufmachen. */
  padding-block: var(--xl);
}


/* --- Ein Bruch im Takt ----------------------------------------------------
   Die langen Seiten sind alle gleich gebaut: wucht, Bildreihe, wucht, und
   so fort. Über zwanzigtausend Pixel gleichmäßig durchgespielt gibt es
   keinen Höhepunkt, weil es kein Tal gibt. Je Seite wird deshalb ein
   Abschnitt eingelassen — der, der das Argument der Seite trägt.

   Auf dunklem Grund ist das ein leiser Schritt, keine Zäsur. Das genügt:
   die Zäsur macht die Glutkontur darin, und den wirklichen Kontrast der
   Seite liefern ohnehin die Fotos.

   Startseite: „Die Entscheidung beginnt vor der Entscheidung."
   Hoteleinrichter und Virtual Staging: der mittlere wucht-Block.
   -------------------------------------------------------------------------- */

/* Die Startseite trägt dafür die Klasse .dunkelfeld am Abschnitt. Vorher
   stand dort eine Abschnittsnummer, und die verrutschte, sobald irgendwo
   ein Abschnitt dazukam — beim Einsetzen der fehlenden Textpaneele genau
   das passiert. Eine Nummer beschreibt eine Stelle, eine Klasse eine
   Absicht. Zumal beide Sprachfassungen verschieden aufgebaut sind: das
   Thesenband steht in der deutschen an Position 10, in der englischen an 8.

   Grund und Farbreihe kommen aus dem Satz weiter oben, den sich .dunkelfeld
   mit Kopf und Fuß teilt; hier steht nur, was diesen Abschnitt davon
   unterscheidet. */
.dunkelfeld,
body:has(.querlauf) main > section:nth-of-type(9),
body:has(main > section.wucht:first-child):not(:has(.querlauf)) main > section:nth-of-type(6) {
  padding-block: calc(var(--xxl) * 1.35);
  border-block: 1px solid var(--linie);
}

/* HIER STAND DIE KONTUR IN ROTGLUT, einmal je Seite, als „der Name der
   Marke als Bild". Auf dunklem Grund war das ein roter Fremdkörper in einer
   Zeile, die sonst nur aus Linien besteht — das eine bunte Wort zog mehr
   Aufmerksamkeit auf sich, als die Stelle verdient. Die gezeichnete Kontur
   allein ist Auszeichnung genug, sie braucht die Farbe nicht.

   Glut steht damit nur noch dort, wo sie etwas bedeutet: in der Auswahl
   markierten Textes und in der Tastaturmarke der Menütafel.

   (Falls die Zeile je zurückkommt: kein .wucht in den Selektor schreiben.
   Der Abschnitt IST das wucht-Element, ein Nachfahre mit dieser Klasse
   existiert nicht — mit .wucht davor blieb die Regel wirkungslos.) */


/* ==========================================================================
   10. Was auf allen Seiten gilt
   ========================================================================== */

/* --- Eine Stufe mehr in der Schrift ---------------------------------------
   Zwischen der 72 Pixel hohen Überschrift und dem 17-Pixel-Fließtext lag
   nichts. Im Text steht die Stufe aber längst: der erste Absatz nach der
   Überschrift ist überall ein kurzer Führungssatz, der zweite der lange
   Fließtext. Das Stilblatt hat beide gleich behandelt.

   Angesprochen über den Nachbarn, nicht über :first-of-type — in manchen
   Abschnitten steht der marker-Absatz davor und wäre sonst der erste.

   24 und nicht 27 Pixel: an einer Stelle ist der Führungssatz zweihundert
   Zeichen lang und lief bei 27 Pixeln über sieben Zeilen — dann ist es
   keine Führung mehr, sondern eine zweite Überschrift. balance greift
   ohnehin nur bei wenigen Zeilen; für einen Absatz ist pretty richtig. */
.wucht :is(h1, h2) + .wucht__rand {
  margin-top: var(--xl);
  max-width: 36ch;
  font-size: clamp(19px, 15px + 0.7vw, 24px);
  font-weight: 200;
  line-height: 1.5;
  color: var(--tinte);
  text-wrap: pretty;
}


/* --- Die Zeile mit dem Namen ----------------------------------------------
   Sie steht als Beschriftung über der Überschrift und liest sich dort wie
   eine Rubrikzeile. Sie trägt aber den Namen des Fotografen, also bekommt
   sie einen Strich davor und wird damit zur Signatur statt zur Rubrik. */
.wucht .marker {
  display: flex;
  align-items: center;
  gap: var(--m);
}

.wucht .marker::before {
  content: "";
  width: clamp(28px, 4vw, 56px);
  height: 1px;
  background: var(--linie-2);
  flex: 0 0 auto;
}


/* --- Die Bewegung wird zusammengezogen ------------------------------------
   .auftritt lag mit derselben Verschiebung und derselben Dauer auf jedem
   Abschnitt jeder Seite. Sechsundzwanzig gleiche Einblendungen sind kein
   Auftritt, sondern ein Zucken, das die ganze Seite begleitet.

   Die Bildreihen behalten ihren Versatz — er trägt Information, die Reihe
   geht von links oben nach rechts unten auf. Die Textblöcke blenden nur
   noch auf, ohne zu wandern. */
.js .wucht .auftritt,
.js .abschluss .auftritt {
  transform: none;
}


/* --- Was der Browser mitbringt --------------------------------------------
   Rollbalken, Auswahl und Unterstreichung liefert der Browser in seinen
   eigenen Farben mit. Auf einer Seite, die sonst jede Linie selbst zieht,
   fällt das auf. */
html {
  scrollbar-width: thin;
  scrollbar-color: var(--linie-2) transparent;
}

a { text-underline-offset: 0.22em; text-decoration-thickness: 1px; }


/* ==========================================================================
   11. Nur die Startseite

   Der Einstiegssatz gibt es ausschließlich auf index.html und
   index-en.html. Alles hier hängt daran und kann keine andere Seite
   treffen, ohne dass irgendwo eine Klasse ins Markup muss.
   ========================================================================== */

/* Der Satz ist die These der Seite, und sein letztes Wort ist ihr
   Gegenstand. Also bekommt genau dieses Wort die Kontur, die sonst den
   hervorgehobenen Zeilen der Überschriften vorbehalten ist: „Viele Häuser
   sind besser als ihre BILDER." — und die Bilder sind hohl, bis jemand sie
   macht. Die Kontur in em, nicht in Pixeln, damit sie bei 172 Pixeln
   Versalhöhe dasselbe Gewicht hat wie bei 40. */
.satz__zeile:last-child {
  -webkit-text-stroke: 0.02em var(--tinte);
  color: transparent;
}

/* --- Der Film hinter dem Einstieg ----------------------------------------
   Der Einstieg ist die einzige Stelle, an der ein bewegtes Bild etwas
   beiträgt: er hat sonst nichts als sieben Zeilen und viel Grund.

   Der Schleier darüber ist nicht geschätzt, sondern gerechnet. Die Zeilen
   stehen in --tinte und die letzte nur als 0.02em-Kontur; über einem
   hellen Hotelbild verschwindet so ein Haarstrich. Gemessen wurde die
   Helligkeit der Filmbilder unter dem Satz, daraus der Wert unten.
   -------------------------------------------------------------------------- */

.satz__film {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
  /* Kein Bild ist so dunkel wie der Seitengrund. Ein leichtes Absenken der
     Sättigung nimmt dem Film das Bunte, damit er hinter der Schrift als
     Material liest und nicht als zweites Motiv. */
  filter: saturate(0.8);
}

.satz::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Gemessen, nicht geschätzt: über Filmbilder des laufenden Videos wurde
     unter jeder Zeile das hellste Pixel gesucht und der Kontrast gegen
     --tinte gerechnet. Der erste Ansatz lag bei 10,9:1 — weit über den
     nötigen 4,5, und damit war vom Film fast nichts zu sehen. Diese Werte
     lassen den schlechtesten Fall bei 7:1 und öffnen die rechte Seite,
     wo keine Schrift steht. */
  /* Zwei Schichten. Die waagerechte deckt die Zeilen und öffnet nach
     rechts, wo keine Schrift steht. Die senkrechte fasst den Fuß, wo der
     Hinweis mittig steht: dort ist die waagerechte am dünnsten und der
     Film oft hell — gemessene 3,98:1 bei geforderten 4,5. Mit dem Fuß
     sind es 4,70, und Unterzeile und Grundlinie gehen von 7,1 auf 8,2.

     Die schwächere der beiden erprobten Stufen. Sie reicht über die Linie
     und ist als Verlauf nicht als Kante zu sehen. */
  background:
    linear-gradient(
      to top,
      rgba(21, 28, 38, 0.45) 0%,
      rgba(21, 28, 38, 0) 22%
    ),
    linear-gradient(
      to right,
      rgba(21, 28, 38, 0.80) 0%,
      rgba(21, 28, 38, 0.72) 45%,
      rgba(21, 28, 38, 0.44) 100%
    );
}

/* Alles Geschriebene liegt über Film und Schleier. */
.satz__inhalt { position: relative; z-index: 2; }

/* Ohne Film greift der Schleier ins Leere und der Grund bleibt der Grund.
   Wer weniger Bewegung möchte, bekommt kein laufendes Bild. */
@media (prefers-reduced-motion: reduce) {
  .satz__film { display: none; }
  .satz::before { display: none; }
}


/* Der Satz stand in der linken oberen Ecke eines ansonsten leeren
   Fensters: auf 1440 × 900 rechnet die Höhenformel eine Versalhöhe von
   85 Pixeln aus, die längste Zeile ist damit rund 400 Pixel breit und
   tausend Pixel daneben sind nichts. Die Zeile über dem Pfeil macht aus
   dem leeren Rest eine Fläche mit Kante statt einer Lücke. */
.satz::after {
  content: "";
  position: absolute;
  left: var(--rand);
  right: var(--rand);
  bottom: calc(var(--l) + 11px);
  height: 1px;
  background: var(--linie-2);
  z-index: 2;
}

/* Der Faden endet genau auf der Grundlinie des Einstiegs, statt daneben zu
   hängen. Deshalb sitzt die Unterkante des Hinweises auf demselben Wert
   wie die Linie.

   Der Hinweis kommt zuletzt, nach den sieben Zeilen und der Unterzeile.
   Nur die Deckkraft, nicht die Lage: das translateX(-50%) hält ihn auf der
   Mittelachse und darf von keiner Bewegung überschrieben werden. */
.satz__entdecken {
  bottom: calc(var(--l) + 11px);
  animation: hinweisEin 1s ease 900ms both;
}

@keyframes hinweisEin { from { opacity: 0; } to { opacity: 1; } }

/* Der Auftritt des Satzes ist der eine gestaltete Augenblick der Seite:
   sieben Zeilen laufen nacheinander von unten ein, das Plakat setzt sich
   zusammen. Überall sonst wurde die Bewegung zurückgenommen. */
@keyframes satzZeile {
  from { opacity: 0; transform: translateY(0.22em); }
  to   { opacity: 1; transform: none; }
}

.satz__zeile { animation: satzZeile .9s cubic-bezier(.16, 1, .3, 1) both; }

.satz__zeile:nth-child(1) { animation-delay:  60ms; }
.satz__zeile:nth-child(2) { animation-delay: 130ms; }
.satz__zeile:nth-child(3) { animation-delay: 200ms; }
.satz__zeile:nth-child(4) { animation-delay: 270ms; }
.satz__zeile:nth-child(5) { animation-delay: 340ms; }
.satz__zeile:nth-child(6) { animation-delay: 410ms; }
.satz__zeile:nth-child(7) { animation-delay: 500ms; }

.satz__unter,
.satz::after { animation: satzZeile 1s cubic-bezier(.16, 1, .3, 1) 640ms both; }


/* --- Die Bildblöcke bleiben liegen, der Text schiebt sich darüber --------
   Die Startseite legte dreizehn Neunerpaneele untereinander — eine lange
   Tapete, an der man vorbeiscrollt. Jetzt liegt der Bildblock still,
   während der folgende Textabschnitt auf ihn zuläuft und ihn zudeckt;
   danach kommt der nächste Block von unten und deckt den Text zu. Bild und
   Text lösen sich ab, statt aneinandergereiht zu werden. Kein Skript,
   nur `position: sticky`.

   Angesprochen über :has(.reihe) statt über eine Liste von Nummern — dann
   gilt es für jede Bildreihe, auch für eine, die später dazukommt.

   ENTSCHEIDEND: das Paneel füllt genau einen Bildschirm. Der erste Versuch
   ließ ihm seine natürliche Höhe (bei 1440 Pixeln rund 1055) und heftete
   ihn mit `bottom: 0` an. Das war in beide Richtungen falsch: oben
   angeheftet bliebe von einem Block, der höher ist als das Fenster, das
   untere Drittel für immer unsichtbar — und `bottom: 0` zieht einen Block,
   der noch unterhalb des Fensters liegt, nach oben an dessen Unterkante.
   Die Blöcke rutschten dadurch sofort alle zusammen.

   Dass sticky überhaupt greift, verdankt sich dem `overflow-x: clip` weiter
   oben: mit `hidden` wäre der Körper ein Scrollbehälter und jedes sticky
   darin wirkungslos. Der Kommentar steht schon dort.
   -------------------------------------------------------------------------- */

/* Paneel wird nur eine Reihe, die ein volles Raster füllt — sieben Kacheln
   und mehr. Die letzten drei Reihen haben sechs, sechs und drei; auf einen
   ganzen Bildschirm gestreckt stand um sie herum ein halber Bildschirm
   Leere, erst darunter, nach dem Zentrieren oben und unten. Umverteilt ist
   nicht weniger.

   Eine Reihe mit drei Kacheln ist kein Bildschirmpaneel, sie ist eine
   Reihe. Sie läuft deshalb wie früher einfach mit. Zehn Paneele tragen den
   Rhythmus, die drei kurzen Reihen setzen ihn ab.

   Kein verschachteltes :has() — das ist nicht erlaubt. Ein Pfad innerhalb
   eines :has() dagegen schon. */
body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) {
  position: sticky;
  top: var(--kopf);
  z-index: 0;

  height: calc(100dvh - var(--kopf));
  padding-block: var(--m);
  margin-top: 0;
  display: flex;
  align-items: center;

  /* HIER STAND overflow: hidden, UND ES HAT DIE GEGENBEWEGUNG VERHINDERT.
     Gemessen stand die Zeitachse der Reihe über den ganzen Scrollweg auf
     null. Der Grund ist nicht der Klebezustand, sondern der Rahmen:
     overflow macht aus dem Paneel einen Scrollrahmen, und `view()` bindet
     immer an den nächstgelegenen. Darin bewegt sich nichts, also läuft
     nichts.

     Beschnitten werden muss auch nichts mehr: die Reihe ist jetzt
     vierundzwanzig Pixel niedriger als ihr Innenraum und bleibt bei zwölf
     Pixeln Trift immer darin. */

  /* Ohne eigenen Grund scheinen durch die Rasterfugen die Bilder des
     Paneels darunter hindurch — während des Wechsels sieht man zwei
     Blöcke gleichzeitig durch die Ritzen. */
  background: var(--grund);

  margin-bottom: 0;
}

/* Die Verweildauer — und zwar nur dort, wo sie gebraucht wird.

   Sie stand zuerst unter jedem der dreizehn Paneele: 5.850 Pixel, ein
   Fünftel der ganzen Seite, und davon war das meiste Leerlauf. Gebraucht
   wird sie an zwei Stellen, nämlich wo zwei Bildreihen direkt aufeinander
   folgen — sonst schiebt sich die zweite sofort über die erste und man
   sieht keine für sich. Überall sonst deckt ohnehin ein Textabschnitt zu,
   und der bringt seine eigene Strecke mit.

   Der Abstand sitzt am zweiten Block der beiden, nicht am ersten: er
   verzögert dessen Ankunft, und währenddessen liegt der erste oben still.
   Dasselbe Ergebnis, aber am richtigen Element. */
body:has(main > .satz) main > section.band--eng:has(> .reihe)
  + section.band--eng:has(> .reihe) {
  margin-top: 50vh;
}

/* --- Das zugedeckte Paneel tritt zurück -----------------------------------
   Ein Paneel, das unter dem nächsten Abschnitt verschwindet, blieb bis
   zuletzt in voller Helligkeit liegen — zwei gleich laute Ebenen
   übereinander. Es dunkelt jetzt ab, während es zugedeckt wird, und zwar
   im Verhältnis zur Strecke, nicht in Stufen.

   Die Schicht hängt am zudeckenden Abschnitt, nicht am Paneel. Der erste
   Versuch hing am Paneel und tat nichts: ein klebendes Element verlässt
   das Fenster nie — es bleibt oben liegen, bis sein Bezugsrahmen endet —,
   und seine eigene Zeitachse erreicht `exit` deshalb nie. Gemessen daran,
   dass Oberkante und Unterkante über 2400 Pixel Scrollweg unverändert bei
   60 und 900 standen. Der Fortschritt steckt im Nachbarn: dessen
   Oberkante wandert in derselben Zeit von 840 auf 40.

   Die Schicht sitzt mit `bottom: 100%` direkt über ihrem Abschnitt und
   deckt damit genau den Teil des Paneels, der noch zu sehen ist.

   `animation-timeline: view()` bindet den Ablauf an die Lage im Fenster
   statt an die Uhr. Das läuft neben dem Hauptstrang und ruckelt nicht.

   Der @supports-Riegel ist Notwehr, keine Zierde: kennt ein Browser
   `animation-timeline` nicht, fällt die Zeile weg, die Animation bekäme
   die Voreinstellung von null Sekunden mit `both` und stünde sofort am
   Ende — alles dauerhaft abgedunkelt. Mit dem Riegel bekommt so ein
   Browser die Schicht gar nicht erst.
   -------------------------------------------------------------------------- */

/* Die Animation hängt am Abschnitt, die Schicht liest nur den Wert. Auf
   dem Pseudoelement selbst blieb die Zeitachse unwirksam — der Schleier
   stand unverändert am Endwert, über den ganzen Scrollweg gemessen. Ein
   Zahlenwert, der sich stufenlos ändern soll, muss dem Browser dafür als
   Zahl bekannt sein; sonst springt er statt zu laufen. */
@property --deckung {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

@supports (animation-timeline: view()) {
  body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz) {
    /* Nicht gleichförmig: ein Foto, das in den Schatten läuft, dunkelt am
       Anfang kaum und gegen Ende schnell. Linear las sich das wie ein
       Schieberegler, den jemand dreht. */
    animation: paneelZurueck cubic-bezier(.45, 0, .55, 1) both;
    animation-timeline: view();
    animation-range: entry 0% entry 100%;
  }

  @keyframes paneelZurueck { to { --deckung: 0.72; } }

  /* --- Das Differential ---------------------------------------------------
     Auf dieser Seite bewegte sich alles exakt eins zu eins mit dem
     Scrollrad: der Textabschnitt schob sich mit genau der Geschwindigkeit
     über das Paneel, mit der man scrollt. Nirgends lief ein Teil einem
     anderen nach. Deshalb las sich das Scrollen wie eine starre
     Übersetzung — Zahnräder, nicht Masse.

     Der Block bekommt jetzt einen Nachlauf: sechzig Pixel tiefer, während
     der Abschnitt hereinkommt, und er holt sie auf dem Weg auf. Die Kurve
     hat einen Wert über eins, das heißt er schießt am Ende ein paar Pixel
     über und kommt zurück. Beschleunigen, bremsen, federn — alles am
     Scrollweg, nicht an der Uhr: es bleibt in der Hand dessen, der scrollt.

     Verschoben wird über `translate`, nicht über `transform`. Der Auftritt
     beim Einlaufen sitzt schon auf `transform`; zwei Animationen auf
     derselben Eigenschaft würden einander auslöschen. Als eigenständige
     Eigenschaft rechnet `translate` sich mit dem transform zusammen,
     statt dagegen. */
  body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz) > .huelle {
    animation: blockNachlauf cubic-bezier(.4, 0, .22, 1.32) both;
    animation-timeline: view();
    animation-range: entry 5% entry 95%;
  }

  @keyframes blockNachlauf { from { translate: 0 72px; } }

  /* Die Gegenbewegung: das Paneel weicht zurück, während der Text kommt.

     Der Platz dafür wird gemacht, nicht genommen. Die Reihe ist 24 Pixel
     niedriger als der Innenraum des Paneels und wandert darin um zwölf
     Pixel auf und ab — so bleibt sie immer innerhalb ihres Raums und kein
     Foto wird beschnitten. Die Kacheln sind dafür acht Pixel flacher; das
     ist der Preis, und er ist kleiner als ein Zuschnitt.

     Hier keine Kurve, sondern linear: eine Parallaxe ist ein festes
     Verhältnis zwischen zwei Geschwindigkeiten. Würde sie beschleunigen
     und bremsen, sähen die Fotos aus, als schwämmen sie. */
  body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) .reihe {
    height: calc(100% - 24px);
    animation: paneelTrift linear both;
    animation-timeline: view();
    /* Nicht in Prozent. Ein klebendes Paneel löst sich nie, sein
       `cover`-Bereich ist deshalb der ganze Rest der Seite — gemessen
       liefen über 1500 Pixel Scrollweg 7,75 Prozent davon ab, die Trift
       wäre unsichtbar geblieben. In Längen gerechnet zeigt der Bereich auf
       das, worum es geht: eine Fensterhöhe herankommen, eine Fensterhöhe
       zugedeckt werden. */
    animation-range: cover 0px cover 190vh;
  }

  @keyframes paneelTrift {
    from { translate: 0 -12px; }
    to   { translate: 0  12px; }
  }

  /* Die Schicht sitzt mit bottom: 100% direkt über ihrem Abschnitt und
     deckt damit genau den Teil des Paneels, der noch zu sehen ist. */
  body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz)::before {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 100%;
    height: 100vh;
    background: var(--schleier);
    opacity: var(--deckung);
    pointer-events: none;
  }

  /* Wer weniger Bewegung möchte, bekommt auch keine, die am Scrollen
     hängt. Das Paneel bleibt dann hell, bis es verdeckt ist. */
  @media (prefers-reduced-motion: reduce) {
    body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz) { animation: none; }
    body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz)::before { display: none; }
  }
}

body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) .reihe {
  height: 100%;
  position: relative;
  z-index: 0;
}

/* Wie viele Rasterzeilen, und ob gestreckt oder im eigenen Verhältnis —
   beides hängt an der Kachelzahl, und beides muss ausdrücklich dastehen.
   Ohne diese Vorgaben behalten die Kacheln ihr 3:2, drei Reihen sind dann
   zusammen 906 Pixel hoch, das Paneel gibt 840, und die dritte Reihe wird
   abgeschnitten — gemessen 148 Pixel.

   Sieben und mehr strecken sich deshalb auf drei Zeilen. Vier bis sechs
   füllen zwei Zeilen und behalten ihr 3:2: gestreckt wären sie 420 statt
   302 Pixel hoch, ein Zuschnitt von vierzig Prozent ins Quadratische, und
   das ist den Fotos gegenüber zu viel. Sie stehen stattdessen mittig, die
   Luft sind gut hundert Pixel oben und unten. */
body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(7)) .reihe {
  grid-template-rows: repeat(3, minmax(0, 1fr));
}

body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(7)) .reihe :is(img, video) {
  aspect-ratio: auto;
  height: 100%;
}

body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)):not(:has(> .reihe > figure:nth-child(7))) .reihe {
  align-content: center;
}

/* Die Leitbild-Reihen vertragen sich damit nicht: ein Motiv über zwei
   Spalten und zwei Zeilen braucht bei neun Kacheln vier Rasterzeilen, das
   Paneel gibt drei — die vierte wurde abgeschnitten. Ein Block, der einen
   ganzen Bildschirm füllt, ist ohnehin für sich der Höhepunkt. Wo
   gestapelt wird, steht das gleichmäßige Raster. */
body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) .reihe > figure:first-child {
  grid-column: auto;
  grid-row: auto;
}

/* Alles, was kein Paneel ist, deckt zu — auch eine kurze Bildreihe.

   Zuerst stand hier :not(:has(> .reihe)), also „alles außer Bildreihen".
   Das ging schief, sobald die kurzen Reihen keine Paneele mehr waren: sie
   hatten damit weder Grund noch z-index und ließen das Paneel, das oben
   liegen geblieben war, durch ihre Rasterfugen durchscheinen. Man sah
   dasselbe Bild über und unter dem Text.

   Denn ein klebendes Paneel löst sich nie: sein Bezugsrahmen ist main, es
   bleibt bis zum Seitenende oben liegen. Was darüber laufen soll, muss
   deckend sein — ohne Ausnahme.

   Jetzt ist die Bedingung dieselbe wie beim Paneel, nur verneint: was kein
   volles Raster hat, deckt zu.


   Nur der Text deckt zu, nicht umgekehrt.

   Ein Zwischenstand ließ die Reihenfolge im Dokument entscheiden, sodass
   auch das Bildpaneel sich über den Text schob. Konsequent war das, gut
   war es nicht: ein Foto, das sich über einen Satz legt, den man gerade
   liest, nimmt ihn weg, statt ihn abzulösen. Text bleibt oben.

   Den eigenen Grund brauchen die Textabschnitte dafür — ohne ihn läge der
   Text durchsichtig auf den Fotos. Wer seinen Grund schon mitbringt
   (Thesenband, Abschlussplatte), behält ihn: diese Regeln stehen weiter
   unten und mit höherer Spezifität. */
body:has(main > .satz) main > section:not(:has(> .reihe > figure:nth-child(4))):not(.satz) {
  position: relative;
  z-index: 1;

  /* --feld steht weiter unten und trägt den radialen Hauch. Es ist nur auf
     Textabschnitten gesetzt; eine kurze Bildreihe fällt auf den flachen
     Grund zurück, denn hinter Fotos wäre der Verlauf ohnehin verdeckt. */
  background: var(--feld, var(--grund));

  /* Mindestens einen Bildschirm hoch, und der Inhalt steht darin mittig.

     Das ist keine Kosmetik, sondern die Bedingung dafür, dass das Stapeln
     überhaupt aufgeht: ein zudeckender Abschnitt, der kleiner ist als ein
     Paneel, kann es nicht zudecken. Die Abschlussplatte war 328 Pixel
     hoch, ein Paneel ist 840 — also lagen altes Paneel, schmales Textband
     und neues Paneel gleichzeitig im Bild und schoben sich aneinander
     vorbei. Hinter dem Abschluss häufte sich das bis zum Seitenende.

     Betroffen waren fünf Abschnitte: 328, 491, 554, 554 und 596 Pixel. */
  min-height: calc(100dvh - var(--kopf));
  display: flex;
  flex-direction: column;
  justify-content: center;

  /* Die Kante, an der man den Vorgang überhaupt erkennt.

     Ohne sie deckt der Text das Paneel zwar zu, aber unsichtbar: seine
     Oberkante ist dunkel auf dunkel, und die Überschrift beginnt erst weit
     darunter. Der Eindruck war deshalb „die Bilder schrumpfen weg" statt
     „der Text schiebt sich darüber". Mit dem Haarstrich läuft eine
     sichtbare Linie über die Fotos, und der Block folgt ihr. */
  border-top: 1px solid var(--linie-2);
}

/* Auf dem Handy steht ein Bild je Zeile. Neun davon auf einen Bildschirm
   gepresst wären Briefmarken; dort bleibt die Tapete. */
@media (max-width: 46rem) {
  body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) {
    position: static;
    height: auto;
    display: block;
    padding-block: var(--xl);
    margin-bottom: 0;
    background: none;
  }

  body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) .reihe {
    height: auto;
    grid-template-rows: none;
  }

  body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4)) .reihe :is(img, video) {
    aspect-ratio: 3 / 2;
    height: auto;
  }

  /* Ohne Stapeln gibt es nichts zuzudecken und nichts abzudunkeln. */
  body:has(main > .satz) main > section:has(> .reihe > figure:nth-child(4))::after { display: none; }

  body:has(main > .satz) main > section.band--eng:has(> .reihe)
    + section.band--eng:has(> .reihe) { margin-top: calc(var(--s) - var(--xl)); }
}


/* --- Das Bildraster bekommt eine Dramaturgie ------------------------------
   Dreizehn Bildreihen, alle dreispaltig, alle gleich groß: ein
   Kontaktabzug. Drei von dreizehn brechen das auf, der Rest bleibt, wie er
   war. Wer variiert, muss sparsam variieren, sonst entsteht kein Rhythmus,
   sondern Unruhe.
   -------------------------------------------------------------------------- */

/* Die erste Reihe nach dem Plakat läuft randlos. Nach sieben Zeilen
   Versalien und viel Weiß stoßen die Fotos an beide Fensterkanten — der
   Wechsel von Schrift zu Bild ist damit eine Aussage. */
body:has(main > .satz) main > section:nth-of-type(2) .reihe {
  padding-inline: 0;
}

/* Die beiden Leitbild-Reihen sind mit dem Stapeln entfallen. Jede Bildreihe
   ist jetzt ein Paneel über den ganzen Bildschirm, und dort wird die Figur
   ohnehin zurückgenommen — die Regeln standen nur noch da und wirkten nicht
   mehr. Steht im Abschnitt über die Paneele erklärt. */


@media (prefers-reduced-motion: reduce) {
  .satz__zeile,
  .satz__unter,
  .satz::after,
  .satz__entdecken { animation: none; opacity: 1; }
}


/* Die Seite scrollt weich. Wer reduzierte Bewegung eingestellt hat, wird
   gesetzt, nicht gefahren — bei über zwanzig Bildschirmhöhen ist das keine
   Kleinigkeit. Stand vorher nicht da. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

@property --scrollstand {
  syntax: "<integer>";
  inherits: false;
  initial-value: 0;
}

.scrollstand { display: none; }

/* Am linken Seitenrand stand die Anzeige zuerst als senkrechte Linie über
   die halbe Fensterhöhe. Sie war dort ein zweites Element neben den
   Paneelen und lief quer zu ihnen — sichtbar genug, um zu stören, ohne
   etwas zu erklären.

   Jetzt hat sie gar kein eigenes Element mehr: die Unterkante der
   Kopfleiste ist der Balken. Die Leiste liegt ohnehin fest über allem,
   ihre Haarlinie läuft über die volle Breite, und sie hellt sich von links
   nach rechts auf. Eine Anzeige, die nichts kostet, weil sie eine Linie
   benutzt, die schon da war.

   Der Prozentwert steht in der Mitte der Leiste. Rechts sitzt das Menü,
   links die Wortmarke; dazwischen ist bei jeder Fensterbreite Platz, und
   nur dort lässt sich der Wert ohne feste Pixelrechnung unterbringen. */
@supports (animation-timeline: scroll()) {
  .scrollstand {
    position: fixed;
    inset: 0 0 auto;
    height: var(--kopf);

    /* Einen über der Leiste. Die Leiste steht auf 9990. */
    z-index: 9991;

    display: flex;
    align-items: center;
    justify-content: center;

    /* Sie zeigt an, sie bedient nicht. */
    pointer-events: none;
  }

  .scrollstand__spur {
    position: absolute;
    inset: auto 0 0;
    height: 1px;

    /* Die Spur selbst bleibt leer: die Haarlinie der Kopfleiste ist schon
       die Spur. Hier läuft nur die Füllung darüber. */
    overflow: hidden;
  }

  .scrollstand__spur::after {
    content: "";
    position: absolute;
    inset: 0;
    background: var(--tinte);
    transform: scaleX(0);
    transform-origin: left;

    animation: scrollFuellen linear both;
    animation-timeline: scroll(root block);
  }

  @keyframes scrollFuellen { to { transform: scaleX(1); } }

  /* Der Wert ist zugleich der Weg zurück nach oben.

     Ein schwebender Knopf in der Ecke war der erste Versuch und war Möbel:
     er stand über den Fotos, brauchte deshalb eine eigene Fläche, damit er
     lesbar blieb, und diese Fläche stand dann im Bild. Jedes Mittel gegen
     das Problem machte das Problem größer.

     Die Anzeige löst es, indem sie das Problem nicht hat. Sie sitzt in der
     Kopfleiste, also auf eigenem Grund, ist ohnehin auf jeder Bildschirmhöhe
     da und sagt bereits, wo man ist — dass sie einen auch zurückbringt, ist
     der kürzeste Weg, den es gibt. Auf dem Telefon ist das Tippen auf die
     oberste Leiste seit jeher genau diese Geste.

     Beim Überfahren schiebt sich die Zahl nach oben heraus und das Wort von
     unten herein. Zwei Zeilen in einer Zelle, der Kasten ist so breit wie
     die breitere von beiden und springt deshalb nicht. */
  .scrollstand__wert {
    pointer-events: auto;
    cursor: pointer;
    text-decoration: none;

    display: grid;
    justify-items: center;
    overflow: hidden;
    height: 11px;

    font-size: 0.62rem;
    font-weight: 500;
    letter-spacing: 0.14em;
    color: var(--leise);
    font-variant-numeric: tabular-nums;
    transition: color .3s ease;
  }

  .scrollstand__zahl,
  .scrollstand__oben {
    grid-area: 1 / 1;
    height: 11px;
    line-height: 11px;
    transition: transform .34s cubic-bezier(.2, .6, .2, 1), opacity .34s ease;
  }

  .scrollstand__oben {
    text-transform: uppercase;
    transform: translateY(11px);
    opacity: 0;
  }

  /* Die Sperrung schiebt das Wort nach links aus der Mitte: der Zwischenraum
     hinter dem letzten Buchstaben zählt zur Breite. */
  .scrollstand__oben { margin-right: -0.14em; }

  .scrollstand__zahl {
    counter-reset: stand var(--scrollstand);
    animation: scrollZaehlen linear both;
    animation-timeline: scroll(root block);
  }

  .scrollstand__zahl::after { content: counter(stand) "%"; }

  @keyframes scrollZaehlen { to { --scrollstand: 100; } }

  .scrollstand__wert:hover,
  .scrollstand__wert:focus-visible { color: var(--tinte); }

  .scrollstand__wert:hover .scrollstand__zahl,
  .scrollstand__wert:focus-visible .scrollstand__zahl {
    transform: translateY(-11px);
    opacity: 0;
  }

  .scrollstand__wert:hover .scrollstand__oben,
  .scrollstand__wert:focus-visible .scrollstand__oben {
    transform: translateY(0);
    opacity: 1;
  }

  .scrollstand__wert:focus-visible {
    outline: 1px solid var(--linie-2);
    outline-offset: 6px;
  }

  @media (prefers-reduced-motion: reduce) {
    .scrollstand__zahl,
    .scrollstand__oben { transition: none; }
  }

  /* Auf dem Handy stand die Anzeige fest auf null Prozent: iOS meldet
     Unterstützung für scroll-getriebene Zeitachsen, der Balken lief aber
     nicht — und eine Anzeige, die falsch anzeigt, ist schlechter als
     keine. Sie geht dort weg.

     Damit entfällt dort auch der Weg nach oben, denn er hängt an ihr. Das
     ist zu verschmerzen: auf dem iPhone bringt ein Tippen auf die
     Statusleiste die Seite ohnehin an den Anfang, und das ist dieselbe
     Geste an fast derselben Stelle. */
  @media (max-width: 46rem) {
    .scrollstand { display: none; }
  }
}


/* ==========================================================================
   12. Drucken

   Muss am Dateiende stehen. Ein früherer Druckblock kam vor den farbigen
   Flächen und verlor bei gleicher Spezifität die Reihenfolge — Fuß und
   Bänder kamen weiterhin dunkel mit heller Schrift aus dem Drucker.
   Gemessen, nicht vermutet.

   Seit die Seite auf dunklem Grund steht, genügt es nicht, einzelne
   Flächen zurückzunehmen: die ganze Farbreihe wird am Wurzelelement
   umgedreht. Dadurch stimmt jede Regel, die Tokens benutzt, von allein.
   ========================================================================== */

/* --- Der Grund hinter den Texten ------------------------------------------
   Vierzehn Textabschnitte hintereinander auf derselben flachen Fläche: die
   Seite las sich wie ein Stapel gleicher Karten. Ein großer, sehr weicher
   radialer Verlauf gibt jedem Abschnitt eine eigene Mitte, ohne dass man
   ihn als Form wahrnimmt — man merkt nur, dass der Text auf etwas liegt.

   Er steht auf der Seite, auf der auch der Text steht: .wucht--links holt
   ihn nach links, .wucht--rechts nach rechts. Damit leuchtet nicht der
   leere Rand, sondern die Zeile.

   Warum eine eigene Marke --feld und nicht einfach background hier?
   Die Regel, die den zudeckenden Abschnitten auf der Startseite ihren
   Grund gibt, hat vier Klassen Spezifität; ein .wucht-Selektor käme
   dagegen nicht an. Also liegt der Verlauf in einer Marke, und beide
   Regeln lesen sie. Eine Stelle, zwei Nutzer.

   Die Marke wird auf dem Abschnitt selbst gesetzt, nicht an :root: nur
   dort lösen sich var(--grund) und var(--hauch) gegen die Farbreihe auf,
   die dieser Abschnitt trägt. Ein .dunkelfeld kehrt seine Reihe um und
   bekommt den passenden Verlauf ohne Zutun. */
main > section.wucht,
main > section.band {
  --feld:
    var(--korn),
    radial-gradient(62% 64% at var(--hauch-ort, 50% 44%),
                    var(--hauch), transparent 72%),
    var(--grund);

  background: var(--feld);
}

.wucht--links  { --hauch-ort: 28% 46%; }
.wucht--rechts { --hauch-ort: 72% 46%; }

@media print {
  :root {
    --grund:     #ffffff;
    --tiefe:     #ffffff;
    --flaeche:   #ffffff;
    --papier:    #ffffff;
    --tinte:     #000000;
    --grau:      #333333;
    --leise:     #555555;
    --linie:     #cccccc;
    --linie-2:   #999999;
    /* Auf Papier kein Verlauf: der Hauch ist die helle Tinte, und die
       verschwände auf Weiß ohnehin — oder käme als grauer Fleck. */
    --hauch:     transparent;
    --korn:      none;
    --matt:      #eeeeee;
  }

  body { background: #fff; color: #000; }

  /* Die Umkehr an :root genügt nicht: diese Flächen setzen ihre Werte am
     Element selbst und schlagen damit die Wurzel. Der Fuß kam deshalb im
     ersten Anlauf hell auf weißem Papier — also unsichtbar. */
  .kopf, .fuss, .band--dunkel, .dunkelfeld, .abschluss, .darunter,
  .dunkelfeld,
  body:has(.querlauf) main > section:nth-of-type(9),
  body:has(main > section.wucht:first-child):not(:has(.querlauf)) main > section:nth-of-type(6) {
    --grund:     #ffffff;
    --tiefe:     #ffffff;
    --flaeche:   #ffffff;
    --papier:    #ffffff;
    --tinte:     #000000;
    --grau:      #333333;
    --leise:     #555555;
    --linie:     #cccccc;
    --linie-2:   #999999;
    /* Auf Papier kein Verlauf: der Hauch ist die helle Tinte, und die
       verschwände auf Weiß ohnehin — oder käme als grauer Fleck. */
    --hauch:     transparent;
    --korn:      none;

    background: none;
    color: #000;
    border: 0;
    padding-block: 20px;
  }

  .satz__zeile:last-child,
  .wucht em { -webkit-text-stroke: 0.02em #000; }

  /* Der Einstiegssatz füllt sonst ein ganzes Blatt mit sieben Zeilen. */
  .satz { height: auto; padding-block: 0; }
  /* Film und Schleier gehören nicht aufs Blatt: der Film druckt als
     schwarzes Rechteck, der Schleier als graue Fläche über der Schrift. */
  .satz::after, .satz::before, .satz__entdecken, .satz__film { display: none; }
}
