/* Kati & Ju — 24.04.2027 — Waldbach-Farbthema

   Farbinventur 18.09.2026: pro Familie nur noch die wirklich unterscheidbaren
   Nuancen (Snapshot davor: design-versionen/2026-09-18-farben/). Außerhalb
   dieses Blocks stehen keine Farbwerte mehr – Transparenzen entstehen aus den
   *-rgb-Tripeln (rgba(var(--color-navy-rgb), .7)) oder per color-mix(). */

:root {
  /* Grün – Navy für Flächen (Nav, Header-Overlay, Login, Tab-Farbe),
     Loden-Dunkel für Text (Überschriften, Hover, Icons), Loden für Links,
     alle Primär-Buttons (seit 18.09.2026 statt Gold-tief, das als Fläche zu
     erdig wirkte), Checkbox, Toggle "an", das Ja-Segment und die aktive
     Namens-Umfrage-Option. */
  --color-navy: #1f3d2b;
  --color-loden-dark: #234a30;
  --color-loden: #3f7350;
  --color-navy-rgb: 31, 61, 43;
  --color-loden-rgb: 63, 115, 80;
  /* Oliv – nur für die Neben-Orte auf der Locations-Karte (locations-map.css). */
  --color-moss: #6f7a3f;

  /* Gold – --color-gold ist Deko auf dunklem Grund (Ränder, Icons, SVGs).
     Tiefes Honiggold --color-gold-deep für kleine Flächen mit weißem Text
     (Badges, Zeit-Pille, Gastgeber-Avatar), für Gold-Text auf hellem Grund
     und für Fokusringe: seit 18.09.2026 der frühere Hover-Ton #916a30
     (Kontrast mit Weiß ≈4.8:1, WCAG AA; davor #a9823f mit ≈3.5:1). Buttons
     tragen es seit 18.09.2026 nicht mehr (siehe Grün). */
  --color-gold: #b08d4a;
  --color-gold-deep: #916a30;
  --color-gold-light: #d3bd7c;
  /* Sattes Logo-Gold (KJ-Monogramm), nur für die Linien-Animation im Couple-Header. */
  --color-gold-crest: #d2a93f;
  --color-gold-light-rgb: 211, 189, 124;

  /* Creme – Seite, Karten, Zeilen/Pillen, Ränder/Tracks. */
  --color-page: #fffaec;
  --color-white: #fffdf8;
  --color-ivory: #f8f1de;
  --color-ivory-dark: #efe4c8;
  --color-ivory-rgb: 248, 241, 222;
  --color-white-rgb: 255, 253, 248;
  /* Ein Beige für alle Formular-, Checkbox- und Sekundär-Button-Ränder. */
  --color-border: #c9bda4;

  /* Text – einheitlicher gedämpfter Text statt uneinheitlicher opacity-Werte
     (ersetzt frühere opacity:.6–.75 auf --color-ink und Bootstraps .text-muted);
     übernimmt auch Sekundär-Buttons und Blockquotes (früher "Rinde"). */
  --color-ink: #29241a;
  --color-muted: #6b6357;

  /* Rot – Alpenrose für Absagen/Gefahr; die helle Variante nur für Fehlertext
     auf dunklem Grund (Login). */
  --color-alpenrose: #b5544a;
  --color-alpenrose-dark: #8f3f37;
  --color-alpenrose-light: #f0b8ac;

  /* Marken-Blau, nur für die Booking.com-Kachel. */
  --color-enzian: #3f6a8a;
  --color-enzian-dark: #2c4d66;

  --font-heading: "Marcellus", Georgia, serif;
  --font-body: "Jost", "Segoe UI", sans-serif;

  /* Eine Grundfarbe für alle UI-Schatten und Foto-Abdunklungen (dunkles
     Waldgrün); reines Schwarz nur für Lightbox und Modal-Backdrop. */
  --shadow-rgb: 28, 42, 23;
  --shadow-soft: 0 10px 30px -12px rgba(var(--shadow-rgb), 0.28);
  --radius-soft: 14px;
  --radius-organic: 14px 30px 14px 14px;
  /* Kleinere Variante derselben Form für Zeilen/Buttons (RSVP-Zeilen,
     Umfrage-Optionen, Forum-Zeilen) – gleiche Handschrift, kleinerer Maßstab. */
  --radius-organic-sm: 10px 22px 10px 10px;
}

/* Höhe des tatsächlich sichtbaren Viewports - die einzige Quelle für alle
   Vollbild-Flächen (Anmeldeseite, Foto-Header, mobiles Menü).

   100dvh ist genau der Bereich, den der Gast in diesem Moment sieht: auf
   iPhone/Android wächst und schrumpft der Wert mit der ein- und ausfahrenden
   Adressleiste. Damit ist die Fläche nie zu kurz (kein Streifen Footer oder
   Seitenhintergrund unter dem Bild) und nie zu lang (kein Teil des Mains, den
   man nicht sieht). Genau deshalb hier dvh und nicht lvh/svh: lvh misst den
   Zustand mit eingeklappter Leiste (zu lang, solange die Adressleiste unten
   steht), svh den mit ausgeklappter (zu kurz, sobald sie einfährt).

   100vh ist nur der Fallback für Browser ohne dvh; dort ersetzt
   viewport-height.js den Wert durch die gemessene Höhe in Pixeln. */
:root {
  --viewport-height: 100vh;
}

@supports (height: 100dvh) {
  :root {
    --viewport-height: 100dvh;
  }
}

* {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* Gleicher Ton wie body: falls iPad-Safari am unteren Rand über das
     Dokumentende hinaus "bounced" (elastisches Overscroll) oder body
     minimal kleiner als der sichtbare Viewport layoutet, blitzt sonst der
     graue Browser-Standardhintergrund statt der Seitenfarbe durch. */
  background-color: var(--color-page);
}

body {
  font-family: var(--font-body);
  color: var(--color-ink);
  background-color: var(--color-page);
  background-image: url("../img/raute-pattern.svg");
  background-repeat: repeat;
  background-size: 120px;
  min-height: var(--viewport-height);
  display: flex;
  flex-direction: column;
  overflow-x: hidden;
}

main.page-content {
  flex: 1 0 auto;
  padding-top: 6rem;
  animation: fade-in-up 0.6s ease both;
}

@media (max-width: 767.98px) {
  body {
    background-image: none;
  }
}

/* Solange das mobile Vollbild-Menü offen ist, den Body fixieren, damit kein
   Rubber-Band-Overscroll (iOS) die Seite hinter dem Overlay durchscheinen
   lässt - siehe nav-scroll.js. */
body.nav-open-lock {
  position: fixed;
  width: 100%;
  overflow: hidden;
}

/* The entrance animation's fill-mode "both" leaves a permanent (no-op)
   transform on this element even after it finishes, which makes it a
   containing block AND stacking context for fixed-position descendants
   (same trap documented above on .navbar-hochzeit and .login-shell). Any
   Bootstrap modal opened from within <main> gets trapped in that local
   stacking context, while Bootstrap appends .modal-backdrop directly to
   <body> — so the backdrop (z-index 1050) paints above the whole trapped
   subtree regardless of the modal's own z-index (1055), swallowing clicks
   on the modal's contents. Lifting <main> above the backdrop only while a
   modal is open fixes this without disturbing the sticky header the rest
   of the time. */
body.modal-open main.page-content {
  position: relative;
  z-index: 1056;
}

main.page-content:has(> .couple-header),
main.page-content:has(> .login-split) {
  padding-top: 0;
}

main.page-content.page-content-no-nav {
  padding-top: 2rem;
}

/* Puffer in Seitenfarbe unterhalb der Login-Vollbildfläche - nur auf dem
   Handy (Spaltenlayout, grüner Bereich über die volle Breite). iOS Safari
   klappt beim ersten Scrollen (oft schon bei der leisesten Wischbewegung)
   die Adressleiste ein und schenkt der Seite dabei rund 40px Viewport dazu.
   Klebt der Footer direkt an der Unterkante, blitzt er in genau diesem
   Moment auf. Der Puffer hat dieselbe Farbe wie der grüne Bereich darüber,
   ist also unsichtbar - der Footer braucht dadurch eine bewusste
   Scrollbewegung, statt von selbst hereinzurutschen.

   Auf dem Desktop (Foto links, Panel rechts) wäre derselbe Puffer als
   grüner Balken unter dem Foto sichtbar, dort bleibt er 0. Dieselbe
   Variable steuert weiter unten den Farbwechsel des html/body-Verlaufs. */
:root {
  --login-buffer: 0px;
}

@media (max-width: 767.98px) {
  :root {
    --login-buffer: clamp(4rem, 14vh, 8rem);
  }
}

main.page-content.page-content-no-nav:has(> .login-split) {
  padding-top: 0;
  padding-bottom: var(--login-buffer) !important;
}

h1, h2, h3, h4, .heading-serif {
  font-family: var(--font-heading);
  color: var(--color-loden-dark);
  font-weight: 400;
  letter-spacing: 0.01em;
}

a {
  color: var(--color-loden);
}

a:hover {
  color: var(--color-gold-deep);
}

/* Bootstrap .text-muted (rgba(...,.75)) liegt auf dem hellen Seitengrund nur
   bei ~4.4:1 – knapp unter AA. Fester, etwas dunklerer Ton statt Transparenz. */
.text-muted {
  color: var(--color-muted) !important;
}

/* Durchgängiger, deutlich sichtbarer Tastatur-Fokus (WCAG 2.4.7). Bootstraps
   Default-Fokusschatten ist auf einigen Elementen zu blass bzw. wird von
   .btn-Transitions verschluckt. :focus-visible trifft nur echte Tab-Navigation,
   nicht Maus-/Touch-Klicks. */
a:focus-visible,
.btn:focus-visible,
.nav-link:focus-visible,
.navbar-toggler:focus-visible,
.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--color-gold-deep);
  outline-offset: 2px;
}

/* Auf dunklem Grund (Navbar, Hero-Panels) muss der Ring hell sein. */
.navbar-hochzeit a:focus-visible,
.navbar-hochzeit .btn:focus-visible,
.navbar-hochzeit .nav-link:focus-visible,
.navbar-hochzeit .navbar-toggler:focus-visible,
.hero-panel a:focus-visible,
.content-hero a:focus-visible {
  outline-color: var(--color-gold-light);
}

/* ---------- Navbar ---------- */

/* Scroll-Fortschritt der Pill: nav-scroll.js schreibt --nav-p von 0 (ganz
   oben, farbloser Ausgangszustand) bis 1 (voll "Frost", seit 18.09.2026 –
   davor ein harter Klassen-Umschlag auf Loden-dunkel→Navy bei 72 %). Alle
   Übergänge unten rechnen mit dieser Variable, damit sich Farbe, Blur,
   Padding und Schrift stufenlos mit dem Scrollen bewegen statt zu kippen.
   Die Klasse .is-scrolled (ab --nav-p = 1) bleibt für Hover/Fokus-Regeln. */
.site-header {
  --nav-p: 0;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1030;
  padding: calc(1rem - 0.5rem * var(--nav-p)) 1rem 1.5rem;
}

.navbar-hochzeit {
  position: relative;
  border-radius: 999px;
  padding: calc(0.55rem - 0.15rem * var(--nav-p)) 0.6rem calc(0.55rem - 0.15rem * var(--nav-p)) 1.25rem;
}

/* Glass background lives on a pseudo-element rather than the navbar itself:
   backdrop-filter on the navbar would make it a containing block for its
   position:fixed mobile overlay child, trapping the full-screen menu inside
   the small pill-shaped navbar box instead of the viewport.

   Zwei Schichten: die Navy-Fläche des Ausgangszustands blendet mit --nav-p
   aus, das Creme-Milchglas ("Frost") blendet ein. Die kurze Transition glättet
   nur die Scroll-Schritte, sie soll dem Finger nicht hinterherlaufen. */
.navbar-hochzeit::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: inherit;
  background-color: rgba(var(--color-navy-rgb), calc(0.7 * (1 - var(--nav-p))));
  background-image: linear-gradient(160deg, rgba(var(--color-white-rgb), calc(0.62 * var(--nav-p))), rgba(var(--color-ivory-rgb), calc(0.5 * var(--nav-p))));
  backdrop-filter: blur(calc(16px + 12px * var(--nav-p))) saturate(calc(150% + 30% * var(--nav-p)));
  -webkit-backdrop-filter: blur(calc(16px + 12px * var(--nav-p))) saturate(calc(150% + 30% * var(--nav-p)));
  border: 1px solid color-mix(in srgb, rgba(var(--color-navy-rgb), 0.14) calc(100% * var(--nav-p)), rgba(255, 255, 255, 0.09));
  box-shadow:
    0 14px 34px -18px rgba(var(--shadow-rgb), calc(0.55 * (1 - var(--nav-p)))),
    0 10px 30px -12px rgba(var(--shadow-rgb), calc(0.28 * var(--nav-p))),
    inset 0 1px 0 rgba(var(--color-white-rgb), calc(0.6 * var(--nav-p)));
  transition: background-color 0.12s linear, background-image 0.12s linear, box-shadow 0.12s linear, backdrop-filter 0.12s linear, border-color 0.12s linear;
}

/* Muted look while the nav floats over the full-bleed photo header — dunkler,
   halbtransparenter Grün-Ton (statt fast unsichtbarem Weiß-Schleier), damit die
   hellen Nav-Links auch über einem hellen Foto-Ausschnitt lesbar bleiben. */
body:has(.couple-header) .navbar-hochzeit::before {
  background-color: rgba(var(--color-navy-rgb), calc(0.28 * (1 - var(--nav-p))));
  border-color: color-mix(in srgb, rgba(var(--color-navy-rgb), 0.14) calc(100% * var(--nav-p)), rgba(255, 255, 255, 0.18));
  backdrop-filter: blur(calc(3px + 25px * var(--nav-p))) saturate(calc(115% + 65% * var(--nav-p)));
  -webkit-backdrop-filter: blur(calc(3px + 25px * var(--nav-p))) saturate(calc(115% + 65% * var(--nav-p)));
  box-shadow:
    0 10px 30px -12px rgba(var(--shadow-rgb), calc(0.28 * var(--nav-p))),
    inset 0 1px 0 rgba(var(--color-white-rgb), calc(0.6 * var(--nav-p)));
}

body:has(.couple-header) .site-header:not(.is-scrolled) .navbar-hochzeit:hover::before {
  background-color: rgba(var(--color-navy-rgb), calc(0.4 * (1 - var(--nav-p))));
  border-color: color-mix(in srgb, rgba(var(--color-navy-rgb), 0.14) calc(100% * var(--nav-p)), rgba(255, 255, 255, 0.28));
  backdrop-filter: blur(calc(4px + 24px * var(--nav-p))) saturate(calc(120% + 60% * var(--nav-p)));
  -webkit-backdrop-filter: blur(calc(4px + 24px * var(--nav-p))) saturate(calc(120% + 60% * var(--nav-p)));
}

/* Auf dem hell werdenden Grund wandern Marke, Toggler-Balken, Links,
   Abmelden-Button, Aktiv-Strich und Fokusring von Elfenbein/Gold-hell nach
   Navy/Gold-tief – ebenfalls stufenlos über --nav-p. Das .site-header-Präfix
   hält die Spezifität über den späteren Basisregeln (.navbar-hochzeit .nav-link). */
.site-header .navbar-hochzeit .navbar-brand {
  color: color-mix(in srgb, var(--color-navy) calc(100% * var(--nav-p)), var(--color-ivory)) !important;
}

/* Toggler-Balken dunkel – außer bei offenem Vollbild-Menü, wo der Toggler
   über dem dunklen Overlay liegt und hell bleiben muss. */
.navbar-toggler.collapsed .navbar-toggler-icon-custom span {
  background-color: color-mix(in srgb, var(--color-navy) calc(100% * var(--nav-p)), var(--color-ivory));
}

.site-header.is-scrolled .navbar-toggler.collapsed:focus-visible {
  outline-color: var(--color-gold-deep);
}

/* Nur im Desktop-Pill: auf Mobile sitzen Links und Abmelden-Button im
   dunklen Vollbild-Overlay und behalten dort ihre helle Schrift. */
@media (min-width: 992px) {
  .site-header .navbar-hochzeit .nav-link {
    color: color-mix(in srgb, rgba(var(--color-navy-rgb), 0.85) calc(100% * var(--nav-p)), rgba(var(--color-ivory-rgb), 0.95)) !important;
  }

  .site-header .navbar-hochzeit .nav-link:hover,
  .site-header .navbar-hochzeit .nav-link.active {
    color: color-mix(in srgb, var(--color-navy) calc(100% * var(--nav-p)), var(--color-white)) !important;
  }

  .site-header .navbar-hochzeit .nav-link:hover {
    background-color: color-mix(in srgb, rgba(var(--color-navy-rgb), 0.07) calc(100% * var(--nav-p)), rgba(255, 255, 255, 0.1));
  }

  .site-header .navbar-hochzeit .nav-link.active::after {
    background-color: color-mix(in srgb, var(--color-gold-deep) calc(100% * var(--nav-p)), var(--color-gold-light));
  }

  .site-header .navbar-hochzeit .btn-outline-light {
    color: color-mix(in srgb, var(--color-navy) calc(100% * var(--nav-p)), var(--color-ivory));
    border-color: color-mix(in srgb, rgba(var(--color-navy-rgb), 0.35) calc(100% * var(--nav-p)), rgba(255, 255, 255, 0.4));
  }

  .site-header.is-scrolled .navbar-hochzeit a:focus-visible,
  .site-header.is-scrolled .navbar-hochzeit .btn:focus-visible,
  .site-header.is-scrolled .navbar-hochzeit .nav-link:focus-visible {
    outline-color: var(--color-gold-deep);
  }
}

