/* =========================================================
   VISTARO LIVING — Design System
   Dark Luxury / Gold · Prototyp
   ========================================================= */

/* ---------- 0. Schriften ----------
   Die Dateien liegen in assets/fonts und werden vom eigenen Server
   ausgeliefert. Frueher kamen sie von Google; dabei geht bei jedem
   Seitenaufruf die IP-Adresse des Besuchers in die USA, ohne dass er
   gefragt wurde — in Deutschland ein bekanntes Abmahnthema.

   Geladen wird nur der Zeichensatz "latin". Der deckt Deutsch samt
   Umlauten und Eszett vollstaendig ab; osteuropaeische Sonderzeichen
   fehlen, die kommen auf dieser Seite nicht vor.

   font-display:swap heisst: Der Text ist sofort lesbar, notfalls kurz in
   der Systemschrift, und wird nachtraeglich ersetzt. Die Alternative waere
   ein leerer Bildschirm, bis die Schrift da ist.

   Wenn ein Schnitt dazukommen soll: Datei nach assets/fonts legen und hier
   einen Block ergaenzen. Bezogen wurden sie ueber die Pakete
   @fontsource/cormorant-garamond und @fontsource/inter. */
@font-face{ font-family:"Cormorant Garamond"; font-style:normal; font-weight:300; font-display:swap;
  src:url("../fonts/cormorant-garamond-latin-300-normal.woff2") format("woff2"); }