.navbar-hochzeit .navbar-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-heading);
  font-size: 1.3rem;
  font-weight: 400;
  letter-spacing: 0.02em;
}

.navbar-hochzeit .navbar-toggler {
  border: none;
  padding: 0.35rem 0.5rem;
  z-index: 1045;
}

@media (max-width: 991.98px) {
  .navbar-hochzeit .navbar-toggler {
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
}

.navbar-hochzeit .navbar-toggler:focus {
  box-shadow: 0 0 0 3px rgba(var(--color-gold-light-rgb), 0.65);
}

.navbar-toggler-icon-custom {
  display: inline-flex;
  flex-direction: column;
  justify-content: space-between;
  width: 22px;
  height: 16px;
  transform-origin: center;
  transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}

.navbar-toggler-icon-custom span {
  display: block;
  height: 2px;
  width: 100%;
  background-color: var(--color-ivory);
  border-radius: 2px;
}

.navbar-toggler:not(.collapsed) .navbar-toggler-icon-custom {
  transform: rotate(180deg);
}

.navbar-hochzeit .navbar-nav {
  gap: 0.2rem;
}

.navbar-hochzeit .nav-link {
  position: relative;
  color: rgba(var(--color-ivory-rgb), 0.95) !important; /* Mobile-Overlay; Desktop siehe --nav-p-Block */
  font-size: 0.95rem;
  font-weight: 500;
  padding: 0.45rem 0.6rem !important;
  border-radius: 999px;
  background-color: rgba(255, 255, 255, 0);
  transition: color 0.12s linear, padding 0.35s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.navbar-hochzeit .nav-link:hover {
  color: var(--color-white) !important;
  padding-left: 1.1rem !important;
  padding-right: 1.1rem !important;
  background-color: rgba(255, 255, 255, 0.1);
}

.navbar-hochzeit .nav-link.active {
  color: var(--color-white) !important;
}

.navbar-hochzeit .nav-link.active::after {
  content: "";
  position: absolute;
  left: 0.6rem;
  right: 0.6rem;
  bottom: 0.2rem;
  height: 2px;
  background-color: var(--color-gold-light);
  border-radius: 2px;
  /* Der goldene Strich zeichnet sich beim Laden von der Mitte aus — kurz
     verzögert, damit er nach dem Einblenden der Seite auffällt. */
  transform: scaleX(0);
  transform-origin: center;
  animation: nav-active-line-in 0.6s cubic-bezier(0.22, 1, 0.36, 1) 0.35s forwards;
}

@keyframes nav-active-line-in {
  to {
    transform: scaleX(1);
  }
}

.navbar-hochzeit .btn-outline-light {
  border-radius: 999px;
  border-color: rgba(255, 255, 255, 0.4);
}

.navbar-hochzeit .btn-outline-light:hover {
  background-color: var(--color-gold-light);
  border-color: var(--color-gold-light);
  color: var(--color-navy);
}

.navbar-hochzeit .btn-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0 !important;
}

.navbar-hochzeit .btn-icon:hover {
  padding: 0 !important;
  transform: scale(1.08);
}

/* Full-screen overlay menu on mobile/tablet */
@media (max-width: 991.98px) {
  .navbar-hochzeit .navbar-collapse {
    position: fixed;
    inset: 0;
    width: 100vw !important;
    height: var(--viewport-height) !important;
    background: linear-gradient(160deg, var(--color-navy) 0%, var(--color-loden-dark) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    visibility: hidden;
    transform: scale(0.97);
    transition: opacity 0.4s ease, transform 0.4s cubic-bezier(0.16, 1, 0.3, 1), visibility 0.4s;
    z-index: 1040;
  }

  .navbar-hochzeit .navbar-collapse.show,
  .navbar-hochzeit .navbar-collapse.collapsing {
    opacity: 1;
    visibility: visible;
    transform: scale(1);
  }

  .navbar-hochzeit .navbar-nav {
    text-align: center;
    gap: 0.5rem;
    margin-left: 0 !important;
  }

  .navbar-hochzeit .navbar-nav .nav-item {
    opacity: 0;
    transform: translateY(18px);
  }

  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item {
    animation: nav-item-in 0.55s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  }

  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(1) { animation-delay: 0.1s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(2) { animation-delay: 0.16s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(3) { animation-delay: 0.22s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(4) { animation-delay: 0.28s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(5) { animation-delay: 0.34s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(6) { animation-delay: 0.4s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(7) { animation-delay: 0.46s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(8) { animation-delay: 0.52s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(9) { animation-delay: 0.58s; }
  .navbar-hochzeit .navbar-collapse.show .navbar-nav .nav-item:nth-child(n+10) { animation-delay: 0.64s; }

  .navbar-hochzeit .navbar-nav .nav-link {
    font-family: var(--font-heading);
    font-size: 1.7rem;
    font-weight: 400;
    padding: 0.5rem 1rem !important;
  }

  /* Im Vollbild-Overlay reicht die weiße Schrift als Aktiv-Markierung —
     kein goldener Strich. */
  .navbar-hochzeit .navbar-nav .nav-link.active::after {
    display: none;
  }

  .navbar-hochzeit .navbar-nav li:last-child {
    margin-top: 1rem;
  }

  /* Der Abmelden-Button ist im schwebenden Pill ein 2.1rem-Icon-Quadrat. Im
     Vollbild-Overlay wäre das ein zu kleines Tap-Ziel und optisch fremd neben
     den großen Serifen-Links — hier als vollwertiger Text-Button. */
  .navbar-hochzeit .navbar-collapse .btn-icon {
    width: auto;
    height: auto;
    gap: 0.5rem;
    border-radius: 999px;
    padding: 0.6rem 1.5rem !important;
    font-family: var(--font-heading);
    font-size: 1.15rem;
  }

  .navbar-hochzeit .navbar-collapse .btn-icon:hover {
    padding: 0.6rem 1.5rem !important;
    transform: none;
  }
}

@keyframes nav-item-in {
  from {
    opacity: 0;
    transform: translateY(18px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ---------- Buttons ---------- */

.btn {
  transition: padding 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.35s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.35s cubic-bezier(0.4, 0, 0.2, 1), color 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.btn:hover {
  padding-left: calc(var(--bs-btn-padding-x) + 0.4rem);
  padding-right: calc(var(--bs-btn-padding-x) + 0.4rem);
}

/* Primär-Buttons in Loden (Klassenname .btn-gold bleibt, damit die Views
   unverändert bleiben). Bis 18.09.2026 Gold-tief mit weißem Text – als
   Fläche wirkte das zu erdig; Gold bleibt Deko/Text-Akzent. */
.btn-gold {
  background-color: var(--color-loden);
  border-color: var(--color-loden);
  color: var(--color-white);
  font-family: var(--font-heading);
  letter-spacing: 0.03em;
}

.btn-gold:hover {
  background-color: var(--color-loden-dark);
  border-color: var(--color-loden-dark);
  color: var(--color-white);
  box-shadow: var(--shadow-soft);
}

.btn-outline-gold {
  background-color: transparent;
  border-color: var(--color-loden);
  color: var(--color-loden-dark);
  font-family: var(--font-heading);
  letter-spacing: 0.03em;
}

.btn-outline-gold:hover {
  background-color: var(--color-loden);
  border-color: var(--color-loden);
  color: var(--color-white);
  box-shadow: var(--shadow-soft);
}

.btn-loden {
  background-color: var(--color-loden);
  border-color: var(--color-loden);
  color: var(--color-white);
}

.btn-loden:hover {
  background-color: var(--color-loden-dark);
  border-color: var(--color-loden-dark);
  color: var(--color-white);
  box-shadow: var(--shadow-soft);
}

/* Sekundär-/Gefahr-Buttons (Admin-Tabellen, Formular-Abbrechen, Forum-Löschen)
   kamen bisher ungestylt aus Bootstrap (Grau #6c757d, Signalrot #dc3545) –
   hier auf Gedämpft bzw. Alpenrose der Palette. */
.btn-outline-secondary {
  --bs-btn-color: var(--color-muted);
  --bs-btn-border-color: var(--color-border);
  --bs-btn-hover-color: var(--color-white);
  --bs-btn-hover-bg: var(--color-muted);
  --bs-btn-hover-border-color: var(--color-muted);
  --bs-btn-active-color: var(--color-white);
  --bs-btn-active-bg: var(--color-muted);
  --bs-btn-active-border-color: var(--color-muted);
}

.btn-outline-danger {
  --bs-btn-color: var(--color-alpenrose-dark);
  --bs-btn-border-color: var(--color-alpenrose);
  --bs-btn-hover-color: var(--color-white);
  --bs-btn-hover-bg: var(--color-alpenrose-dark);
  --bs-btn-hover-border-color: var(--color-alpenrose-dark);
  --bs-btn-active-color: var(--color-white);
  --bs-btn-active-bg: var(--color-alpenrose-dark);
  --bs-btn-active-border-color: var(--color-alpenrose-dark);
}

.btn-link.text-danger {
  color: var(--color-alpenrose-dark) !important;
}

/* ---------- Formulare ---------- */
/* Bootstraps blauer Fokus-Ring (#0d6efd) und blaue Checkboxen brechen die
   Palette. Ein goldener Ring, Häkchen in Loden. Die globale
   :focus-visible-Outline (oben) greift zusätzlich nur bei Tastatur-Fokus –
   damit es keinen Doppel-Ring gibt, hier für Formularfelder abschalten. */
.form-control,
.form-select {
  border-color: var(--color-border);
  color: var(--color-ink);
}

.form-control:focus,
.form-select:focus {
  border-color: var(--color-gold-deep);
  box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--color-gold-deep) 25%, transparent);
  color: var(--color-ink);
}

.form-control:focus-visible,
.form-select:focus-visible,
.form-check-input:focus-visible {
  outline: none;
}

.form-control::placeholder {
  color: var(--color-muted);
  opacity: 0.7;
}

.form-check-input {
  border-color: var(--color-border);
}

.form-check-input:checked {
  background-color: var(--color-loden);
  border-color: var(--color-loden);
}

.form-check-input:focus {
  border-color: var(--color-gold-deep);
  box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--color-gold-deep) 25%, transparent);
}

/* Zugangscodes (Admin > Gäste) und Request-IDs: statt Bootstrap-Pink eine
   Elfenbein-Pille in Loden-Dunkel. */
code {
  font-size: 0.85em;
  color: var(--color-loden-dark);
  background-color: var(--color-ivory);
  border: 1px solid var(--color-ivory-dark);
  border-radius: 6px;
  padding: 0.15em 0.55em;
  letter-spacing: 0.06em;
  white-space: nowrap;
}

/* ---------- Cards / Sections ---------- */

.card-hochzeit {
  background-color: var(--color-white);
  border: 1px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic);
  box-shadow: var(--shadow-soft);
  transition: transform 0.25s ease, box-shadow 0.25s ease;
}

.card-hochzeit:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 36px -14px rgba(var(--shadow-rgb), 0.32);
}

/* Die Startseiten-Karten ohne Kachel-Markup (Grundinfos, Zusage, Nachricht,
   Namensfrage) verhalten sich beim Hover wie die Kacheln: Die Karte bleibt
   stehen und behält ihren Schatten, nur der Kopf (Titel + Marke) reagiert.
   Sprung und Schattenwechsel aus .card-hochzeit:hover wirkten bei diesen
   großen Textkarten unruhig; bei der Namensfrage fiel zusätzlich auf, dass
   sie als einzige Kachel im Raster ihren Schatten änderte. Derselbe Ansatz
   wie bei .tile-card:hover. */
.info-card:hover,
.rsvp-card:hover,
.message-card:hover,
.card-hochzeit.name-poll:hover {
  transform: none;
  box-shadow: var(--shadow-soft);
}

/* ---------- RSVP (Willkommen) ---------- */

.rsvp-persons {
  display: flex;
  flex-direction: column;
}

/* Personen werden nur durch eine Haarlinie getrennt – keine eigene Fläche pro
   Zeile, damit die Schalter allein die Aufmerksamkeit bekommen. */
.rsvp-person-row {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 1.5rem;
  flex-wrap: wrap;
  padding: 0.85rem 0;
  border-bottom: 1px solid var(--color-ivory-dark);
}

.rsvp-person-row:last-child {
  border-bottom: 0;
}

/* Feste Mindestbreite, damit die Schalter mehrerer Personen bündig
   untereinander stehen statt je nach Namenslänge zu springen. */
.rsvp-person-name {
  min-width: 9rem;
  font-weight: 600;
  color: var(--color-ink);
}

.rsvp-plusone {
  padding: 0.85rem 1.1rem;
  background-color: var(--color-page);
  border-radius: var(--radius-organic-sm);
}

.rsvp-plusone-name {
  max-width: 24rem;
  display: none;
}

.rsvp-plusone:has(.toggle-switch-input:checked) .rsvp-plusone-name {
  display: block;
}

.toggle-switch-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.toggle-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
  cursor: pointer;
  user-select: none;
  margin: 0;
}

.toggle-switch-track {
  position: relative;
  width: 46px;
  height: 26px;
  flex-shrink: 0;
  background-color: var(--color-alpenrose);
  border-radius: 999px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.15);
  transition: background-color 0.2s ease;
}

.toggle-switch-thumb {
  position: absolute;
  top: 3px;
  left: 3px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background-color: var(--color-white);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 0.2s ease;
}

.toggle-switch-input:checked ~ .toggle-switch-track {
  background-color: var(--color-loden);
}

.toggle-switch-input:checked ~ .toggle-switch-track .toggle-switch-thumb {
  transform: translateX(20px);
}

.toggle-switch-input:focus-visible ~ .toggle-switch-track {
  outline: 2px solid var(--color-gold);
  outline-offset: 2px;
}

.toggle-switch-text-on,
.toggle-switch-text-off {
  font-weight: 600;
  font-size: 0.95rem;
  min-width: 8.5rem;
}

.toggle-switch-text-on {
  display: none;
  color: var(--color-loden-dark);
}

.toggle-switch-text-off {
  display: inline;
  color: var(--color-alpenrose-dark);
}

.toggle-switch-input:checked ~ .toggle-switch-text-on {
  display: inline;
}

.toggle-switch-input:checked ~ .toggle-switch-text-off {
  display: none;
}

/* Mobile: Name und Schalter untereinander statt nebeneinander. Der feste
   min-width der Schaltertexte (8.5rem) + ein langer Name sprengen sonst auf
   schmalen Screens die Zeile und erzeugen einen zerklüfteten Umbruch. In der
   gestapelten Variante darf der Schaltertext beliebig schmal werden, und die
   ganze Zeile wird zum großen Tap-Ziel. */
@media (max-width: 575.98px) {
  .rsvp-person-row {
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
  }

  .rsvp-person-row .toggle-switch,
  .rsvp-plusone .toggle-switch {
    width: 100%;
    justify-content: space-between;
  }

  .toggle-switch-text-on,
  .toggle-switch-text-off {
    min-width: 0;
    text-align: right;
  }
}

/* Drei-Positionen-Schieber der Zusage-Umfrage: "Ich komme nicht" | "Bitte
   wählen" | "Ich komme". Drei versteckte Radios liegen VOR der Spur, sodass
   der Knopf rein per CSS (~) positioniert und gefärbt wird – ohne JS bleibt
   alles bedienbar. Die Mitte ist der bewusste Startzustand ohne Vorauswahl;
   .is-locked (nach einer getroffenen Wahl) blendet sie aus. */
.rsvp-tristate {
  position: relative;
  flex-shrink: 0;
}

.rsvp-tristate-input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.rsvp-tristate-track {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  padding: 3px;
  background-color: var(--color-ivory-dark);
  border-radius: 999px;
  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.12);
}

.rsvp-tristate-thumb {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 3px;
  /* Genau ein Drittel des Innenbereichs = Breite eines Segments, damit
     translateX(100%/200%) exakt auf den Segmenten landet. */
  width: calc((100% - 6px) / 3);
  border-radius: 999px;
  background-color: var(--color-white);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25);
  transform: translateX(100%);
  transition: transform 0.25s ease, background-color 0.25s ease;
}

.rsvp-tristate-seg {
  position: relative;
  z-index: 1;
  margin: 0;
  padding: 0.4rem 0.8rem;
  text-align: center;
  font-weight: 600;
  font-size: 0.9rem;
  line-height: 1.25;
  white-space: nowrap;
  color: var(--color-muted);
  cursor: pointer;
  user-select: none;
  transition: color 0.2s ease;
}

.rsvp-tristate-seg:hover {
  color: var(--color-ink);
}

.rsvp-tristate-seg-short {
  display: none;
}

.rsvp-tristate-input:nth-of-type(1):checked ~ .rsvp-tristate-track .rsvp-tristate-thumb {
  transform: translateX(0);
  background-color: var(--color-alpenrose);
}

.rsvp-tristate-input:nth-of-type(3):checked ~ .rsvp-tristate-track .rsvp-tristate-thumb {
  transform: translateX(200%);
  background-color: var(--color-loden);
}

.rsvp-tristate-input:nth-of-type(1):checked ~ .rsvp-tristate-track .rsvp-tristate-seg-no,
.rsvp-tristate-input:nth-of-type(3):checked ~ .rsvp-tristate-track .rsvp-tristate-seg-yes {
  color: var(--color-white);
}

.rsvp-tristate-input:nth-of-type(2):checked ~ .rsvp-tristate-track .rsvp-tristate-seg-open {
  color: var(--color-ink);
}

.rsvp-tristate-input:focus-visible ~ .rsvp-tristate-track {
  outline: 2px solid var(--color-gold);
  outline-offset: 2px;
}

/* Gesperrte Mitte: Wahl ist getroffen, "Bitte wählen" nur noch als
   blasser Platzhalter zwischen den beiden Seiten. */
.rsvp-tristate.is-locked .rsvp-tristate-seg-open {
  color: var(--color-muted);
  opacity: 0.4;
  cursor: not-allowed;
}

/* Statuszeile des Auto-Speicherns (nur mit JS sichtbar). */
.rsvp-autosave-status {
  font-size: 0.9rem;
}

.rsvp-autosave-status.is-error {
  color: var(--color-alpenrose-dark);
}

/* Mobil (Zeile ist dann gestapelt, siehe .rsvp-person-row oben): Schieber
   über die volle Breite. Drei volle Beschriftungen passen trotzdem nicht
   nebeneinander in die Spur – außen genügt unter der Frage "Kommst du?"
   ein klares Ja/Nein. */
@media (max-width: 575.98px) {
  .rsvp-person-row .rsvp-tristate {
    width: 100%;
  }

  .rsvp-tristate-seg {
    padding-inline: 0.3rem;
    font-size: 0.8rem;
  }

  .rsvp-tristate-seg-long {
    display: none;
  }

  .rsvp-tristate-seg-short {
    display: inline;
  }
}

/* ---------- RSVP status (Admin > Gäste) ---------- */

.rsvp-status-list {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  font-size: 0.85rem;
  white-space: nowrap;
}

.rsvp-status-yes,
.rsvp-status-no,
.rsvp-status-open,
.rsvp-status-plusone {
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.rsvp-status-yes::before,
.rsvp-status-no::before,
.rsvp-status-open::before {
  flex-shrink: 0;
  font-weight: 700;
}

.rsvp-status-yes {
  color: var(--color-loden-dark);
}

.rsvp-status-yes::before {
  content: "✓";
}

.rsvp-status-no {
  color: var(--color-alpenrose-dark);
}

.rsvp-status-no::before {
  content: "✕";
}

/* Noch keine Rückmeldung. */
.rsvp-status-open {
  color: var(--color-muted);
}

.rsvp-status-open::before {
  content: "○";
}

.rsvp-status-plusone {
  color: var(--color-gold-deep);
  font-weight: 600;
}

/* ---------- Tile grid (Willkommen) ---------- */
/* CSS Grid, not the Bootstrap row/col flex grid — a tile needs to span two
   rows (see .tile-row-2), which flexbox-based columns can't express. */

.tile-grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  grid-auto-rows: minmax(20rem, auto);
  gap: 1.5rem;
}

.tile-col-4 {
  grid-column: span 4;
}

.tile-col-6 {
  grid-column: span 6;
}

.tile-col-8 {
  grid-column: span 8;
}

.tile-col-12 {
  grid-column: span 12;
}

.tile-row-2 {
  grid-row: span 2;
}

/* 991.98px statt nur 767.98px: das 12-spaltige Bento-Raster (V5-Kacheln,
   s.u.) ist auf echte Desktop-Breiten ausgelegt. Auf einem 11"-iPad im
   Hochformat (834px, innerhalb des Bootstrap-.container-Bereichs "md" mit
   max-width 720px) blieb bislang das Desktop-Raster aktiv und quetschte
   Bild+Titel+Text jeder Kachel auf ein Drittel der Containerbreite - daher
   dieselbe Grenze wie beim Nav-Umbruch auf das Hamburger-Menü
   (navbar-expand-lg, Zeile ~266). */
@media (max-width: 991.98px) {
  .tile-grid {
    grid-template-columns: 1fr;
  }

  .tile-col-4,
  .tile-col-6,
  .tile-col-8,
  .tile-col-12 {
    grid-column: 1;
  }

  .tile-row-2 {
    grid-row: span 1;
  }
}

.tile-card {
  position: relative;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}

.tile-card-status {
  position: absolute;
  top: 0.7rem;
  right: 0.7rem;
  z-index: 2;
}

.tile-card-status .badge {
  box-shadow: 0 3px 10px -3px rgba(var(--shadow-rgb), 0.45);
}

/* The card itself stays put on hover — only the photo reacts. */
.tile-card:hover {
  transform: none;
  box-shadow: var(--shadow-soft);
}

/* flex (not a fixed height) so the photo absorbs all of any extra height a
   grid row imposes — e.g. a normal tile sharing a row with a taller feature
   tile, or a tile spanning two rows (.tile-row-2) — instead of leaving dead
   space under the body text. The body (below) is sized to its own content
   only, so it stays a fixed height while the photo grows. */
.tile-card-image {
  position: relative;
  flex: 1 1 auto;
  min-height: 216px;
  overflow: hidden;
}

.tile-card-image::before {
  content: "";
  position: absolute;
  inset: -12%;
  background:
    linear-gradient(150deg, rgba(var(--color-loden-rgb), 0.5) 0%, rgba(var(--color-navy-rgb), 0.68) 100%),
    var(--tile-photo, url("../img/nebel-wald-fog-forest-herbst.webp")) center / cover;
  transform: scale(1);
  transition: transform 0.6s ease;
}

.tile-card:hover .tile-card-image::before {
  transform: scale(1.1);
}

/* Reine Foto-Kacheln (Willkommen): gleiche Rundung, Rahmen und Schatten wie
   die übrigen Kacheln, aber ohne Text und ohne Link – deshalb kein Hover-Zoom
   und nur ein Hauch des Kachel-Verlaufs, das Foto selbst soll wirken.

   16:9 statt einer festen Höhe, weil die Hochkant-Schnitte fast quadratisch
   sind: In einem flachen Band bliebe von den Gesichtern nichts übrig. */
.tile-card-photo {
  /* Derselbe Loden-nach-Navy-Verlauf wie über den Kachelfotos, nur schwächer
     (0.3/0.4 statt 0.5/0.68): Dort muss er weißen Text tragen, hier soll man
     die Gesichter erkennen. Als Variable, weil ihn die Breitbild-Regel weiter
     unten erneut braucht. */
  --photo-tint: linear-gradient(150deg, rgba(var(--color-loden-rgb), 0.3) 0%, rgba(var(--color-navy-rgb), 0.4) 100%);
  /* Brennpunkt des Ausschnitts, hier die Werte des ersten Fotos: Jedes Motiv
     hat die Gesichter woanders, jede Kachel überschreibt sie deshalb selbst
     (siehe Willkommen.cshtml). */
  --photo-focus: 88%;
  --photo-focus-wide: 85%;
}

.tile-card-photo .tile-card-image {
  flex: 0 0 auto;
  aspect-ratio: 16 / 9;
  min-height: 12rem;
}

/* Derselbe langsame Ken-Burns-Drift wie auf dem Kopfbild und der Anmeldeseite
   (title-photo-drift): sanft hinein- und wieder herauszoomen. Er ersetzt den
   Hover-Zoom der übrigen Kacheln – die Animation gewinnt gegen dessen
   transform ohnehin, und anklickbar ist diese Kachel nicht. Bei scale(1.16)
   liegen 8% Überstand je Seite unter dem Rand, der Versatz von 3%/2,2% bleibt
   also innerhalb der Fläche. */
.tile-card-photo .tile-card-image::before {
  inset: 0;
  background: var(--photo-tint), var(--tile-photo) center var(--photo-focus) / cover;
  transform-origin: 50% 50%;
  animation: title-photo-drift 24s ease-in-out infinite alternate;
  will-change: transform;
}

/* Ab Laptop- und iPad-Querformat-Breite (dieselbe Grenze, an der auch das
   Kachelraster auf Desktop umschaltet) der breite Schnitt desselben Fotos.
   21:9 statt seiner vollen 19:10: Bei voller Containerbreite wäre die Kachel
   sonst rund 600px hoch. Weggeschnitten wird dadurch nur Himmel oben und ein
   schmaler Streifen unten; --photo-focus-wide hält dabei die Gesichter
   komplett im Bild. Fehlt --tile-photo-wide, bleibt es beim hochkantnahen
   Bild. */
@media (min-width: 992px) {
  .tile-card-photo .tile-card-image {
    aspect-ratio: 21 / 9;
  }

  .tile-card-photo .tile-card-image::before {
    background-image: var(--photo-tint), var(--tile-photo-wide, var(--tile-photo));
    background-position: center var(--photo-focus-wide);
  }
}

/* Admin-Kachel: kein Foto-Banner mehr, sondern eine kompakte Zeile
   (Marke + Titel/Beschreibung + "Öffnen →") – sie ist ein Werkzeug-Link
   für das Brautpaar, kein Inhalt für Gäste. Überschreibt das
   V5-Grid-Layout des Kachel-Bodys (s.u.). */
.tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.35rem;
  min-height: 0;
}

.tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body-text {
  display: block;
  flex: 1 1 auto;
  min-width: 0;
}

.tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body-text h3 {
  font-size: 1.25rem;
}

.tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body-text p {
  margin-top: 0.15rem;
}

.tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body::after {
  content: "Öffnen →";
  margin: 0;
  padding: 0;
  flex-shrink: 0;
}

/* External booking-site tiles (Übernachtung) have no photo either — each
   gets its own muted gradient so the two stay visually distinct from each
   other and from the internal tiles above. Their banner is only half the
   height of a normal tile photo, so they don't need the 20rem grid row the
   photo tiles rely on — the grid sizes to content instead. */
.tile-grid-compact {
  grid-auto-rows: auto;
}

.tile-card-airbnb .tile-card-image,
.tile-card-booking .tile-card-image {
  flex: 0 0 108px;
  min-height: 108px;
}

.tile-card-airbnb .tile-card-image::before {
  background:
    radial-gradient(130% 130% at 14% -14%, rgba(var(--color-gold-light-rgb), 0.22) 0%, rgba(var(--color-gold-light-rgb), 0) 55%),
    linear-gradient(160deg, var(--color-alpenrose), var(--color-alpenrose-dark));
}

.tile-card-booking .tile-card-image::before {
  background:
    radial-gradient(130% 130% at 14% -14%, rgba(var(--color-gold-light-rgb), 0.22) 0%, rgba(var(--color-gold-light-rgb), 0) 55%),
    linear-gradient(160deg, var(--color-enzian), var(--color-enzian-dark));
}

/* Route-planning tiles on the Anreise page have no photo/banner at all —
   just the plain card background with a flat tile-mark icon, same as any
   other icon+text row in tile-card-body. */
.tile-card-route .tile-card-body {
  min-height: 0;
}

/* Airbnb / Booking.com wordmark, centered on the gradient banner above. */
.tile-card-logo {
  position: absolute;
  inset: 0;
  z-index: 1;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  color: var(--color-white);
}

.tile-card-logo svg {
  width: 34px;
  height: 34px;
  flex-shrink: 0;
}

.tile-card-logo-text {
  font-family: var(--font-body);
  font-size: 1.65rem;
  font-weight: 600;
  letter-spacing: -0.01em;
}

@media (max-width: 380px) {
  .tile-card-logo-text {
    font-size: 1.35rem;
  }
}

/* Tile mark — thin-line square, sits in the light body text, not on the photo.
   min-height keeps the white area a consistent height across tiles whose
   description wraps to a different number of lines. */
.tile-card .tile-card-body {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 0.9rem;
  padding: 1.1rem 1.1rem 1.2rem;
  min-height: 6.75rem;
  text-align: left;
}

.tile-mark {
  position: relative;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  border-radius: 12px;
  border: 2px solid var(--color-gold-light);
  background-color: transparent;
  color: var(--color-gold-light);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.25s ease, background-color 0.25s ease, color 0.25s ease;
}

.tile-card:hover .tile-mark {
  border-color: var(--color-gold);
  color: var(--color-gold);
}

.tile-grid-compact .tile-card:hover .tile-mark {
  color: var(--color-gold-deep);
}

.tile-mark svg {
  width: 22px;
  height: 22px;
  transition: transform 0.5s ease;
}

/* _TileIcon (viewBox 64, stroke-width 5) wird in drei Größen eingesetzt
   (22 / 26 / 35 px). Ohne Ausgleich wirken die Linien dadurch unterschiedlich
   dick — hier auf ~2 px effektive Strichstärke normiert. */
.tile-mark svg { stroke-width: 5.8; }
.ablauf-item-marker svg { stroke-width: 4.9; }
.content-hero-icon svg { stroke-width: 4.1; }

.tile-card:hover .tile-mark svg {
  transform: rotate(-14deg);
}

.tile-card-body-text h3 {
  margin-bottom: 0;
  letter-spacing: 0.01em;
  transition: color 0.35s ease, letter-spacing 0.35s ease;
}

.tile-card:hover .tile-card-body-text h3 {
  color: var(--color-gold-deep);
  letter-spacing: 0.05em;
}

.tile-card-body-text p {
  color: var(--color-muted);
  font-size: 0.9rem;
  margin: 0.35rem 0 0;
}

.tile-card-feature .tile-card-image {
  min-height: 336px;
}

/* Feature tiles get a taller photo only in the desktop grid, where the wider
   column already sets them apart. Stacked single-column below 992px (siehe
   .tile-grid-Breakpoint oben), that height difference just reads as an
   inconsistent list. */
@media (max-width: 991.98px) {
  .tile-card-feature .tile-card-image {
    min-height: 216px;
  }
}

/* ---------- V5-Kacheln — nur Startseiten-Grid ----------
   Foto schrumpft zum schmalen Banner, der weiße Body führt: Icon als
   Haarlinien-Marke auf Titelhöhe, große Marcellus-Überschrift, eine Zeile
   Text, "Ansehen →" als CTA unten. Greift ausschließlich in .tile-grid
   OHNE .tile-grid-compact — die Anreise- und Übernachtungs-Kacheln
   (kompaktes Grid) behalten ihr bisheriges Layout unverändert.
   Kein Markup-Eingriff: .tile-card-body-text wird per display:contents
   aufgelöst, damit Marke und *nur* der Titel eine Zeile bilden und die
   Beschreibung darunter über die volle Breite läuft. */

/* Zeilen wachsen mit dem Inhalt (kein 20rem-Mindestmaß mehr). Dadurch
   bleibt der Body kompakt und die CTA sitzt direkt unter dem Text —
   überschüssige Zeilenhöhe (z.B. neben der hohen row-2-Kachel) wandert
   ins Foto, nicht als Leerraum in den Body. */
.tile-grid:not(.tile-grid-compact) {
  grid-auto-rows: auto;
}

.tile-grid:not(.tile-grid-compact) .tile-card-image {
  flex: 1 1 auto;
  min-height: 150px;
}

/* Feature-, Hoch- (row-2) und Vollbreiten-Kacheln: etwas höheres
   Mindest-Banner, damit die visuelle Hierarchie des Rasters erhalten bleibt. */
.tile-grid:not(.tile-grid-compact) .tile-card-feature .tile-card-image,
.tile-grid:not(.tile-grid-compact) .tile-row-2 .tile-card-image,
.tile-grid:not(.tile-grid-compact) .tile-col-12 .tile-card-image {
  min-height: 180px;
}

.tile-grid:not(.tile-grid-compact) .tile-card-body {
  display: grid;
  grid-template-columns: auto 1fr;
  column-gap: 0.7rem;
  row-gap: 0.5rem;
  align-items: center;
  flex: 0 0 auto;
  padding: 1.3rem 1.35rem 1.4rem;
}

.tile-grid:not(.tile-grid-compact) .tile-card-body-text {
  display: contents;
}

.tile-grid:not(.tile-grid-compact) .tile-mark {
  grid-column: 1;
  grid-row: 1;
  width: 30px;
  height: 30px;
  border: none;
  border-bottom: 2px solid var(--color-gold-light);
  border-radius: 0;
  padding-bottom: 2px;
  color: var(--color-gold-deep);
  transition: border-color 0.25s ease, color 0.25s ease;
}

.tile-grid:not(.tile-grid-compact) .tile-mark svg {
  width: 22px;
  height: 22px;
}

.tile-grid:not(.tile-grid-compact) .tile-card:hover .tile-mark {
  border-color: var(--color-gold);
  color: var(--color-gold-deep);
}

.tile-grid:not(.tile-grid-compact) .tile-card:hover .tile-mark svg {
  transform: none;
}

.tile-grid:not(.tile-grid-compact) .tile-card-body-text h3 {
  grid-column: 2;
  grid-row: 1;
  align-self: center;
  margin: 0;
  font-family: var(--font-heading);
  font-size: 1.5rem;
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--color-loden-dark);
}

.tile-grid:not(.tile-grid-compact) .tile-card:hover .tile-card-body-text h3 {
  color: var(--color-gold-deep);
  letter-spacing: 0.01em;
}

.tile-grid:not(.tile-grid-compact) .tile-card-body-text p {
  grid-column: 1 / -1;
  grid-row: 2;
  margin: 0;
  color: var(--color-muted);
  font-size: 0.9rem;
  line-height: 1.4;
}

/* CTA ohne Markup: Pseudo-Element direkt unter der Beschreibung. */
.tile-grid:not(.tile-grid-compact) .tile-card-body::after {
  content: "Ansehen →";
  grid-column: 1 / -1;
  margin-top: 0.35rem;
  padding-top: 0.5rem;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.8rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-gold-deep);
  transition: transform 0.3s ease;
}

.tile-grid:not(.tile-grid-compact) .tile-card:hover .tile-card-body::after {
  transform: translateX(4px);
}

/* Mobile has no :hover — highlight whichever tile is currently centered
   while scrolling instead (see tile-scroll-active.js). Same visual result
   as the hover rules above, just driven by .is-active rather than :hover.
   991.98px, damit das Tablet-Hochformat (stacked layout, s.o.) dieselbe
   Touch-Logik wie das Smartphone bekommt. */
@media (max-width: 991.98px) {
  .tile-grid:not(.tile-grid-compact) .tile-card.is-active .tile-card-image::before {
    transform: scale(1.1);
  }

  .tile-grid:not(.tile-grid-compact) .tile-card.is-active .tile-mark {
    border-color: var(--color-gold);
    color: var(--color-gold-deep);
  }

  .tile-grid:not(.tile-grid-compact) .tile-card.is-active .tile-card-body-text h3 {
    color: var(--color-gold-deep);
  }

  .tile-grid:not(.tile-grid-compact) .tile-card.is-active .tile-card-body::after {
    transform: translateX(4px);
  }

  /* Namensfrage-Karte ist kein .tile-card, sondern .card-hochzeit.name-poll —
     bekommt dieselbe .is-active-Logik, gespiegelt aus deren :hover-Regeln.
     Wie die Kacheln ohne Schattenwechsel: nur der Kopf reagiert. */
  .tile-grid:not(.tile-grid-compact) .name-poll.is-active .card-lead h2 {
    color: var(--color-gold-deep);
  }

  /* Grundinfos-, Zusage- und Nachricht-Karte (oberhalb des Rasters, siehe
     Hover-Regeln bei .info-card/.rsvp-card/.message-card). */
  .info-card.is-active .card-lead h2,
  .rsvp-card.is-active .card-lead h2,
  .message-card.is-active .card-lead h2 {
    color: var(--color-gold-deep);
  }

  .info-card.is-active .card-lead .tile-mark,
  .rsvp-card.is-active .card-lead .tile-mark,
  .message-card.is-active .card-lead .tile-mark,
  .tile-grid:not(.tile-grid-compact) .name-poll.is-active .card-lead .tile-mark {
    border-color: var(--color-gold);
  }
}

/* Countdown-Kachel: kein Foto, keine Verlinkung — reiner Infotext im
   Kachel-Stil, ersetzt den bisherigen Countdown-Badge im Kopfbereich. */
.tile-card-countdown {
  cursor: default;
}

.tile-grid:not(.tile-grid-compact) .tile-card-countdown .tile-card-body::after {
  content: none;
}

.tile-card-countdown-figure {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  padding: 0 1.35rem 1.6rem;
  text-align: center;
}

.tile-card-countdown-number {
  display: inline-block;
  font-family: var(--font-heading);
  font-size: clamp(3rem, 7vw, 4.5rem);
  line-height: 1;
  color: var(--color-gold-deep);
  transition: transform 0.25s ease;
}

.tile-card-countdown:hover .tile-card-countdown-number,
.tile-card-countdown:active .tile-card-countdown-number {
  transform: scale(1.08);
}

.tile-card-countdown-label {
  font-size: 0.9rem;
  color: var(--color-muted);
}

/* Kontakt-Kachel: wie die Countdown-Kachel ohne Foto und ohne Verlinkung der
   ganzen Fläche – anklickbar sind nur die Telefon- und Mail-Zeilen. */
.tile-card-kontakt {
  cursor: default;
}

.tile-grid:not(.tile-grid-compact) .tile-card-kontakt .tile-card-body::after {
  content: none;
}

/* auto-fit: nebeneinander, solange beide Spalten mindestens 16rem breit
   bleiben – darunter (Handy, gestapeltes Raster) untereinander. */
.tile-card-kontakt-people {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1.2rem 2rem;
  padding: 0 1.35rem 1.6rem;
}

.tile-card-kontakt-person {
  display: flex;
  flex-direction: column;
  gap: 0.45rem;
}

.tile-card-kontakt-name {
  font-family: var(--font-heading);
  font-size: 1.15rem;
  color: var(--color-gold-deep);
}

.tile-card-kontakt-line {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  font-size: 0.95rem;
  color: var(--color-ink);
  text-decoration: none;
  /* Die Mail-Adressen sind länger als eine Handy-Spalte breit ist. */
  overflow-wrap: anywhere;
  transition: color 0.25s ease;
}

.tile-card-kontakt-line:hover,
.tile-card-kontakt-line:focus-visible {
  color: var(--color-gold-deep);
  text-decoration: underline;
}

.tile-card-kontakt-line-icon {
  display: flex;
  width: 18px;
  height: 18px;
  flex-shrink: 0;
  color: var(--color-gold);
}

/* stroke-width wie bei .tile-mark auf ~2 px effektive Strichstärke normiert
   (viewBox 64 bei 18 px Darstellung, siehe Block bei .tile-mark svg). */
.tile-card-kontakt-line-icon svg {
  width: 100%;
  height: 100%;
  stroke-width: 7.1;
}

.badge-alpenrose {
  background-color: var(--color-alpenrose-dark);
  color: var(--color-white);
}

/* ---------- Couple photo header ---------- */

.couple-header {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  margin-bottom: clamp(3rem, 8vw, 6rem);
  overflow: hidden;
  /* Exakt die sichtbare Bildschirmhöhe - Desktop, iPad (hoch wie quer) und
     iPhone gleichermaßen, siehe --viewport-height. min-height statt height,
     damit der Header auf sehr flachen Displays mitwachsen darf, statt Logo
     und Titel abzuschneiden. */
  min-height: var(--viewport-height);
  display: flex;
  align-items: center;
  justify-content: center;
}

/* iPhone (Hochformat): iOS Safari zeichnet hinter seiner halbtransparenten
   Tab-Leiste am unteren Rand den Seiteninhalt, der unterhalb von 100dvh
   liegt - die Leiste zählt nicht zum Viewport. Endet der Header exakt bei
   100dvh, scheint dort der cremefarbene Seitenhintergrund durch und das
   Titelbild wirkt abgeschnitten. Deshalb wird der Header um die Leistenhöhe
   verlängert ("Bottom-Bleed"), das Foto läuft hinter der Leiste weiter.
   Das padding-bottom hält Logo/Titel weiterhin im sichtbaren Bereich
   zentriert, der Scroll-Pfeil rückt um denselben Betrag nach oben. */
@media (max-width: 767.98px) {
  .couple-header {
    --safari-bottom-bleed: 100px;
    min-height: calc(var(--viewport-height) + var(--safari-bottom-bleed));
    padding-bottom: var(--safari-bottom-bleed);
  }
}

/* Flache Displays (iPhone im Querformat, kleines Browserfenster): Inhalt
   kompakter, damit Logo, Titel und Datum zusammen auf den Bildschirm passen
   und der Header nicht über die Viewporthöhe hinauswächst. */
@media (orientation: landscape) and (max-height: 560px) {
  .couple-header-content {
    padding: 1.25rem;
  }

  .couple-header-content .couple-header-crest {
    width: clamp(88px, 20vh, 150px);
    height: clamp(88px, 20vh, 150px);
    margin: 0.4rem 0;
  }

  .couple-header-content h1 {
    font-size: clamp(1.8rem, 7vh, 2.8rem);
  }

  .couple-header-divider {
    width: min(320px, 70%);
    margin: 0.2rem 0 0.6rem;
  }

  .couple-header-sub {
    font-size: 0.95rem;
  }

  .couple-header-scroll-cue {
    display: none;
  }
}

.couple-header-photo {
  position: absolute;
  inset: 0;
  overflow: hidden;
}

/* Gleicher Ken-Burns-Effekt wie auf dem Titelbild der Anmeldeseite
   (siehe .login-split-photo img / @keyframes title-photo-drift). */
.couple-header-photo img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform-origin: 50% 50%;
  animation: title-photo-drift 24s ease-in-out infinite alternate;
  will-change: transform;
}

.couple-header::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(var(--color-navy-rgb), 0.55) 0%, rgba(var(--color-navy-rgb), 0.4) 45%, rgba(var(--color-navy-rgb), 0.65) 100%);
}

.couple-header-content {
  position: relative;
  z-index: 1;
  color: var(--color-ivory);
  padding: 2rem;
  width: 100%;
  max-width: 720px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}

.couple-header-content h1 {
  color: var(--color-ivory);
  font-size: clamp(2.4rem, 6vw, 4rem);
  margin-bottom: 0.5rem;
  opacity: 0;
  animation: couple-header-fade-up 1s ease 0.35s both;
}

.couple-header-content .couple-header-crest {
  width: clamp(140px, 22vw, 220px);
  height: clamp(140px, 22vw, 220px);
  object-fit: cover;
  margin: 1.5rem 0;
  opacity: 0;
  animation: couple-header-fade-up 1s ease 0.2s both;
}

.couple-header-divider {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(420px, 82%);
  margin: 0.4rem 0 1.1rem;
}

.couple-header-ornament {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.couple-header-ornament-stroke {
  fill: none;
  stroke: var(--color-gold-crest);
  stroke-width: 2.4;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
  animation: couple-header-ornament-draw 1.7s cubic-bezier(0.22, 0.9, 0.32, 1) 0.9s both;
}

.couple-header-ornament-leaf {
  animation-duration: 1.1s;
  animation-delay: 1.3s;
}

@keyframes couple-header-ornament-draw {
  to {
    stroke-dashoffset: 0;
  }
}

.couple-header-divider-spark {
  position: absolute;
  left: 50%;
  top: 50%;
  z-index: 1;
  width: 8px;
  height: 8px;
  margin: -4px 0 0 -4px;
  border-radius: 50%;
  background: var(--color-gold-crest);
  opacity: 0;
  transform: scale(0);
  animation: couple-header-divider-spark 0.9s ease 2.55s both;
}

@keyframes couple-header-divider-spark {
  0% {
    opacity: 0;
    transform: scale(0);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-gold-crest) 0%, transparent);
  }
  30% {
    opacity: 1;
    transform: scale(2.2);
    box-shadow: 0 0 18px 6px color-mix(in srgb, var(--color-gold-crest) 65%, transparent);
  }
  70% {
    opacity: 0.9;
    transform: scale(1);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-gold-crest) 0%, transparent);
  }
  100% {
    opacity: 0;
    transform: scale(0.6);
    box-shadow: 0 0 0 0 color-mix(in srgb, var(--color-gold-crest) 0%, transparent);
  }
}