@font-face{ font-family:"Cormorant Garamond"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/cormorant-garamond-latin-400-normal.woff2") format("woff2"); }
@font-face{ font-family:"Cormorant Garamond"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/cormorant-garamond-latin-500-normal.woff2") format("woff2"); }
@font-face{ font-family:"Cormorant Garamond"; font-style:italic; font-weight:300; font-display:swap;
  src:url("../fonts/cormorant-garamond-latin-300-italic.woff2") format("woff2"); }
@font-face{ font-family:"Cormorant Garamond"; font-style:italic; font-weight:400; font-display:swap;
  src:url("../fonts/cormorant-garamond-latin-400-italic.woff2") format("woff2"); }
@font-face{ font-family:"Inter"; font-style:normal; font-weight:300; font-display:swap;
  src:url("../fonts/inter-latin-300-normal.woff2") format("woff2"); }
@font-face{ font-family:"Inter"; font-style:normal; font-weight:400; font-display:swap;
  src:url("../fonts/inter-latin-400-normal.woff2") format("woff2"); }
@font-face{ font-family:"Inter"; font-style:normal; font-weight:500; font-display:swap;
  src:url("../fonts/inter-latin-500-normal.woff2") format("woff2"); }

/* ---------- 1. Tokens ---------- */
:root{
  --ink:        #0A0A0C;
  --ink-2:      #0F0F12;
  --ink-3:      #15151A;
  --ink-4:      #1C1C22;
  --cream:      #F4F1EA;
  --cream-dim:  #C9C5BC;
  --muted:      #8E8A82;
  --gold:       #C9A24B;
  --gold-lite:  #E9D19A;
  --gold-deep:  #8C6E28;
  --line:       rgba(255,255,255,.10);
  --line-soft:  rgba(255,255,255,.055);

  --ff-display: "Cormorant Garamond", "Playfair Display", Georgia, "Times New Roman", serif;
  --ff-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  /* Die Hero-Schrift skaliert mit der Breite UND der Hoehe. Ohne den vh-Anteil
     wird die Headline auf flachen Fenstern (z. B. 1440x760) so hoch, dass sie
     in den fixierten Header laeuft. */
  --fs-hero:   clamp(3.2rem, min(11.5vw, 17.5vh), 12.5rem);
  --fs-h1:     clamp(2.6rem, 6.4vw, 6.4rem);
  --fs-h2:     clamp(2.1rem, 4.6vw, 4.6rem);
  --fs-h3:     clamp(1.5rem, 2.4vw, 2.4rem);
  --fs-lead:   clamp(1.05rem, 1.35vw, 1.35rem);
  --fs-body:   clamp(.97rem, 1.02vw, 1.06rem);
  --fs-small:  .84rem;
  --fs-label:  .68rem;

  --pad-x:     clamp(1.25rem, 5vw, 6rem);
  --sec-y:     clamp(5rem, 12vh, 11rem);

  /* Senkrechter Rhythmus zwischen Ueberzeile, Ueberschrift und Text.
     Gemessen am 16.09.2026 auf allen 17 deutschen Seiten bei 390 und
     1280 px: der Abstand war an 14 Stellen exakt 0 px, darunter bei
     "Fuer Firmen", "Warum unsere Gaeste wiederkommen", "Gut zu wissen"
     und ueber jedem Apartmentnamen. Grund war nicht eine zu kleine Zahl,
     sondern gar keine: h1 bis h4 haben margin:0, p hat nur margin-bottom,
     und der Abstand stand nur dort, wo jemand ihn von Hand als
     style="margin-top:..." ins Markup geschrieben hatte — in acht
     verschiedenen Groessen. Wo er vergessen wurde, klebten die Zeilen
     aufeinander.

     Deshalb stehen die drei Abstaende jetzt hier und gelten ueberall.
     Wer eine Ueberschrift ergaenzt, muss nichts mehr mitdenken. */
  --gap-label: clamp(1.15rem, 1.8vw, 1.7rem);  /* Ueberzeile  -> Ueberschrift */
  --gap-head:  clamp(1.5rem,  2.4vw, 2.3rem);  /* Ueberschrift -> Vorspann    */
  --gap-sub:   clamp(1.05rem, 1.5vw, 1.4rem);  /* Kartentitel  -> Kartentext  */

  --maxw:      1560px;
  --radius:    2px;

  --ease:      cubic-bezier(.22,1,.36,1);
  --ease-io:   cubic-bezier(.65,0,.35,1);
  --dur:       .75s;
}

/* ---------- 2. Reset ---------- */
*,*::before,*::after{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; scroll-behavior:smooth; overflow-x:clip; }
/* Sprungmarken. Der Kopf ist position:fixed und zwischen 77px (Handy) und
   101,3px (ab 1280px Breite) hoch — gemessen am 10.09.2026 ueber acht
   Fenstergroessen. Ohne scroll-margin-top scrollt der Browser den Anker
   exakt an den oberen Fensterrand, und der Kopf legt sich darueber: man
   landet auf einem Abschnitt, dessen Ueberschrift man nicht sieht.

   Der Wert ist derselbe clamp wie das padding-top bei .phero, plus etwas
   Luft. Gesetzt auf section[id], nicht auf jedes [id] — sonst gilt die
   Regel auch fuer Formularfelder und Akkordeon-Knoepfe, und deren
   Fokus-Sprung wuerde unnoetig weit springen. */
section[id]{ scroll-margin-top:clamp(8.5rem,15vh,11rem); }
body{
  margin:0; background:var(--ink); color:var(--cream);
  font-family:var(--ff-body); font-size:var(--fs-body); font-weight:300;
  line-height:1.68; letter-spacing:.005em;
  -webkit-font-smoothing:antialiased; -moz-osx-font-smoothing:grayscale;
  overflow-x:clip;
}
body.is-locked{ overflow:hidden; }
img,svg,video{ display:block; max-width:100%; }
/* Jedes Bild steckt in einem <picture>, damit moderne Browser die kleinere WebP-Fassung
   laden und aeltere das JPEG bekommen. Das <picture> darf die Geometrie nicht veraendern:
   viele Bildcontainer geben dem img height:100%, das braucht einen Elternteil mit Hoehe. */
picture{ display:block; width:100%; height:100%; }
a{ color:inherit; text-decoration:none; }
button{ font:inherit; color:inherit; background:none; border:0; cursor:pointer; }
h1,h2,h3,h4{ margin:0; font-weight:300; letter-spacing:-.02em; line-height:1.02; font-family:var(--ff-display); }
p{ margin:0 0 1.1em; }
::selection{ background:var(--gold); color:#0a0a0c; }
:focus-visible{ outline:1px solid var(--gold); outline-offset:4px; }

/* ---------- 3. Utilities ---------- */
.wrap{ width:100%; max-width:var(--maxw); margin-inline:auto; padding-inline:var(--pad-x); }
.wrap-narrow{ width:100%; max-width:940px; margin-inline:auto; padding-inline:var(--pad-x); }
.section{ padding-block:var(--sec-y); position:relative; }
.center{ text-align:center; }
.gold{ color:var(--gold); }
.serif{ font-family:var(--ff-display); }
.italic{ font-style:italic; }
.dim{ color:var(--cream-dim); }
.mute{ color:var(--muted); }
.lead{ font-size:var(--fs-lead); line-height:1.6; color:var(--cream-dim); font-weight:300; }
.tiny{ font-size:var(--fs-small); }
.mb0{ margin-bottom:0; }
/* .mt-l steht nicht mehr hier, sondern ganz am Ende der Datei.
   Begruendung dort. */
.hr{ height:1px; background:var(--line-soft); border:0; margin:0; }
.nowrap{ white-space:nowrap; }

.eyebrow{
  display:inline-flex; align-items:center; gap:.7rem;
  font-size:var(--fs-label); font-weight:500; letter-spacing:.34em;
  text-transform:uppercase; color:var(--gold);
}
.eyebrow::before{
  content:""; width:clamp(20px,3vw,46px); height:1px; background:currentColor; opacity:.6;
}
.eyebrow.no-line::before{ display:none; }

/* ---------- 3a. Senkrechter Rhythmus ----------
   Siehe die Begruendung bei --gap-label weiter oben. Die Regeln greifen
   ueber den Nachbarschafts-Selektor, damit sie nur dort wirken, wo die
   Ueberschrift wirklich direkt auf die Ueberzeile folgt, und nicht in
   Listen oder Akkordeons.

   .legal ist ausgenommen: die Rechtstexte haben ihren eigenen, engeren
   Rhythmus (.legal h2{ margin:2.6rem 0 1rem }). Mit dem grossen Abstand
   wuerden AGB und Datenschutz auf dem Handy doppelt so lang. */
.eyebrow + h1,
.eyebrow + h2,
.eyebrow + h3,
.eyebrow + h4,
.eyebrow + p{ margin-top:var(--gap-label); }

h1 + p,
h2 + p{ margin-top:var(--gap-head); }

.legal h2 + p,
.legal h3 + p{ margin-top:0; }

.h-xl{ font-size:var(--fs-h1); }
.h-l{ font-size:var(--fs-h2); }
.h-m{ font-size:var(--fs-h3); }

.grid{ display:grid; gap:clamp(1.4rem,3vw,3rem); }
.g2{ grid-template-columns:repeat(2,1fr); }
.g3{ grid-template-columns:repeat(3,1fr); }
.g4{ grid-template-columns:repeat(4,1fr); }
@media (max-width:1000px){ .g3,.g4{ grid-template-columns:repeat(2,1fr); } }
@media (max-width:720px){ .g2,.g3,.g4{ grid-template-columns:1fr; } }

/* ---------- 4. Textur, Grain, Cursor ---------- */
.grain{
  position:fixed; inset:-120%; z-index:9000; pointer-events:none; opacity:.05;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  animation:grainShift 7s steps(6) infinite; mix-blend-mode:overlay;
}
@keyframes grainShift{
  0%{transform:translate(0,0)}    16%{transform:translate(-3%,-4%)}
  33%{transform:translate(2%,-2%)} 50%{transform:translate(-2%,3%)}
  66%{transform:translate(3%,2%)}  83%{transform:translate(-1%,-3%)} 100%{transform:translate(0,0)}
}
.cursor,.cursor-ring{
  position:fixed; top:0; left:0; z-index:9500; pointer-events:none;
  border-radius:50%; mix-blend-mode:difference; will-change:transform;
}
.cursor{ width:6px; height:6px; background:var(--gold-lite); margin:-3px 0 0 -3px; }
.cursor-ring{
  width:38px; height:38px; margin:-19px 0 0 -19px; border:1px solid rgba(233,209,154,.55);
  transition:width .35s var(--ease),height .35s var(--ease),margin .35s var(--ease),opacity .3s,border-color .3s;
}
.cursor-ring.is-hot{ width:74px; height:74px; margin:-37px 0 0 -37px; border-color:var(--gold); }
@media (hover:none),(max-width:900px){ .cursor,.cursor-ring{ display:none; } }

/* ---------- 5. Preloader ---------- */
.loader{
  position:fixed; inset:0; z-index:9800; background:var(--ink);
  display:grid; place-items:center; transition:opacity .6s ease;
}
.loader__inner{ text-align:center; }
.loader__mark{ width:82px; height:82px; margin:0 auto 1.6rem; }
.loader__mark path,.loader__mark line{
  stroke:var(--gold); fill:none; stroke-width:1.1;
  stroke-dasharray:400; stroke-dashoffset:400; animation:draw 1.5s var(--ease) forwards;
}
@keyframes draw{ to{ stroke-dashoffset:0; } }
.loader__word{
  font-size:var(--fs-label); letter-spacing:.55em; text-transform:uppercase;
  color:var(--muted); padding-left:.55em;
}
.loader__bar{ width:min(280px,52vw); height:1px; background:var(--line); margin:1.4rem auto 0; overflow:hidden; }
.loader__bar i{ display:block; height:100%; width:0; background:var(--gold); transition:width .2s linear; }
.loader__num{ margin-top:.9rem; font-size:.7rem; letter-spacing:.3em; color:var(--muted); }
body.loaded .loader{ opacity:0; pointer-events:none; }

/* Vorhang / Seitenübergang */
.curtain{
  position:fixed; inset:0; z-index:9700; pointer-events:none; display:flex;
}
.curtain span{
  flex:1; background:var(--ink-2); transform:scaleY(0); transform-origin:top;
  transition:transform .62s var(--ease);
}
.curtain.in span{ transform:scaleY(1); transform-origin:bottom; }
.curtain.out span{ transform:scaleY(0); transform-origin:top; }
.curtain span:nth-child(2){ transition-delay:.05s } .curtain span:nth-child(3){ transition-delay:.1s }
.curtain span:nth-child(4){ transition-delay:.15s } .curtain span:nth-child(5){ transition-delay:.2s }

/* ---------- 6. Header ---------- */
.hdr{
  position:fixed; top:0; left:0; right:0; z-index:900;
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:clamp(1rem,2vw,1.6rem) var(--pad-x);
  transition:transform .5s var(--ease),background .4s,backdrop-filter .4s,border-color .4s,padding .4s;
  border-bottom:1px solid transparent;
}
.hdr.solid{
  background:rgba(10,10,12,.72); backdrop-filter:blur(18px) saturate(140%);
  border-bottom-color:var(--line-soft); padding-block:clamp(.7rem,1.2vw,1rem);
}
.hdr.hide{ transform:translateY(-105%); }
/* Schutzschleier: Solange der Header transparent ist, liegt unter ihm ein weicher
   Verlauf. Dadurch bleibt die Wortmarke lesbar, falls Inhalt darunter durchscrollt. */
.hdr::before{
  content:""; position:absolute; inset:0; z-index:-1; pointer-events:none;
  background:linear-gradient(180deg, rgba(10,10,12,.82) 0%, rgba(10,10,12,.45) 55%, transparent 100%);
  transition:opacity .4s;
}
.hdr.solid::before{ opacity:0; }
.hdr__logo{ display:flex; align-items:center; gap:.75rem; }
.hdr__logo svg{ width:30px; height:30px; }
/* Wortmarke: "VISTARO" oben, "Living" darunter.
   Der Unterzeiler wird per Flexbox auf exakt dieselbe Breite verteilt,
   damit beide Zeilen links wie rechts buendig stehen - unabhaengig von der Schrift. */
.hdr__wm{ display:block; }
.hdr__logo b{
  display:block; font-family:var(--ff-display); font-size:1.22rem; font-weight:400; line-height:1;
  letter-spacing:.36em; text-transform:uppercase; margin-right:-.36em;
}
.hdr__logo em{
  display:flex; justify-content:space-between; font-style:normal; font-size:.58rem; line-height:1;
  letter-spacing:0; color:var(--gold); margin-top:.5rem; text-transform:none;
}
.nav{ display:flex; align-items:center; gap:clamp(1.2rem,2.4vw,2.6rem); }
.nav a{
  position:relative; font-size:.79rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--cream-dim); padding-block:.4rem; transition:color .3s;
}
.nav a::after{
  content:""; position:absolute; left:0; bottom:0; width:100%; height:1px; background:var(--gold);
  transform:scaleX(0); transform-origin:right; transition:transform .45s var(--ease);
}
.nav a:hover{ color:var(--cream); } .nav a:hover::after{ transform:scaleX(1); transform-origin:left; }
.nav a.active{ color:var(--gold); } .nav a.active::after{ transform:scaleX(1); }
.hdr__cta{ display:flex; align-items:center; gap:1rem; }
@media (max-width:1080px){ .nav.desktop{ display:none; } }
@media (max-width:640px){
  .hdr__cta .btn--ghost{ display:none; }
  .hdr__logo svg{ width:26px; height:26px; }
  .hdr__logo b{ font-size:1.02rem; letter-spacing:.28em; }
}

.burger{ display:none; width:44px; height:44px; position:relative; }
.burger i{
  position:absolute; left:11px; width:22px; height:1px; background:var(--cream); transition:.4s var(--ease);
}
.burger i:nth-child(1){ top:19px; } .burger i:nth-child(2){ top:25px; }
.burger.open i:nth-child(1){ top:22px; transform:rotate(45deg); background:var(--gold); }
.burger.open i:nth-child(2){ top:22px; transform:rotate(-45deg); background:var(--gold); }
@media (max-width:1080px){ .burger{ display:block; } }

.menu{
  position:fixed; inset:0; z-index:880; background:var(--ink-2);
  clip-path:circle(0% at calc(100% - 44px) 44px); transition:clip-path .85s var(--ease);
  display:flex; flex-direction:column; justify-content:center; padding:6rem var(--pad-x) 3rem;
}
.menu.open{ clip-path:circle(150% at calc(100% - 44px) 44px); }
.menu__list{ list-style:none; margin:0; padding:0; }
.menu__list li{ overflow:hidden; }
.menu__list a{
  display:block; font-family:var(--ff-display); font-size:clamp(2rem,7vw,4.4rem);
  padding-block:.14em; transform:translateY(110%); transition:transform .7s var(--ease),color .3s;
}
.menu.open .menu__list a{ transform:translateY(0); }
.menu__list li:nth-child(2) a{ transition-delay:.06s } .menu__list li:nth-child(3) a{ transition-delay:.12s }
.menu__list li:nth-child(4) a{ transition-delay:.18s } .menu__list li:nth-child(5) a{ transition-delay:.24s }
.menu__list li:nth-child(6) a{ transition-delay:.3s }  .menu__list li:nth-child(7) a{ transition-delay:.36s }
.menu__list a:hover{ color:var(--gold); }
/* Drei Kontaktwege statt einer Textzeile. Auf dem Handy untereinander und
   gross genug zum Treffen (44px ist das Mindestmass fuer Fingerziele), auf
   breiten Schirmen nebeneinander. */
.menu__meta{
  margin-top:auto; padding-top:2rem; border-top:1px solid var(--line-soft);
  display:grid; gap:.5rem;
}
.menu__weg{
  display:flex; align-items:center; gap:.95rem; min-height:52px;
  padding:.7rem .95rem; border:1px solid var(--line-soft); border-radius:var(--radius);
  color:var(--cream-dim); text-decoration:none; background:rgba(255,255,255,.02);
  transition:border-color .35s,background .35s,color .35s;
}
.menu__weg:hover,.menu__weg:focus-visible{ border-color:var(--gold); background:rgba(201,162,75,.07); color:var(--cream); }
.menu__sym{ flex:none; width:22px; height:22px; color:var(--gold); }
.menu__sym svg{ width:100%; height:100%; display:block; }
.menu__weg b{ font-weight:400; font-size:.95rem; color:var(--cream); }
.menu__weg em{ font-style:normal; font-size:.78rem; color:var(--muted); margin-left:auto; text-align:right; }
/* WhatsApp hat eine eigene Hausfarbe. Nur das Symbol bekommt sie — der Rest
   bleibt Vistaro, sonst sieht die Kachel aus wie eingeklebt. */
.menu__weg--wa .menu__sym{ color:#25d366; }
@media (min-width:560px){
  .menu__meta{ grid-template-columns:repeat(3,1fr); gap:.6rem; }
  .menu__weg{ flex-direction:column; align-items:flex-start; gap:.55rem; padding:1rem; }
  .menu__weg em{ margin-left:0; text-align:left; }
}

.progress{ position:fixed; top:0; left:0; height:2px; width:0; background:linear-gradient(90deg,var(--gold-deep),var(--gold-lite)); z-index:950; }

/* ---------- 7. Buttons ---------- */
.btn{
  --bg:var(--gold); --fg:#0b0b0d;
  position:relative; display:inline-flex; align-items:center; justify-content:center; gap:.7rem;
  padding:1.05em 2.2em; border-radius:999px; overflow:hidden; isolation:isolate;
  font-size:.78rem; font-weight:500; letter-spacing:.2em; text-transform:uppercase;
  color:var(--fg); background:var(--bg); transition:color .45s var(--ease),transform .5s var(--ease);
  will-change:transform;
}
.btn::before{
  content:""; position:absolute; inset:0; z-index:-1; background:var(--cream);
  transform:translateY(101%); transition:transform .55s var(--ease); border-radius:inherit;
}
.btn:hover::before{ transform:translateY(0); }
.btn:hover{ color:#0b0b0d; }
.btn--ghost{ --bg:transparent; --fg:var(--cream); border:1px solid var(--line); }
.btn--ghost::before{ background:var(--gold); }
.btn--ghost:hover{ color:#0b0b0d; border-color:var(--gold); }
.btn--lg{ padding:1.25em 2.8em; font-size:.82rem; }
.btn i{ font-style:normal; transition:transform .45s var(--ease); }
.btn:hover i{ transform:translateX(5px); }

.link-u{
  display:inline-flex; align-items:center; gap:.6rem; padding-bottom:.3rem;
  font-size:.78rem; letter-spacing:.2em; text-transform:uppercase; color:var(--gold);
  border-bottom:1px solid rgba(201,162,75,.35); transition:border-color .4s,gap .4s;
}
.link-u:hover{ border-color:var(--gold); gap:1rem; }

/* ---------- 8. Reveals ---------- */
[data-reveal]{ opacity:0; transform:translateY(38px); transition:opacity 1.05s var(--ease),transform 1.05s var(--ease); }
[data-reveal].seen{ opacity:1; transform:none; }
[data-reveal="fade"]{ transform:none; }
[data-reveal="left"]{ transform:translateX(-46px); }
[data-reveal="right"]{ transform:translateX(46px); }
@media (max-width:700px){
  [data-reveal="left"],[data-reveal="right"]{ transform:translateY(38px); }
}
[data-reveal="scale"]{ transform:scale(1.06); }
[data-reveal].seen{ transform:none; }

.mask{ display:block; overflow:hidden; }
.mask > span{ display:block; transform:translateY(105%); transition:transform 1.1s var(--ease); }
.mask.seen > span,.seen .mask > span{ transform:translateY(0); }
.mask:nth-child(2) > span{ transition-delay:.08s } .mask:nth-child(3) > span{ transition-delay:.16s }
.mask:nth-child(4) > span{ transition-delay:.24s }

.img-mask{ position:relative; overflow:hidden; }
.img-mask::after{
  content:""; position:absolute; inset:0; background:var(--ink); transform-origin:right;
  transition:transform 1.15s var(--ease);
}
.img-mask.seen::after{ transform:scaleX(0); }
.img-mask img{ transition:transform 1.6s var(--ease); }

.stagger > *{ opacity:0; transform:translateY(30px); transition:opacity .9s var(--ease),transform .9s var(--ease); }
.stagger.seen > *{ opacity:1; transform:none; }
.stagger.seen > *:nth-child(1){transition-delay:.05s} .stagger.seen > *:nth-child(2){transition-delay:.13s}
.stagger.seen > *:nth-child(3){transition-delay:.21s} .stagger.seen > *:nth-child(4){transition-delay:.29s}
.stagger.seen > *:nth-child(5){transition-delay:.37s} .stagger.seen > *:nth-child(6){transition-delay:.45s}
.stagger.seen > *:nth-child(7){transition-delay:.53s} .stagger.seen > *:nth-child(8){transition-delay:.61s}

/* ---------- 9. Hero ---------- */
/* Das padding-top haelt den Bereich unter dem fixierten Header frei.
   Weil der Inhalt per flex-end unten sitzt, ist das die sichere Obergrenze. */
.hero{
  position:relative; min-height:100svh; display:flex; align-items:flex-end; overflow:hidden;
  padding-top:clamp(7.5rem,17vh,11rem);
}
.hero__bg{ position:absolute; inset:-6% -3%; z-index:0; }
.hero__bg img{
  width:100%; height:100%; object-fit:cover; opacity:.72;
  transform:scale(1.14); animation:kenburns 26s ease-in-out infinite alternate;
}
@keyframes kenburns{ from{ transform:scale(1.14) translate3d(0,0,0);} to{ transform:scale(1.24) translate3d(-2%,-2%,0);} }
.hero__veil{
  position:absolute; inset:0; z-index:1;
  background:
    radial-gradient(120% 90% at 18% 20%, rgba(201,162,75,.16), transparent 55%),
    linear-gradient(180deg, rgba(10,10,12,.86) 0%, rgba(10,10,12,.42) 38%, rgba(10,10,12,.94) 92%);
}
.hero__content{ position:relative; z-index:3; width:100%; padding-bottom:clamp(2.5rem,7vh,5rem); }
.hero__title{
  font-size:var(--fs-hero); line-height:.86; letter-spacing:-.035em; font-weight:300;
}
/* Die drei Zeilen steigen einzeln hinter einer Maske hervor.

   Drei Kleinigkeiten machen hier den Unterschied zwischen "Text erscheint"
   und "Text tritt auf":

   1. Der Abstand zwischen den Zeilen. Bei .1s Versatz starten alle drei
      praktisch gleichzeitig und man liest einen Block. Bei .17s liest man drei
      Saetze nacheinander — genau das, wofuer die Punkte im Text stehen.
   2. Die Unschaerfe. Sie kostet einen Wimpernschlag Rechenzeit, einmalig beim
      Laden, und ist der Grund, warum die Bewegung teuer aussieht statt
      technisch. Ohne sie wirkt dieselbe Bewegung flach.
   3. Der Goldstrich darunter zieht als Letztes auf, nach der dritten Zeile.
      Er ist derselbe Strich wie links an der Wortmarke der Buehne
      (.stage__cap::before) — die Seite wiederholt damit ein Zeichen, statt
      ein neues zu erfinden.

   Bei "Bewegung reduzieren" faellt alles davon weg: der Sammelblock ganz unten
   im Blatt setzt jede Dauer auf .001s, die Zeilen stehen dann sofort. */
.hero__title .ln{ display:block; overflow:hidden; }
.hero__title .ln > span{
  display:block; transform:translateY(112%); filter:blur(9px);
  transition:transform 1.15s var(--ease), filter .8s ease;
}
body.loaded .hero__title .ln > span{ transform:translateY(0); filter:blur(0); }
body.loaded .hero__title .ln:nth-child(2) > span{ transition-delay:.17s }
body.loaded .hero__title .ln:nth-child(3) > span{ transition-delay:.34s }
.hero__title::after{
  content:""; display:block; height:1px; width:clamp(3.2rem,8vw,6.5rem);
  margin-top:clamp(.8rem,2vh,1.4rem);
  background:linear-gradient(90deg,var(--gold),rgba(201,162,75,0));
  transform:scaleX(0); transform-origin:0 50%;
  transition:transform 1.1s var(--ease) 1.05s;
}
body.loaded .hero__title::after{ transform:scaleX(1); }
.hero__title em{ font-style:italic; color:var(--gold-lite); }
.hero__row{
  display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between;
  gap:2.5rem; margin-top:clamp(1.6rem,4vh,3rem);
}
.hero__sub{ max-width:44ch; opacity:0; transform:translateY(24px); transition:.9s var(--ease) .55s; }
body.loaded .hero__sub{ opacity:1; transform:none; }
.hero__acts{ display:flex; flex-wrap:wrap; gap:1rem; opacity:0; transform:translateY(24px); transition:.9s var(--ease) .68s; }
body.loaded .hero__acts{ opacity:1; transform:none; }
.hero__top{
  position:absolute; z-index:3; left:var(--pad-x); right:var(--pad-x); top:clamp(5.5rem,12vh,8rem);
  display:flex; justify-content:space-between; gap:2rem; font-size:.72rem; letter-spacing:.28em;
  text-transform:uppercase; color:var(--muted); opacity:0; transition:opacity 1s ease .9s;
}
body.loaded .hero__top{ opacity:1; }

/* ---------- 9b. Bildbuehne im Kopf ----------
   Fuenf Raumfotos aus allen drei Wohnungen liegen deckungsgleich
   uebereinander. Beim Scrollen wird der Kopfbereich festgehalten und die Fotos
   werden nacheinander darueber aufgeblendet, jedes mit einer eigenen langsamen
   Kamerabewegung.

   WICHTIG fuer spaetere Aenderungen: Der Ruhezustand steht hier oben und ist
   bewusst genau der alte Hero — ein Bild, volle Bildschirmhoehe, Ken-Burns.
   Alles Weitere greift ausschliesslich unter .stage.is-on, und diese Klasse
   setzt vistaro.js erst, wenn alle fuenf Fotos nachweislich geladen sind.
   Faellt irgendetwas davon aus, bleibt der alte Hero stehen. */
.stage{ position:relative; --stage-blur:7px; }
.stage__f{
  position:absolute; inset:0; margin:0;
  opacity:0;
}
/* Ohne Skript ist nur das erste Foto zu sehen — der alte Hero. */
.stage__f:first-child{ opacity:1; }

/* Wortmarke des Raums, mittig am linken Rand: Goldstrich, darueber der Name
   der Wohnung, darunter das Stichwort.

   Zwei Zeilen und nicht eine: Seit die Buehne alle drei Wohnungen zeigt, steht
   dort der Wohnungsname — und "Luana Design Apartment" neben "Wohnen" in einer
   Zeile ist auf einem 390-Pixel-Handy breiter als der Bildschirm. Uebereinander
   passt es ueberall, und der Name in Gold ueber dem groesseren Stichwort liest
   sich ohnehin besser als beides nebeneinander.

   Die Raeume sind ueberwiegend hell — weisse Waende, helles Holz. Heller Text
   auf hellem Foto liest sich nicht. Deshalb liegt unter der Schrift ein
   schmaler dunkler Verlauf am linken Rand (.stage__cap::after, bewusst hinter
   den Text gelegt), und die Schrift traegt zusaetzlich einen weichen Schatten.
   Auf dunklen Raeumen faellt beides nicht auf, auf hellen rettet es die
   Lesbarkeit. */
.stage__cap{
  position:absolute; z-index:4; left:0; top:50%;
  margin:0; transform:translateY(-50%);
  padding-left:var(--pad-x); padding-right:clamp(2rem,6vw,5rem);
  display:flex; align-items:center; gap:clamp(.7rem,1.4vw,1.1rem);
  font-size:.7rem; letter-spacing:.34em; text-transform:uppercase; color:var(--cream);
  text-shadow:0 1px 12px rgba(10,10,12,.85), 0 0 3px rgba(10,10,12,.6);
  opacity:0; transition:opacity .5s var(--ease); pointer-events:none;
}
.stage__cap::before{
  content:""; position:relative; z-index:1;
  width:clamp(24px,3.5vw,48px); height:1px; background:var(--gold);
  box-shadow:0 0 8px rgba(10,10,12,.7);
}
.stage__cap::after{
  content:""; position:absolute; z-index:0; left:0; top:50%;
  width:100%; height:14rem; transform:translateY(-50%);
  background:radial-gradient(70% 50% at 0% 50%, rgba(10,10,12,.62), transparent 72%);
  pointer-events:none;
}
.stage__cap b,
.stage__cap span{ position:relative; z-index:1; }
.stage__cap__t{ display:flex; flex-direction:column; align-items:flex-start; gap:.45rem; min-width:0; }
.stage__cap b{ font-weight:400; font-size:.62rem; color:var(--gold-lite); letter-spacing:.2em; }
.stage__cap.on{ opacity:1; }

/* Hauchduenne Fortschrittslinie an der Unterkante: zeigt, dass der Abschnitt
   ein Ende hat. Ohne sie fragen sich Besucher, ob die Seite haengt.
   Die Spur ist dunkel gehalten, weil sie meist vor hellen Waenden liegt. */
.stage__bar{
  position:absolute; z-index:4; left:0; right:0; bottom:0; height:2px;
  background:rgba(10,10,12,.3);
  opacity:0; transition:opacity .5s var(--ease); pointer-events:none;
}
.stage__bar i{
  display:block; height:100%; width:100%; background:var(--gold);
  transform:scaleX(var(--pp,0)); transform-origin:0 50%;
}
.stage.is-on .stage__bar{ opacity:1; }

/* Aktiv: Die Buehne wird mehrere Bildschirmhoehen hoch, der Kopf bleibt kleben. */
.stage.is-on{ height:calc(100svh * var(--stage-len,3)); }
.stage.is-on .stage__pin{ position:sticky; top:0; height:100svh; min-height:0; }
/* --o (Deckkraft), --z (Zoom), --dx (seitliche Drift) und --bf (Unschaerfe)
   setzt das Skript pro Foto. Die Ken-Burns-Dauerschleife weicht der
   scrollgesteuerten Bewegung.

   Zur Unschaerfe: Das neue Foto kommt weich herein und zieht sich beim
   Aufblenden scharf. Das ist der Griff, der den Wechsel teuer aussehen laesst —
   und zugleich der teuerste, den es hier gibt: eine Weichzeichnung ueber die
   ganze Bildschirmflaeche kostet auf dem Handy echte Rechenzeit.
   Zwei Vorkehrungen dagegen:

     * --bf ist ausserhalb des Wechsels exakt 0. blur(0px) ist praktisch
       umsonst; nur die 42 Prozent eines Abschnitts, in denen wirklich
       ueberblendet wird, kosten etwas.
     * --stage-blur ist auf dem Handy kleiner. Die Flaeche ist dort zwar
       kleiner, die Rechenleistung aber sehr viel kleiner.

   Die weichen Raender, die dabei entstehen, sieht niemand: .hero__bg steht mit
   inset:-6% -3% ueber den sichtbaren Bereich hinaus und .hero schneidet ab. */
.stage.is-on .stage__f{
  opacity:var(--o,0);
  filter:blur(calc(var(--bf,0) * var(--stage-blur)));
  will-change:opacity,filter;
}
@media (max-width:900px){ .stage{ --stage-blur:3.5px; } }
/* Abdunkeln ueber brightness und NICHT ueber opacity — das ist der Unterschied
   zwischen "dunkler" und "durchsichtig", und er ist hier entscheidend.

   Vorher stand an dieser Stelle opacity:.88. Das sah ueberall richtig aus, bis
   auf eine Stelle: ganz am Ende der Buehne. Das Skript laesst das abgehende
   Foto auf voller Deckkraft liegen (o = 1 fuer i === b) — waehrend eines
   Wechsels ist das egal, weil das naechste Foto sofort weiterwandert. Beim
   letzten Foto aber ist b fest auf n-2 geklemmt, misch bleibt auf 1 stehen,
   und damit liegen dauerhaft zwei Ebenen uebereinander. Bei 88 Prozent
   Deckkraft schien die untere zu rund 11 Prozent durch: ein stehendes
   Geisterbild des vorletzten Raums, das nur am Ende sichtbar war.
   Gemessen am 31.08.2026, siehe _quelle/pruefbilder/ghost-vorher.png.

   brightness(.88) ergibt vor dem fast schwarzen --ink (10,10,12) rechnerisch
   dasselbe Bild — der Unterschied liegt bei gut einem Helligkeitswert von 255
   und ist nicht zu sehen. Aber die Ebene ist blickdicht, und damit kann
   grundsaetzlich nichts mehr durchscheinen, egal was das Skript stapelt.
   Wer hier wieder auf opacity umstellt, holt das Geisterbild zurueck. */
.stage.is-on .hero__bg img{
  animation:none; opacity:1; filter:brightness(.88);
  transform:scale(var(--z,1.06)) translate3d(var(--dx,0),0,0);
  will-change:transform;
}
/* Der dunkle Verlauf ist nur da, damit die Ueberschrift lesbar bleibt. Sobald
   die Ueberschrift weggeblendet ist, zieht er sich zurueck und gibt die Raeume
   frei. --veil-op kommt aus dem Skript. */
.stage.is-on .hero__veil{ opacity:var(--veil-op,1); }
/* Der Titel tritt beim Hineingehen zurueck. --hero-op kommt aus dem Skript. */
.stage.is-on .hero__content{
  opacity:var(--hero-op,1);
  transform:translate3d(0,var(--hero-shift,0),0);
  will-change:opacity,transform;
}

/* Sub-Hero für Unterseiten */
/* align-items:flex-end heisst: der Textblock haengt am unteren Rand und
   waechst nach OBEN. Solange er kurz ist, faellt das nicht auf. Wird er
   laenger, schiebt er sich unter den festen Kopf — gemessen am 10.09.2026
   auf apartments.html: Textblock 430px hoch (zweizeilige Ueberschrift plus
   vierzeiliger Vorspann), Oberkante bei 74px, Kopf endet bei 101px. Die
   Krume "Start / Apartments" lag damit hinter der Wortmarke, der Beizeiler
   "Luana Design Apartments" hinter dem "Living". Auf allen anderen Seiten
   ist der Block 254-305px hoch und blieb darunter — der Fehler steckte
   also nicht in einer Seite, sondern in dieser Regel, und die naechste
   laengere Ueberschrift haette ihn wieder ausgeloest.

   padding-top reserviert den Platz des Kopfes. Weil min-height gilt und
   nicht height, aendert sich fuer kurze Blocks gar nichts: sie haengen
   weiterhin unten, der Kasten bleibt 62svh hoch. Erst wenn der Text mehr
   Platz braucht, waechst der Kasten nach unten statt der Text nach oben.

   Die Zahl ist gemessen, nicht geschaetzt: der Kopf ist zwischen 77px
   (Handy) und 101,3px (ab 1280px Breite) hoch. clamp(7.5rem,14vh,10rem)
   liegt ueberall darueber, am knappsten bei 1280x800 mit 18,7px Luft. */
.phero{ position:relative; min-height:62svh; display:flex; align-items:flex-end; overflow:hidden;
  padding-top:clamp(7.5rem,14vh,10rem); padding-bottom:clamp(2.5rem,6vh,5rem); }
.phero__bg{ position:absolute; inset:0; }
.phero__bg img{ width:100%; height:100%; object-fit:cover; opacity:.55; transform:scale(1.08); }
.phero::after{
  content:""; position:absolute; inset:0;
  background:linear-gradient(180deg,rgba(10,10,12,.9),rgba(10,10,12,.45) 45%,rgba(10,10,12,.97));
}
.phero__c{ position:relative; z-index:2; width:100%; }
/* Stand bis zum 16.09.2026 auf .6rem und damit unter dem Rhythmus der
   uebrigen Seite: gemessen 9,6 px zwischen Ueberzeile und Seitentitel auf
   jeder der elf Seiten mit Kopfbild. */
.phero h1{ font-size:var(--fs-h1); margin-top:var(--gap-label); }
.phero--slim{ min-height:0; padding-top:clamp(9rem,18vh,13rem); padding-bottom:clamp(1.5rem,4vh,3rem); background:
  radial-gradient(80% 120% at 12% 0%, rgba(201,162,75,.10), transparent 60%), var(--ink); }
.phero--slim::after{ display:none; }
.crumbs{ font-size:.7rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-bottom:1.2rem; }
.crumbs a:hover{ color:var(--gold); }

/* ---------- 10. Marquee ---------- */
.marquee{ overflow:hidden; border-block:1px solid var(--line-soft); padding-block:1.15rem; background:var(--ink-2); }
.marquee__t{ display:flex; width:max-content; animation:slide 42s linear infinite; }
.marquee:hover .marquee__t{ animation-play-state:paused; }
@keyframes slide{ to{ transform:translateX(-50%); } }
.marquee span{
  display:inline-flex; align-items:center; gap:2.6rem; padding-inline:1.3rem;
  font-family:var(--ff-display); font-size:clamp(1rem,1.7vw,1.6rem); color:var(--cream-dim); white-space:nowrap;
}
.marquee span::after{ content:"◆"; font-size:.5em; color:var(--gold); }

/* ---------- 11. Sektionskopf ---------- */
.sechead{ display:flex; flex-wrap:wrap; align-items:flex-end; justify-content:space-between; gap:clamp(1.4rem,3vw,3rem); margin-bottom:clamp(2.4rem,5vw,4.5rem); }
.sechead__l{ max-width:62ch; }
.sechead h2{ font-size:var(--fs-h2); margin-top:var(--gap-label); }
.sechead p{ margin-top:var(--gap-head); max-width:52ch; }

/* ---------- 12. Karten / Apartments ---------- */
.card{
  position:relative; display:block; background:var(--ink-2); border:1px solid var(--line-soft);
  overflow:hidden; transition:border-color .5s,transform .7s var(--ease);
}
.card:hover{ border-color:rgba(201,162,75,.42); }
.card__media{ position:relative; overflow:hidden; aspect-ratio:4/3; }
.card__media img{ width:100%; height:100%; object-fit:cover; transition:transform 1.4s var(--ease),filter .8s; filter:saturate(.85) brightness(.85); }
.card:hover .card__media img{ transform:scale(1.07); filter:saturate(1) brightness(1); }
.card__media::after{ content:""; position:absolute; inset:0; background:linear-gradient(180deg,transparent 45%,rgba(10,10,12,.85)); }
.card__tag{
  position:absolute; z-index:2; top:1rem; left:1rem; padding:.45em 1em; border-radius:999px;
  background:rgba(10,10,12,.7); backdrop-filter:blur(8px); border:1px solid var(--line);
  font-size:.62rem; letter-spacing:.22em; text-transform:uppercase; color:var(--gold-lite);
}
.card__body{ padding:clamp(1.4rem,2.2vw,2.1rem); }
.card__title{ font-size:clamp(1.5rem,2.2vw,2.05rem); }
/* Colin am 16.09.2026 zur Apartments-Seite: "Zwischen dem Namen der
   Apartments und dem Text darunter bisschen mehr Abstand rein." Gemessen
   waren es 0 px — der Kartentitel ist ein h2 bzw. h3 mit margin:0, der
   Text ein p ohne margin-top. */
.card__title + p,
.pin__panel figcaption h3 + p{ margin-top:var(--gap-sub); }
.card__loc{ font-size:.72rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-bottom:.7rem; }
.card__facts{ display:flex; flex-wrap:wrap; gap:1.4rem; margin-top:1.2rem; padding-top:1.2rem; border-top:1px solid var(--line-soft); font-size:.78rem; color:var(--cream-dim); }
.card__facts b{ display:block; font-weight:400; color:var(--muted); font-size:.62rem; letter-spacing:.2em; text-transform:uppercase; margin-bottom:.25rem; }
.card__foot{ display:flex; align-items:center; justify-content:space-between; gap:1rem; margin-top:1.5rem; }
.price{ font-family:var(--ff-display); font-size:1.6rem; }
.price small{ font-family:var(--ff-body); font-size:.68rem; letter-spacing:.18em; text-transform:uppercase; color:var(--muted); margin-left:.5rem; }

/* Pin-Scroll Showcase */
.pin{ position:relative; }
.pin__sticky{ position:sticky; top:0; height:100svh; display:flex; align-items:center; overflow:hidden; }
.pin__track{ display:flex; gap:clamp(1rem,2vw,2.2rem); padding-inline:var(--pad-x); will-change:transform; }
.pin__panel{
  position:relative; flex:0 0 clamp(280px,38vw,560px); height:clamp(380px,64vh,660px);
  overflow:hidden; border:1px solid var(--line-soft); background:var(--ink-2);
}
.pin__panel img{ width:100%; height:100%; object-fit:cover; filter:brightness(.7) saturate(.85); transition:transform 1.4s var(--ease),filter .8s; }
.pin__panel:hover img{ transform:scale(1.06); filter:brightness(.95) saturate(1); }
/* Die echten Wohnungsfotos sind unten hell (Dielen, Teppich, Fliesen). Der Verlauf
   liegt deshalb auf dem Panel und nicht nur hinter der Bildunterschrift — sonst
   steht die Schrift beim Hover auf hellem Boden. */
.pin__panel::after{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:linear-gradient(180deg,rgba(10,10,12,0) 42%,rgba(10,10,12,.42) 66%,rgba(10,10,12,.88) 100%);
}
.pin__panel figcaption{
  position:absolute; z-index:1; inset:auto 0 0 0; padding:clamp(1.2rem,2vw,2rem);
  background:linear-gradient(transparent,rgba(10,10,12,.55));
}
.pin__panel h3{ font-size:clamp(1.4rem,2.1vw,2rem); }
.pin__intro{ flex:0 0 clamp(260px,26vw,420px); align-self:center; }
@media (max-width:900px){
  .pin__sticky{ position:static; height:auto; }
  .pin__track{ flex-direction:column; transform:none !important; }
  .pin__panel{ flex:none; width:100%; height:min(70vw,420px); }
  .pin__intro{ flex:none; width:100%; }
}

/* ---------- 13. Split / Feature ---------- */
.split{ display:grid; grid-template-columns:1.05fr .95fr; gap:clamp(2rem,5vw,5.5rem); align-items:center; }
.split.rev > *:first-child{ order:2; }
@media (max-width:880px){ .split{ grid-template-columns:1fr; } .split.rev > *:first-child{ order:0; } }
.figure{ position:relative; overflow:hidden; }
.figure img{ width:100%; height:100%; object-fit:cover; }
.figure--tall{ aspect-ratio:4/5; }
.figure--wide{ aspect-ratio:16/11; }
.figure__badge{
  position:absolute; right:0; bottom:0; padding:clamp(1rem,2vw,1.8rem);
  background:var(--ink); border-top:1px solid var(--gold); min-width:min(62%,240px);
}
.figure__badge b{ display:block; font-family:var(--ff-display); font-size:clamp(1.8rem,3vw,2.8rem); color:var(--gold-lite); line-height:1; }
.figure__badge span{ font-size:.66rem; letter-spacing:.22em; text-transform:uppercase; color:var(--muted); }

/* Handschriftliche Unterschrift unter dem Portraet auf "Ueber uns".
   Der Schriftzug ist ein reiner SVG-Pfad, keine Schriftart — er braucht also
   nichts nachzuladen und bleibt bei jeder Groesse scharf. */
.sig{ margin:clamp(1.4rem,2.6vw,2.2rem) 0 0; }
.sig__mark{ display:block; width:min(264px,72%); height:auto; color:var(--cream); opacity:.9; }
.sig figcaption{ margin-top:.9rem; }
.sig figcaption b{ display:block; font-size:.72rem; font-weight:400; letter-spacing:.24em; text-transform:uppercase; color:var(--cream-dim); }
.sig figcaption span{ display:block; margin-top:.4rem; font-size:.82rem; color:var(--muted); }

.list-check{ list-style:none; margin:1.8rem 0 0; padding:0; }
.list-check li{ position:relative; padding:0 0 1rem 2rem; color:var(--cream-dim); }
.list-check li::before{
  content:""; position:absolute; left:0; top:.62em; width:9px; height:9px;
  border:1px solid var(--gold); transform:rotate(45deg);
}
.list-check b{ color:var(--cream); font-weight:400; }

/* ---------- 14. Stats ---------- */
.stats{ display:grid; grid-template-columns:repeat(4,1fr); border-top:1px solid var(--line-soft); }
@media (max-width:820px){ .stats{ grid-template-columns:repeat(2,1fr); } }
.stat{ padding:clamp(1.8rem,3.4vw,3.2rem) clamp(1rem,2vw,2rem); border-right:1px solid var(--line-soft); border-bottom:1px solid var(--line-soft); }
.stat:last-child{ border-right:0; }
@media (max-width:820px){ .stat:nth-child(2n){ border-right:0; } }
.stat b{ display:block; font-family:var(--ff-display); font-size:clamp(2.4rem,4.6vw,4rem); line-height:1; color:var(--cream); }
.stat b i{ font-style:normal; color:var(--gold); }
.stat span{ display:block; margin-top:.9rem; font-size:.7rem; letter-spacing:.22em; text-transform:uppercase; color:var(--muted); }

/* ---------- 15. Buchungsleiste ---------- */
.bookbar{
  display:grid; grid-template-columns:repeat(3,1fr) auto; gap:1px;
  background:var(--line-soft); border:1px solid var(--line); backdrop-filter:blur(14px);
}
.bookbar__f{ background:rgba(15,15,18,.9); padding:1.1rem 1.4rem; transition:background .35s; }
.bookbar__f:focus-within{ background:rgba(22,22,26,.96); }
.bookbar__f label{ display:block; font-size:.6rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-bottom:.5rem; transition:color .35s; }
.bookbar__f:focus-within label{ color:var(--gold); }
.bookbar__f input,.bookbar__f select{
  width:100%; background:transparent; border:0; color:var(--cream); font-family:var(--ff-body);
  font-size:.95rem; padding:0; color-scheme:dark;
}
/* Das eingebaute Kalendersymbol ist mausgrau, sitzt je nach Browser woanders
   und wird bei schmalen Feldern kommentarlos weggelassen. Darum: ausblenden
   und ein eigenes setzen, das ueberall gleich aussieht. Es bleibt bedienbar,
   weil ein Klick auf die ganze Kachel den Kalender oeffnet (siehe vistaro.js). */
.bookbar__f input[type="date"]::-webkit-calendar-picker-indicator{
  opacity:0; width:0; padding:0; margin:0;
}
.bookbar__f--datum{ position:relative; cursor:pointer; }
.bookbar__ic{
  position:absolute; right:1.1rem; top:50%; transform:translateY(-25%);
  width:19px; height:19px; color:var(--gold); opacity:.75;
  pointer-events:none; transition:opacity .3s,color .3s;
}
.bookbar__ic svg{ width:100%; height:100%; display:block; }
.bookbar__f--datum:hover .bookbar__ic,
.bookbar__f--datum:focus-within .bookbar__ic{ opacity:1; color:var(--gold-lite); }
/* Platz freihalten, damit ein langes Datum nicht unter dem Symbol verschwindet.
   min-width:0 muss dazu. Rasterfelder schrumpfen sonst nie unter die Eigenbreite
   ihres Inhalts, und ein Datumsfeld bringt eine feste Mindestbreite mit — der
   Innenabstand kaeme oben drauf und die Leiste waere breiter als der Schirm. */
.bookbar__f{ min-width:0; }
.bookbar__f--datum input{ padding-right:1.8rem; min-width:0; }
.bookbar__go{ background:var(--gold); color:#0b0b0d; padding:0 clamp(1.4rem,3vw,2.6rem); font-size:.75rem; letter-spacing:.2em; text-transform:uppercase; font-weight:500; transition:background .4s; }
.bookbar__go:hover{ background:var(--cream); }

/* Auf dem Handy lief die Leiste vorher in zwei Spalten. Drei Felder in zwei
   Spalten lassen zwangslaeufig eine Kachel leer, und der Knopf bekam als
   eigene Zeile keine Hoehe mehr, weil oben nur seitliche Polsterung steht.
   Darum hier: Anreise und Abreise nebeneinander, Gaeste ueber die volle
   Breite, Knopf mit echter Hoehe. */
@media (max-width:820px){
  .bookbar{ grid-template-columns:1fr 1fr; }
  .bookbar__f:nth-child(3){ grid-column:1/-1; }
  .bookbar__f{ padding:.95rem 1.1rem; }
  .bookbar__f input,.bookbar__f select{ font-size:1.05rem; }
  .bookbar__go{
    grid-column:1/-1; padding:1.15rem 1.4rem; font-size:.78rem;
    display:flex; align-items:center; justify-content:center; gap:.6rem;
  }
}

/* ---------- 15b. Ergebnis der Gesamtsuche ----------
   Hängt direkt unter der Buchungsleiste und übernimmt deren Rahmen, damit
   Suche und Ergebnis wie ein Stück wirken. Sichtbar erst mit .on — vorher
   steht die Leiste allein, wie bisher. */
.suche{ display:none; margin-top:-1px; border:1px solid var(--line); background:rgba(15,15,18,.92); }
.suche.on{ display:block; }
.suche__kopf{
  display:flex; align-items:baseline; justify-content:space-between; gap:1rem;
  padding:1.15rem 1.4rem; border-bottom:1px solid var(--line-soft);
}
.suche__kopf h3{ font-size:1.15rem; color:var(--cream); }
.suche__x{ background:none; border:0; color:var(--muted); font-size:.62rem; letter-spacing:.22em; text-transform:uppercase; transition:color .3s; }
.suche__x:hover{ color:var(--cream); }
.suche__liste{ list-style:none; margin:0; padding:0; }
.suche__z{
  display:grid; grid-template-columns:1.5fr .9fr 1fr auto; align-items:center;
  gap:1.2rem; padding:1.15rem 1.4rem; border-bottom:1px solid var(--line-soft);
}
.suche__z:last-child{ border-bottom:0; }
.suche__w b{ display:block; font-size:.98rem; color:var(--cream); font-weight:400; }
.suche__w span{ display:block; margin-top:.35rem; font-size:.63rem; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
/* Der Punkt links vom Wort sagt dasselbe wie das Wort — für alle, die
   Farben nicht unterscheiden, steht die Auskunft trotzdem im Text. */
/* Zwei Zeilen, nicht eine: oben der Zustand, darunter bei freien Wohnungen
   das durchgehend freie Fenster. Der aeussere Kasten stapelt, der innere
   span haelt Punkt und Wort weiter nebeneinander. Deshalb steht der Text
   jedes Zustands in einem span — auch da, wo es keine zweite Zeile gibt:
   ohne ihn wuerde das <i> im Stapel zu einer eigenen Zeile und der Punkt
   saesse ueber statt neben dem Wort. */
.suche__st{ display:grid; gap:.34rem; font-size:.82rem; color:var(--cream-dim); }
.suche__st > span{ display:flex; align-items:center; gap:.55rem; }
.suche__st i{ width:.45rem; height:.45rem; border-radius:50%; background:var(--muted); flex:none; }
/* Eingerueckt auf die Textkante der Zeile darueber: Punktbreite (.45rem)
   plus Abstand (.55rem) ergibt genau 1rem. So haengt die Angabe sichtbar am
   Wort "Frei" und faengt keine eigene Spalte an.
   Margin, nicht Padding: Padding verschoebe nur den Text, der Kasten bliebe
   an der alten Kante stehen — und damit auch das, was eine Pruefung messen
   kann. Die Einrueckung soll den Kasten bewegen. */
.suche__fen{ margin-left:1rem; font-size:.67rem; letter-spacing:.04em; color:var(--muted); }
.suche__z.is-frei .suche__st{ color:var(--gold-lite); }
.suche__z.is-frei .suche__st i{ background:var(--gold); }
.suche__z.is-eng .suche__st i{ background:var(--gold-deep); }
.suche__z.is-belegt .suche__st i{ background:#5f5a55; }
.suche__p b{ display:block; font-family:var(--ff-display); font-size:1.35rem; color:var(--cream); }
.suche__z.is-belegt .suche__p b{ font-family:var(--ff-body); font-size:.88rem; color:var(--cream-dim); }
.suche__p small{ display:block; margin-top:.3rem; font-size:.63rem; letter-spacing:.1em; color:var(--muted); }
.suche__akt{ display:flex; gap:.6rem; justify-content:flex-end; }
.suche__b{
  display:inline-block; padding:.66rem 1.1rem; font-size:.65rem; letter-spacing:.18em;
  text-transform:uppercase; white-space:nowrap; border:1px solid var(--line);
  background:transparent; color:var(--cream-dim);
  transition:border-color .35s,color .35s,background .35s;
}
.suche__b:hover{ border-color:var(--gold); color:var(--cream); }
.suche__b--gold{ background:var(--gold); border-color:var(--gold); color:#0b0b0d; font-weight:500; }
.suche__b--gold:hover{ background:var(--cream); border-color:var(--cream); color:#0b0b0d; }
.suche__fuss{ padding:1rem 1.4rem 1.15rem; font-size:.72rem; color:var(--muted); border-top:1px solid var(--line-soft); }
@media (max-width:820px){
  /* Auf dem Handy stapelt sich die Zeile: Name und Zustand nebeneinander,
     Preis und Knöpfe darunter — alles linksbündig unter dem Namen, damit
     das Auge eine Kante hat. */
  .suche__z{ grid-template-columns:1fr auto; gap:.75rem 1rem; }
  .suche__p{ grid-column:1/-1; }
  .suche__p b{ font-size:1.2rem; }
  .suche__akt{ grid-column:1/-1; justify-content:flex-start; flex-wrap:wrap; }
}

/* ---------- 16. Slider / Stimmen ---------- */
.quotes{ position:relative; }
.quotes__track{ display:grid; align-items:start; }
.quote{
  grid-area:1 / 1; width:100%; margin:0; text-align:center; opacity:0; transform:translateY(20px);
  transition:opacity .8s var(--ease),transform .8s var(--ease); pointer-events:none;
}
.quote.on{ opacity:1; transform:none; pointer-events:auto; }
.quote p{
  font-family:var(--ff-display); font-size:clamp(1.4rem,2.9vw,2.7rem); line-height:1.3; font-style:italic;
  color:var(--cream); max-width:24ch; margin-inline:auto; text-wrap:balance;
}
.quote cite{ display:block; margin-top:1.8rem; font-style:normal; font-size:.72rem; letter-spacing:.26em; text-transform:uppercase; color:var(--muted); }
.quotes__nav{ display:flex; align-items:center; justify-content:center; gap:1.6rem; margin-top:clamp(2rem,4vw,3.4rem); }
.qdot{ width:34px; height:1px; background:var(--line); transition:background .4s; }
.qdot.on{ background:var(--gold); }
.qarrow{ width:46px; height:46px; border:1px solid var(--line); border-radius:50%; display:grid; place-items:center; transition:.4s; color:var(--cream-dim); }
.qarrow:hover{ border-color:var(--gold); color:var(--gold); }
.stars{ color:var(--gold); letter-spacing:.3em; font-size:.8rem; }

/* ---------- 17. Accordion ---------- */
.acc{ border-top:1px solid var(--line-soft); }
.acc__item{ border-bottom:1px solid var(--line-soft); }
.acc__q{
  width:100%; display:flex; align-items:center; justify-content:space-between; gap:2rem; text-align:left;
  padding:clamp(1.2rem,2.4vw,1.9rem) 0; font-family:var(--ff-display); font-size:clamp(1.15rem,1.9vw,1.6rem);
  color:var(--cream); transition:color .35s;
}
.acc__q:hover{ color:var(--gold); }
.acc__q i{ position:relative; flex:none; width:16px; height:16px; }
.acc__q i::before,.acc__q i::after{ content:""; position:absolute; inset:50% 0 auto 0; height:1px; background:currentColor; transition:transform .45s var(--ease); }
.acc__q i::after{ transform:rotate(90deg); }
.acc__item.open .acc__q{ color:var(--gold); }
.acc__item.open .acc__q i::after{ transform:rotate(0); }
.acc__a{ height:0; overflow:hidden; transition:height .55s var(--ease); }
.acc__a div{ padding-bottom:1.8rem; max-width:74ch; color:var(--cream-dim); }

/* ---------- 18. Galerie / Lightbox ---------- */
.gal{ display:grid; grid-template-columns:repeat(4,1fr); gap:clamp(.5rem,1vw,1rem); }
.gal a{ position:relative; overflow:hidden; aspect-ratio:1; }
.gal a:first-child{ grid-column:span 2; grid-row:span 2; aspect-ratio:auto; }
.gal img{ width:100%; height:100%; object-fit:cover; filter:brightness(.82); transition:transform 1.2s var(--ease),filter .6s; }
.gal a:hover img{ transform:scale(1.06); filter:brightness(1); }
@media (max-width:720px){ .gal{ grid-template-columns:repeat(2,1fr); } .gal a:first-child{ grid-column:span 2; grid-row:auto; aspect-ratio:4/3; } }
.lb{ position:fixed; inset:0; z-index:9600; background:rgba(8,8,10,.96); display:none; }
.lb.on{ display:block; }
/* Die Spur ist der eigentliche Rollbereich. scroll-snap laesst sie immer auf
   einem ganzen Bild stehenbleiben, overscroll-behavior verhindert, dass das
   Wischen am Ende die Seite dahinter mitzieht. */
.lb__spur{
  position:absolute; inset:0; display:flex; overflow-x:auto; overflow-y:hidden;
  scroll-snap-type:x mandatory; scroll-behavior:auto; overscroll-behavior:contain;
  -webkit-overflow-scrolling:touch; scrollbar-width:none;
}
.lb__spur::-webkit-scrollbar{ display:none; }
/* grid-template-rows/-columns sind hier kein Zierrat, sondern der Grund,
   warum das Bild ueberhaupt in den Bildschirm passt.

   Ohne sie legt place-items:center das Bild in eine implizite Zeile der
   Groesse auto. Auto heisst: die Zeile waechst, bis der Inhalt hineinpasst.
   Das max-height:100% des Bildes misst sich dann an genau dieser
   mitwachsenden Zeile — es begrenzt sich selbst an sich selbst und
   begrenzt damit gar nichts. Gebunden hat am Ende nur max-width, und ein
   breites Foto in einem flachen Fenster wurde hoeher gezeichnet als der
   Bildschirm; oben und unten schnitt .lb__spur mit overflow:hidden ab.

   Gemessen bei 1300x760: Bild 1239x885 in einem 760 hohen Fenster, also
   156 Pixel zu viel. Bei 1440x620 waren es 993 statt 620. In hohen
   Fenstern fiel es nicht auf, weil dort die Breite zuerst bindet — deshalb
   ist der Fehler lange durchgerutscht.

   minmax(0,1fr) macht aus der Zeile eine feste Groesse: genau der Platz,
   der nach dem Innenabstand uebrig ist. Erst dadurch bekommt max-height
   etwas zu messen. Die 0 als Untergrenze ist noetig, weil 1fr von sich aus
   min-content als Minimum hat und damit wieder mitwachsen wuerde. */
.lb__dia{
  flex:0 0 100%; width:100%; height:100%; scroll-snap-align:center; scroll-snap-stop:always;
  display:grid; grid-template-rows:minmax(0,1fr); grid-template-columns:minmax(0,1fr);
  place-items:center; padding:clamp(1rem,4vmin,3rem);
}
.lb__dia img{ max-width:100%; max-height:100%; object-fit:contain; display:block; }

.lb__x{
  position:absolute; top:1.2rem; right:1.2rem; z-index:2;
  font-size:.7rem; letter-spacing:.24em; text-transform:uppercase; color:var(--cream-dim);
  background:rgba(10,10,12,.7); border:1px solid var(--line); border-radius:var(--radius);
  padding:.7rem 1.1rem; transition:border-color .3s,color .3s;
}
.lb__x:hover{ border-color:var(--gold); color:var(--cream); }

.lb__pf{
  position:absolute; top:50%; transform:translateY(-50%); z-index:2;
  width:52px; height:52px; display:grid; place-items:center; font-size:1.1rem;
  color:var(--cream-dim); background:rgba(10,10,12,.66);
  border:1px solid var(--line); border-radius:50%;
  transition:border-color .3s,color .3s,background .3s,opacity .3s;
}
.lb__pf:hover:not(:disabled){ border-color:var(--gold); color:var(--gold-lite); background:rgba(10,10,12,.85); }
.lb__pf:disabled{ opacity:.22; cursor:default; }
.lb__pf--zurueck{ left:1.2rem; }
.lb__pf--vor{ right:1.2rem; }

.lb__zaehler{
  position:absolute; left:50%; bottom:1.4rem; transform:translateX(-50%); z-index:2; margin:0;
  font-size:.68rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted);
  background:rgba(10,10,12,.7); border:1px solid var(--line); border-radius:var(--radius);
  padding:.55rem 1.1rem;
}

/* Auf dem Handy sind Pfeile ueberfluessig — dort wird gewischt. Sie wuerden
   nur das Bild verdecken. Der Zaehler bleibt, damit man weiss, wie viel folgt. */
@media (max-width:640px){
  .lb__pf{ display:none; }
  .lb__zaehler{ bottom:1rem; }
  .lb__x{ top:.9rem; right:.9rem; padding:.6rem .9rem; }
}

/* ---------- 19. Buchungsspalte, Kalender, Buchungsfenster ----------

   Frueher hing hier ein fertiges Smoobu-Widget in einem iframe. Das sah aus
   wie ein Fremdkoerper: weisser Kasten, fremde Schrift, 760 Pixel hoch,
   mitten in einer dunklen Spalte. Ausserdem laedt ein iframe sofort beim
   Seitenaufruf — die IP-Adresse jedes Besuchers geht damit an Smoobu, bevor
   er ueberhaupt buchen wollte.

   Jetzt zeichnen wir den Kalender selbst. Die Zahlen dafuer (frei/belegt,
   Preis, Mindestnaechte) holt die Netlify-Funktion unter /api/verfuegbarkeit.
   Smoobu kommt erst ins Spiel, wenn jemand wirklich auf "Jetzt buchen"
   drueckt — dann im Fenster unten, nicht in einem neuen Tab. */

.booking{ background:var(--ink-2); border:1px solid var(--line); padding:clamp(1rem,2vw,1.6rem); }
.booking__head{ display:flex; flex-wrap:wrap; align-items:baseline; justify-content:space-between; gap:1rem; margin-bottom:1.2rem; }
.booking__head h3{ font-size:1.5rem; }
.booking__note{ margin-top:.9rem; font-size:.72rem; color:var(--muted); }
.sticky-book{ position:sticky; top:110px; }
@media (max-width:980px){ .sticky-book{ position:static; } }

/* Zweispaltiges Detail-Layout (Text + Buchungsspalte) */
.dgrid{ display:grid; grid-template-columns:1.15fr .85fr; gap:clamp(2rem,4vw,4.5rem); align-items:start; }
@media (max-width:980px){ .dgrid{ grid-template-columns:1fr; } }

/* --- Kopf des Kalenders: Monat und zwei Pfeile --- */
.kal{ --zelle:2.9rem; font-family:var(--ff-body); }
.kal__kopf{ display:flex; align-items:center; justify-content:space-between; gap:.6rem; margin-bottom:1rem; }
.kal__monat{ font-family:var(--ff-display); font-size:1.25rem; font-weight:400; letter-spacing:.02em; color:var(--cream); }
.kal__nav{ display:flex; gap:.35rem; }
.kal__nav button{
  width:2rem; height:2rem; display:grid; place-items:center;
  background:transparent; border:1px solid var(--line); color:var(--cream-dim);
  font-size:.85rem; line-height:1; cursor:pointer; transition:border-color .3s,color .3s;
}
.kal__nav button:hover:not(:disabled){ border-color:var(--gold); color:var(--gold-lite); }
.kal__nav button:disabled{ opacity:.25; cursor:default; }

/* --- Wochentage und Tagesraster --- */
.kal__wo,.kal__gitter{ display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
.kal__wo{ margin-bottom:.4rem; }
.kal__wo span{ text-align:center; font-size:.56rem; letter-spacing:.18em; text-transform:uppercase; color:var(--muted); }

.kal__tag{
  position:relative; min-height:var(--zelle);
  display:flex; flex-direction:column; align-items:center; justify-content:center; gap:1px;
  background:transparent; border:1px solid transparent; border-radius:2px;
  color:var(--cream); font-family:inherit; font-size:.82rem; line-height:1;
  padding:.25rem 0; cursor:pointer;
  transition:background .25s,border-color .25s,color .25s;
}
.kal__tag em{ font-style:normal; font-size:.54rem; letter-spacing:.02em; color:var(--muted); transition:color .25s; }
.kal__tag--leer{ visibility:hidden; }

/* Belegt oder in der Vergangenheit: durchgestrichen und nicht anklickbar.
   Der Strich ist deutlicher als blosses Ausgrauen — auf dunklem Grund sieht
   man den Unterschied zwischen "grau" und "etwas grauer" sonst kaum. */
.kal__tag--weg,.kal__tag--vorbei{ color:var(--muted); cursor:default; }
.kal__tag--weg em,.kal__tag--vorbei em{ color:transparent; }
.kal__tag--vorbei{ opacity:.4; }
.kal__tag--weg::after{
  content:""; position:absolute; left:22%; right:22%; top:50%;
  height:1px; background:rgba(255,255,255,.22); transform:rotate(-18deg);
}

.kal__tag--frei:hover{ border-color:rgba(201,162,75,.55); }
/* Ein belegter Tag, der als Abreisetag noch taugt: durchgestrichen, aber
   anklickbar. So lassen sich Aufenthalte lückenlos an fremde Buchungen
   anschließen — am Abreisemorgen ist die Wohnung ja wieder frei. */
.kal__tag--weg.kal__tag--frei{ cursor:pointer; }
.kal__tag--frei:focus-visible{ outline:1px solid var(--gold); outline-offset:1px; }

/* Auswahl: die beiden Enden voll in Gold, die Naechte dazwischen angedeutet. */
.kal__tag--drin{ background:rgba(201,162,75,.14); border-radius:0; }
.kal__tag--an,.kal__tag--ab{ background:var(--gold); color:var(--ink); border-color:var(--gold); }
.kal__tag--an em,.kal__tag--ab em{ color:rgba(10,10,12,.65); }
.kal__tag--an{ border-radius:2px 0 0 2px; }
.kal__tag--ab{ border-radius:0 2px 2px 0; }
.kal__tag--an.kal__tag--ab{ border-radius:2px; }

/* --- Legende, Auswahlzusammenfassung, Knopf --- */
.kal__legende{ display:flex; flex-wrap:wrap; gap:.4rem 1rem; margin-top:.9rem; font-size:.6rem; color:var(--muted); }
.kal__legende span{ display:inline-flex; align-items:center; gap:.4rem; }
.kal__legende i{ width:9px; height:9px; border:1px solid var(--line); border-radius:1px; display:inline-block; }
.kal__legende i.frei{ border-color:rgba(201,162,75,.55); }
.kal__legende i.gold{ background:var(--gold); border-color:var(--gold); }
.kal__legende i.weg{ position:relative; }
.kal__legende i.weg::after{ content:""; position:absolute; inset:0; margin:auto; width:11px; height:1px; background:rgba(255,255,255,.3); transform:rotate(-18deg); }

.kal__summe{
  margin-top:1.1rem; padding-top:1.1rem; border-top:1px solid var(--line-soft);
  display:grid; gap:.55rem;
}
.kal__zeile{ display:flex; align-items:baseline; justify-content:space-between; gap:1rem; font-size:.8rem; color:var(--cream-dim); }
.kal__zeile b{ font-weight:400; color:var(--cream); }
.kal__zeile--gesamt{ padding-top:.55rem; border-top:1px solid var(--line-soft); font-size:.95rem; }
.kal__zeile--gesamt b{ font-family:var(--ff-display); font-size:1.45rem; color:var(--gold-lite); }
.kal__warn{ font-size:.7rem; color:var(--gold-lite); line-height:1.5; }
.kal__zurueck{
  justify-self:start; background:none; border:0; padding:0; cursor:pointer;
  font-family:var(--ff-body); font-size:.66rem; color:var(--muted);
  text-decoration:underline; text-underline-offset:3px; transition:color .3s;
}
.kal__zurueck:hover{ color:var(--cream-dim); }
.kal__summe .btn{ width:100%; justify-content:center; margin-top:.3rem; }

/* --- Zustaende: laedt, gestoert --- */
.kal__lade{ display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
.kal__lade i{ min-height:var(--zelle); background:var(--ink-3); border-radius:2px; animation:kalpuls 1.4s var(--ease) infinite; }
@keyframes kalpuls{ 0%,100%{ opacity:.45 } 50%{ opacity:.9 } }
@media (prefers-reduced-motion:reduce){ .kal__lade i{ animation:none } }

.kal__hinweis{ font-size:.78rem; color:var(--cream-dim); line-height:1.6; }
.kal__hinweis .btn{ width:100%; justify-content:center; margin-top:1rem; }

@media (max-width:980px){ .kal{ --zelle:3.2rem; } }

/* --- Buchungsfenster: Smoobu, aber erst auf Klick ---
   Der iframe bekommt seine Adresse erst hier drin gesetzt. Vor dem Klick
   existiert keine Verbindung zu Smoobu. */
.bkf{
  position:fixed; inset:0; z-index:9700; display:none;
  background:rgba(8,8,10,.94); padding:clamp(.5rem,3vmin,2.5rem);
  place-items:center;
}
.bkf.on{ display:grid; }
.bkf__box{
  position:relative; width:min(920px,100%); height:min(88vh,900px);
  display:flex; flex-direction:column;
  background:var(--ink-2); border:1px solid var(--line);
}
/* 02.09.2026: Die feste Hoehe oben ist fuer den Smoobu-Rahmen gedacht — der
   braucht Platz, sonst scrollt der Gast im iframe statt auf der Seite. Fuer
   die Einwilligungsfrage ist sie falsch: seit die Klappe von 94 auf 57 Woerter
   gekuerzt ist, schwimmen zwei Saetze in einem 900 Pixel hohen Kasten, und das
   sieht nach Ladefehler aus statt nach Frage.

   Deshalb kein Aendern der Grundregel, sondern eine zweite Bauform: solange
   nur die Frage im Fenster steht, waechst der Kasten mit seinem Inhalt.
   max-height bleibt, damit eine sehr lange Uebersetzung (Franzoesisch ist die
   laengste, 75 Woerter) auf kleinen Schirmen nicht aus dem Bild laeuft.

   Gesetzt wird die Klasse an genau zwei Stellen in vistaro.js: klappeZeigen()
   setzt sie, laden() nimmt sie weg. auf() ruft immer genau eine der beiden
   auf, damit ist jeder Weg abgedeckt — auch der, bei dem die Einwilligung
   schon im localStorage steht und die Klappe nie erscheint. */
.bkf--frage .bkf__box{ height:auto; max-height:min(88vh,900px); }
/* Gemessen am 02.09.2026 auf einem iPhone SE (360x640): die franzoesische
   Klappe braucht 681px, erlaubt sind dort 563px (88vh). Ohne diese Regel
   fehlt dem Gast das untere Drittel — und zwar genau die Fusszeile mit
   Telefonnummer und E-Mail, also der Beleg dafuer, dass er auch ohne
   Zustimmung buchen kann. Eine Einwilligung, deren Alternative man nicht
   lesen kann, ist keine freiwillige.

   Das war schon vor der Kuerzung so, nur unauffaelliger: der Kasten stand
   fest auf 563px und die laengere Klappe lief genauso unten heraus. Der
   Fehler ist hier nur zum ersten Mal gemessen worden.

   start statt center: solange alles hineinpasst, ist der Kasten genau so
   hoch wie sein Inhalt, dann sind start und center dasselbe Bild. Stoesst
   er an die Obergrenze, faengt der Text oben an und man scrollt nach unten.
   Bei center wuerde stattdessen der Anfang oben abgeschnitten — die Sorte
   Ueberlauf, die man nicht zurueckscrollen kann. */
.bkf--frage .bkf__buehne{ place-items:start center; overflow-y:auto; }
.bkf__kopf{
  display:flex; align-items:center; justify-content:space-between; gap:1rem;
  padding:.9rem clamp(.9rem,2vw,1.5rem); border-bottom:1px solid var(--line);
}
.bkf__kopf h3{ font-family:var(--ff-display); font-size:1.15rem; font-weight:400; color:var(--cream); }
.bkf__kopf p{ font-size:.66rem; color:var(--muted); margin-top:.2rem; }
/* Der Eintrage-Hinweis. Er ist eine Arbeitsanweisung, keine Fussnote, und
   darf deshalb heller stehen als die Zeile darueber — sonst liest ihn
   niemand und der Gast tippt doch wieder falsche Tage ein. Die Daten
   selbst tragen die Goldfarbe des Hauses; sie sind das, was abgetippt
   wird. Nicht umbrechen lassen: "02.09.26" auf zwei Zeilen waere genau
   der Lesefehler, den die Zeile verhindern soll. */
.bkf__kopf p.bkf__ein{ color:var(--cream-dim); margin-top:.35rem; }
.bkf__kopf p.bkf__ein b{ color:var(--gold-lite); font-weight:400; white-space:nowrap; }
.bkf__kopf p.bkf__ein[hidden]{ display:none; }
.bkf__x{
  flex:0 0 auto; background:transparent; border:1px solid var(--line); color:var(--cream-dim);
  font-family:var(--ff-body); font-size:.62rem; letter-spacing:.2em; text-transform:uppercase;
  padding:.5rem .9rem; cursor:pointer; transition:border-color .3s,color .3s;
}
.bkf__x:hover{ border-color:var(--gold); color:var(--gold-lite); }
/* Die Bühne: dunkler Ladehinweis unten, der iframe darüber. Der iframe
   blendet erst auf, wenn Smoobu geantwortet hat — sonst steht eine
   Sekunde lang ein weisses Rechteck im dunklen Rahmen. */
.bkf__buehne{ position:relative; flex:1 1 auto; display:grid; place-items:center; background:var(--ink-3); }
.bkf__warte{ font-size:.72rem; letter-spacing:.16em; text-transform:uppercase; color:var(--muted); }
.bkf__buehne iframe{
  position:absolute; inset:0; width:100%; height:100%; border:0; background:#fff;
  opacity:0; transition:opacity .45s var(--ease);
}
.bkf__buehne iframe.da{ opacity:1; }
.bkf__fuss{ padding:.7rem clamp(.9rem,2vw,1.5rem); border-top:1px solid var(--line); font-size:.62rem; color:var(--muted); }
.bkf__fuss a{ color:var(--cream-dim); text-decoration:underline; text-underline-offset:3px; }

/* ---------- 20. Formular ---------- */
.form{ display:grid; gap:1.6rem; }
.field label{ display:block; font-size:.64rem; letter-spacing:.24em; text-transform:uppercase; color:var(--muted); margin-bottom:.7rem; }
.field input,.field textarea,.field select{
  width:100%; background:transparent; border:0; border-bottom:1px solid var(--line);
  color:var(--cream); font-family:var(--ff-body); font-size:1rem; padding:.65rem 0; transition:border-color .4s;
  color-scheme:dark;
}
.field input:focus,.field textarea:focus,.field select:focus{ outline:0; border-color:var(--gold); }
.field textarea{ min-height:130px; resize:vertical; }
.form__row{ display:grid; grid-template-columns:1fr 1fr; gap:1.6rem; }
@media (max-width:640px){ .form__row{ grid-template-columns:1fr; } }
.form__note{ font-size:.72rem; color:var(--muted); }
.form{ grid-template-columns:1fr 1fr; }
.field--full{ grid-column:1 / -1; }
@media (max-width:640px){ .form{ grid-template-columns:1fr; } }
.field label.check,.check{ display:flex; gap:.8rem; align-items:flex-start; text-transform:none; letter-spacing:0; font-size:.82rem; color:var(--cream-dim); line-height:1.6; margin:0; cursor:pointer; }
.field .check input[type="checkbox"]{ width:16px; height:16px; margin-top:.24rem; accent-color:var(--gold); flex:0 0 auto; border-bottom:0; }
.check a{ color:var(--gold); text-decoration:underline; text-underline-offset:3px; }

/* Der Einwilligungshaken auf rechnung.html (13.10.2026). Anordnung,
   Groesse und Farbe bringt .check schon mit; hier kommt nur dazu, was
   dieser eine Satz an dieser einen Stelle braucht.

   Die Zeilenbegrenzung: Das Formular steht in .wrap-narrow, also
   940 px minus Rand — auf einem 1440er Bildschirm 796 px. Bei 0,82 rem
   (13,12 px) laufen darin rund 120 Zeichen in eine Zeile. Bei 92ch
   bricht der Satz nach etwa 607 px um, dieselbe Grenze, die das Band
   seit dem 29.09.2026 benutzt (.nlb__check). Eine Einwilligung, deren
   Zeilen man beim Zurueckspringen verliert, liest niemand.

   Der Abstand nach oben: Der Formularraster setzt zwischen alle Felder
   1,6 rem. Damit saesse der Haken genauso weit unter "Land" wie "Ort"
   unter "Postleitzahl" — als waere er das naechste Feld der Anschrift.
   Er ist aber etwas anderes: freiwillig, und das einzige Element hier,
   das nichts mit der Rechnung zu tun hat. Die halbe Zeile mehr sagt
   das, ohne es hinschreiben zu muessen.

   Nicht kleiner als 0,82 rem: Der Haken darf nach Artikel 7 Absatz 4
   DSGVO nicht Bedingung fuer die Rechnung sein (dasselbe prueft
   pruefe_einwilligung.py am gebauten HTML nach). Was freiwillig ist,
   muss man vorher lesen koennen — Kleingedrucktes waere hier das
   Gegenteil einer Einwilligung. */
.rg__check{ max-width:92ch; margin-top:.6rem; }

/* ---------- 21. CTA-Band ---------- */
.cta{ position:relative; overflow:hidden; text-align:center; padding-block:clamp(5rem,13vh,10rem); }
.cta__bg{ position:absolute; inset:0; }
.cta__bg img{ width:100%; height:100%; object-fit:cover; opacity:.3; }
.cta::after{ content:""; position:absolute; inset:0; background:radial-gradient(70% 70% at 50% 50%,rgba(201,162,75,.14),rgba(10,10,12,.92) 70%); }
.cta__c{ position:relative; z-index:2; }
.cta h2{ font-size:var(--fs-h2); }

/* ---------- 21b. Newsletter-Band ueber der Fusszeile (29.09.2026) ----------
   Es soll auffallen, ohne sich vorzudraengen. Deshalb kein eigener
   Hintergrund und keine Rahmen ringsum, sondern nur eine feine Linie
   nach oben — dieselbe, mit der auch die Fusszeile beginnt. Gelesen wird
   das Band dadurch als letzte Zeile des Inhalts und nicht als
   Werbeflaeche, die jemand dazwischengeschoben hat.

   Der Einwilligungssatz steht unter der Zeile und nicht daneben. Neben
   der Zeile waere er entweder abgeschnitten oder so klein, dass ihn
   niemand liest — und ein Satz, den niemand liest, ist genau das, was
   eine Einwilligung angreifbar macht. Unter der Zeile darf er die Breite
   haben, die er braucht. Schmal wird das Band ueber die Zeilenhoehe.

   :focus-within hebt das Band leicht an, sobald jemand ins Feld tippt.
   Das ist der einzige Zustand, in dem es lauter werden darf. */
.nlb{ border-top:1px solid var(--line-soft); padding-block:clamp(1.6rem,3vh,2.4rem); }
.nlb__f{ display:grid; gap:.9rem; }
.nlb__zeile{
  display:flex; align-items:center; gap:clamp(1rem,2.4vw,2.2rem); flex-wrap:wrap;
}
.nlb__t{ display:flex; align-items:baseline; gap:.7rem; flex-wrap:wrap; flex:1 1 22rem; min-width:0; }
.nlb__t strong{ font-size:.94rem; font-weight:500; color:var(--cream); letter-spacing:.01em; }
.nlb__t .dim{ font-size:.78rem; line-height:1.5; }
.nlb__email{
  flex:1 1 15rem; min-width:0; background:transparent; border:0;
  border-bottom:1px solid var(--line); color:var(--cream);
  font-family:var(--ff-body); font-size:.92rem; padding:.5rem 0;
  transition:border-color .4s; color-scheme:dark;
}
.nlb__email::placeholder{ color:var(--muted); }
.nlb__email:focus{ outline:0; border-color:var(--gold); }
.nlb__ab{ flex:0 0 auto; }
/* Die Beschriftung des Feldes ist sichtbar nicht noetig — daneben steht
   der Satz, und im Feld steht der Platzhalter. Fuer einen Screenreader
   ist sie es sehr wohl: ein Eingabefeld ohne Namen wird als "Eingabe"
   vorgelesen. display:none wuerde sie auch dort entfernen, deshalb der
   Umweg ueber die Bildschirmlese-Technik. */
.nlb__vh{
  position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip:rect(0 0 0 0); white-space:nowrap; border:0;
}
.nlb__check{ font-size:.72rem; line-height:1.6; color:var(--muted); max-width:92ch; }
.nlb__check input[type="checkbox"]{
  width:15px; height:15px; margin-top:.2rem; accent-color:var(--gold); flex:0 0 auto;
}
/* Das Band auf dem Handy.
   ------------------------------------------------------------------
   Hier stand bis zum 30.09.2026 ein Fehler, der wie eine Geschmacksfrage
   aussah. Colin schickte einen Screenshot: Titel, dann ein Loch, dann
   die Unterzeile, dann ein noch groesseres Loch, dann das Eingabefeld.
   "Riesen abstaende und nicht schoen."

   Es waren keine Abstaende. Es waren zwei Elemente, die sich in der
   Hoehe aufgeblasen haben. .nlb__zeile schaltet hier von Reihe auf
   Spalte um — und flex-basis gilt immer in Richtung der Hauptachse.
   In der Reihe bedeutete flex:1 1 22rem an .nlb__t "mindestens 352 px
   breit"; in der Spalte bedeutet dieselbe Zeile "mindestens 352 px
   hoch". Dasselbe beim Feld: aus 240 px Mindestbreite wurden 240 px
   Mindesthoehe. Gemessen am lebenden Stand: Titelblock 352 px,
   Feld 240 px, das ganze Band 816 px statt 200 px.

   Sichtbar wird das als Leere, weil beide Elemente ihren Inhalt oben
   behalten und der Rest leer nachlaeuft — beim Titelblock zusaetzlich
   auseinandergezogen, weil zwei umbrochene Flex-Zeilen sich den
   ueberschuessigen Platz teilen. Der Platzhalter im 240 px hohen Feld
   sitzt mittig, die Unterstreichung ganz unten; dazwischen liegen die
   120 px, die auf dem Screenshot wie ein Gestaltungsfehler wirken.

   Die Abhilfe sind die beiden flex:0 0 auto. Sie sagen: nimm die Hoehe
   deines Inhalts. Nachgemessen am lebenden Stand, beide Male mit
   erzwungener Spalte, damit nur die Regel und nicht die Breite den
   Unterschied macht: Band 322 px statt 816 px, Titelblock 49 statt 352,
   Feld 47 statt 240.

   Auf echte 390 px Breite verengt, wo Titel und Einwilligungssatz
   wirklich umbrechen: Band 579 px statt 982, Titelblock 111 statt 352,
   Feld 47 statt 240. Der Einwilligungssatz waechst dabei von 221 px auf
   253 px — das ist die groessere Schrift, also gewollt und nicht der
   Fehler. Die 400 px, die verschwinden, waren alle leer.

   Durchgesucht am 30.09.2026, ob dieselbe Falle anderswo steht: Im
   ganzen Stylesheet gibt es nur zwei flex-Kurzschreibweisen mit einer
   rem-Basis, und beide stehen hier. .pin__track schaltet ebenfalls auf
   Spalte um, setzt seine Kinder dort aber ausdruecklich auf flex:none.

   Zwei Sachen sind nicht Fehlerbehebung, sondern Absicht:
   Das Feld bekommt 1rem statt 0,92rem. Unter 16 px zoomt iOS Safari
   die ganze Seite heran, sobald jemand hineintippt, und springt danach
   nicht von selbst zurueck — der Besucher steht dann in einer
   vergroesserten Seite und sucht den Knopf. Und es bekommt 0,8rem
   Innenabstand: damit ist die Tippflaeche 45 px hoch statt 35 und
   liegt ueber den 44 px, die als kleinste sichere Groesse gelten.
   Der Einwilligungssatz geht von 0,72rem auf 0,76rem — auf dem Handy
   ist das der Unterschied zwischen gelesen und ueberblaettert, und ein
   Satz, den niemand liest, ist keine Einwilligung. */
@media (max-width:720px){
  .nlb__zeile{ flex-direction:column; align-items:stretch; gap:1rem; }
  .nlb__t{ flex:0 0 auto; flex-direction:column; align-items:flex-start; gap:.3rem; }
  .nlb__email{ flex:0 0 auto; font-size:1rem; padding:.8rem 0; }
  .nlb__ab{ width:100%; text-align:center; }
  .nlb__check{ font-size:.76rem; }
}

/* ---------- 22. Footer ---------- */
.ftr{ background:var(--ink-2); border-top:1px solid var(--line-soft); padding-top:clamp(3.5rem,8vh,6rem); }
.ftr__grid{ display:grid; grid-template-columns:1.4fr 1fr 1fr 1.2fr; gap:clamp(2rem,4vw,4rem); }
@media (max-width:980px){ .ftr__grid{ grid-template-columns:1fr 1fr; } }
@media (max-width:600px){ .ftr__grid{ grid-template-columns:1fr; } }
.ftr h2{ font-family:var(--ff-body); font-size:.66rem; letter-spacing:.26em; text-transform:uppercase; color:var(--gold); margin:0 0 1.4rem; font-weight:500; }
.ftr ul{ list-style:none; margin:0; padding:0; display:grid; gap:.8rem; }
.ftr a{ color:var(--cream-dim); transition:color .3s,padding-left .3s; font-size:.92rem; }
.ftr a:hover{ color:var(--gold); padding-left:.35rem; }
.ftr__word{
  margin-top:clamp(3rem,7vw,6rem); font-family:var(--ff-display); line-height:.8;
  font-size:clamp(3.4rem,15.5vw,15rem); letter-spacing:-.03em; text-align:center;
  background:linear-gradient(180deg,rgba(244,241,234,.16),rgba(201,162,75,.28));
  -webkit-background-clip:text; background-clip:text; color:transparent; user-select:none;
}
/* Der untere Rand ist absichtlich so gross. Gemessen am 31.08.2026 bei 1440,
   1280, 768 und 390 px Breite: der schwebende Kontaktknopf (131x43 px, fest
   unten rechts) lag auf jeder Seite genau auf "Braunschweig · Wolfsburg" und
   verdeckte davon 91 der 146 px. Aufgefallen ist es erst auf einem Screenshot
   der Fusszeile — beim Durchscrollen sieht man es nicht, weil man am Ende der
   Seite selten stehenbleibt.

   Der Knopf schwebt, nimmt also keinen Platz ein; der Platz muss ihm hier
   gegeben werden. 6rem sind seine Hoehe plus sein Abstand zum unteren Rand
   plus Luft. Nachgemessen bleiben danach 21 px zwischen Text und Knopf. */
.ftr__bar{ display:flex; flex-wrap:wrap; gap:1.2rem; justify-content:space-between; padding-block:1.6rem 6rem; border-top:1px solid var(--line-soft); margin-top:1.5rem; font-size:.74rem; color:var(--muted); }

/* ---------- 23. Diverses ---------- */
.tile{ background:var(--ink-2); border:1px solid var(--line-soft); padding:clamp(1.6rem,2.6vw,2.4rem); transition:border-color .5s,background .5s; }
.tile:hover{ border-color:rgba(201,162,75,.35); background:var(--ink-3); }
.tile__n{ font-family:var(--ff-display); font-size:1.1rem; color:var(--gold); display:block; margin-bottom:1.1rem; }
.tile h3{ font-size:1.35rem; margin-bottom:var(--gap-sub); }
.tile p{ color:var(--cream-dim); font-size:.95rem; margin:0; }

.note{ border-left:1px solid var(--gold); padding:.2rem 0 .2rem 1.4rem; color:var(--cream-dim); }
.legal h2{ font-size:clamp(1.4rem,2.4vw,2rem); margin:2.6rem 0 1rem; }
.legal h3{ font-size:1.15rem; font-family:var(--ff-body); font-weight:500; margin:1.8rem 0 .6rem; letter-spacing:0; }
.legal p,.legal li{ color:var(--cream-dim); }
.legal ul{ padding-left:1.2rem; }
.legal .todo{ color:var(--gold); font-style:italic; }

.badge-row{ display:flex; flex-wrap:wrap; gap:.6rem; margin-top:1.4rem; }
.badge{ font-size:.66rem; letter-spacing:.18em; text-transform:uppercase; color:var(--cream-dim); border:1px solid var(--line); border-radius:999px; padding:.5em 1.1em; }

.amen{ display:grid; grid-template-columns:repeat(3,1fr); gap:.9rem 2rem; list-style:none; padding:0; margin:0; }
@media (max-width:760px){ .amen{ grid-template-columns:repeat(2,1fr); } }
.amen li{ font-size:.9rem; color:var(--cream-dim); padding-bottom:.7rem; border-bottom:1px solid var(--line-soft); }

.map{ position:relative; aspect-ratio:16/7; background:var(--ink-3); border:1px solid var(--line-soft); display:grid; place-items:center; overflow:hidden; }
.map img{ position:absolute; inset:0; width:100%; height:100%; object-fit:cover; opacity:.42; }
/* Seit hier echte Stadtfotos liegen, braucht der Platzhalterhinweis einen eigenen
   dunklen Traeger — sonst verschwindet die Schrift im hellen Himmel des Fotos. */
.map::after{ content:""; position:absolute; inset:0; background:linear-gradient(180deg,rgba(10,10,12,.28),rgba(10,10,12,.70)); }
/* Die beiden :not() sind Absicht. Ohne sie greift diese Regel auch auf den
   Ortskreis und die Herkunftszeile weiter unten — sie ist spezifischer als
   deren eigene Regeln — und macht aus beiden einen dunklen Kasten in
   Versalien. Bei der Herkunftszeile waere das nicht nur hässlich: Versalien
   mit .26em Sperrung sind in .6rem kaum noch zu lesen, und lesbar bleiben
   muss sie. */
.map span:not(.map__kreis):not(.map__quelle){ position:relative; z-index:1; font-size:.72rem; letter-spacing:.26em; text-transform:uppercase; color:var(--cream-dim);
  background:rgba(10,10,12,.78); border:1px solid var(--line); border-radius:var(--radius); padding:.7rem 1.3rem; }
/* Der Knopf mitten auf der Kachel. Er ersetzt den alten Satz
   "Kartenausschnitt folgt beim Livegang" — der durfte nicht stehen
   bleiben, sobald die Seite wirklich live ist. */
.map__link{
  position:relative; z-index:2; font-size:.72rem; letter-spacing:.26em; text-transform:uppercase;
  color:var(--cream-dim); background:rgba(10,10,12,.82); border:1px solid var(--line);
  border-radius:var(--radius); padding:.7rem 1.3rem; text-decoration:none;
  transition:border-color .4s,color .4s,background .4s;
}
.map__link:hover{ border-color:var(--gold); color:var(--cream); background:rgba(10,10,12,.92); }
.map__link i{ font-style:normal; color:var(--gold); margin-left:.2em; }

/* Sobald ein echter Kartenausschnitt in der Kachel liegt (karten_einbauen.py
   setzt die Klasse), darf er hell sein — es ist ja der Inhalt und nicht mehr
   nur Stimmungsbild hinter einem Hinweis. Der dunkle Schleier wird flacher,
   sonst wären Straßennamen nicht mehr lesbar. */
.map--echt img{ opacity:.92; }
.map--echt::after{ background:linear-gradient(180deg,rgba(10,10,12,.10),rgba(10,10,12,.42)); }
/* Der Knopf rutscht in die Ecke, sobald eine echte Karte darunter liegt —
   in der Mitte würde er genau den Ortskreis verdecken. */
.map--echt .map__link{ position:absolute; right:1rem; bottom:1rem; }

/* ---------- Herkunftszeile ----------
   Google erlaubt Bildschirmfotos seiner Karten, verlangt aber, dass die
   Herkunftsangabe sichtbar bleibt: nicht abgeschnitten, nicht verdeckt, nicht
   in den Seitenfuß geschoben. Gestaltung und Platzierung darf man anpassen,
   solange die Angabe nah am Bild und lesbar bleibt — genau deshalb steht sie
   hier in der Kachel und nicht unten auf der Seite.

   "Lesbar" ist hier die harte Anforderung, nicht die Optik. Darum bewusst
   keine Versalien, keine Sperrung und ein eigener dunkler Träger: Auf einem
   Satellitenbild wechselt der Untergrund von schwarzem Asphalt zu weißem Dach,
   und ohne Träger verschwindet die Zeile stellenweise ganz. */
.map__quelle{
  position:absolute; z-index:2; left:1rem; bottom:1rem; max-width:62%;
  /* .62rem sind rund 10 Pixel — dieselbe Groesse, in der Google die Angabe
     selbst setzt. Kleiner waere huebscher und genau deshalb falsch. */
  font-size:.62rem; line-height:1.45; color:rgba(232,226,214,.82);
  background:rgba(10,10,12,.62); border-radius:var(--radius);
  padding:.35em .7em; pointer-events:none;
}
/* Schmaler Bildschirm: unten wird es eng, weil rechts der Knopf sitzt. Die
   Zeile bekommt die ganze Breite, der Knopf geht nach oben. Verkleinern wäre
   der falsche Ausweg — die Angabe muss lesbar bleiben. */
@media (max-width:760px){
  .map__quelle{ left:.6rem; right:.6rem; bottom:.6rem; max-width:none; font-size:.55rem; }
  .map--echt .map__link{ top:.6rem; right:.6rem; bottom:auto; }
}

/* ---------- Zoomfahrt ----------
   Mehrere Karten desselben Ortes liegen uebereinander, von weit nach nah.
   Beim Hineinscrollen waechst die jeweils sichtbare Ebene weiter und blendet
   aus, waehrend die naechste aus dem Kleinen heraus aufblendet. Weil alle
   denselben Mittelpunkt haben, liest das Auge das als eine durchgehende Fahrt.

   Zwei Ebenen ergeben einen Sprung, drei ergeben zwei. Drei ist der Regelfall:
   von der Stadt bis auf die Strasse sind es rund 30-fach, und das ist fuer
   einen Sprung zu viel — Anfangs- und Endbild haben dann nichts Gemeinsames
   mehr, und man sieht zwei Bilder statt einer Bewegung.

   Grundzustand ist bewusst der FERTIGE: die nahe Karte sichtbar. Ohne
   JavaScript, bei abgeschalteter Bewegung oder wenn das Skript nicht laedt,
   sieht man damit sofort das, worauf es ankommt — nur eben ohne Fahrt. Erst
   das Skript setzt data-stufe und schiebt den Anfangszustand davor.

   data-stufe statt einer Klasse, weil die Fahrt mehr als zwei Halte hat: mit
   Klassen braeuchte es fuer jeden Halt eine eigene, und das Skript muesste
   beim Weiterfahren jedes Mal die vorige entfernen. Ein Attribut kennt immer
   nur einen Wert.

   .weich bleibt getrennt von data-stufe. Kaemen beide zugleich, liefe die
   Fahrt schon beim Laden einmal rueckwaerts ab — sichtbar als Blende von der
   nahen Karte auf die Uebersicht. Das Skript setzt .weich darum erst ein Bild
   spaeter, wenn der Anfangszustand ohne Uebergang schon steht. */
.map--zoom .map__eb{ position:absolute; inset:0; display:block; opacity:0; }
.map--zoom:not([data-stufe]) .map__eb:last-of-type{ opacity:1; }

.map--zoom.weich .map__eb{
  transition:transform 1.5s cubic-bezier(.22,.61,.36,1), opacity .9s ease;
  will-change:transform,opacity;
}

/* Die Vergroesserungen sind bewusst NICHT die echten Zoomfaktoren.
   Zwischen zwei Ebenen liegt in Wirklichkeit Faktor vier bis acht; wuerde die
   abgehende Ebene wirklich so weit aufgezogen, saehe man am Ende nur noch
   Bildmatsch aus einem 1600 Pixel breiten jpg. 1.9 ist genug Bewegung, damit
   das Auge die Richtung liest, und die Blende erledigt den Rest. Die
   hereinkommende Ebene startet bei .82 statt bei 1/1.9 — sie ist die, die man
   gleich scharf sehen soll, also darf sie nicht erst durch die Unschaerfe. */
.map--zoom[data-stufe="0"] .map__eb[data-eb="0"]{ opacity:1; transform:scale(1);   }
.map--zoom[data-stufe="0"] .map__eb[data-eb="1"]{ opacity:0; transform:scale(.82); }
.map--zoom[data-stufe="0"] .map__eb[data-eb="2"]{ opacity:0; transform:scale(.68); }

.map--zoom[data-stufe="1"] .map__eb[data-eb="0"]{ opacity:0; transform:scale(1.9); }
.map--zoom[data-stufe="1"] .map__eb[data-eb="1"]{ opacity:1; transform:scale(1);   }
.map--zoom[data-stufe="1"] .map__eb[data-eb="2"]{ opacity:0; transform:scale(.82); }

.map--zoom[data-stufe="2"] .map__eb[data-eb="0"]{ opacity:0; transform:scale(3.6); }
.map--zoom[data-stufe="2"] .map__eb[data-eb="1"]{ opacity:0; transform:scale(1.9); }
.map--zoom[data-stufe="2"] .map__eb[data-eb="2"]{ opacity:1; transform:scale(1);   }

/* Der Kreis kommt erst am Ende der Fahrt dazu — waehrend des Zooms wuerde er
   mitwandern und die Bewegung unruhig machen. Welche Stufe die letzte ist,
   haengt an der Zahl der Bilder, deshalb setzt das Skript dafuer .am-ziel
   statt dass das CSS mitzaehlt.

   animation:none ist der Kern dieser Regel, nicht die Deckkraft. Der Kreis
   atmet (siehe kreisAtmen weiter unten), und eine laufende Animation schlaegt
   jede normale Angabe — ohne das Abschalten stuende der Kreis waehrend der
   ganzen Fahrt im Bild, egal was hier opacity sagt. Am Ziel darf er wieder
   atmen, aber erst nach dem Einblenden (.6s Wartezeit + .7s Blende = 1.3s),
   sonst risse die Animation ihn sofort auf volle Deckkraft. */
.map--zoom[data-stufe] .map__kreis{ opacity:0; animation:none; }
.map--zoom.weich       .map__kreis{ transition:opacity .7s ease .6s; }
.map--zoom.am-ziel     .map__kreis{ opacity:1; }
@media (prefers-reduced-motion:no-preference){
  .map--zoom.am-ziel .map__kreis{ animation:kreisAtmen 4.5s var(--ease) 1.3s infinite; }
}
/* Der Kreis markiert den Bereich, nicht die Tür. Bewusst weich und groß:
   Die genaue Hausnummer bekommt der Gast am Tag vor Anreise, und der Kreis
   soll nicht versehentlich mehr verraten, als im Text steht. */
.map__kreis{
  position:absolute; z-index:1; left:50%; top:50%; transform:translate(-50%,-50%);
  width:min(34%,190px); aspect-ratio:1; border-radius:50%;
  background:radial-gradient(circle,rgba(201,162,75,.30),rgba(201,162,75,.10) 60%,transparent 72%);
  border:1px solid rgba(201,162,75,.55); pointer-events:none;
}
@media (prefers-reduced-motion:no-preference){
  .map__kreis{ animation:kreisAtmen 4.5s var(--ease) infinite; }
}
@keyframes kreisAtmen{
  0%,100%{ transform:translate(-50%,-50%) scale(1);    opacity:1;   }
  50%    { transform:translate(-50%,-50%) scale(1.06); opacity:.82; }
}

/* ---------- 24. Schwebender Kontaktknopf ----------
   Unten rechts, auf jeder Seite. Zu ist er ein schmaler Knopf, offen klappen
   darueber zwei Kacheln auf: anrufen und WhatsApp.

   Zur Einordnung in die z-index-Landschaft dieser Datei:
     880  Menue-Overlay
     900  Kopfzeile
     950  Fortschrittsbalken
    9600  Lightbox
    9700  Buchungsfenster
   Der Knopf liegt bewusst auf 870, also UNTER dem Menue. Wer das Menue
   geoeffnet hat, findet dieselben Kontaktwege dort drin; zwei Angebote
   gleichzeitig waeren nur Unordnung. Aus demselben Grund verschwindet er,
   sobald das Buchungsfenster oder die Lightbox laeuft (body.is-locked). */
.ruf{
  position:fixed; z-index:870; right:clamp(1rem,2.5vw,2rem); bottom:clamp(1rem,2.5vw,2rem);
  display:flex; flex-direction:column; align-items:flex-end; gap:.6rem;
  opacity:0; transform:translateY(14px); pointer-events:none;
  transition:opacity .45s var(--ease), transform .45s var(--ease);
}
.ruf[hidden]{ display:none; }
.ruf.da{ opacity:1; transform:none; pointer-events:auto; }
/* Waehrend Buchungsfenster oder Lightbox offen sind, ist er im Weg. */
body.is-locked .ruf{ opacity:0; pointer-events:none; transform:translateY(14px); }

.ruf__knopf{
  display:inline-flex; align-items:center; gap:.6rem;
  padding:.72rem 1.1rem; cursor:pointer;
  background:var(--ink-2); border:1px solid var(--gold); border-radius:var(--radius);
  color:var(--gold-lite); font-family:var(--ff-body);
  font-size:.66rem; letter-spacing:.22em; text-transform:uppercase;
  box-shadow:0 14px 34px rgba(0,0,0,.55);
  transition:background .35s var(--ease), color .35s var(--ease);
}
.ruf__knopf:hover{ background:var(--gold); color:var(--ink); }
.ruf__ikon{ position:relative; width:18px; height:18px; flex:none; }
.ruf__ikon svg{
  position:absolute; inset:0; width:100%; height:100%;
  transition:opacity .3s var(--ease), transform .3s var(--ease);
}
.ruf__ikon--zu{ opacity:0; transform:rotate(-90deg); }
.ruf[aria-hidden="false"] .ruf__ikon--auf,
.ruf.offen .ruf__ikon--auf{ opacity:0; transform:rotate(90deg); }
.ruf.offen .ruf__ikon--zu{ opacity:1; transform:none; }

/* Die Klappe. Zu ist sie nicht nur unsichtbar, sondern per visibility auch
   aus der Tabulator-Reihenfolge genommen — sonst springt der Fokus in zwei
   Links, die niemand sieht. */
.ruf__panel{
  display:flex; flex-direction:column; gap:.45rem; width:min(19rem,calc(100vw - 2.5rem));
  opacity:0; visibility:hidden; transform:translateY(10px) scale(.98); transform-origin:100% 100%;
  transition:opacity .35s var(--ease), transform .35s var(--ease), visibility .35s;
}
.ruf.offen .ruf__panel{ opacity:1; visibility:visible; transform:none; }

.ruf__weg{
  display:flex; align-items:center; gap:.85rem; min-height:52px;
  padding:.7rem .95rem; text-decoration:none;
  background:var(--ink-2); border:1px solid var(--line); border-radius:var(--radius);
  color:var(--cream-dim); box-shadow:0 14px 34px rgba(0,0,0,.5);
  transition:border-color .35s, background .35s, color .35s;
}
.ruf__weg:hover,.ruf__weg:focus-visible{ border-color:var(--gold); background:var(--ink-3); color:var(--cream); }
.ruf__sym{ flex:none; width:21px; height:21px; color:var(--gold); }
.ruf__sym svg{ width:100%; height:100%; display:block; }
.ruf__weg--wa .ruf__sym{ color:#25d366; }
.ruf__txt{ display:flex; flex-direction:column; gap:.15rem; min-width:0; }
.ruf__txt b{ font-weight:400; font-size:.9rem; color:var(--cream); }
.ruf__txt em{ font-style:normal; font-size:.74rem; color:var(--muted); }
/* Rueckmeldung nach dem Kopieren auf dem Rechner. Die Breite bleibt gleich,
   damit die Kachel beim Wechsel nicht zuckt. */
.ruf__weg.kopiert .ruf__txt em{ color:var(--gold-lite); }

@media (max-width:560px){
  .ruf__label{ position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); }
  .ruf__knopf{ padding:.85rem; }
  .ruf__ikon{ width:20px; height:20px; }
}

/* ---------- 25. Einwilligung vor dem Buchungsfenster ----------
   Steht in .bkf__buehne anstelle des iframes, solange niemand zugestimmt hat.
   Der Rahmen kommt aus .bkf, hier steht nur der Inhalt der Klappe. */
.zust{
  max-width:34rem; margin:auto; padding:clamp(1.4rem,4vw,2.4rem); text-align:left;
}
.zust h4{
  font-family:var(--ff-display); font-size:1.25rem; font-weight:400;
  color:var(--cream); margin:0 0 .9rem;
}
.zust p{ font-size:.86rem; line-height:1.7; color:var(--cream-dim); margin:0 0 .9rem; }
/* Hier standen .zust ul / .zust li / .zust li::before — die Rautenpunkte der
   dreigliedrigen Aufzaehlung. Die Klappe hat seit dem 02.09.2026 keine
   Aufzaehlung mehr, die Angaben stehen im Fliesstext. Regeln ohne Ziel sind
   nicht harmlos: beim naechsten Umbau haette jemand ein <ul> eingebaut und
   sich gewundert, woher die Rauten kommen. Die Begruendung fuer die Kuerzung
   steht in sprachen/js_bauen.py bei zust_text. */
.zust__knoepfe{ display:flex; flex-wrap:wrap; align-items:center; gap:.9rem 1.2rem; }
.zust__merk{
  display:flex; align-items:center; gap:.6rem; cursor:pointer;
  font-size:.78rem; color:var(--cream-dim);
}
.zust__merk input{ accent-color:var(--gold); width:16px; height:16px; flex:none; }
/* Auf dem Handy bricht .zust__knoepfe um, der Haken "Auswahl merken" steht
   dann als letzte Zeile direkt ueber der Fusszeile — und die beiden lesen
   sich zusammen wie ein Block, obwohl das eine eine Auswahl ist und das
   andere der Hinweis auf den Weg ohne Zustimmung.

   Der Abstand hier stand seit jeher auf 1.2rem und hat nie gewirkt: die
   Fusszeile ist ein <p> in .zust, und .zust p (Gewicht 0-1-1) sticht
   .zust__fuss (0-1-0). Gemessen am 02.09.2026, margin-top war berechnet
   0px. Deshalb .zust .zust__fuss — zwei Klassen, damit die Regel gewinnt,
   ohne dass jemand !important danebenschreiben muss.

   Uebersteuert wurden dabei auch font-size (.72rem gedacht, .86rem gerendert)
   und color (--muted gedacht, --cream-dim gerendert). Beides bleibt jetzt
   bewusst so, wie es tatsaechlich aussieht, statt auf die alte Absicht
   zurueckgesetzt zu werden: in dieser Zeile stehen Telefonnummer und
   E-Mail, also der Nachweis, dass man auch ohne Zustimmung buchen kann.
   Diese Zeile kleiner und blasser zu machen als den Text darueber waere
   genau der Aufbau, den Aufsichtsbehoerden bei Einwilligungen bemaengeln.
   Der Abstand darueber ist deshalb das Einzige, was hier gesetzt wird. */
.zust .zust__fuss{ margin:1.7rem 0 0; }
.zust__fuss a{ color:var(--cream-dim); text-decoration:underline; text-underline-offset:3px; }

/* ---------- 26. Sprachumschalter ----------
   Ein <details> mit echten Links, kein JavaScript-Widget. Das hat drei
   Gruende, und alle drei sind schon einmal teuer bezahlt worden:

   Er funktioniert ohne JS. Faellt vistaro.js aus — Netzfehler, Blocker,
   Tippfehler beim naechsten Umbau — bleibt die Seite trotzdem in fuenf
   Sprachen erreichbar.

   Suchmaschinen folgen echten <a href>. Ein Umschalter, der die Sprache per
   JS wechselt, hinterlaesst keine Adresse, die man indexieren oder in
   WhatsApp schicken kann.

   Auf- und Zuklappen kann der Browser von sich aus, samt Tastatur und
   Screenreader. Selbstgebaut waere das mehr Code und weniger korrekt.

   Der Knopf zeigt nur das Kuerzel (DE, EN, FR, PL, UA). Ausgeschrieben
   ("Deutsch") waere er auf dem Handy breiter als die Wortmarke daneben —
   gemessen am 31.08.2026 bei 390 px: 74 px statt 38 px.

   Wichtig: Die Liste liegt absolut, nicht im Fluss. Andernfalls schiebt sie
   beim Aufklappen die Kopfzeile auseinander und der ganze Seiteninhalt
   ruckt. */
.lang{ position:relative; flex:none; }
.lang__knopf{
  display:flex; align-items:center; gap:.4rem; cursor:pointer; list-style:none;
  padding:.42rem .6rem .42rem .68rem; border:1px solid var(--line); border-radius:var(--radius);
  font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--cream-dim); background:transparent;
  transition:color .3s, border-color .3s, background .3s;
}
/* Das voreingestellte Dreieck der Browser passt nicht zum Rest; es wird in
   allen Engines einzeln abgeschaltet, weil sie es unterschiedlich nennen. */
.lang__knopf::-webkit-details-marker{ display:none; }
.lang__knopf::marker{ content:""; }
.lang__knopf:hover{ color:var(--cream); border-color:var(--line-soft); }
.lang__knopf:focus-visible{ outline:1px solid var(--gold); outline-offset:2px; }
.lang__pfeil{
  width:6px; height:6px; border-right:1px solid currentColor; border-bottom:1px solid currentColor;
  transform:translateY(-2px) rotate(45deg); transition:transform .35s var(--ease);
}
.lang[open] .lang__knopf{ color:var(--gold); border-color:rgba(201,162,75,.45); }
.lang[open] .lang__pfeil{ transform:translateY(1px) rotate(-135deg); }

.lang__liste{
  position:absolute; top:calc(100% + .55rem); right:0; z-index:2;
  min-width:11.5rem; margin:0; padding:.4rem; list-style:none;
  background:rgba(15,15,18,.96); backdrop-filter:blur(18px) saturate(140%);
  border:1px solid var(--line); border-radius:var(--radius);
  box-shadow:0 18px 40px rgba(0,0,0,.45);
  animation:langAuf .28s var(--ease);
}
@keyframes langAuf{ from{ opacity:0; transform:translateY(-6px); } to{ opacity:1; transform:none; } }
.lang__liste a{
  display:flex; align-items:center; gap:.7rem;
  padding:.52rem .7rem; border-radius:var(--radius);
  font-size:.82rem; color:var(--cream-dim);
  transition:color .25s, background .25s;
}
.lang__liste a:hover{ color:var(--cream); background:rgba(255,255,255,.05); }
.lang__liste a:focus-visible{ outline:1px solid var(--gold); outline-offset:-1px; }
.lang__liste i{
  flex:none; width:1.9rem; font-style:normal;
  font-size:.66rem; letter-spacing:.12em; text-transform:uppercase; color:var(--muted);
}
/* Die gerade gewaehlte Sprache. Sie bleibt anklickbar (das ist die einzige
   Moeglichkeit, die Liste per Tastatur wieder zu verlassen, ohne zu wechseln),
   ist aber deutlich als aktuelle Fassung markiert. */
.lang__liste a[aria-current]{ color:var(--gold); }
.lang__liste a[aria-current] i{ color:var(--gold); }

/* Auf dem Handy verschwindet der Verfuegbarkeits-Knopf (siehe Abschnitt 6),
   der Sprachumschalter aber nicht: wer die Seite auf Englisch oder
   Ukrainisch braucht, braucht sie dort am dringendsten. Er rueckt nur
   naeher an den Rand. */
@media (max-width:640px){
  .lang__knopf{ padding:.38rem .5rem .38rem .56rem; font-size:.68rem; }
  .lang__liste{ min-width:10.5rem; }
}

@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{ animation-duration:.001s !important; transition-duration:.001s !important; }
  [data-reveal]{ opacity:1 !important; transform:none !important; }
  .mask > span{ transform:none !important; }
}

/* ---------- 27. Newsletter-Popup ----------
   Das Fenster, das beim Verlassen der Seite kommt und den
   Willkommenscode anbietet. Das Markup baut build.py in die Fusszeile
   jeder Seite ausser den Rechts- und Verteilerseiten; geoeffnet wird es
   von newsletter() in vistaro.js.

   z-index 9600: ueber Kopfzeile (900), Menue (880) und Kontaktknopf
   (870), aber unter dem Buchungsfenster (9700). Wer gerade bucht, soll
   nicht von einem Rabattfenster unterbrochen werden — und falls doch
   einmal beides offen ist, gewinnt das, womit Geld verdient wird.

   body.is-locked kommt vom Buchungsfenster und wird hier mitbenutzt: es
   sperrt das Scrollen und blendet den Kontaktknopf aus. Beides ist
   genau das, was hier gebraucht wird; eine zweite Klasse dafuer waere
   eine zweite Stelle, an der man es beim naechsten Mal vergisst. */
.nl{
  position:fixed; inset:0; z-index:9600; display:grid; place-items:center;
  padding:clamp(1rem,4vmin,2.5rem);
}
.nl[hidden]{ display:none; }
.nl__hg{
  position:absolute; inset:0; background:rgba(8,8,10,.86);
  -webkit-backdrop-filter:blur(3px); backdrop-filter:blur(3px);
  opacity:0; transition:opacity .45s var(--ease);
}
.nl.da .nl__hg{ opacity:1; }
.nl__k{
  position:relative; width:min(100%,38rem); max-height:100%; overflow-y:auto;
  background:var(--ink-2); border:1px solid var(--line);
  padding:clamp(1.8rem,4.5vw,3.2rem);
  opacity:0; transform:translateY(18px) scale(.985);
  transition:opacity .5s var(--ease), transform .5s var(--ease);
}
.nl.da .nl__k{ opacity:1; transform:none; }
/* Der goldene Schimmer oben, wie bei den Karten. Rein dekorativ und
   deshalb ohne eigenes Element im Markup. */
.nl__k::before{
  content:""; position:absolute; inset:0; pointer-events:none;
  background:radial-gradient(90% 60% at 50% 0%,rgba(201,162,75,.13),transparent 70%);
}
.nl__k > *{ position:relative; }
.nl__x{
  position:absolute; top:.9rem; right:.9rem; z-index:2;
  width:2.4rem; height:2.4rem; display:grid; place-items:center;
  background:transparent; border:1px solid var(--line); color:var(--cream-dim);
  cursor:pointer; transition:border-color .3s,color .3s;
}
.nl__x:hover{ border-color:var(--gold); color:var(--gold-lite); }
.nl__x svg{ width:16px; height:16px; }
.nl__t{ font-size:clamp(1.7rem,3.4vw,2.6rem); line-height:1.1; }
.nl__s{ color:var(--cream-dim); font-size:.95rem; margin-top:var(--gap-head); }
.nl__f{ display:grid; gap:1.3rem; margin-top:clamp(1.6rem,3vw,2.2rem); }
.nl__feld{ display:block; cursor:pointer; }
.nl__feld span{
  display:block; font-size:.64rem; letter-spacing:.24em; text-transform:uppercase;
  color:var(--muted); margin-bottom:.6rem;
}
.nl__feld input{
  width:100%; background:transparent; border:0; border-bottom:1px solid var(--line);
  color:var(--cream); font-family:var(--ff-body); font-size:1rem; padding:.6rem 0;
  transition:border-color .4s; color-scheme:dark;
}
.nl__feld input:focus{ outline:0; border-color:var(--gold); }
/* .check bringt Anordnung und Groesse schon mit (Abschnitt 20). Hier
   kommt nur dazu, was der Satz im Popup braucht: Er ist lang und soll
   trotzdem nicht wie Kleingedrucktes aussehen — eine Einwilligung, die
   man ueberliest, ist keine. */
.nl__check{ font-size:.78rem; line-height:1.65; color:var(--cream-dim); }
.nl__check input[type="checkbox"]{
  width:17px; height:17px; margin-top:.2rem; accent-color:var(--gold); flex:0 0 auto;
}
.nl__ab{ justify-self:start; }
.nl__fein{ font-size:.7rem; color:var(--muted); line-height:1.6; }
.nl__fein a{ color:var(--cream-dim); }
/* .link-u bringt Versalien, 12,5 px und 2,5 px Sperrung mit. Im
   Kleingedruckten (10,6 px) sah das Wort "DATENSCHUTZ" dadurch groesser
   aus als der Satz, in dem es steht, und sprang in eine eigene Zeile.
   Hier soll es aussehen wie ein Link im Satz und nicht wie eine
   Ueberschrift. Gemessen am 30.09.2026: 12,48 px gegen 10,56 px. */
.nl__fein a.link-u{
  font-size:inherit; letter-spacing:.02em; text-transform:none;
}
/* Auf schmalen Geraeten sitzt das Fenster unten und geht bis an die
   Raender. Oben bleibt ein Rest der Seite sichtbar: Man soll sehen,
   dass man nicht weggeklickt wurde, sondern etwas davor liegt.

   Die Masse darunter sind am 30.09.2026 dazugekommen. Anlass war Colin
   mit einem Screenshot vom Handy: "riesen abstaende und nicht schoen."
   Nachgemessen bei 390 px Breite war die Karte 781 px hoch, auf einem
   iPhone 14 stehen bei max-height:92vh aber nur 685 px zur Verfuegung.
   Das Fenster musste also in sich gescrollt werden — und wer mittendrin
   hineinsieht, sieht genau das: Abstaende ohne Anfang und Ende.

   Die Abstaende selbst waren fuer den Bildschirm gerechnet und wurden
   unveraendert mit aufs Handy genommen: 27,2 px ueber der Ueberschrift,
   36,8 px zwischen ihr und der Unterzeile, 20,8 px zwischen den
   Feldern. Auf einem Bildschirm ist das Ruhe, auf einem Handy ist es
   Leere.

   Gemessen nach der Aenderung: 602 px statt 781 px, also 179 px
   gespart. Damit passt das Fenster auf gaengigen Geraeten hinein, ohne
   sich selbst zu scrollen. Auf sehr kleinen (iPhone SE, 320 x 667)
   bleiben 730 px gegen 614 px Platz; dort wird weiter gescrollt, und
   das ist richtig so. Der Einwilligungssatz ist so lang, wie er sein
   muss, und kuerzen darf man ihn nicht, um Platz zu sparen.

   Deshalb geht auch keine dieser Zeilen unter 0,72 rem beim
   Einwilligungssatz: Ein Satz, den man ueberliest, ist keine
   Einwilligung — dieselbe Ueberlegung wie oben bei .nl__check. */
@media (max-width:520px){
  .nl{ place-items:end center; padding:0; }
  .nl__k{
    width:100%; max-height:92vh; border-left:0; border-right:0; border-bottom:0;
    padding:1.5rem 1.35rem 1.7rem;
  }
  .nl__ab{ justify-self:stretch; text-align:center; }

  /* Der Schliessknopf sitzt oben rechts ueber allem. Bei 320 px lief die
     Zeile "Direkt buchen lohnt sich" darunter durch, gemessen 31 px
     Ueberdeckung. Die Breitenbegrenzung laesst sie vorher umbrechen. */
  .nl__k .eyebrow{ max-width:calc(100% - 3.2rem); }

  .nl__t{ font-size:1.45rem; line-height:1.15; margin-top:.75rem; }
  .nl__s{ font-size:.86rem; line-height:1.55; margin-top:.55rem; }
  .nl__f{ margin-top:1.35rem; gap:1rem; }
  .nl__feld span{ font-size:.6rem; margin-bottom:.35rem; }
  .nl__feld input{ padding:.45rem 0; }
  .nl__check{ font-size:.72rem; line-height:1.5; }
  .nl__fein{ font-size:.66rem; line-height:1.5; }
}

/* ---------- 14. Hilfsklassen ganz zum Schluss ----------
   .mt-l stand bis zum 16.09.2026 oben bei den Utilities in Zeile 145 und
   war damit wirkungslos, wo es am noetigsten war. Gemessen: die
   Ausstattungsliste auf allen drei Apartmentseiten traegt
   class="amen mt-l", bekam aber exakt 0 px Abstand nach oben — weil
   .amen{ margin:0 } weiter unten in derselben Datei steht und bei
   gleicher Spezifitaet die spaetere Regel gewinnt. Dasselbe bei
   ul.list-check auf eigentuemer, firmen und langzeit: 28,8 px statt 51,2.
   Colin dazu mit Screenshot: "Der Abstand von 'Ausstattung' zu den
   Ausstattungsthemen darunter ist sehr, sehr eng."

   Eine Hilfsklasse, die man ans Markup schreibt, soll auch gelten.
   Deshalb steht sie jetzt hinter allen Bausteinen. Wer kuenftig eine
   Komponente ergaenzt, kann .mt-l nicht mehr versehentlich aushebeln. */
.mt-l{ margin-top:clamp(2rem,4vw,3.5rem); }