.couple-header-sub {
  font-size: 1.1rem;
  opacity: 0;
  margin-bottom: 0;
  animation: couple-header-fade-up-sub 1s ease 2.7s both;
}

@keyframes couple-header-fade-up {
  from {
    opacity: 0;
    transform: translateY(22px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes couple-header-fade-up-sub {
  from {
    opacity: 0;
    transform: translateY(22px);
  }
  to {
    opacity: 0.9;
    transform: translateY(0);
  }
}

.couple-header-scroll-cue {
  position: absolute;
  left: 50%;
  /* Home-Indicator/Adressleiste einrechnen (viewport-fit=cover), sonst sitzt
     der Pfeil auf dem iPhone unter der Systemleiste. */
  bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
  z-index: 1;
  display: inline-flex;
  padding: 0.5rem;
  color: var(--color-ivory);
  text-decoration: none;
  opacity: 0;
  animation: couple-header-scroll-cue-in 1s ease 0.9s both;
  transition: color 0.2s ease;
}

/* Auf dem iPhone um den Bottom-Bleed des Headers nach oben rücken, damit
   der Pfeil nicht hinter der Safari-Tab-Leiste verschwindet. */
@media (max-width: 767.98px) {
  .couple-header-scroll-cue {
    bottom: calc(2rem + env(safe-area-inset-bottom, 0px) + var(--safari-bottom-bleed, 0px));
  }
}

.couple-header-scroll-cue:hover,
.couple-header-scroll-cue:focus-visible {
  color: var(--color-gold-light);
}

.couple-header-scroll-cue-icon {
  display: block;
  filter: drop-shadow(0 2px 4px rgba(0, 0, 0, 0.35));
  animation: couple-header-bounce 1.8s ease-in-out 1.9s infinite;
}

@keyframes couple-header-scroll-cue-in {
  from {
    opacity: 0;
    transform: translate(-50%, 14px);
  }
  to {
    opacity: 0.85;
    transform: translate(-50%, 0);
  }
}

@keyframes couple-header-bounce {
  0%, 100% {
    transform: translateY(0);
  }
  50% {
    transform: translateY(8px);
  }
}

/* ---------- Hero-System „Aurora" (seit 18.09.2026) ----------

   Eine Fläche für alle Heros (Willkommen mit Foto, Content-/Admin-Seiten mit
   Icon): Navy mit zwei weichen Lichtflecken – Loden oben rechts, Gold unten
   links – statt des früheren Diagonal-Verlaufs, darüber feines Korn aus einem
   feTurbulence-SVG, damit die Fläche nicht glatt wirkt. Verbindendes Element
   auf der Willkommensseite das „Siegel" (.hero-seal): Kreis mit Haarlinie
   auf Abstand fürs Foto; die Content-Heros tragen ihr Icon als
   Haarlinien-Marke wie die Karten-Köpfe.
   Vorschau/Entscheidung: https://claude.ai/artifact/JZ8THf97g9qTNLgXZzAg37
   Snapshot davor: design-versionen/2026-09-18-aurora-hero/ (drehende
   Goldringe, Icon-Unterstrich-Marke, Hover-Letter-Spacing). */

/* Die Mittelpunkte der beiden Lichtflecken sind registrierte Custom
   Properties, damit der Browser sie interpolieren kann (Verlaufs-Positionen
   sind sonst nicht animierbar). Ohne @property-Unterstützung bleiben die
   Startwerte stehen – die Animation ist unten per @supports gekapselt. */
@property --hero-glow-x { syntax: "<percentage>"; inherits: false; initial-value: 90%; }
@property --hero-glow-y { syntax: "<percentage>"; inherits: false; initial-value: 0%; }
@property --hero-gold-x { syntax: "<percentage>"; inherits: false; initial-value: 6%; }
@property --hero-gold-y { syntax: "<percentage>"; inherits: false; initial-value: 100%; }

.hero-panel,
.content-hero {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  color: var(--color-ivory);
  background:
    radial-gradient(60% 120% at var(--hero-glow-x) var(--hero-glow-y), rgba(var(--color-loden-rgb), 0.5) 0%, rgba(var(--color-loden-rgb), 0) 62%),
    radial-gradient(50% 110% at var(--hero-gold-x) var(--hero-gold-y), rgba(var(--color-gold-light-rgb), 0.26) 0%, rgba(var(--color-gold-light-rgb), 0) 60%),
    var(--color-navy);
  border-radius: var(--radius-organic);
  box-shadow:
    var(--shadow-soft),
    inset 0 0 0 1px rgba(var(--color-gold-light-rgb), 0.3);
}

/* Lichtflecken wandern langsam (22 s hin, 22 s zurück) – der Loden-Fleck
   von oben rechts bis über die Mitte, der Gold-Fleck von unten links bis
   in die rechte Hälfte; der Loden-Fleck ist dafür in der Mitte gedämpft
   (0.5 statt 0.75), sonst überstrahlt er den Text. Bei prefers-reduced-motion greift die globale
   Abschaltung am Dateiende. Der @supports-Test steht stellvertretend für
   @property-Unterstützung (gleiche Browser-Generation); ohne ihn würde der
   Wert in alten Browsern bei 50 % hart springen. */
@supports (color: color-mix(in srgb, red, blue)) {
  .hero-panel,
  .content-hero {
    animation: hero-aurora 22s ease-in-out infinite alternate;
  }
}

@keyframes hero-aurora {
  from {
    --hero-glow-x: 90%;
    --hero-glow-y: 0%;
    --hero-gold-x: 6%;
    --hero-gold-y: 100%;
  }
  to {
    --hero-glow-x: 40%;
    --hero-glow-y: 60%;
    --hero-gold-x: 60%;
    --hero-gold-y: 30%;
  }
}

/* Korn: liegt per z-index -1 unter dem Inhalt, aber (dank isolation) über
   dem Hintergrund der Fläche. */
.hero-panel::after,
.content-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.07;
  mix-blend-mode: soft-light;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.hero-panel h1, .hero-panel h2,
.content-hero h1 {
  color: var(--color-ivory);
  margin: 0;
  line-height: 1.12;
  text-wrap: balance;
}

.hero-panel p,
.content-hero p {
  margin: 0;
  color: rgba(var(--color-ivory-rgb), 0.84);
}

/* Siegel – Kreis mit Haarlinie auf Abstand, dieselbe Form wie Avatare und
   die Medaillon-Marken der Abschnittsüberschriften (kein abgerundetes
   Quadrat, das wäre die einzige Fremdform auf der Seite). Größe setzt der
   Verwender (.hero-panel-photo). */
.hero-seal {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: 50%;
  outline: 1px solid rgba(var(--color-gold-light-rgb), 0.6);
  outline-offset: 6px;
  color: var(--color-gold-light);
  transition: outline-color 0.3s ease;
}

.hero-panel:hover .hero-seal {
  outline-color: var(--color-gold-light);
}

.hero-seal img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: 55% 35%;
  border-radius: inherit;
  display: block;
}

/* ---------- Willkommen: Foto-Siegel + Begrüßung ---------- */

.hero-panel {
  scroll-margin-top: 6rem;
  padding: 2.75rem 3rem;
}

.hero-panel-with-photo {
  display: flex;
  align-items: center;
  gap: 2.1rem;
}

.hero-panel-photo {
  width: 104px;
  height: 104px;
}

.hero-panel-body {
  display: grid;
  gap: 0.55rem;
  min-width: 0;
}

/* „Hallo" als Eyebrow über den Namen – Jost, gesperrt, Gold. */
.hero-panel-hallo {
  display: block;
  font-family: var(--font-body);
  font-size: 1.55rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--color-gold-light);
  margin-bottom: 0.4rem;
}

.hero-panel h1 {
  font-size: clamp(2.1rem, 4.6vw, 3.1rem);
}

.hero-panel-body p {
  font-size: 1.08rem;
}

/* Begrüßung kommt als Markdown (ggf. mehrere Absätze). */
.hero-panel-body p + p {
  margin-top: 0.6rem;
}

@media (max-width: 575.98px) {
  .hero-panel {
    padding: 1.9rem 1.4rem;
  }

  /* Mobil gestapelt und zentriert – Foto über dem Text, wie ein Medaillon. */
  .hero-panel-with-photo {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 1.5rem;
  }

  .hero-panel-body {
    justify-items: center;
  }

  .hero-panel-photo {
    width: 96px;
    height: 96px;
  }

}

/* ---------- Content page hero (Ablauf, Anreise, Übernachtung, Locations, Fotos, Forum, Admin) ---------- */

/* Grid statt Flex: .content-hero-text löst sich per display:contents auf,
   damit Icon und h1 in derselben Zeile mittig zueinander stehen (wie
   .card-lead) und der Untertitel darunter in der Textspalte beginnt. Die
   Gruppe steht mittig in der Fläche (justify-content), der Text selbst
   bleibt linksbündig; minmax(0, max-content) lässt lange Thread-Titel
   umbrechen statt die Fläche zu sprengen. */
.content-hero {
  padding: 2.1rem 2.5rem;
  margin-bottom: 2rem;
  display: grid;
  grid-template-columns: auto minmax(0, max-content);
  justify-content: center;
  align-items: center;
  column-gap: 1.1rem;
  row-gap: 0.3rem;
  text-align: left;
}

.content-hero-text {
  display: contents;
}

/* Icon als Haarlinien-Marke (Icon + Gold-Unterstrich) wie in den
   Karten-Köpfen (.card-lead .tile-mark), nur größer. Das Siegel
   (.hero-seal) trägt nur das Foto. */
.content-hero-icon {
  grid-column: 1;
  grid-row: 1;
  align-self: center;
  width: 44px;
  border-bottom: 2px solid var(--color-gold-light);
  padding-bottom: 3px;
  color: var(--color-gold-light);
  display: flex;
  justify-content: center;
  transition: border-color 0.25s ease;
}

.content-hero:hover .content-hero-icon {
  border-color: var(--color-gold);
}

.content-hero-icon svg {
  width: 32px;
  height: 32px;
}

.content-hero h1 {
  grid-column: 2;
  font-size: clamp(1.6rem, 3.4vw, 2.2rem);
  min-width: 0;
}

.content-hero p {
  grid-column: 2;
  max-width: 38rem;
}

/* Mobile: Siegel bleibt neben dem Titel (48 px), lange Titel brechen um. */
@media (max-width: 575.98px) {
  .content-hero {
    padding: 1.5rem 1.4rem;
    column-gap: 0.85rem;
  }

  .content-hero-icon {
    width: 38px;
  }

  .content-hero-icon svg {
    width: 26px;
    height: 26px;
  }
}


/* ---------- Content body typography ---------- */

/* Ersetzt Bootstraps fs-5 auf den Inhaltskarten: 1,25 rem sind auf dem
   Handy zu groß (fünf Wörter pro Zeile), ab Tablet-Breite bleibt die
   gewohnte Größe. */
.content-text {
  font-size: 1.05rem;
}

@media (min-width: 768px) {
  .content-text {
    font-size: 1.25rem;
  }
}

/* Lead-Absatz einer Inhaltskarte (Anreise): Einleitung oberhalb der
   Abschnitte, mit Haarlinie als Abschluss statt eigener Karte. */
.content-lead {
  padding-bottom: 1.25rem;
  margin-bottom: 1.75rem;
  border-bottom: 1px solid var(--color-ivory-dark);
}

.content-lead p:last-child {
  margin-bottom: 0;
}

.content-body h2,
.content-body h3 {
  margin-top: 2rem;
  margin-bottom: 0.75rem;
}

.content-body h2:first-child,
.content-body h3:first-child {
  margin-top: 0;
}

.content-body p {
  margin-bottom: 1.1rem;
}

.content-body p:last-child {
  margin-bottom: 0;
}

.content-body ul,
.content-body ol {
  margin-bottom: 1.1rem;
  padding-left: 1.4rem;
}

.content-body li {
  margin-bottom: 0.4rem;
}

.content-body a {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, var(--color-gold) 40%, transparent);
  text-underline-offset: 3px;
}

.content-body a:hover {
  text-decoration-color: var(--color-gold);
}

.content-body blockquote {
  border-left: 3px solid var(--color-gold);
  padding-left: 1.1rem;
  margin: 1.5rem 0;
  color: var(--color-muted);
  font-style: italic;
}

.content-body img {
  max-width: 100%;
  border-radius: var(--radius-soft);
}

/* Section heading with a flat tile-mark icon (Anreise page), instead of an
   emoji baked into the markdown text. */
/* Variante "Medaillon" (Review 18.09.2026): Icon auf einem Elfenbein-Kreis
   mit feinem Goldring – ein leiser Verwandter der Ablauf-Timeline-Marker –,
   größerer Titel und eine nach rechts auslaufende Goldlinie. Dadurch setzt
   sich die Überschrift deutlich vom 1,25-rem-Fließtext ab. */
.content-section-heading {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  margin-top: 2.6rem;
  margin-bottom: 1rem;
}

.content-section-heading:first-child {
  margin-top: 0;
}

.content-section-heading::after {
  content: "";
  flex: 1 1 24px;
  min-width: 24px;
  height: 1px;
  background: linear-gradient(90deg, var(--color-gold-light), rgba(var(--color-gold-light-rgb), 0));
}

.content-section-heading h2 {
  margin: 0;
  font-size: 1.35rem;
  /* Marcellus gibt es nur in 400 – ein höherer Wert würde vom Browser
     künstlich fett gerechnet. */
  font-weight: 400;
  line-height: 1.15;
  letter-spacing: 0.02em;
  color: var(--color-loden-dark);
}

.content-section-heading .tile-mark {
  width: 38px;
  height: 38px;
  border: none;
  border-radius: 50%;
  padding: 0;
  background-color: var(--color-ivory);
  box-shadow: inset 0 0 0 1px var(--color-gold-light);
  color: var(--color-gold-deep);
}

.content-section-heading .tile-mark svg {
  width: 19px;
  height: 19px;
  stroke-width: 5.4;
}

/* Ist die Abschnittsüberschrift das erste Kind einer Karte, ist sie deren
   Kopf (Locations-Karten, Inhaltskarte auf Übernachtung/Ablauf) und reagiert
   auf den Karten-Hover wie .card-lead auf der Startseite: Titel in Gold-tief,
   Medaillon-Ring in Gold. Weitere Überschriften in derselben Karte (und die
   Abschnitte der Grundinfos-Karte hinter dem .card-lead) bleiben ruhig. */
.content-section-heading:first-child h2 {
  transition: color 0.35s ease;
}

.content-section-heading:first-child .tile-mark {
  transition: box-shadow 0.25s ease;
}

.card-hochzeit:hover > .content-section-heading:first-child h2 {
  color: var(--color-gold-deep);
}

.card-hochzeit:hover > .content-section-heading:first-child .tile-mark {
  box-shadow: inset 0 0 0 1px var(--color-gold);
}

@media (max-width: 575.98px) {
  .content-section-heading {
    gap: 0.75rem;
    margin-top: 2.2rem;
  }

  .content-section-heading::after {
    display: none;
  }

  .content-section-heading h2 {
    font-size: 1.2rem;
  }

  .content-section-heading .tile-mark {
    width: 34px;
    height: 34px;
  }
}

/* Haarlinien-Marke wie in den V5-Kacheln für Karten-Köpfe (.card-lead) und
   Kompakt-Kacheln; Abschnittsüberschriften nutzen das Medaillon (oben).
   Bewusst auf .tile-card eingeschränkt: Die Locations-Karten liegen zwar im
   Kompakt-Raster, tragen aber eine .content-section-heading als Kopf und
   sollen aussehen wie die Abschnitte der Grundinfos-Karte. */
.tile-grid-compact .tile-card .tile-mark,
.info-card .card-lead .tile-mark,
.rsvp-card .card-lead .tile-mark,
.message-card .card-lead .tile-mark,
.name-poll .card-lead .tile-mark {
  width: 30px;
  height: 30px;
  border: none;
  border-bottom: 2px solid var(--color-gold-light);
  border-radius: 0;
  padding-bottom: 2px;
  color: var(--color-gold-deep);
}

.tile-grid-compact .tile-card .tile-mark svg,
.info-card .card-lead .tile-mark svg,
.rsvp-card .card-lead .tile-mark svg,
.message-card .card-lead .tile-mark svg,
.name-poll .card-lead .tile-mark svg {
  width: 22px;
  height: 22px;
}

/* Externer-Link-Pfeil (statt Unicode "↗", das in Marcellus zu dünn und zu
   tief sitzt): kleines SVG in Gold, an der Schrift ausgerichtet. */
.ext-arrow {
  display: inline-block;
  width: 0.7em;
  height: 0.7em;
  margin-left: 0.2em;
  vertical-align: 0.05em;
  color: var(--color-gold-deep);
  flex-shrink: 0;
}

.content-body hr {
  border: none;
  border-top: 1px solid var(--color-ivory-dark);
  margin: 2rem 0;
}

/* ---------- Ablauf timeline ---------- */
/* Each item carries its own --accent custom property so the marker, time
   pill and hover states can all reference one color — the same gold as
   badge-gold (Buttons sind seit 18.09.2026 Loden). */

.ablauf-timeline {
  position: relative;
  padding: 0.5rem 0;
  /* Auf Desktop nicht über die volle Containerbreite: der Text nutzt
     ohnehin nur die linke Hälfte, vollbreite Karten wirken wie eine
     Tabelle. Zentriert, mit Marker/Linie weiterhin links. */
  max-width: 820px;
  margin-left: auto;
  margin-right: auto;
}

/* Die Einleitungskarte über der Timeline bekommt dieselbe Breite, damit
   beide eine gemeinsame Spalte bilden. */
.ablauf-intro {
  max-width: 820px;
  margin-left: auto;
  margin-right: auto;
}

.ablauf-timeline::before {
  content: "";
  position: absolute;
  top: 28px;
  bottom: 28px;
  left: 27px;
  width: 2px;
  background: linear-gradient(180deg, var(--color-gold-light), var(--color-gold) 50%, var(--color-gold-light));
  opacity: 0.6;
}

.ablauf-item {
  --accent: var(--color-gold-deep);
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 1.25rem;
  padding-bottom: 2rem;
}

.ablauf-item:last-child {
  padding-bottom: 0;
}

.ablauf-item-marker {
  position: relative;
  z-index: 1;
  flex-shrink: 0;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background-color: var(--color-white);
  border: 2px solid var(--accent);
  color: var(--accent);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-soft);
  transition: background-color 0.35s ease, color 0.35s ease, transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s ease;
}

/* Ring that blooms outward from the marker on hover, echoing the pulsing
   badge-glow used on the couple-header date badge. */
.ablauf-item-marker::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1px solid var(--accent);
  opacity: 0;
  transform: scale(0.75);
  transition: opacity 0.35s ease, transform 0.35s ease;
  pointer-events: none;
}

.ablauf-item-marker svg {
  width: 26px;
  height: 26px;
  transition: transform 0.5s ease;
}

.ablauf-item-card {
  flex: 1;
  min-width: 0;
  background-color: var(--color-white);
  border: 1px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic);
  padding: 1rem 1.35rem;
  box-shadow: var(--shadow-soft);
  transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.3s ease, border-color 0.3s ease;
}

.ablauf-item:hover .ablauf-item-card,
.ablauf-item:focus-within .ablauf-item-card {
  transform: translateY(-6px);
  box-shadow: 0 20px 42px -16px rgba(var(--shadow-rgb), 0.38);
  border-color: var(--accent);
}

.ablauf-item:hover .ablauf-item-marker,
.ablauf-item:focus-within .ablauf-item-marker {
  background-color: var(--accent);
  color: var(--color-white);
  transform: scale(1.08);
  box-shadow: 0 12px 26px -10px rgba(var(--shadow-rgb), 0.45);
}

.ablauf-item:hover .ablauf-item-marker svg,
.ablauf-item:focus-within .ablauf-item-marker svg {
  transform: rotate(-14deg) scale(1.05);
}

.ablauf-item:hover .ablauf-item-marker::after,
.ablauf-item:focus-within .ablauf-item-marker::after {
  opacity: 0.55;
  transform: scale(1);
}

.ablauf-item-time {
  display: inline-block;
  font-family: var(--font-heading);
  font-size: 0.78rem;
  letter-spacing: 0.08em;
  color: var(--color-white);
  background-color: var(--accent);
  padding: 0.3em 0.95em;
  border-radius: 999px;
  margin-bottom: 0.55rem;
  box-shadow: 0 6px 16px -8px rgba(var(--shadow-rgb), 0.4);
  transition: transform 0.3s ease;
}

.ablauf-item:hover .ablauf-item-time,
.ablauf-item:focus-within .ablauf-item-time {
  transform: translateY(-1px);
}

.ablauf-item-card h3 {
  margin: 0 0 0.35rem;
  font-size: 1.25rem;
  transition: color 0.3s ease, letter-spacing 0.3s ease;
}

.ablauf-item:hover .ablauf-item-card h3,
.ablauf-item:focus-within .ablauf-item-card h3 {
  color: var(--accent);
  letter-spacing: 0.02em;
}

.ablauf-item-card p {
  margin: 0;
  color: var(--color-muted);
}

/* Staggered entrance: each item observes independently (see scroll-reveal.js),
   but items that enter the viewport together should still cascade in rather
   than pop as a block. */
.ablauf-item:nth-child(1) { transition-delay: 0s; }
.ablauf-item:nth-child(2) { transition-delay: 0.08s; }
.ablauf-item:nth-child(3) { transition-delay: 0.16s; }
.ablauf-item:nth-child(4) { transition-delay: 0.24s; }
.ablauf-item:nth-child(5) { transition-delay: 0.32s; }
.ablauf-item:nth-child(n+6) { transition-delay: 0.4s; }

@media (max-width: 575.98px) {
  .ablauf-timeline::before {
    left: 21px;
  }

  .ablauf-item-marker {
    width: 44px;
    height: 44px;
  }

  .ablauf-item-marker svg {
    width: 20px;
    height: 20px;
  }

  .ablauf-item-card {
    padding: 0.85rem 1.1rem;
  }
}

/* ---------- Login page ---------- */
/* Save-the-Date-Split: Fotofläche + dunkles Panel mit dem runden
   24/April-2027-Badge, wie auf der Save-the-Date-Karte. */

.login-split {
  position: relative;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-right: calc(50% - 50vw);
  /* Foto + grüner Bereich füllen zusammen genau den sichtbaren Viewport
     (siehe --viewport-height). Der Footer liegt damit immer knapp unterhalb
     der Kante und wird erst beim Scrollen sichtbar. min-height statt height:
     passt der Inhalt bei sehr flachem Fenster nicht, wächst die Fläche lieber
     mit, als das Formular abzuschneiden. */
  min-height: var(--viewport-height);
  height: auto;
  display: flex;
  overflow: hidden;
  background-color: var(--color-navy);
}

.login-split-photo {
  position: relative;
  flex: 1 1 56%;
  min-height: 320px;
  /* Das Foto wird durch die Drift-Animation leicht größer als sein Rahmen –
     der Überstand darf nicht ins Panel ragen. */
  overflow: hidden;
}

.login-split-photo img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  /* Langsamer Ken-Burns-Effekt: das Bild zoomt über gut 20 Sekunden
     spürbar hinein und wandert dabei ein Stück nach links unten,
     dann ebenso langsam wieder zurück. Durch ease-in-out ist die Bewegung
     an den Umkehrpunkten fast null – erst nach ein paar Sekunden sichtbar. */
  transform-origin: 50% 50%;
  animation: title-photo-drift 24s ease-in-out infinite alternate;
  will-change: transform;
}

@keyframes title-photo-drift {
  from {
    transform: scale(1) translate3d(0, 0, 0);
  }
  to {
    transform: scale(1.16) translate3d(-3%, 2.2%, 0);
  }
}

.login-split-photo::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(200deg, rgba(var(--color-navy-rgb), 0.05) 0%, rgba(var(--color-navy-rgb), 0.32) 100%);
}

.login-split-panel {
  position: relative;
  flex: 1 1 44%;
  background-color: var(--color-navy);
  padding: 4rem;
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 1.6rem;
  color: var(--color-ivory);
}

.login-split-panel::before {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(120% 90% at 100% 0%, rgba(var(--color-loden-rgb), 0.35) 0%, rgba(var(--color-navy-rgb), 0) 60%);
  pointer-events: none;
}

.login-split-badge {
  align-self: flex-start;
  margin-bottom: 1.4rem;
  width: 124px;
  height: 124px;
  border-radius: 50%;
  border: 1.5px solid var(--color-gold-light);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.login-split-badge-day {
  font-family: var(--font-heading);
  font-size: 2.25rem;
  line-height: 1;
  color: var(--color-gold-crest);
}

.login-split-badge-rule {
  width: 22px;
  height: 1px;
  background: var(--color-gold-light);
  opacity: 0.65;
  margin: 0.35rem 0;
}

.login-split-badge-month,
.login-split-badge-year {
  font-family: var(--font-body);
  font-size: 0.66rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-ivory);
}

.login-split-badge-year {
  opacity: 0.75;
  margin-top: 0.1rem;
}

.login-split-eyebrow {
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--color-gold-light);
}

.login-split-title {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: clamp(2.4rem, 3.4vw, 3.4rem);
  line-height: 1.05;
  color: var(--color-ivory);
}

.login-split-title .login-title-amp {
  display: inline-block;
  color: var(--color-gold-crest);
  font-style: italic;
  font-size: 0.78em;
  margin: 0 0.16em;
  transform: rotate(-6deg);
}

.login-split-intro {
  margin: 0;
  max-width: 26rem;
  color: rgba(var(--color-ivory-rgb), 0.78);
  font-size: 0.95rem;
  line-height: 1.7;
}

.login-split-form {
  max-width: 22.5rem;
}

/* Fehlermeldung (falscher Code, zu viele Versuche, abgelaufene Seite): statt
   Bootstraps rosa Kasten eine zarte Alpenrosen-Tönung auf dem grünen Panel,
   Haarlinien-Rand und dieselbe Blattform wie die Zeilen im Rest der Seite. */
.login-split-form .alert-danger {
  margin: 0 0 1.25rem;
  padding: 0.75rem 1rem;
  background: color-mix(in srgb, var(--color-alpenrose) 18%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-alpenrose-light) 40%, transparent);
  border-radius: var(--radius-organic-sm);
  color: var(--color-ivory);
  font-family: var(--font-body);
  font-size: 0.9rem;
  line-height: 1.55;
}

.login-split-form .alert-danger ul {
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Die Unterstreichung des Eingabefelds greift die Fehlerfarbe auf, solange
   die Meldung steht. */
.login-split-form:has(.alert-danger li:not([style*="none"])) .login-split-field {
  border-color: var(--color-alpenrose-light);
}

.login-split-field {
  position: relative;
  border-bottom: 1px solid rgba(var(--color-gold-light-rgb), 0.5);
  transition: border-color 0.3s ease;
}

.login-split-field:focus-within {
  border-color: var(--color-gold-light);
}

.login-split-field input {
  width: 100%;
  height: 44px;
  background: transparent;
  border: none;
  outline: none;
  font-family: var(--font-body);
  font-size: 1.05rem;
  color: var(--color-ivory);
  padding: 0;
}

.login-split-field input::placeholder {
  color: rgba(var(--color-ivory-rgb), 0.5);
  opacity: 1;
}

.login-split-form .text-danger {
  display: block;
  margin-top: 0.5rem;
  font-size: 0.85rem;
  color: var(--color-alpenrose-light);
}

.login-split-submit {
  margin-top: 1.25rem;
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  background: none;
  border: none;
  color: var(--color-gold-light);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
  padding: 0.5rem 0;
  transition: color 0.2s ease, gap 0.2s ease;
}

.login-split-submit:hover,
.login-split-submit:focus-visible {
  color: var(--color-ivory);
  gap: 0.85rem;
}

@media (max-width: 767.98px) {
  .login-split {
    flex-direction: column;
    /* Titelbild + grüner Bereich nehmen zusammen exakt die sichtbare
       Bildschirmhöhe ein (siehe --viewport-height). */
    min-height: var(--viewport-height);
    height: auto;
  }

  /* Das Foto ist die nachgiebige Fläche: es startet bei gut einem Drittel
     der Bildschirmhöhe und gibt Platz ab (bis hinunter zu 120px), wenn das
     Formular darunter mehr braucht - etwa auf kleinen Displays oder bei
     eingeblendeter Fehlermeldung. Der grüne Bereich bleibt dadurch immer
     vollständig sichtbar. */
  .login-split-photo {
    flex: 0 1 auto;
    height: clamp(120px, calc(var(--viewport-height) * 0.36), 320px);
    min-height: 120px;
  }

  .login-split-panel {
    /* Wächst in den Rest des Viewports hinein (füllt also den Bildschirm
       aus), wird aber nie unter seine Inhaltshöhe gestaucht. */
    flex: 1 0 auto;
    justify-content: center;
    padding: 2.25rem 1.75rem calc(2rem + env(safe-area-inset-bottom, 0px));
    align-items: center;
    text-align: center;
    gap: 1.25rem;
  }

  .login-split-badge {
    order: 1;
    position: static;
    align-self: center;
    width: 104px;
    height: 104px;
  }

  .login-split-eyebrow {
    order: 2;
  }

  .login-split-title {
    order: 3;
    font-size: 2.35rem;
  }

  .login-split-intro {
    order: 4;
    max-width: 20rem;
  }

  .login-split-form {
    order: 5;
    width: 100%;
    max-width: 20rem;
  }

  .login-split-field input {
    text-align: center;
  }

  .login-split-submit {
    width: 100%;
    justify-content: center;
    height: 44px;
    padding: 0;
  }
}

/* Kurze Bildschirme im Hochformat (iPhone SE & Co.): Inhalt des grünen
   Bereichs straffen, damit Foto + Formular ohne Scrollen in die
   Viewporthöhe passen. */
@media (max-width: 767.98px) and (max-height: 700px) {
  .login-split-panel {
    padding: 1.75rem 1.5rem calc(1.5rem + env(safe-area-inset-bottom, 0px));
    gap: 0.9rem;
  }

  .login-split-badge {
    width: 84px;
    height: 84px;
    margin-bottom: 0.4rem;
  }

  .login-split-badge-day {
    font-size: 1.75rem;
  }

  .login-split-title {
    font-size: 2rem;
  }

  .login-split-intro {
    font-size: 0.88rem;
    line-height: 1.5;
  }

  .login-split-submit {
    margin-top: 0.75rem;
  }
}

/* iPhone im Querformat: gestapelt wäre hier nichts mehr zu sehen - Foto und
   grüner Bereich stehen nebeneinander, damit beides in die flache
   Viewporthöhe passt. */
@media (max-width: 991.98px) and (orientation: landscape) and (max-height: 560px) {
  .login-split {
    flex-direction: row;
  }

  .login-split-photo {
    flex: 1 1 42%;
    height: auto;
    min-height: 0;
  }

  .login-split-panel {
    flex: 1 1 58%;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.25rem max(1.25rem, env(safe-area-inset-right, 0px)) 1.25rem 1.25rem;
  }

  .login-split-badge {
    display: none;
  }

  .login-split-title {
    font-size: 1.9rem;
  }

  .login-split-intro {
    font-size: 0.85rem;
    line-height: 1.45;
    max-width: 24rem;
  }

  .login-split-submit {
    margin-top: 0.5rem;
  }
}

/* iPad im Hochformat: schmale Panelspalte, deshalb weniger Innenabstand,
   sonst wird der Text zwischen den 4rem-Rändern zerquetscht. */
@media (min-width: 768px) and (max-width: 991.98px) and (min-height: 561px) {
  .login-split-photo {
    flex: 1 1 46%;
  }

  .login-split-panel {
    flex: 1 1 54%;
    padding: 3rem 2.25rem;
  }

  .login-split-badge {
    width: 104px;
    height: 104px;
    margin-bottom: 1rem;
  }

  .login-split-title {
    font-size: 2.6rem;
  }
}

/* ---------- Scroll reveal ---------- */

[data-reveal] {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}

[data-reveal].is-visible {
  opacity: 1;
  transform: translateY(0);
}

@keyframes fade-in-up {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* ---------- Footer ---------- */

.footer-hochzeit {
  background-color: transparent;
  text-align: center;
}

/* Auf der Anmeldeseite tragen Seite und Dokument dieselbe Farbe wie der
   Login-Split: der Puffer unter der Fläche, ein eventueller Spalt während des
   Ein-/Ausfahrens der iOS-Adressleiste und das Gummiband-Overscroll am
   oberen Rand bleiben dadurch unsichtbar statt hell aufzublitzen.

   Ab genau der Stelle, an der der Puffer endet und der (cremefarbene) Footer
   beginnt - login-split-Höhe (--viewport-height) plus Pufferhöhe
   (--login-buffer, auf dem Desktop 0) - wechselt die Farbe auf dasselbe
   Creme wie der Footer. Ohne diesen Wechsel blitzt beim Gummiband-Overscroll
   unten (über das Dokumentende hinausziehen) das dunkle Navy/Grün direkt unter
   dem hellen Footer auf. */
html:has(main.page-content > .login-split),
body:has(main.page-content > .login-split) {
  background: linear-gradient(
    to bottom,
    var(--color-navy) 0,
    var(--color-navy) calc(var(--viewport-height) + var(--login-buffer)),
    var(--color-page) calc(var(--viewport-height) + var(--login-buffer))
  );
  /* Der background-Shorthand oben setzt background-color auf transparent
     zurück. iOS Safari nimmt aber genau die background-color von html/body
     für den Bereich unterhalb des Dokumentendes (hinter der Tab-Leiste und
     beim Overscroll) - ohne explizite Farbe wird der Streifen dort weiß
     statt footer-creme. */
  background-color: var(--color-page);
  background-repeat: no-repeat;
}

/* Auf der Anmeldeseite (Login-Split) bleibt der Footer-Hintergrund voll
   sichtbar, überall sonst ist er transparent. */
main.page-content:has(> .login-split) + .footer-hochzeit {
  background-color: var(--color-page);
}

.footer-hochzeit .footer-legal {
  padding: 0.65rem 0;
  font-size: 0.75rem;
}

.footer-hochzeit .footer-legal a {
  color: var(--color-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  display: inline-block;
  padding: 0.35rem 0.25rem;
}

.footer-hochzeit .footer-legal a:hover {
  color: var(--color-loden-dark);
}

.footer-hochzeit .footer-legal .footer-legal-sep {
  margin: 0 0.5rem;
  opacity: 0.6;
}

/* ---------- Locked state (Fotos) ---------- */

.locked-panel {
  text-align: center;
  padding: 3.5rem 1.5rem;
  background: var(--color-white);
  border: 1px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic);
  box-shadow: var(--shadow-soft);
}

.locked-panel .lock-icon {
  width: 56px;
  height: 56px;
  color: var(--color-gold);
}

/* ---------- Photo gallery ---------- */

.upload-dropzone {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  text-align: center;
  padding: 2.25rem 1.25rem;
  border: 2px dashed var(--color-gold-light);
  border-radius: var(--radius-soft);
  background-color: var(--color-ivory);
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.upload-dropzone:hover {
  border-color: var(--color-gold);
  background-color: var(--color-ivory-dark);
}

.upload-dropzone.is-dragover {
  border-color: var(--color-gold);
  background-color: var(--color-ivory-dark);
  transform: scale(1.01);
}

.upload-dropzone-icon {
  width: 40px;
  height: 40px;
  color: var(--color-gold);
}

.upload-dropzone-text {
  font-family: var(--font-heading);
  color: var(--color-loden-dark);
  font-size: 1.05rem;
}

.upload-dropzone-hint {
  color: var(--color-muted);
  font-size: 0.85rem;
}

.upload-preview {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(90px, 1fr));
  gap: 0.6rem;
  margin-top: 1rem;
}

.upload-preview:empty {
  margin-top: 0;
}

.upload-preview-item {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 8px;
  overflow: hidden;
  box-shadow: var(--shadow-soft);
}

.upload-preview-item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.upload-preview-name {
  position: absolute;
  inset: auto 0 0 0;
  padding: 0.2rem 0.4rem;
  font-size: 0.65rem;
  color: var(--color-white);
  background: linear-gradient(0deg, rgba(0, 0, 0, 0.55), transparent);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.upload-preview-more {
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: var(--color-ivory-dark);
  color: var(--color-muted);
  font-size: 0.8rem;
  text-align: center;
  padding: 0.5rem;
}

.upload-progress {
  position: relative;
  margin-top: 1rem;
  height: 10px;
  border-radius: 999px;
  background-color: var(--color-ivory-dark);
  overflow: hidden;
}

.upload-progress-bar {
  height: 100%;
  width: 0%;
  background-color: var(--color-gold);
  border-radius: 999px;
  transition: width 0.15s ease;
}

.upload-progress-label {
  display: block;
  margin-top: 0.35rem;
  font-size: 0.8rem;
  color: var(--color-muted);
  text-align: center;
}

.photo-grid {
  display: grid;
  grid-template-columns: repeat(1, 1fr);
  gap: 0.75rem;
}

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

@media (min-width: 992px) {
  .photo-grid { grid-template-columns: repeat(3, 1fr); }
}

@media (min-width: 1200px) {
  .photo-grid { grid-template-columns: repeat(4, 1fr); }
}

.photo-grid img {
  width: 100%;
  height: 220px;
  object-fit: cover;
  border-radius: 10px;
  cursor: pointer;
  transition: transform 0.25s ease, box-shadow 0.25s ease;
  box-shadow: var(--shadow-soft);
}

.photo-grid img:hover {
  transform: scale(1.03);
}

.admin-photo-tile {
  position: relative;
}

/* Room photo row (Übernachtung — Sammüller) */
.room-photo-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0.9rem;
}

@media (min-width: 576px) {
  .room-photo-grid {
    grid-template-columns: repeat(3, 1fr);
  }
}

.room-photo-grid img {
  width: 100%;
  height: 210px;
  object-fit: cover;
  border-radius: var(--radius-soft);
  box-shadow: var(--shadow-soft);
}

.hr-subtle {
  border: none;
  border-top: 2px solid var(--color-gold);
  opacity: 0.6;
  margin: 1.75rem 0;
}

.admin-photo-tile {
  border-radius: 10px;
  overflow: hidden;
}

/* Uploader-Name unten links auf dem Foto, damit der Admin sieht, von wem
   ein Bild stammt, ohne es öffnen zu müssen. */
.admin-photo-meta {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 1.4rem 0.75rem 0.55rem;
  font-size: 0.75rem;
  color: var(--color-white);
  background: linear-gradient(0deg, rgba(var(--shadow-rgb), 0.65), transparent);
  pointer-events: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Löschen als runder Icon-Button mit dunklem Glas-Hintergrund oben rechts –
   der bisherige rote Umriss ohne Fläche war auf hellen Fotos unlesbar. */
.admin-photo-delete {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  z-index: 2;
}

.admin-photo-delete-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  height: 2.25rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background-color: rgba(var(--shadow-rgb), 0.55);
  color: var(--color-white);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  cursor: pointer;
  transition: background-color 0.2s ease, transform 0.2s ease;
}

.admin-photo-delete-btn:hover,
.admin-photo-delete-btn:focus-visible {
  background-color: var(--color-alpenrose-dark);
  transform: scale(1.06);
}

.admin-photo-delete-btn svg {
  width: 1rem;
  height: 1rem;
}

/* ---------- Photo lightbox (custom overlay, appended directly to <body>
   so its position:fixed is relative to the real viewport — not trapped by
   main.page-content's transform-as-containing-block quirk documented above) ---------- */

html.photo-lightbox-open,
html.photo-lightbox-open body {
  overflow: hidden;
}

.photo-lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 1080;
  display: flex;
  align-items: center;
  justify-content: center;
  background-color: rgba(var(--shadow-rgb), 0.92);
  padding: 3.5rem 1rem;
}

.photo-lightbox-stage {
  max-width: 100%;
  max-height: 100%;
  display: flex;
}

.photo-lightbox-img {
  display: block;
  max-width: 100%;
  max-height: calc(100dvh - 7rem);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 10px;
  box-shadow: var(--shadow-soft);
}

.photo-lightbox-close,
.photo-lightbox-nav {
  position: fixed;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0.5);
  color: var(--color-white);
  cursor: pointer;
  transition: background-color 0.2s ease;
}

.photo-lightbox-close:hover,
.photo-lightbox-nav:hover {
  background-color: rgba(0, 0, 0, 0.75);
}

.photo-lightbox-close {
  top: 1rem;
  right: 1rem;
  width: 2.25rem;
  height: 2.25rem;
  z-index: 2;
}

.photo-lightbox-close svg {
  width: 1.1rem;
  height: 1.1rem;
}

.photo-lightbox-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 2.75rem;
  height: 2.75rem;
}

.photo-lightbox-nav svg {
  width: 1.4rem;
  height: 1.4rem;
}

.photo-lightbox-prev {
  left: 0.75rem;
}

.photo-lightbox-next {
  right: 0.75rem;
}

.photo-lightbox-counter {
  position: fixed;
  left: 50%;
  bottom: 1rem;
  transform: translateX(-50%);
  padding: 0.2rem 0.75rem;
  border-radius: 999px;
  background-color: rgba(0, 0, 0, 0.5);
  color: var(--color-white);
  font-size: 0.8rem;
}

@media (max-width: 576px) {
  .photo-lightbox-overlay {
    padding: 3rem 0.5rem;
  }

  .photo-lightbox-nav {
    width: 2.25rem;
    height: 2.25rem;
  }
}

/* ---------- Forum ---------- */

/* Trennlinie nur ZWISCHEN Themen (kein <hr> mehr nach dem letzten Eintrag). */
.thread-list > a {
  display: block;
}

.thread-list > a + a {
  border-top: 1px solid var(--color-ivory-dark);
}

.thread-row {
  border-radius: var(--radius-organic-sm);
  transition: background-color 0.2s ease;
}

.thread-row:hover {
  background-color: var(--color-ivory-dark);
}

.post-bubble {
  display: flex;
  gap: 0.9rem;
  align-items: flex-start;
  background: var(--color-white);
  border: 1px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic);
  box-shadow: var(--shadow-soft);
}

.post-bubble.own-post {
  border-left: 3px solid var(--color-gold);
}

.post-body {
  flex: 1 1 auto;
  min-width: 0;
}

.post-head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.6rem;
}

.post-author {
  font-weight: 600;
}

.post-time {
  margin-left: auto;
  font-size: 0.8rem;
  color: var(--color-muted);
  white-space: nowrap;
}

/* Initialen-Kreis: Loden für Gäste, Gold für das Brautpaar (Gastgeber). */
.post-avatar {
  flex-shrink: 0;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-heading);
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  color: var(--color-white);
  background-color: var(--color-loden);
}

.post-avatar-host {
  background-color: var(--color-gold-deep);
}

.badge-host {
  background-color: var(--color-ivory);
  color: var(--color-gold-deep);
  border: 1px solid var(--color-gold-light);
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: middle;
}

/* ---------- Admin area ---------- */

.navbar-hochzeit-admin .navbar-nav {
  gap: 0.05rem;
}

.navbar-hochzeit-admin .nav-link {
  font-size: 0.9rem;
  white-space: nowrap;
}

/* Im mobilen Vollbild-Menü liegen die zwei <ul> (Fachbereichs-Links, und
   Zur-Hochzeitsseite + Abmelden) sonst als Flex-Row nebeneinander (siehe
   .navbar-hochzeit .navbar-collapse oben) - dadurch stünde "Zur
   Hochzeitsseite" neben statt unter den anderen Links. Nur hier auf
   Spalten-Layout umstellen, damit die zweite Liste darunter erscheint;
   die Desktop-Ansicht (>=992px) bleibt unverändert (dort regelt Bootstrap
   die Zeilen-Anordnung der beiden <ul> nebeneinander). */
@media (max-width: 991.98px) {
  .navbar-hochzeit-admin .navbar-collapse {
    flex-direction: column;
    /* 11 Einträge sind auf kleinen Displays (iPhone SE, Querformat) höher
       als der Viewport. Mit justify-content:center würde dann "Übersicht"
       oben abgeschnitten und unerreichbar - deshalb scrollbar, und die
       Zentrierung über auto-Margins der beiden <ul>s: die fallen bei
       Überlauf auf 0 zurück, das Menü beginnt dann einfach oben. */
    justify-content: flex-start;
    overflow-y: auto;
    padding-block: max(1.5rem, env(safe-area-inset-top, 0px)) max(1.5rem, env(safe-area-inset-bottom, 0px));
  }

  .navbar-hochzeit-admin .navbar-nav:first-of-type {
    margin-top: auto;
  }

  .navbar-hochzeit-admin .navbar-nav:last-of-type {
    margin-bottom: auto;
  }

  /* Bootstraps ".me-auto" (margin-right:auto!important, für die
     Desktop-Reihen-Anordnung der beiden <ul>s gedacht) hebelt im mobilen
     Spalten-Layout oben die align-items:center-Zentrierung aus: ein
     Auto-Margin auf der Cross-Achse zieht das erste <ul> (Fachbereichs-Links)
     an den linken Rand statt es zu zentrieren - dadurch wirkte das ganze
     Menü gegenüber "Zur Hochzeitsseite"/Abmelden versetzt. */
  .navbar-hochzeit-admin .navbar-collapse .navbar-nav.me-auto {
    margin-right: 0 !important;
  }

  /* Die allgemeine Regel ".navbar-hochzeit .navbar-nav li:last-child" (oben)
     setzt vor dem letzten Eintrag JEDER <ul> einen Abstand - hier gibt es
     zwei <ul>s, dadurch entsteht ein unpassender Abstand mitten in der
     Fachbereichs-Liste (vor "Forum-Moderation"). Den heben wir auf und
     setzen die Trennung stattdessen vor "Zur Hochzeitsseite", dem Beginn
     der zweiten Gruppe. Der Abmelden-Button (letzter Eintrag der zweiten
     <ul>) behält seinen 1rem-Abstand aus der allgemeinen Regel - wie auf
     der Hochzeitsseite; ohne ihn klebt der Pill direkt unter
     "Zur Hochzeitsseite", weil ihm der Zeilenhöhen-Puffer der Links fehlt. */
  .navbar-hochzeit-admin .navbar-nav:first-of-type li:last-child {
    margin-top: 0;
  }

  .navbar-hochzeit-admin .navbar-nav:last-of-type li:first-child {
    margin-top: 1rem;
  }
}

.admin-actions {
  display: flex;
  justify-content: flex-end;
  margin-bottom: 1rem;
}

/* ---------- Zuklappbare Admin-Bereiche (Gäste: Zugänge / Personen) ---------- */

.admin-section {
  margin-bottom: 1.75rem;
}

.admin-section-heading {
  margin: 0 0 0.75rem;
}

/* Die ganze Kopfzeile ist der Schalter: Titel in Marcellus, Zähler in
   einer Elfenbein-Pille, Chevron rechts, das sich beim Zuklappen dreht. */
.admin-section-toggle {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: 100%;
  padding: 0.35rem 0.25rem;
  background: none;
  border: 0;
  border-bottom: 1px solid var(--color-ivory-dark);
  text-align: left;
  color: var(--color-loden-dark);
  cursor: pointer;
  transition: color 0.2s ease;
}

.admin-section-toggle:hover {
  color: var(--color-gold-deep);
}

.admin-section-toggle:focus-visible {
  outline: 2px solid var(--color-gold-deep);
  outline-offset: 2px;
  border-radius: 6px;
}

.admin-section-title {
  font-family: var(--font-heading);
  font-size: 1.35rem;
  letter-spacing: 0.02em;
}

.admin-section-count {
  font-family: var(--font-body);
  font-size: 0.8rem;
  font-weight: 500;
  color: var(--color-muted);
  padding: 0.15rem 0.7rem;
  border: 1px solid var(--color-ivory-dark);
  border-radius: 999px;
  background-color: var(--color-ivory);
  white-space: nowrap;
}

.admin-section-count .rsvp-status-yes-inline {
  color: var(--color-loden-dark);
  font-weight: 600;
}

.admin-section-chevron {
  width: 1.2rem;
  height: 1.2rem;
  margin-left: auto;
  flex-shrink: 0;
  color: var(--color-gold-deep);
  transition: transform 0.3s ease;
}

.admin-section-toggle.collapsed .admin-section-chevron {
  transform: rotate(-90deg);
}

@media (max-width: 575.98px) {
  .admin-section-toggle {
    flex-wrap: wrap;
    gap: 0.4rem 0.6rem;
  }

  .admin-section-title {
    font-size: 1.2rem;
  }
}

.stat-tile {
  background-color: var(--color-white);
  border: 1px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic);
  box-shadow: var(--shadow-soft);
  padding: 1.5rem 1rem;
  text-align: center;
  height: 100%;
}

.stat-tile .stat-tile-value {
  font-family: var(--font-heading);
  font-size: 2.4rem;
  font-weight: 400;
  font-variant-numeric: lining-nums tabular-nums;
  color: var(--color-gold-deep);
  line-height: 1.1;
}

.stat-tile .stat-tile-label {
  color: var(--color-muted);
  margin-top: 0.35rem;
  font-size: 0.9rem;
}

.stat-tile-link {
  display: block;
  text-decoration: none;
  transition: box-shadow 0.15s ease, transform 0.15s ease;
}

.stat-tile-link:hover,
.stat-tile-link:focus-visible {
  box-shadow: 0 14px 34px -14px rgba(var(--shadow-rgb), 0.35);
  transform: translateY(-2px);
}

.stat-tile-sub {
  margin-top: 0.5rem;
  font-size: 0.8rem;
  white-space: nowrap;
}

.stat-tile-sub-yes {
  color: var(--color-loden-dark);
}

.stat-tile-sub-no {
  color: var(--color-alpenrose-dark);
}

.stat-tile-sub-open {
  color: var(--color-muted);
}

/* Mobile (halbe Spalte, ~130px): Zusagen/Absagen/offen untereinander statt
   in einer nowrap-Zeile, die sonst rechts aus der Kachel läuft. Die Punkte
   dazwischen entfallen. Namensfrage- und Besuche-Kachel sind unter 576px
   ohnehin volle Breite (col-12), dort braucht es keine Sonderregel. */
@media (max-width: 575.98px) {
  .stat-tile-sub {
    white-space: normal;
  }

  .stat-tile-sub-rsvp > span {
    display: block;
  }

  .stat-tile-sub-sep {
    display: none;
  }
}

/* Mini-Tabelle in der Besuche-Kachel: Zeitfenster × Gäste/Brautpaar */
.stat-tile-table {
  width: 100%;
  margin-top: 0.85rem;
  border-top: 1px solid var(--color-ivory-dark);
  font-size: 0.8rem;
  font-variant-numeric: lining-nums tabular-nums;
}

.stat-tile-table th,
.stat-tile-table td {
  padding: 0.3rem 0.25rem 0;
  font-weight: 400;
}

.stat-tile-table thead th {
  color: var(--color-muted);
  font-size: 0.7rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  padding-top: 0.55rem;
}

.stat-tile-table tbody th {
  text-align: left;
  color: var(--color-muted);
  white-space: nowrap;
}

.stat-tile-table td {
  text-align: right;
  color: var(--color-loden-dark);
}

.stat-tile-table thead th:not(:first-child) {
  text-align: right;
}

.table-hochzeit thead th {
  font-family: var(--font-heading);
  font-weight: 400;
  color: var(--color-loden-dark);
  border-bottom: 2px solid var(--color-ivory-dark) !important;
  font-size: 0.95rem;
  padding: 0.6rem 0.75rem;
}

.table-hochzeit tbody td {
  padding: 0.85rem 0.75rem;
  vertical-align: middle;
}

.table-hochzeit tbody tr {
  border-radius: var(--radius-soft);
  transition: background-color 0.2s ease;
}

.table-hochzeit tbody tr:hover > td {
  background-color: var(--color-ivory-dark);
}

.table-hochzeit tbody tr.guest-row td {
  padding-bottom: 0.25rem;
}

.table-hochzeit tbody tr.guest-meta-row td {
  padding-top: 0;
  padding-bottom: 0.75rem;
}

/* Bootstrap setzt die Zellen-Hintergrundfarbe direkt auf <td>/<th>
   (--bs-table-bg), daher muss die Zebra-Streifung ebenfalls auf den
   Zellen sitzen statt auf <tr> - sonst wird sie von Bootstrap überdeckt. */
.table-hochzeit tbody tr.guest-row-odd.guest-row > td,
.table-hochzeit tbody tr.guest-row-odd.guest-meta-row > td {
  background-color: var(--color-ivory);
}

.table-hochzeit tbody tr.guest-row:hover > td,
.table-hochzeit tbody tr.guest-row:hover + tr.guest-meta-row > td,
.table-hochzeit tbody tr.guest-meta-row:hover > td {
  background-color: var(--color-ivory-dark);
}

.guest-row-actions {
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  gap: 0.4rem;
}

.sortable-col {
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}

.sortable-col::after {
  content: "\21C5";
  display: inline-block;
  margin-left: 0.35rem;
  font-size: 0.8em;
  color: var(--color-loden-dark);
  opacity: 0.35;
}

.sortable-col[aria-sort="ascending"]::after {
  content: "\2191";
  opacity: 1;
}

.sortable-col[aria-sort="descending"]::after {
  content: "\2193";
  opacity: 1;
}

/* Mobile: die Admin-Tabellen (Logs, Forum) scrollen horizontal in
   .table-responsive — Innenabstände und Button-Größe zurücknehmen, damit
   weniger Scrollbreite nötig ist. */
@media (max-width: 767.98px) {
  .table-hochzeit thead th,
  .table-hochzeit tbody td {
    padding: 0.5rem 0.5rem;
    font-size: 0.9rem;
  }

  .table-hochzeit .btn-sm {
    padding: 0.2rem 0.5rem;
    font-size: 0.8rem;
  }
}

.guest-name {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.3rem 0.5rem;
}

.guest-name .badge {
  font-size: 0.65rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.badge-admin {
  background-color: var(--color-ivory);
  color: var(--color-gold-deep);
  border: 1px solid var(--color-gold-light);
}

/* Gästeliste unter 768px als Karten statt 6-spaltiger Tabelle: Aktionen
   und Zusage lagen bisher rechts außerhalb des Bildschirms. Die Tabelle
   bleibt semantisch erhalten (Screenreader), wird aber als Block gerendert;
   jede Zelle bekommt ihr Label aus data-label. Die Meta-Zeile
   ("Zuletzt gesehen") hängt sich als Fuß unter die Karte. */
@media (max-width: 767.98px) {
  .guest-table,
  .guest-table tbody,
  .guest-table tr,
  .guest-table td {
    display: block;
    width: 100%;
  }

  .guest-table thead {
    display: none;
  }

  .guest-table tbody tr.guest-row {
    background-color: var(--color-white);
    border: 1px solid var(--color-ivory-dark);
    border-bottom: none;
    /* Obere Hälfte der organischen Ecke (14 / 30) – das Token selbst hat
       vier Werte und kann hier nicht als Kurzform eingesetzt werden. */
    border-radius: 14px 30px 0 0;
    padding: 0.9rem 1rem 0.25rem;
  }

  .guest-table tbody tr.guest-meta-row {
    background-color: var(--color-white);
    border: 1px solid var(--color-ivory-dark);
    border-top: none;
    border-radius: 0 0 14px 14px;
    padding: 0 1rem 0.8rem;
    margin-bottom: 1rem;
  }

  /* Bootstrap malt jede Zelle mit --bs-table-bg (#fff) – innerhalb der
     cremefarbenen Karte (#fffdf8) ergibt das einen eckigen weißen Kasten,
     der aus den Rundungen herausschaut. Zellen hier vollständig transparent,
     die Karte (tr) trägt den Hintergrund. */
  .guest-table tbody tr > td,
  .guest-table tbody tr.guest-row-odd.guest-row > td,
  .guest-table tbody tr.guest-row-odd.guest-meta-row > td,
  .guest-table tbody tr.guest-row:hover > td,
  .guest-table tbody tr.guest-row:hover + tr.guest-meta-row > td,
  .guest-table tbody tr.guest-meta-row:hover > td {
    --bs-table-bg: transparent;
    --bs-table-accent-bg: transparent;
    background-color: transparent;
    box-shadow: none;
  }

  /* Zebra-Streifen der Desktop-Tabelle auf die ganze Karte übertragen. */
  .guest-table tbody tr.guest-row-odd {
    background-color: var(--color-ivory);
  }

  .guest-table tbody tr.guest-row td {
    padding: 0.35rem 0;
    font-size: 0.92rem;
  }

  .guest-table tbody tr.guest-meta-row td {
    padding: 0.35rem 0 0;
    font-size: 0.8rem;
  }

  /* Die umschließende Tabellen-Karte wird unsichtbar – sonst liegen die
     Gäste-Karten in einer zweiten Karte (Rahmen im Rahmen). */
  .card-hochzeit:has(> .guest-table) {
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 0 !important;
  }

  .card-hochzeit:has(> .guest-table):hover {
    transform: none;
  }

  .guest-table td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--color-muted);
    margin-bottom: 0.1rem;
  }

  .guest-table td.guest-cell-name {
    font-size: 1.05rem;
    padding-bottom: 0.5rem !important;
  }

  .guest-table td.guest-cell-actions {
    padding-top: 0.6rem !important;
  }

  .guest-table .guest-row-actions {
    flex-wrap: wrap;
    justify-content: flex-start;
  }

  .guest-table .rsvp-status-list {
    white-space: normal;
  }

  .guest-table .guest-cell-empty {
    display: none;
  }
}

.badge-loden {
  background-color: var(--color-loden);
  color: var(--color-white);
}

.badge-muted {
  background-color: var(--color-ivory-dark);
  color: var(--color-ink);
  opacity: 0.75;
}

/* Einladungsstatus in der Gästeliste: eine Skala von neutral (angelegt) über
   Gold (gedruckt/versendet) bis Loden (übergeben) – dieselbe Farbsprache wie
   die Zusage-Status, damit die Zeile nicht in Signalfarben zerfällt. */
.badge-invite {
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.badge-invite-created {
  background-color: var(--color-ivory-dark);
  color: var(--color-muted);
}

.badge-invite-printed {
  background-color: var(--color-ivory);
  color: var(--color-gold-deep);
  border: 1px solid var(--color-gold-light);
}

.badge-invite-sent {
  background-color: var(--color-gold-deep);
  color: var(--color-white);
}

.badge-invite-handed {
  background-color: var(--color-loden);
  color: var(--color-white);
}

/* Statusauswahl in der Gästetabelle: das Badge selbst ist die Auswahl.
   Das Select liegt transparent darin und erbt Farbe und Schrift; der
   Pfeil ist ein Rahmen in currentColor, damit er auf jeder Badge-Farbe passt. */
.invite-status-form {
  margin: 0;
}

.invite-status-pill {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 0;
  transition: background-color 0.2s ease, color 0.2s ease;
}

.invite-status-pill::after {
  content: "";
  position: absolute;
  right: 0.7em;
  top: 50%;
  width: 0.4em;
  height: 0.4em;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-70%) rotate(45deg);
  pointer-events: none;
}

.invite-status-select {
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  border: 0;
  border-radius: inherit;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  padding: 0.35em 1.9em 0.35em 0.75em;
  cursor: pointer;
}

.invite-status-select:focus-visible {
  outline: 2px solid var(--color-gold-deep);
  outline-offset: 2px;
}

.invite-status-select:disabled {
  cursor: progress;
  opacity: 0.6;
}

.invite-status-select option {
  background-color: var(--color-white);
  color: var(--color-ink);
}

/* Personen-Übersicht: Summenleiste unter der Tabelle (bewusst kein <tfoot>,
   damit sie unabhängig von ein-/ausgeblendeten Spalten immer volle Breite hat). */
.person-badge {
  margin-left: 0.35rem;
  vertical-align: middle;
  font-size: 0.65rem;
}

.person-table tbody td .rsvp-status-yes,
.person-table tbody td .rsvp-status-no,
.person-table tbody td .rsvp-status-open {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.9rem;
}

.person-total {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: 0.5rem 1.5rem;
  margin-top: 0.5rem;
  padding: 0.9rem 0.75rem 0.25rem;
  border-top: 2px solid var(--color-ivory-dark);
}

.person-total-left,
.person-total-right {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.person-total-label {
  font-family: var(--font-heading);
  font-size: 1.1rem;
  color: var(--color-loden-dark);
}

.person-total-counts {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem 1rem;
  font-size: 1rem;
}

.person-total-counts .rsvp-status-yes,
.person-total-counts .rsvp-status-no,
.person-total-counts .rsvp-status-open {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  white-space: nowrap;
}

/* Mobil: Gruppe ausblenden (steht im Detailbereich). */
@media (max-width: 575.98px) {
  .person-table .person-col-group {
    display: none;
  }

  .person-total {
    padding-left: 0.5rem;
    padding-right: 0.5rem;
  }
}

/* ---------- Namensfrage-Umfrage ---------- */

/* Karten-Kopf im Kachel-Stil: Icon-Marke + Überschrift in einer Zeile. */
.card-lead {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem 0.85rem;
  margin-bottom: 1rem;
}

.card-lead h2 {
  margin: 0;
  font-family: var(--font-heading);
  font-weight: 400;
  font-size: 1.5rem;
  line-height: 1.05;
  letter-spacing: 0.01em;
  color: var(--color-loden-dark);
}

.name-poll .card-lead h2 {
  transition: color 0.35s ease;
}

.name-poll:hover .card-lead h2 {
  color: var(--color-gold-deep);
}

.name-poll .card-lead {
  margin-bottom: 1.25rem;
}

/* Die drei Startseiten-Karten ohne Kachel-Markup (Grundinfos, Zusage,
   Nachricht) bekommen denselben Kopf-Hover wie Kacheln und Namensfrage:
   Titel in Gold-tief, Haarlinien-Marke in Gold. Der Hover hängt jeweils nur
   am Karten-Kopf (.card-lead); die Abschnittsüberschriften in der
   Grundinfos-Karte bleiben ruhig.
   Mobile Entsprechung per .is-active siehe Media-Query bei .tile-card.is-active. */
.info-card .card-lead h2,
.rsvp-card .card-lead h2,
.message-card .card-lead h2 {
  transition: color 0.35s ease;
  /* Eine Stufe über den Abschnittsüberschriften (.content-section-heading
     h2, 1,5 rem): Der Karten-Kopf trägt nur die 30-px-Haarlinien-Marke und
     wirkte neben den 44-px-Medaillons der Abschnitte sonst kleiner. */
  font-size: 1.75rem;
}

@media (max-width: 575.98px) {
  .info-card .card-lead h2,
  .rsvp-card .card-lead h2,
  .message-card .card-lead h2 {
    font-size: 1.5rem;
  }
}

.info-card .card-lead .tile-mark,
.rsvp-card .card-lead .tile-mark,
.message-card .card-lead .tile-mark,
.name-poll .card-lead .tile-mark {
  transition: border-color 0.25s ease;
}

.info-card:hover .card-lead h2,
.rsvp-card:hover .card-lead h2,
.message-card:hover .card-lead h2 {
  color: var(--color-gold-deep);
}

.info-card:hover .card-lead .tile-mark,
.rsvp-card:hover .card-lead .tile-mark,
.message-card:hover .card-lead .tile-mark,
.name-poll:hover .card-lead .tile-mark {
  border-color: var(--color-gold);
}

.name-poll-intro {
  margin-bottom: 0.35rem;
  line-height: 1.65;
}

.name-poll-intro-aside {
  margin-bottom: 1.75rem;
  font-size: 0.92rem;
}

/* Stimmgewicht steht als eigene Zeile unter dem Status (nicht mehr als
   Pille neben der Überschrift, die auf dem Handy in eine eigene Zeile brach). */
.name-poll-weight {
  margin-top: 0.4rem;
  color: var(--color-gold-deep);
  font-weight: 600;
}

.name-poll-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1.25rem;
}

.name-poll-option {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  padding: 1.5rem 1.25rem;
  text-align: center;
  background-color: var(--color-white);
  border: 2px solid var(--color-ivory-dark);
  border-radius: var(--radius-organic-sm);
  color: var(--color-ink);
  cursor: pointer;
  transition: transform 0.15s ease, border-color 0.15s ease,
    background-color 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}

.name-poll-option:hover {
  border-color: var(--color-gold-light);
  transform: translateY(-2px);
  box-shadow: var(--shadow-soft);
}

.name-poll-option:focus-visible {
  outline: 3px solid var(--color-gold-deep);
  outline-offset: 2px;
}

.name-poll-option-title {
  font-family: var(--font-heading);
  font-size: 1.2rem;
  line-height: 1.15;
}

.name-poll-option-sub {
  font-size: 0.9rem;
  color: var(--color-muted);
}

.name-poll-option.is-active {
  background-color: var(--color-loden);
  border-color: var(--color-loden);
  color: var(--color-white);
  box-shadow: var(--shadow-soft);
}

.name-poll-option.is-active .name-poll-option-sub {
  color: var(--color-ivory);
}

.name-poll-option.is-active .name-poll-option-title::after {
  content: " ✓";
}

.name-poll-option.is-inactive {
  opacity: 0.5;
}

.name-poll-option.is-inactive:hover {
  opacity: 0.8;
}

.name-poll-status {
  margin-top: 1.35rem;
  font-size: 0.9rem;
  line-height: 1.55;
}

/* Status-Text wechselt per JS – Mindesthöhe, damit die Karte beim
   Eskalieren nicht bei jedem Klick springt. */
.name-poll-status-text {
  min-height: 2.8em;
  transition: color 0.25s ease;
}

.name-poll[data-name-poll].is-busy {
  opacity: 0.6;
  pointer-events: none;
}

/* Wer auf Mr. Espach steht, bekommt Mrs. Droppelmann trotzdem dezent
   angeboten: nicht ausgegraut, dafür ein goldener Lichtschein, der langsam
   am Rand entlangwandert. (Espach steht im DOM vor Droppelmann → ~.) */
@property --name-poll-sweep {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

.name-poll-option-espach.is-active ~ .name-poll-option-droppelmann,
.name-poll-option-espach.is-active ~ .name-poll-option-droppelmann:hover {
  opacity: 1;
  border-color: var(--color-gold-light);
}

.name-poll-option-espach.is-active ~ .name-poll-option-droppelmann::before {
  content: "";
  position: absolute;
  inset: -3px;
  border-radius: inherit;
  padding: 3px;
  background: conic-gradient(
    from var(--name-poll-sweep),
    transparent 0deg 200deg,
    var(--color-gold-light) 270deg,
    var(--color-gold-deep) 320deg,
    var(--color-ivory) 345deg,
    transparent 360deg
  );
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  mask-composite: exclude;
  pointer-events: none;
  animation: name-poll-sweep 3s linear infinite;
}

@keyframes name-poll-sweep {
  to { --name-poll-sweep: 360deg; }
}

/* "Nudge": Espach-Klicks eskalieren in drei Stufen (data-stage 1–3), bevor
   wirklich gespeichert wird. Espach schrumpft pro Stufe, Droppelmann winkt. */
.name-poll.is-nudging .name-poll-status {
  color: var(--color-gold-deep);
  font-style: italic;
}

.name-poll.is-celebrating .name-poll-status {
  color: var(--color-gold-deep);
  font-weight: 600;
}

.name-poll[data-stage] .name-poll-option-espach {
  border-style: dashed;
  border-color: var(--color-gold-light);
}

.name-poll[data-stage] .name-poll-option-espach .name-poll-option-sub {
  color: var(--color-gold-deep);
  font-weight: 600;
}

.name-poll[data-stage="1"] .name-poll-option-espach { transform: scale(0.96); opacity: 0.9; }
.name-poll[data-stage="2"] .name-poll-option-espach { transform: scale(0.91); opacity: 0.8; }
.name-poll[data-stage="3"] .name-poll-option-espach { transform: scale(0.86); opacity: 0.7; }

.name-poll[data-stage] .name-poll-option-droppelmann {
  border-color: var(--color-gold-deep);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--color-gold) 18%, transparent), var(--shadow-soft);
}

.name-poll[data-stage="2"] .name-poll-option-droppelmann { transform: scale(1.03); }
.name-poll[data-stage="3"] .name-poll-option-droppelmann { transform: scale(1.06); }

/* Brautpaar klickt Espach: kein Nudge, nur ein kurzes "NÖ" (is-refusing),
   danach springt die Wahl per JS zurück auf Droppelmann. */
.name-poll.is-refusing .name-poll-status {
  color: var(--color-alpenrose-dark);
  font-weight: 600;
}

.name-poll.is-refusing .name-poll-option-espach {
  border-style: dashed;
  border-color: var(--color-alpenrose);
  transform: scale(0.9);
  opacity: 0.75;
}

.name-poll.is-refusing .name-poll-option-espach .name-poll-option-sub {
  color: var(--color-alpenrose-dark);
  font-weight: 700;
}

/* "NÖ" als Text statt Emoji aus dem Button schweben lassen. */
.name-poll-pop.name-poll-pop-text {
  font-family: var(--font-heading);
  font-size: 1.6rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--color-alpenrose-dark);
}

/* Espach zuckt kurz zusammen … */
.name-poll-option.name-poll-shrink {
  animation: name-poll-shrink 0.5s ease;
}

/* … Droppelmann winkt einladend … */
.name-poll-option.name-poll-wave {
  animation: name-poll-wave 0.7s ease;
  z-index: 1;
}

/* … und hüpft vor Freude, wenn's geklappt hat. */
.name-poll-option.name-poll-bounce {
  animation: name-poll-bounce 0.8s cubic-bezier(0.22, 1, 0.36, 1) both;
  z-index: 1;
}

/* Emoji, das aus dem Button nach oben schwebt (per JS eingefügt). */
.name-poll-pop {
  position: absolute;
  left: 50%;
  top: 0.2rem;
  font-size: 1.9rem;
  line-height: 1;
  pointer-events: none;
  z-index: 2;
  animation: name-poll-pop 1.4s ease-out both;
}

@keyframes name-poll-shrink {
  0% { filter: none; }
  30% { transform: scale(0.8) rotate(-2deg); }
  60% { transform: scale(0.9) rotate(1.5deg); }
  100% { filter: none; }
}

@keyframes name-poll-wave {
  0% { transform: rotate(0); }
  20% { transform: rotate(-3deg) translateY(-4px); }
  40% { transform: rotate(3deg) translateY(-6px); }
  60% { transform: rotate(-2deg) translateY(-3px); }
  80% { transform: rotate(1.5deg) translateY(-1px); }
  100% { transform: rotate(0); }
}

@keyframes name-poll-bounce {
  0% { transform: scale(1); }
  30% { transform: scale(1.1) translateY(-8px); }
  55% { transform: scale(0.98) translateY(2px); }
  100% { transform: scale(1); }
}

@keyframes name-poll-pop {
  0% {
    opacity: 0;
    transform: translate(-50%, 0.4rem) scale(0.4);
  }
  20% {
    opacity: 1;
    transform: translate(-50%, -0.6rem) scale(1.25);
  }
  100% {
    opacity: 0;
    transform: translate(-50%, -3.2rem) scale(1) rotate(12deg);
  }
}

@media (max-width: 575.98px) {
  .name-poll-options {
    grid-template-columns: 1fr;
  }
}

/* ---------- Reduced motion ---------- */

/* ---------- Gast-Nachrichten ans Brautpaar ---------- */

/* Hinweis auf der Admin-Kachel (Willkommen-Seite), wenn ungelesene Nachrichten
   vorliegen: Alpenrose-Pill mit pulsierendem Punkt, sitzt in der kompakten
   Admin-Zeile zwischen Text und "Öffnen →". */
.tile-card-notify {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  flex-shrink: 0;
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  background-color: var(--color-alpenrose-dark);
  color: var(--color-white);
  font-size: 0.8rem;
  font-weight: 600;
  letter-spacing: 0.01em;
  white-space: nowrap;
  box-shadow: 0 3px 10px -3px rgba(var(--shadow-rgb), 0.45);
}

.tile-card-notify-dot {
  position: relative;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background-color: var(--color-white);
}

.tile-card-notify-dot::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-color: var(--color-white);
  animation: notify-ping 1.8s ease-out infinite;
}

@keyframes notify-ping {
  0% { transform: scale(1); opacity: 0.7; }
  100% { transform: scale(2.8); opacity: 0; }
}

@media (max-width: 575.98px) {
  .tile-grid:not(.tile-grid-compact) .tile-card-admin .tile-card-body {
    flex-wrap: wrap;
  }

  .tile-card-notify {
    order: 3;
    width: 100%;
    justify-content: center;
  }
}

/* Ungelesen-Zähler neben dem Nav-Link "Nachrichten" im Admin-Bereich. */
.nav-count {
  display: inline-block;
  min-width: 1.35em;
  margin-left: 0.3em;
  padding: 0.05em 0.45em;
  border-radius: 999px;
  background-color: var(--color-alpenrose);
  color: var(--color-white);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.5;
  text-align: center;
  vertical-align: 0.1em;
}

/* Nachrichtenliste im Admin-Bereich */
.message-row {
  transition: background-color 0.15s ease;
}

.message-row-unread {
  background-color: color-mix(in srgb, var(--color-alpenrose) 6%, transparent);
  border-left: 3px solid var(--color-alpenrose);
}

.message-body {
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  line-height: 1.55;
}

@media (prefers-reduced-motion: reduce) {
  .tile-card-notify-dot::after {
    animation: none;
    display: none;
  }

  html {
    scroll-behavior: auto;
  }

  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }

  [data-reveal] {
    opacity: 1;
    transform: none;
  }
}

/* ---------- AGB-Z (Zustimmungsseite für einzelne Gäste, Home/AgbZ) ---------- */

.agbz-preview {
  padding: 0.85rem 1.1rem;
  border-radius: var(--radius-soft);
  border-left: 3px solid var(--color-gold-deep);
  background-color: var(--color-ivory);
  color: var(--color-ink);
}

.agbz-text h2 {
  margin-bottom: 0.25rem;
}

.agbz-version,
.agbz-hint,
.agbz-amendment {
  color: var(--color-muted);
  font-size: 0.9em;
}

.agbz-amendment {
  font-family: var(--font-body);
}

.agbz-reread {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--color-ivory-dark);
}

.agbz-reread summary {
  cursor: pointer;
  color: var(--color-loden-dark);
  margin-bottom: 1rem;
}

.agbz-consent .form-check-input:disabled,
.agbz-consent .form-check-input:disabled ~ .form-check-label {
  opacity: 1;
}

.agbz-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  margin-top: 1.25rem;
}

/* Wächst mit jeder Ablehnungsstufe (agbz.js setzt --agbz-zoom) und liegt
   über dem ausweichenden Ablehnen-Button, falls der darüber springt. */
.agbz-accept {
  position: relative;
  z-index: 2;
  transform: scale(var(--agbz-zoom, 1));
  transform-origin: left center;
  margin-right: calc((var(--agbz-zoom, 1) - 1) * 6rem);
  transition: transform 0.35s cubic-bezier(0.4, 0, 0.2, 1), margin-right 0.35s cubic-bezier(0.4, 0, 0.2, 1), padding 0.35s cubic-bezier(0.4, 0, 0.2, 1), box-shadow 0.35s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.agbz-decline {
  position: relative;
  z-index: 1;
  transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1), padding 0.35s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.35s cubic-bezier(0.4, 0, 0.2, 1), color 0.35s cubic-bezier(0.4, 0, 0.2, 1);
}

.agbz-status {
  min-height: 1.5em;
  margin: 1rem 0 0;
  color: var(--color-alpenrose-dark);
}
