/* ---------------------------------------------------------------------------
   Drecksjuniore — Designsystem
   Farben, Abstände, Schriftgrössen und Bewegung laufen über Tokens.
   Hell/Dunkel ist damit nur eine Umschaltung von Werten, kein zweites Layout.
   --------------------------------------------------------------------------- */

:root {
  /* Flächen und Text */
  --bg: #fbfbfc;
  --bg-soft: #f5f6f8;
  --surface: #ffffff;
  --surface-2: #f4f5f7;
  --surface-3: #eceef1;
  --border: #e6e8ec;
  --border-strong: #d2d6dd;
  --text: #16181d;
  --text-soft: #3f444d;
  --muted: #6b7280;

  /* Akzent */
  --accent: #4c5fd7;
  --accent-hover: #3d4fc0;
  --accent-soft: #eef0ff;
  --accent-line: #c9cff8;
  --on-accent: #ffffff;

  /* Zustände */
  --danger: #c53a2f;
  --danger-soft: #fdeceb;
  --success: #1c7a4c;
  --success-soft: #e6f6ee;
  --warning: #96600f;
  --warning-soft: #fdf2df;

  /* Form */
  --radius-sm: 10px;
  --radius: 14px;
  --radius-lg: 22px;

  /* Höhe. Vier Stufen statt zwei — das ist der Unterschied zwischen
     "ruhig geschichtet" und "flach mit Rahmen drum". */
  --shadow-xs: 0 1px 2px rgba(18, 22, 33, .04);
  --shadow: 0 1px 2px rgba(18, 22, 33, .04), 0 2px 8px rgba(18, 22, 33, .05);
  --shadow-md: 0 2px 4px rgba(18, 22, 33, .04), 0 8px 24px rgba(18, 22, 33, .07);
  --shadow-lg: 0 4px 8px rgba(18, 22, 33, .05), 0 20px 48px rgba(18, 22, 33, .12);

  /* Abstände */
  --sp-1: .25rem;  --sp-2: .5rem;   --sp-3: .75rem;  --sp-4: 1rem;
  --sp-5: 1.5rem;  --sp-6: 2rem;    --sp-7: 2.75rem; --sp-8: 4rem;

  /* Bewegung. Eine gemeinsame Kurve hält alle Übergänge im selben Rhythmus. */
  --ease: cubic-bezier(.32, .72, 0, 1);
  --ease-out: cubic-bezier(.16, 1, .3, 1);
  --dur-1: .12s;
  --dur-2: .22s;
  --dur-3: .38s;

  --header-h: 64px;
  --content: 64rem;
}

[data-theme="dark"] {
  --bg: #0f1115;
  --bg-soft: #0b0c10;
  --surface: #16191f;
  --surface-2: #1d2128;
  --surface-3: #252932;
  --border: #262b34;
  --border-strong: #39404b;
  --text: #e8eaee;
  --text-soft: #b8bec8;
  --muted: #8f96a3;

  --accent: #8298ff;
  --accent-hover: #9aacff;
  --accent-soft: #1b2140;
  --accent-line: #33406e;
  --on-accent: #0c0f16;

  --danger: #f08279;
  --danger-soft: #331f1e;
  --success: #5fc793;
  --success-soft: #14281e;
  --warning: #dfae5f;
  --warning-soft: #2a2317;

  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow: 0 1px 2px rgba(0, 0, 0, .4), 0 2px 8px rgba(0, 0, 0, .3);
  --shadow-md: 0 2px 4px rgba(0, 0, 0, .4), 0 8px 24px rgba(0, 0, 0, .4);
  --shadow-lg: 0 4px 8px rgba(0, 0, 0, .45), 0 20px 48px rgba(0, 0, 0, .55);
}

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

* { box-sizing: border-box; }

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

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background: var(--bg-soft);
  color: var(--text);
  /* "Inter" steht vorn, falls die Schrift später selbst ausgeliefert wird —
     bis dahin greift die Systemschrift, ohne dass hier etwas zu ändern wäre. */
  font-family: "Inter", "Inter var", system-ui, -apple-system, "Segoe UI Variable Text",
               "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

/* Ein sehr leiser Verlauf hinter allem. Nimmt der Fläche das Papierhafte,
   ohne dass man ihn bewusst als Farbe wahrnimmt. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(900px 500px at 12% -8%, color-mix(in srgb, var(--accent) 7%, transparent), transparent 70%),
    radial-gradient(700px 420px at 92% 4%, color-mix(in srgb, var(--accent) 5%, transparent), transparent 65%);
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
a:focus-visible, button:focus-visible, input:focus-visible,
textarea:focus-visible, select:focus-visible, summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Fliessende Grössen: kein Sprung an der Bruchstelle, sondern ein Verlauf. */
h1, h2, h3 { line-height: 1.2; margin: 0 0 var(--sp-2); text-wrap: balance; }
h1 { font-size: clamp(1.6rem, 1.25rem + 1.4vw, 2.1rem); font-weight: 700; letter-spacing: -.028em; }
h2 { font-size: clamp(1.2rem, 1.08rem + .5vw, 1.4rem); font-weight: 660; letter-spacing: -.02em; }
h3 { font-size: 1.03rem; font-weight: 640; letter-spacing: -.012em; }
p { margin: 0 0 var(--sp-4); }
hr { border: 0; border-top: 1px solid var(--border); margin: var(--sp-5) 0; }
::selection { background: var(--accent-soft); color: var(--accent); }

/* --- Bewegung ------------------------------------------------------------- */

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}
@keyframes fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: .35; transform: scale(.75); }
}
@keyframes shimmer {
  from { background-position: -160% 0; }
  to   { background-position: 260% 0; }
}

/* Der Inhalt fährt beim Seitenwechsel leicht hoch. Einmal, kurz, gestaffelt —
   der Unterschied zwischen "ist da" und "erscheint". */
main > * { animation: rise var(--dur-3) var(--ease-out) both; }
main > *:nth-child(2) { animation-delay: .04s; }
main > *:nth-child(3) { animation-delay: .08s; }
main > *:nth-child(4) { animation-delay: .12s; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    scroll-behavior: auto !important;
  }
}

/* --- Kopfzeile ------------------------------------------------------------ */

.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  padding: 0 var(--sp-5);
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: saturate(180%) blur(14px);
  -webkit-backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  color: var(--text);
  font-weight: 680;
  letter-spacing: -.022em;
  text-decoration: none;
  flex-shrink: 0;
}
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: 10px;
  background: linear-gradient(140deg, var(--accent), color-mix(in srgb, var(--accent) 45%, #a855f7));
  color: #fff;
  font-size: .8rem;
  font-weight: 800;
  letter-spacing: -.02em;
  box-shadow: 0 2px 8px color-mix(in srgb, var(--accent) 35%, transparent);
  transition: transform var(--dur-2) var(--ease);
}
.brand:hover .brand-mark { transform: rotate(-6deg) scale(1.06); }

/* Navigation. Der aktive Punkt bekommt einen Strich statt einer Farbfläche —
   ruhiger, und der Zustand bleibt trotzdem eindeutig. */
.site-nav { display: flex; gap: var(--sp-1); margin-left: var(--sp-2); flex: 1; min-width: 0; }
.site-nav a {
  position: relative;
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: .93rem;
  font-weight: 540;
  white-space: nowrap;
  transition: color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}
.site-nav a::after {
  content: "";
  position: absolute;
  left: var(--sp-3); right: var(--sp-3); bottom: .3rem;
  height: 2px;
  border-radius: 2px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--dur-2) var(--ease);
}
.site-nav a:hover { color: var(--text); background: var(--surface-2); text-decoration: none; }
.site-nav a.active { color: var(--accent); }
.site-nav a.active::after { transform: scaleX(1); }

.header-actions { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0; }

/* --- Mobil: Burger und Schublade ------------------------------------------ */

/* Der Burger existiert nur unterhalb der Bruchstelle — siehe Abschnitt
   "Responsiv" ganz unten, dort wird zwischen Leiste und Schublade getauscht. */
.nav-toggle { display: none; }

.nav-backdrop {
  position: fixed;
  inset: 0;
  z-index: 60;
  background: rgba(10, 12, 16, .45);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-2) var(--ease);
}
body.nav-open .nav-backdrop { opacity: 1; pointer-events: auto; }

/* Die Schublade bleibt immer im Baum und wird nur verschoben — das hält den
   Übergang flüssig und den Inhalt für Screenreader auffindbar. */
.nav-drawer {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  z-index: 61;
  width: min(19rem, 84vw);
  padding: var(--sp-5) var(--sp-4) var(--sp-6);
  background: var(--surface);
  border-left: 1px solid var(--border);
  box-shadow: var(--shadow-lg);
  transform: translateX(101%);
  visibility: hidden;
  transition: transform var(--dur-3) var(--ease), visibility var(--dur-3);
  display: flex;
  flex-direction: column;
  overflow-y: auto;
  overscroll-behavior: contain;
}
body.nav-open .nav-drawer { transform: none; visibility: visible; }

.drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--sp-3);
  margin-bottom: var(--sp-5);
}
.drawer-user {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  margin-bottom: var(--sp-4);
  border-radius: var(--radius);
  background: var(--surface-2);
  font-size: .92rem;
  min-width: 0;
}
.drawer-user .name { font-weight: 620; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.drawer-link {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-3);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-weight: 540;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.drawer-link:hover { background: var(--surface-2); text-decoration: none; }
.drawer-link.active { background: var(--accent-soft); color: var(--accent); }
.drawer-link svg { width: 1.15rem; height: 1.15rem; opacity: .65; flex-shrink: 0; }
.drawer-link.active svg { opacity: 1; }
.drawer-sep { height: 1px; background: var(--border); margin: var(--sp-3) 0; }

/* --- Reiter-Leiste unten -------------------------------------------------- */
/* Am Desktop gibt es sie nicht: dort steht .site-nav in der Kopfzeile. Unter
   1024px wandert die Navigation in die Schublade, und dann fehlt der Blick
   darauf, wo man gerade ist — genau die Frage, die beim Wischen zwischen den
   Reitern aufkommt. Die Breite ist der Grund für die kurzen Beschriftungen:
   sechs Spalten auf 375px lassen je 62px, „Abstimmungen" bräuchte das Doppelte. */
.tab-bar { display: none; }

@media (max-width: 1024px) {
  .tab-bar {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    position: fixed;
    left: 0; right: 0; bottom: 0;
    /* Unter der Schublade (61) und ihrem Verdunkler (60): ist das Menü offen,
       gehört die Leiste mit ins Abgedunkelte. */
    z-index: 40;
    background: var(--surface);
    border-top: 1px solid var(--border);
    /* Die Gestentaste unten am Bildschirm frisst sonst die untere Zeile. */
    padding-bottom: env(safe-area-inset-bottom, 0px);
  }
  .tab-bar a {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    min-width: 0;
    padding: .5rem .1rem .55rem;
    color: var(--muted);
    font-size: .6rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: -.01em;
    transition: color var(--dur-1) var(--ease);
  }
  .tab-bar a:hover { text-decoration: none; }
  .tab-bar a span {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .tab-bar svg { width: 1.3rem; height: 1.3rem; opacity: .7; }
  .tab-bar a.active { color: var(--accent); }
  .tab-bar a.active svg { opacity: 1; }

  /* Platz schaffen, sonst verschwindet das Letzte auf jeder Seite hinter der
     Leiste — Fusszeile, Absenden-Knopf, letztes Foto. */
  body { padding-bottom: calc(3.6rem + env(safe-area-inset-bottom, 0px)); }
}

/* Burger-Symbol: drei Striche, die sich beim Öffnen zum Kreuz falten. */
.burger { display: block; width: 18px; height: 12px; position: relative; }
.burger span {
  position: absolute;
  left: 0;
  width: 100%;
  height: 2px;
  border-radius: 2px;
  background: currentColor;
  transition: transform var(--dur-2) var(--ease), opacity var(--dur-1) var(--ease);
}
.burger span:nth-child(1) { top: 0; }
.burger span:nth-child(2) { top: 5px; }
.burger span:nth-child(3) { top: 10px; }
body.nav-open .burger span:nth-child(1) { transform: translateY(5px) rotate(45deg); }
body.nav-open .burger span:nth-child(2) { opacity: 0; }
body.nav-open .burger span:nth-child(3) { transform: translateY(-5px) rotate(-45deg); }

/* --- Hauptbereich --------------------------------------------------------- */

main {
  flex: 1;
  width: 100%;
  max-width: var(--content);
  margin: 0 auto;
  padding: var(--sp-6) var(--sp-5) var(--sp-8);
}
main.center { display: flex; align-items: center; justify-content: center; max-width: 100%; }
main.wide { max-width: 82rem; }

.page-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--sp-4);
  flex-wrap: wrap;
  margin-bottom: var(--sp-6);
}
.page-head p { color: var(--muted); margin: 0; }

.section { margin-bottom: var(--sp-7); }
.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--sp-4);
  margin-bottom: var(--sp-4);
}
.section-head h2 { margin: 0; }
.section-head a { font-size: .9rem; font-weight: 540; }

.stack { display: flex; flex-direction: column; gap: var(--sp-3); }
.row { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.spacer { flex: 1; }
.muted { color: var(--muted); }
.small { font-size: .875rem; }
.tiny { font-size: .8rem; }
.nowrap { white-space: nowrap; }

/* --- Karten --------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1.25rem;
  box-shadow: var(--shadow);
}
.card-tight { padding: .9rem 1rem; }
.card + .card { margin-top: .75rem; }

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

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .45rem;
  padding: .55rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  color: var(--text);
  font: inherit;
  font-size: .93rem;
  font-weight: 600;
  line-height: 1.3;
  cursor: pointer;
  text-decoration: none;
  transition: background .15s ease, border-color .15s ease, color .15s ease;
  white-space: nowrap;
}
.btn:hover { text-decoration: none; background: var(--border); }
.btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .5; cursor: not-allowed; }

.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-hover); }
.btn-outline { background: transparent; border-color: var(--border-strong); color: var(--text); }
.btn-outline:hover { background: var(--surface-2); }
.btn-ghost { background: transparent; color: var(--muted); }
.btn-ghost:hover { background: var(--surface-2); color: var(--text); }
.btn-danger { background: transparent; border-color: var(--border-strong); color: var(--danger); }
.btn-danger:hover { background: var(--danger-soft); border-color: var(--danger); }
.btn-sm { padding: .35rem .7rem; font-size: .85rem; }
.btn-lg { padding: .7rem 1.4rem; font-size: 1rem; }
.btn-block { width: 100%; }
.btn svg { width: 1.05em; height: 1.05em; flex-shrink: 0; }

.icon-btn {
  width: 2.3rem; height: 2.3rem;
  padding: 0;
  display: inline-grid; place-items: center;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--muted);
  cursor: pointer;
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }
.icon-btn svg { width: 1.15rem; height: 1.15rem; display: block; }

.inline-form { display: inline; }

/* --- Badges --------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .2rem .55rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--muted);
  font-size: .78rem;
  font-weight: 650;
  letter-spacing: .01em;
  white-space: nowrap;
}
.badge-accent { background: var(--accent-soft); color: var(--accent); }
.badge-success { background: var(--success-soft); color: var(--success); }
.badge-danger { background: var(--danger-soft); color: var(--danger); }
.badge-warning { background: var(--warning-soft); color: var(--warning); }

.badge-live { background: var(--danger-soft); color: var(--danger); }
.badge-live .dot {
  width: .5rem; height: .5rem;
  border-radius: 50%;
  background: currentColor;
  animation: pulse 1.8s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: .35; transform: scale(.75); }
}
@media (prefers-reduced-motion: reduce) {
  .badge-live .dot { animation: none; }
}

/* --- Avatare -------------------------------------------------------------- */

.avatar {
  --size: 2rem;
  width: var(--size);
  height: var(--size);
  flex-shrink: 0;
  border-radius: 50%;
  display: inline-grid;
  place-items: center;
  overflow: hidden;
  font-size: calc(var(--size) * .38);
  font-weight: 700;
  letter-spacing: -.02em;
  color: #fff;
  background: hsl(var(--hue, 220) 55% 45%);
  user-select: none;
}
[data-theme="dark"] .avatar { background: hsl(var(--hue, 220) 45% 42%); }
.avatar img { width: 100%; height: 100%; object-fit: cover; }
.avatar-sm { --size: 1.6rem; }
.avatar-lg { --size: 3rem; }
.avatar-xl { --size: 4.5rem; }

.avatar-stack { display: flex; }
.avatar-stack .avatar { border: 2px solid var(--surface); margin-left: -.5rem; }
.avatar-stack .avatar:first-child { margin-left: 0; }

.person { display: inline-flex; align-items: center; gap: .5rem; }

/* --- Events --------------------------------------------------------------- */

.event-card {
  display: flex;
  gap: 1rem;
  align-items: flex-start;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 1rem 1.1rem;
  box-shadow: var(--shadow);
  transition: border-color .15s ease, transform .15s ease;
}
.event-card:hover { border-color: var(--border-strong); }
.event-card.is-cancelled { opacity: .62; }
.event-card.is-cancelled .event-card-title { text-decoration: line-through; }

.date-chip {
  flex-shrink: 0;
  width: 3.4rem;
  text-align: center;
  padding: .4rem .2rem .45rem;
  border-radius: var(--radius-sm);
  background: var(--surface-2);
  border: 1px solid var(--border);
  line-height: 1.1;
}
.date-chip .month { display: block; font-size: .68rem; font-weight: 700; text-transform: uppercase; color: var(--accent); letter-spacing: .04em; }
.date-chip .day { display: block; font-size: 1.35rem; font-weight: 700; }
.date-chip .time { display: block; font-size: .7rem; color: var(--muted); margin-top: .1rem; }

.event-card-body { flex: 1; min-width: 0; }
.event-card-title { font-size: 1.05rem; font-weight: 650; color: var(--text); }
.event-card-title:hover { color: var(--accent); text-decoration: none; }
.event-card-meta { display: flex; flex-wrap: wrap; gap: .35rem .8rem; color: var(--muted); font-size: .875rem; margin-top: .2rem; }
.event-card-meta .item { display: inline-flex; align-items: center; gap: .3rem; }
.event-card-meta svg { width: .95em; height: .95em; opacity: .75; }
.event-card-side { display: flex; flex-direction: column; align-items: flex-end; gap: .4rem; flex-shrink: 0; }

/* Event-Detail */
.event-hero { margin-bottom: 1.5rem; }
.event-hero h1 { margin-bottom: .6rem; }
.event-facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: .9rem;
  margin: 1.25rem 0;
}
.fact { display: flex; gap: .6rem; align-items: flex-start; }
.fact svg { width: 1.15rem; height: 1.15rem; color: var(--accent); flex-shrink: 0; margin-top: .15rem; }
.fact .label { font-size: .75rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); font-weight: 650; }
.fact .value { font-weight: 550; }

.prose { line-height: 1.7; overflow-wrap: anywhere; }
.prose a { text-decoration: underline; }

/* Luft über Zwischentiteln. Ohne das steht eine Überschrift genauso weit vom
   Absatz darüber wie zwei Absätze voneinander, und ein langer Text (etwa die
   Datenschutzerklärung) liest sich als eine einzige Wand. */
.prose h2 { margin-top: var(--sp-6); }
.prose h3 { margin-top: var(--sp-5); }
.prose > :first-child { margin-top: 0; }
.prose ul { margin: 0 0 var(--sp-4); }

.detail-grid { display: grid; grid-template-columns: 1fr; gap: 1.5rem; align-items: start; }
@media (min-width: 900px) {
  .detail-grid { grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); gap: 2rem; }
  .detail-grid > .sidebar { position: sticky; top: calc(var(--header-h) + 1.5rem); }
}

/* RSVP */
.rsvp-buttons { display: flex; gap: .5rem; flex-wrap: wrap; }
.rsvp-buttons .btn { flex: 1; min-width: 7rem; }
.rsvp-buttons .btn.selected[data-status="yes"] { background: var(--success); border-color: var(--success); color: #fff; }
.rsvp-buttons .btn.selected[data-status="maybe"] { background: var(--warning); border-color: var(--warning); color: #fff; }
.rsvp-buttons .btn.selected[data-status="no"] { background: var(--danger); border-color: var(--danger); color: #fff; }

.attendee-group + .attendee-group { margin-top: 1.1rem; }
.attendee-group h3 { font-size: .78rem; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin-bottom: .5rem; }
.attendee-list { display: flex; flex-direction: column; gap: .45rem; }
.attendee { display: flex; align-items: center; gap: .55rem; font-size: .92rem; }
.attendee .note { color: var(--muted); font-size: .85rem; }

.capacity-bar { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin-top: .5rem; }
.capacity-bar span { display: block; height: 100%; background: var(--accent); border-radius: 999px; }

/* Video-Panel */
.video-panel {
  background: linear-gradient(135deg, var(--accent-soft), color-mix(in srgb, var(--accent-soft) 40%, var(--surface)));
  border: 1px solid color-mix(in srgb, var(--accent) 25%, var(--border));
  border-radius: var(--radius);
  padding: 1.1rem 1.2rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}
.video-panel .icon {
  width: 2.6rem; height: 2.6rem;
  display: grid; place-items: center;
  border-radius: var(--radius-sm);
  background: var(--accent);
  color: var(--on-accent);
  flex-shrink: 0;
}
.video-panel .icon svg { width: 1.3rem; height: 1.3rem; }
.video-panel .text { flex: 1; min-width: 10rem; }
.video-panel .text strong { display: block; }

/* --- Kommentare ----------------------------------------------------------- */

.comment { display: flex; gap: .75rem; padding: .85rem 0; border-top: 1px solid var(--border); }
.comment:first-of-type { border-top: 0; }
.comment-body { flex: 1; min-width: 0; }
.comment-head { display: flex; align-items: baseline; gap: .5rem; flex-wrap: wrap; }
.comment-head .name { font-weight: 650; font-size: .92rem; }
.comment-text { white-space: pre-wrap; overflow-wrap: anywhere; margin-top: .15rem; }
.comment .delete { opacity: 0; transition: opacity .15s ease; }
.comment:hover .delete, .comment:focus-within .delete { opacity: 1; }

/* --- Galerie -------------------------------------------------------------- */

.gallery-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: .6rem;
}
.gallery-item {
  position: relative;
  aspect-ratio: 1;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.gallery-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .25s ease; }
.gallery-item:hover img { transform: scale(1.04); }
.gallery-item .overlay {
  position: absolute; inset: auto 0 0 0;
  padding: 1.6rem .55rem .45rem;
  background: linear-gradient(transparent, rgba(0, 0, 0, .72));
  color: #fff;
  font-size: .78rem;
  opacity: 0;
  transition: opacity .2s ease;
}
.gallery-item:hover .overlay, .gallery-item:focus-within .overlay { opacity: 1; }
.gallery-item .delete { position: absolute; top: .35rem; right: .35rem; opacity: 0; }
.gallery-item:hover .delete, .gallery-item:focus-within .delete { opacity: 1; }

.album-tabs { display: flex; gap: .4rem; overflow-x: auto; padding-bottom: .5rem; margin-bottom: 1rem; scrollbar-width: thin; }
.album-tabs a {
  padding: .35rem .75rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  color: var(--muted);
  font-size: .85rem;
  font-weight: 550;
  white-space: nowrap;
}
.album-tabs a:hover { background: var(--surface-2); text-decoration: none; }
.album-tabs a.active { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.picker-thumb .picker-file {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  padding: .4rem;
  background: var(--surface-2);
  color: var(--muted);
  font-size: .65rem;
  text-align: center;
  overflow: hidden;
  word-break: break-all;
}

/* Video in der Galerie: dieselbe Kachel wie ein Foto, mit Abspielzeichen. */
.gallery-item .video-badge {
  position: absolute;
  left: .5rem;
  bottom: .5rem;
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  padding: .2rem .45rem;
  border-radius: 999px;
  background: rgba(0, 0, 0, .62);
  color: #fff;
  font-size: .7rem;
  font-weight: 600;
  pointer-events: none;
}
.gallery-item .video-badge svg { width: .8rem; height: .8rem; }
/* Solange ffmpeg rechnet, gibt es noch kein Standbild. */
.gallery-item .video-placeholder {
  display: grid;
  place-items: center;
  aspect-ratio: 3 / 2;
  background: var(--surface-2);
  color: var(--muted);
  font-size: .8rem;
}
.lightbox video {
  max-width: 100%;
  max-height: 86vh;
  border-radius: var(--radius-sm);
  background: #000;
}

/* Lightbox */
.lightbox {
  position: fixed; inset: 0; z-index: 200;
  display: none;
  place-items: center;
  background: rgba(0, 0, 0, .88);
  padding: 1.5rem;
}
.lightbox.open { display: grid; }
.lightbox img { max-width: 100%; max-height: 86vh; border-radius: var(--radius-sm); }
.lightbox .caption { position: absolute; bottom: 1.2rem; left: 0; right: 0; text-align: center; color: #eee; font-size: .9rem; padding: 0 2rem; }
.lightbox .close { position: absolute; top: 1rem; right: 1rem; background: rgba(255, 255, 255, .12); color: #fff; border: 0; }
.lightbox .nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  background: rgba(255, 255, 255, .12); color: #fff; border: 0;
  width: 2.8rem; height: 2.8rem;
}
.lightbox .nav.prev { left: 1rem; }
.lightbox .nav.next { right: 1rem; }

/* --- Formulare ------------------------------------------------------------ */

.form-field { margin-bottom: 1.1rem; }
.form-field > label,
.form-label {
  display: block;
  margin-bottom: .35rem;
  font-size: .875rem;
  font-weight: 600;
  color: var(--text);
}
.form-help { font-size: .82rem; color: var(--muted); margin-top: .3rem; }

input[type="text"], input[type="password"], input[type="email"], input[type="number"],
input[type="url"], input[type="datetime-local"], input[type="date"], input[type="search"],
textarea, select {
  width: 100%;
  background: var(--bg);
  border: 1px solid var(--border-strong);
  color: var(--text);
  padding: .55rem .7rem;
  border-radius: var(--radius-sm);
  font: inherit;
  transition: border-color .15s ease, box-shadow .15s ease;
}
[data-theme="dark"] input, [data-theme="dark"] textarea, [data-theme="dark"] select { background: var(--surface-2); }
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 18%, transparent);
}
textarea { resize: vertical; min-height: 5rem; line-height: 1.6; }
/* max-width, weil die native Dateiauswahl ihre eigene Breite mitbringt
   (Knopf plus Dateiname) und die Einstellungsseite auf dem Handy sonst
   seitwaerts schiebt. */
input[type="file"] { padding: .4rem; background: var(--surface-2); border-style: dashed; cursor: pointer; max-width: 100%; }

.checkbox-field { display: flex; align-items: flex-start; gap: .6rem; margin-bottom: .7rem; }
.checkbox-field input[type="checkbox"] { width: 1.05rem; height: 1.05rem; margin-top: .25rem; accent-color: var(--accent); flex-shrink: 0; }
.checkbox-field label { font-weight: 500; margin: 0; }

.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr)); gap: 0 1rem; }

.errorlist { list-style: none; padding: 0; margin: .35rem 0 0; color: var(--danger); font-size: .85rem; }
.form-error { color: var(--danger); font-size: .9rem; }

.form-actions { display: flex; gap: .6rem; align-items: center; margin-top: 1.5rem; flex-wrap: wrap; }

.auth-card { width: 100%; max-width: 23rem; background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); padding: 2rem; box-shadow: var(--shadow-lg); }
.auth-card h1 { margin-top: 0; font-size: 1.5rem; }

.auth-brand { text-align: center; margin-bottom: 1.5rem; }
.auth-brand .brand-mark { width: 44px; height: 44px; font-size: 1.1rem; border-radius: 13px; margin: 0 auto .9rem; }
.auth-brand h1 { margin: 0 0 .25rem; }
.auth-brand p { margin: 0; }

/* --- Meldungen ------------------------------------------------------------ */

.messages { list-style: none; padding: 0; margin: 0 0 1.25rem; display: flex; flex-direction: column; gap: .5rem; }
.messages li {
  padding: .65rem .9rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  font-size: .92rem;
  overflow-wrap: anywhere;
}
.messages li.success { background: var(--success-soft); border-color: color-mix(in srgb, var(--success) 30%, transparent); color: var(--success); }
.messages li.error { background: var(--danger-soft); border-color: color-mix(in srgb, var(--danger) 30%, transparent); color: var(--danger); }
.messages li.warning { background: var(--warning-soft); border-color: color-mix(in srgb, var(--warning) 30%, transparent); color: var(--warning); }
.messages li.info { background: var(--accent-soft); border-color: color-mix(in srgb, var(--accent) 25%, transparent); color: var(--accent); }

.empty {
  text-align: center;
  padding: 2.5rem 1.5rem;
  color: var(--muted);
  border: 1px dashed var(--border-strong);
  border-radius: var(--radius);
  background: var(--surface);
}
.empty svg { width: 2rem; height: 2rem; opacity: .5; margin-bottom: .5rem; }

/* --- Tabellenartige Listen ------------------------------------------------ */

.list-row {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .7rem 0;
  border-top: 1px solid var(--border);
}
.list-row:first-child { border-top: 0; }

.copy-field { display: flex; gap: .5rem; align-items: stretch; }
.copy-field input { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: .82rem; }

/* --- Videokonferenz-Raum -------------------------------------------------- */

body.meet-page { background: #0b0d10; color: #e9ebee; height: 100vh; overflow: hidden; }
body.meet-page main { max-width: none; padding: 0; }

.meet {
  position: fixed;
  inset: 0;
  display: flex;
  flex-direction: column;
  background: #0b0d10;
}

.meet-bar {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .7rem 1rem;
  border-bottom: 1px solid #23262c;
  flex-shrink: 0;
}
.meet-bar .title { font-weight: 650; font-size: .95rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.meet-bar .status { font-size: .82rem; color: #9aa1ad; }

.meet-stage { flex: 1; padding: .75rem; overflow: hidden; display: flex; }
.meet-grid {
  flex: 1;
  display: grid;
  gap: .6rem;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
  align-content: center;
  overflow-y: auto;
}
.meet-grid.count-1 { grid-template-columns: 1fr; }
.meet-grid.count-2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 380px), 1fr)); }

.tile {
  position: relative;
  aspect-ratio: 16 / 9;
  background: #16191f;
  border: 1px solid #23262c;
  border-radius: 12px;
  overflow: hidden;
  display: grid;
  place-items: center;
  min-height: 0;
}
.tile.speaking { border-color: #6b8afd; box-shadow: 0 0 0 2px rgba(107, 138, 253, .35); }
.tile.screen { aspect-ratio: auto; grid-column: 1 / -1; max-height: 70vh; }
.tile video { width: 100%; height: 100%; object-fit: cover; display: block; }
.tile.screen video { object-fit: contain; background: #000; }
.tile .placeholder {
  width: 4.5rem; height: 4.5rem;
  border-radius: 50%;
  display: grid; place-items: center;
  font-size: 1.5rem; font-weight: 700; color: #fff;
  background: hsl(var(--hue, 220) 45% 42%);
}
.tile .label {
  position: absolute; left: .5rem; bottom: .5rem;
  display: flex; align-items: center; gap: .35rem;
  padding: .2rem .5rem;
  border-radius: 6px;
  background: rgba(0, 0, 0, .6);
  font-size: .78rem;
  max-width: calc(100% - 1rem);
}
.tile .label .name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tile .muted-icon { color: #f0817a; display: none; }
.tile.mic-off .muted-icon { display: block; }

.meet-controls {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: .6rem;
  padding: .85rem 1rem calc(.85rem + env(safe-area-inset-bottom));
  border-top: 1px solid #23262c;
  flex-shrink: 0;
  flex-wrap: wrap;
}
.meet-btn {
  width: 3.1rem; height: 3.1rem;
  border-radius: 50%;
  border: 1px solid #2f333b;
  background: #1c1f26;
  color: #e9ebee;
  display: grid; place-items: center;
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}
.meet-btn:hover { background: #262a33; }
.meet-btn svg { width: 1.3rem; height: 1.3rem; }
.meet-btn.off { background: #f0817a; border-color: #f0817a; color: #1a1113; }
.meet-btn.active { background: #6b8afd; border-color: #6b8afd; color: #0d1016; }
.meet-btn.leave { background: #d64545; border-color: #d64545; color: #fff; width: auto; padding: 0 1.4rem; border-radius: 999px; gap: .5rem; font: inherit; font-weight: 650; display: inline-flex; align-items: center; }
.meet-btn.leave:hover { background: #bd3a3a; }

.meet-overlay {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  background: rgba(11, 13, 16, .95);
  z-index: 10;
  padding: 1.5rem;
  text-align: center;
}
.meet-overlay .box { max-width: 24rem; }
.meet-overlay h2 { color: #fff; }
.meet-overlay p { color: #9aa1ad; }


/* ===========================================================================
   Politur — überschreibt bewusst einzelne Werte der Komponenten oben.
   Steht am Ende, damit die gewachsenen Regeln unangetastet bleiben und
   trotzdem klar ist, was zum neuen Erscheinungsbild gehört.
   =========================================================================== */

/* --- Karten und Flächen --------------------------------------------------- */

.card {
  padding: var(--sp-5);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: box-shadow var(--dur-2) var(--ease), transform var(--dur-2) var(--ease);
}
.card + .card { margin-top: var(--sp-3); }
.card-tight { padding: var(--sp-4); }

/* Nur Karten, die tatsächlich irgendwohin führen, heben sich beim Zeigen an.
   Sonst wirkt eine ganze Seite unruhig. */
a.card:hover, .card:has(> a:hover) { box-shadow: var(--shadow-md); transform: translateY(-1px); }

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

.btn {
  padding: .58rem 1.05rem;
  border-radius: var(--radius-sm);
  font-weight: 580;
  letter-spacing: -.006em;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease),
              transform var(--dur-1) var(--ease);
}
/* Der Druckpunkt. Winzig, aber er macht den Unterschied zwischen einer
   Fläche und etwas, das sich bedienen lässt. */
.btn:active { transform: translateY(1px); }
.btn-primary {
  box-shadow: 0 1px 2px color-mix(in srgb, var(--accent) 30%, transparent),
              inset 0 1px 0 color-mix(in srgb, #fff 18%, transparent);
}
.btn-primary:hover {
  box-shadow: 0 3px 12px color-mix(in srgb, var(--accent) 34%, transparent),
              inset 0 1px 0 color-mix(in srgb, #fff 18%, transparent);
}
.btn-lg { padding: .78rem 1.5rem; }

.icon-btn {
  width: 2.4rem; height: 2.4rem;
  border-radius: var(--radius-sm);
  border-color: transparent;
  transition: background var(--dur-1) var(--ease), color var(--dur-1) var(--ease);
}
.icon-btn:hover { background: var(--surface-2); color: var(--text); }

/* --- Event-Karten --------------------------------------------------------- */

.event-card {
  padding: var(--sp-4);
  border-radius: var(--radius);
  box-shadow: var(--shadow-xs);
  transition: box-shadow var(--dur-2) var(--ease), transform var(--dur-2) var(--ease),
              border-color var(--dur-2) var(--ease);
}
.event-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
  border-color: color-mix(in srgb, var(--accent) 22%, var(--border));
}
.event-card-title { font-weight: 620; letter-spacing: -.014em; }

.date-chip {
  width: 3.6rem;
  border-radius: var(--radius-sm);
  background: linear-gradient(170deg, var(--accent-soft), color-mix(in srgb, var(--accent-soft) 45%, var(--surface)));
  border-color: var(--accent-line);
  padding: var(--sp-2) var(--sp-1) .55rem;
}
.date-chip .day { font-size: 1.4rem; letter-spacing: -.03em; }

.capacity-bar { height: 7px; background: var(--surface-3); }
.capacity-bar span {
  background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 60%, #a855f7));
  transition: width var(--dur-3) var(--ease);
}

.video-panel { border-radius: var(--radius); box-shadow: var(--shadow-xs); }

/* --- Formulare ------------------------------------------------------------ */

.form-field input, .form-field textarea, .form-field select,
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="datetime-local"], textarea, select {
  border-radius: var(--radius-sm);
  transition: border-color var(--dur-1) var(--ease), box-shadow var(--dur-1) var(--ease);
}
.form-field input:focus, .form-field textarea:focus, .form-field select:focus,
input:focus, textarea:focus, select:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}

/* --- Passwortfeld mit Auge ------------------------------------------------ */

/* Die Huelle setzt das Skript in base.html; hier steht nur das Aussehen. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { width: 100%; padding-right: 2.9rem; }
.pw-toggle {
  position: absolute;
  right: .3rem;
  top: 50%;
  transform: translateY(-50%);
  width: 2.2rem; height: 2.2rem;
  padding: 0;
  display: grid; place-items: center;
  border: 0;
  border-radius: var(--radius-sm);
  background: none;
  color: var(--muted);
  cursor: pointer;
  transition: color var(--dur-1) var(--ease), background var(--dur-1) var(--ease);
}
.pw-toggle:hover { color: var(--text); background: var(--surface-2); }
.pw-toggle svg { width: 1.15rem; height: 1.15rem; display: block; }
.pw-eye, .pw-eye-off { display: grid; }
.pw-toggle .pw-eye-off { display: none; }
.pw-wrap.is-visible .pw-toggle .pw-eye { display: none; }
.pw-wrap.is-visible .pw-toggle .pw-eye-off { display: grid; }
.pw-wrap.is-visible .pw-toggle { color: var(--accent); }

.auth-card {
  box-shadow: var(--shadow-lg);
  border-radius: var(--radius-lg);
  animation: rise var(--dur-3) var(--ease-out) both;
  position: relative;
  z-index: 1;
  /* Leicht durchscheinend, damit man das Foto dahinter ahnt, ohne dass die
     Eingabefelder an Kontrast verlieren. */
  background: color-mix(in srgb, var(--surface) 92%, transparent);
  backdrop-filter: saturate(160%) blur(16px);
  -webkit-backdrop-filter: saturate(160%) blur(16px);
}

/* Foto hinter der Anmeldung. Liegt hinter allem, nicht nur hinter der Karte —
   darum am body und nicht im Hauptbereich. */
.auth-bg {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
}
/* Von der Eingangs-Animation ausgenommen: ein transform auf einem fixierten
   Element macht es kurzzeitig zum Bezugsrahmen und lässt das Bild springen. */
main > .auth-bg { animation: none; }
.auth-bg img { width: 100%; height: 100%; object-fit: cover; object-position: center 40%; }
.auth-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    radial-gradient(80% 70% at 50% 45%, rgba(10, 12, 18, .35), rgba(10, 12, 18, .68)),
    linear-gradient(160deg, color-mix(in srgb, var(--accent) 30%, transparent), transparent 60%);
}
[data-theme="light"] .auth-bg::after {
  background:
    radial-gradient(80% 70% at 50% 45%, rgba(250, 250, 252, .58), rgba(250, 250, 252, .84)),
    linear-gradient(160deg, color-mix(in srgb, var(--accent) 16%, transparent), transparent 60%);
}

/* Auf dem Handy faellt die Karte ganz weg. Eine Flaeche, die den Schirm
   fuellt, verdeckt zwangslaeufig das ganze Foto - und sie erklaert nichts:
   wer hier landet, weiss, wo er sich anmeldet. Uebrig bleiben die zwei Felder,
   der Haken, der Knopf und der Link. Den Kontrast tragen die Felder selbst
   plus ein Hauch Textschatten, nicht mehr ein Kasten dahinter. */
@media (max-width: 720px) {
  .auth-brand { display: none; }

  .auth-card {
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding: 0;
    max-width: 22rem;
  }

  .auth-card label,
  .auth-card .muted,
  .auth-card a { text-shadow: 0 1px 4px rgba(0, 0, 0, .6); }
  [data-theme="light"] .auth-card label,
  [data-theme="light"] .auth-card .muted,
  [data-theme="light"] .auth-card a { text-shadow: 0 1px 4px rgba(255, 255, 255, .85); }

  /* Die Felder sind jetzt das einzige Flaechenelement - entsprechend deutlich. */
  .auth-card input[type="text"],
  .auth-card input[type="password"] {
    background: color-mix(in srgb, var(--surface) 94%, transparent);
    border-color: var(--border-strong);
    box-shadow: var(--shadow);
  }
  .auth-card .checkbox-field { padding: .1rem 0; }

  /* Der Schleier haelt jetzt allein die Lesbarkeit - etwas kraeftiger als am
     Desktop, aber so, dass das Foto klar erkennbar bleibt. */
  .auth-bg::after {
    background:
      radial-gradient(95% 65% at 50% 42%, rgba(8, 10, 16, .3), rgba(8, 10, 16, .66)),
      linear-gradient(160deg, color-mix(in srgb, var(--accent) 22%, transparent), transparent 60%);
  }
  [data-theme="light"] .auth-bg::after {
    background:
      radial-gradient(95% 65% at 50% 42%, rgba(250, 250, 252, .42), rgba(250, 250, 252, .74)),
      linear-gradient(160deg, color-mix(in srgb, var(--accent) 12%, transparent), transparent 60%);
  }
}

/* --- Meldungen ------------------------------------------------------------ */

.messages li { border-radius: var(--radius-sm); box-shadow: var(--shadow-xs); }

/* --- Bildflächen ---------------------------------------------------------- */

/* Zum Austauschen: eine eigene Datei unter core/static/core/img/ ablegen und
   im Template auf sie zeigen. Solange nichts hinterlegt ist, greift der
   Verlauf unten — nie ein leeres graues Rechteck. */
.media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius);
  background:
    linear-gradient(135deg,
      color-mix(in srgb, var(--accent) 22%, var(--surface-2)),
      color-mix(in srgb, var(--accent) 6%, var(--surface-2)) 55%,
      color-mix(in srgb, #a855f7 12%, var(--surface-2)));
  isolation: isolate;
}
.media img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-3) var(--ease);
}
a:hover > .media img, .media:hover img { transform: scale(1.035); }
.media-16x9 { aspect-ratio: 16 / 9; }
.media-4x3  { aspect-ratio: 4 / 3; }
.media-1x1  { aspect-ratio: 1 / 1; }

/* Verlauf über dem Bild, damit Text darauf immer lesbar bleibt. */
.media-overlay::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(8, 10, 15, .72), rgba(8, 10, 15, .18) 52%, transparent);
}
.media-caption {
  position: absolute;
  left: var(--sp-5); right: var(--sp-5); bottom: var(--sp-4);
  z-index: 1;
  color: #fff;
}
.media-caption h1, .media-caption h2 { color: #fff; margin-bottom: var(--sp-1); }
.media-caption p { color: rgba(255, 255, 255, .82); margin: 0; }

/* Vorschaufläche, solange ein Bild noch lädt. */
.media.is-loading::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg, transparent 20%,
              color-mix(in srgb, #fff 22%, transparent) 42%, transparent 64%);
  background-size: 220% 100%;
  animation: shimmer 1.5s linear infinite;
}

/* --- Hero ----------------------------------------------------------------- */

.hero {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  padding: clamp(var(--sp-5), 4vw, var(--sp-7));
  margin-bottom: var(--sp-6);
  background:
    radial-gradient(120% 140% at 8% 0%, color-mix(in srgb, var(--accent) 16%, var(--surface)), transparent 62%),
    radial-gradient(100% 130% at 96% 8%, color-mix(in srgb, #a855f7 13%, var(--surface)), transparent 58%),
    var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow);
}
/* Das Bild sitzt rechts und blendet nach links aus, wo der Text steht. So
   bleibt es kräftig genug, dass man Gesichter erkennt, ohne der Überschrift
   den Untergrund wegzunehmen. Fehlt die Datei, bleibt der Verlauf von oben. */
.hero { min-height: 18rem; display: flex; flex-direction: column; justify-content: center; }
.hero-media {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Der Bildausschnitt. Kleinerer Wert zeigt mehr vom oberen Bildrand,
     groesserer mehr vom unteren. Hier tiefer gelegt, damit die Koepfe
     nicht an den unteren Rand rutschen. */
  object-position: center 55%;
  opacity: .92;
  z-index: 0;
  pointer-events: none;
  /* Nach rechts geschoben, damit die Person am linken Bildrand aus der
     Ausblendung herauskommt. Was rechts hinausragt, schneidet .hero ab. */
  transform: translateX(6%);
  /* Die Blende endet weiter links als vorher (92 statt 78) und wird erst
     später voll deckend - dadurch bleibt links mehr vom Bild stehen.
     Für den Textkontrast sorgt jetzt .hero::before, nicht mehr diese Blende. */
  -webkit-mask-image: linear-gradient(to left, #000 0%, #000 46%, transparent 92%);
          mask-image: linear-gradient(to left, #000 0%, #000 46%, transparent 92%);
}
[data-theme="dark"] .hero-media { opacity: .78; }

/* Schleier hinter dem Text. Liegt zwischen Bild und Inhalt und garantiert den
   Kontrast unabhängig davon, wie hell das Bild an dieser Stelle ist. */
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to right,
    var(--surface) 4%,
    color-mix(in srgb, var(--surface) 74%, transparent) 26%,
    color-mix(in srgb, var(--surface) 26%, transparent) 44%,
    transparent 60%);
}
.hero > *:not(.hero-media) { position: relative; z-index: 2; max-width: 34rem; }

/* Schmale Schirme: nebeneinander geht nicht mehr, also legt sich das Bild
   hinter den ganzen Block und wird dafür deutlich zurückgenommen. */
/* Auf dem Handy ist kein Platz fuer Bild UND Text nebeneinander. Statt das
   Foto zum unlesbaren Geist hinter dem Text zu machen, bekommt es ein eigenes
   Band darueber - dort sieht man die Gesichter tatsaechlich. */
@media (max-width: 720px) {
  .hero {
    min-height: 0;
    padding: 0;
    display: block;
    overflow: hidden;
  }
  .hero::before { display: none; }
  .hero-media {
    position: static;
    width: 100%;
    height: auto;
    aspect-ratio: 16 / 10;
    object-position: center 45%;
    opacity: 1;
    transform: none;
    -webkit-mask-image: none;
            mask-image: none;
  }
  [data-theme="dark"] .hero-media { opacity: .92; }
  .hero > *:not(.hero-media) {
    max-width: none;
    padding-left: var(--sp-5);
    padding-right: var(--sp-5);
  }
  .hero > h1 { margin-top: var(--sp-5); }
  .hero-actions { padding-bottom: var(--sp-5); margin-top: var(--sp-4); }
}

/* --- Bildband über einer Seite -------------------------------------------- */

/* Wie das Hero, aber flacher und mit dem Titel direkt auf dem Bild. */
.page-banner {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-lg);
  margin-bottom: var(--sp-6);
  aspect-ratio: 21 / 8;
  min-height: 11rem;
  background: var(--surface-2);
  box-shadow: var(--shadow);
}
.page-banner img {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
  /* Siehe .hero-media: tiefer gelegt, damit die Gesichter oberhalb des
     Verlaufs mit dem Titel sitzen. */
  object-position: center 68%;
}
.page-banner::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(8, 10, 15, .78), rgba(8, 10, 15, .25) 55%, rgba(8, 10, 15, .05));
}
.page-banner .banner-text {
  position: absolute;
  left: clamp(var(--sp-4), 3vw, var(--sp-6));
  right: clamp(var(--sp-4), 3vw, var(--sp-6));
  bottom: clamp(var(--sp-4), 3vw, var(--sp-5));
  z-index: 1;
  color: #fff;
}
.page-banner h1 { color: #fff; margin: 0 0 var(--sp-1); }
.page-banner p { color: rgba(255, 255, 255, .85); margin: 0; }
@media (max-width: 560px) { .page-banner { aspect-ratio: 16 / 9; border-radius: var(--radius); } }

.hero h1 { margin-bottom: var(--sp-2); }
.hero p { color: var(--muted); margin: 0; max-width: 46ch; }
.hero-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-5); }

/* --- Leerzustände --------------------------------------------------------- */

/* Eine leere Liste ist kein Fehler, sondern eine Einladung. */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--sp-3);
  padding: var(--sp-7) var(--sp-5);
  border-radius: var(--radius);
  border: 1px dashed var(--border-strong);
  background: color-mix(in srgb, var(--surface) 55%, transparent);
  color: var(--muted);
}
.empty .empty-icon {
  width: 3.2rem; height: 3.2rem;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--accent-soft);
  color: var(--accent);
}
.empty .empty-icon svg { width: 1.5rem; height: 1.5rem; }
.empty h3 { color: var(--text); margin: 0; }
.empty p { margin: 0; max-width: 38ch; }

/* --- Gallerie ------------------------------------------------------------- */

.gallery-item {
  border-radius: var(--radius-sm);
  overflow: hidden;
  transition: transform var(--dur-2) var(--ease), box-shadow var(--dur-2) var(--ease);
}
.gallery-item:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); }

/* --- Listenzeilen --------------------------------------------------------- */

.list-row { transition: background var(--dur-1) var(--ease); border-radius: var(--radius-sm); }
.list-row:hover { background: var(--surface-2); }

/* --- Abstimmungen --------------------------------------------------------- */

/* Statt des Datumsklotzes der Event-Karte: eine Abstimmung hat noch kein
   Datum, darum an derselben Stelle nur das Symbol. */
.poll-chip { display: grid; place-items: center; min-height: 3.1rem; color: var(--accent); }
.poll-chip svg { width: 1.5rem; height: 1.5rem; }

.poll-option {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--sp-4);
  box-shadow: var(--shadow-xs);
  transition: border-color var(--dur-2) var(--ease), background var(--dur-2) var(--ease);
}
.poll-option + .poll-option { margin-top: var(--sp-3); }
.poll-option.is-best {
  border-color: var(--accent-line);
  background: color-mix(in srgb, var(--accent-soft) 45%, var(--surface));
}
.poll-option.is-decided {
  border-color: color-mix(in srgb, var(--success) 45%, var(--border));
  background: color-mix(in srgb, var(--success-soft) 55%, var(--surface));
}
.poll-option.is-past { opacity: .6; }

.poll-option-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-3);
}
.poll-option-head .when { min-width: 0; flex: 1; }
.poll-option-head .value { font-weight: 650; line-height: 1.3; }

/* Die drei Antwortknöpfe. Radios statt Buttons: so steht die ganze Antwort in
   einem Formular und geht mit einem Klick raus, statt pro Vorschlag einmal. */
.vote-choices { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-2); }
.vote-choices.is-single { grid-template-columns: minmax(0, 1fr); }

.vote-choice { position: relative; display: block; }
.vote-choice input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.vote-choice span {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--sp-1);
  min-height: 2.5rem;
  padding: .5rem .55rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.15;
  text-align: center;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.vote-choice:hover span { border-color: var(--accent-line); }
.vote-choice input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.vote-choice input:checked + span { color: #fff; border-color: transparent; }
.vote-choice[data-choice="yes"] input:checked + span { background: var(--success); }
.vote-choice[data-choice="maybe"] input:checked + span { background: var(--warning); }
.vote-choice[data-choice="no"] input:checked + span { background: var(--danger); }
.vote-choice[data-choice="pick"] input:checked + span { background: var(--accent); }
.vote-choice[data-choice="pick"] span { justify-content: flex-start; text-align: left; }

.vote-bar {
  display: flex;
  height: 7px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--surface-3);
  margin: var(--sp-3) 0 var(--sp-2);
}
.vote-bar span { display: block; height: 100%; transition: width var(--dur-3) var(--ease); }
.vote-bar .yes { background: var(--success); }
.vote-bar .maybe { background: var(--warning); }
.vote-bar .no { background: var(--danger); }
.vote-bar .pick { background: var(--accent); }

.vote-tally {
  display: flex;
  align-items: center;
  gap: var(--sp-2) var(--sp-4);
  flex-wrap: wrap;
  font-size: .82rem;
  color: var(--muted);
}
.vote-tally .item { display: inline-flex; align-items: center; gap: .35rem; }
.vote-tally .swatch { width: .5rem; height: .5rem; border-radius: 999px; flex-shrink: 0; }
.vote-tally .swatch.yes { background: var(--success); }
.vote-tally .swatch.maybe { background: var(--warning); }
.vote-tally .swatch.no { background: var(--danger); }
.vote-tally .swatch.pick { background: var(--accent); }

.vote-people {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
  margin-top: var(--sp-2);
  font-size: .82rem;
  color: var(--muted);
}

.poll-result {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding: var(--sp-4) var(--sp-5);
  border-radius: var(--radius);
  border: 1px solid color-mix(in srgb, var(--success) 30%, var(--border));
  background: color-mix(in srgb, var(--success-soft) 60%, var(--surface));
  margin-bottom: var(--sp-5);
}
.poll-result .icon {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  background: var(--success);
  color: #fff;
  flex-shrink: 0;
}
.poll-result .icon svg { width: 1.4rem; height: 1.4rem; }
.poll-result .text { flex: 1; min-width: 10rem; display: flex; flex-direction: column; gap: .15rem; }
.poll-result .value { font-weight: 700; font-size: 1.05rem; }

/* Vorschlagszeilen im Formular */
.option-row { display: flex; align-items: center; gap: var(--sp-2); }
.option-row + .option-row { margin-top: var(--sp-2); }
.option-row input { flex: 1; min-width: 0; }
.option-row .icon-btn { flex-shrink: 0; }

/* Umschalter im Event-Formular: Termin steht fest / wird abgestimmt.
   Gebaut wie .vote-choice - der Knopf ist die Beschriftung, das Radio liegt
   unsichtbar darueber und traegt den Zustand. */
.segmented { display: inline-flex; gap: var(--sp-2); flex-wrap: wrap; }
.segment { position: relative; margin: 0; }
.segment input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}
.segment span {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
  padding: .5rem 1rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text-soft);
  font-size: .9rem;
  font-weight: 600;
  line-height: 1.2;
  transition: background var(--dur-1) var(--ease), border-color var(--dur-1) var(--ease),
              color var(--dur-1) var(--ease);
}
.segment:hover span { border-color: var(--accent-line); }
.segment input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: 2px; }
.segment input:checked + span { background: var(--accent); border-color: transparent; color: var(--on-accent); }

/* Hinweiskasten mit Symbol und einem Weg heraus */
.notice {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
  flex-wrap: wrap;
  padding: var(--sp-4);
  margin-bottom: var(--sp-4);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-2);
}
.notice .icon {
  display: grid;
  place-items: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: var(--radius-sm);
  background: var(--surface-3);
  color: var(--text-soft);
  flex-shrink: 0;
}
.notice .icon svg { width: 1.2rem; height: 1.2rem; }
.notice .text { flex: 1; min-width: 11rem; display: flex; flex-direction: column; gap: .15rem; }

/* Terminfindung auf der Event-Seite: die Vorschlaege mit dem Stand,
   abgestimmt wird auf der Abstimmungsseite selbst. */
.date-poll-list { display: flex; flex-direction: column; gap: var(--sp-2); }
.date-poll-row {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-3);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface-2);
}
.date-poll-row.is-best {
  border-color: color-mix(in srgb, var(--accent) 40%, var(--border));
  background: color-mix(in srgb, var(--accent-soft) 45%, var(--surface));
}
.date-poll-row .when {
  flex: 1;
  min-width: 11rem;
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  flex-wrap: wrap;
}
.date-poll-row .tally { display: inline-flex; gap: var(--sp-3); font-size: .82rem; color: var(--muted); }
.date-poll-row .tally .item { display: inline-flex; align-items: center; gap: .3rem; }
.date-poll-row .tally .swatch { width: .5rem; height: .5rem; border-radius: 999px; flex-shrink: 0; }
.date-poll-row .tally .swatch.yes { background: var(--success); }
.date-poll-row .tally .swatch.maybe { background: var(--warning); }
.date-poll-row .tally .swatch.no { background: var(--danger); }

/* Termin noch offen: gestrichelt statt durchgezogen, ueberall gleich. */
.event-card.is-tentative .date-chip {
  background: var(--surface-2);
  border: 1px dashed var(--border-strong);
  color: var(--muted);
}

/* Bilder auswaehlen - das native Feld wird vom Skript versteckt und durch
   Knopf, Zaehler und Vorschau ersetzt. Ohne Skript bleibt es sichtbar. */
.picker-native { display: none; }
.picker-head { display: flex; align-items: center; gap: var(--sp-3); flex-wrap: wrap; }
.picker-previews { display: flex; gap: var(--sp-2); flex-wrap: wrap; margin-top: var(--sp-3); }
.picker-thumb {
  position: relative;
  width: 4.5rem;
  height: 4.5rem;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.picker-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.picker-thumb .icon-btn {
  position: absolute;
  top: 2px;
  right: 2px;
  width: 1.5rem;
  height: 1.5rem;
  background: rgba(0, 0, 0, .55);
  border-color: transparent;
  color: #fff;
  font-size: 1rem;
  line-height: 1;
}

/* Profilbild zuschneiden: Leinwand zum Verschieben, runde Maske darueber. */
.cropper { margin-top: var(--sp-3); }
.crop-stage {
  position: relative;
  width: max-content;
  max-width: 100%;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--surface-2);
}
.crop-canvas { display: block; touch-action: none; cursor: grab; }
.crop-canvas:active { cursor: grabbing; }
.crop-mask {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 9999px color-mix(in srgb, var(--surface) 25%, rgba(0, 0, 0, .55));
  pointer-events: none;
}
.crop-tools { display: flex; align-items: center; gap: var(--sp-3); margin-top: var(--sp-3); flex-wrap: wrap; }
.crop-tools input[type="range"] { flex: 1; min-width: 8rem; accent-color: var(--accent); }

/* Mitgliederverwaltung */
.member-actions { display: flex; gap: var(--sp-2); flex-wrap: wrap; }

/* Filterleiste der Galerie. Auf schmalen Schirmen rutschen die beiden
   Auswahlfelder untereinander - 11rem Grundbreite reicht fuer die laengsten
   Eventnamen, ohne dass sie auf dem Handy gequetscht nebeneinander stehen. */
.filter-bar {
  display: flex;
  align-items: flex-end;
  gap: var(--sp-3);
  flex-wrap: wrap;
  padding: var(--sp-4);
  margin-bottom: var(--sp-5);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
}
.filter-field {
  display: flex;
  flex-direction: column;
  gap: .3rem;
  flex: 1 1 11rem;
  min-width: 0;
}
.filter-field label { font-size: .8rem; font-weight: 600; color: var(--muted); margin: 0; }
.filter-bar .btn { flex-shrink: 0; }

/* Tagesgruppen in der Galerie: eine Zeile Ueberschrift, dann das Raster.
   So bleibt ein Abend beisammen, statt sich unter alles andere zu mischen. */
.photo-day + .photo-day { margin-top: var(--sp-6); }
.photo-day-head {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  margin: 0 0 var(--sp-3);
  font-size: .95rem;
  font-weight: 650;
}
.photo-day-head .rule { flex: 1; height: 1px; background: var(--border); }
.photo-day-head .count {
  font-size: .8rem;
  font-weight: 500;
  color: var(--muted);
  white-space: nowrap;
}

/* --- Kalender ------------------------------------------------------------- */

.cal-toolbar {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  flex-wrap: wrap;
  margin-bottom: var(--sp-4);
}
.cal-steps { display: flex; align-items: center; gap: var(--sp-1); }
.cal-heading {
  flex: 1;
  min-width: 8rem;
  margin: 0;
  font-size: 1.15rem;
  font-weight: 680;
  letter-spacing: -.02em;
}
.cal-views { margin: 0; padding: 0; }

/* Wochenansicht: am Desktop sieben Spalten, auf dem Handy sieben Zeilen —
   nebeneinander bliebe von jedem Titel eine Silbe übrig. */
.cal-week { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: var(--sp-2); }
.cal-day {
  display: flex;
  flex-direction: column;
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  overflow: hidden;
}
.cal-day.is-weekend { background: var(--surface-2); }
.cal-day.is-today { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset; }
.cal-day-head {
  display: flex;
  align-items: baseline;
  gap: .3rem;
  padding: var(--sp-2) var(--sp-3);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 60%, transparent);
}
.cal-day-head .dow { font-size: .72rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); }
.cal-day-head .num { font-size: 1.05rem; font-weight: 700; }
.cal-day-head .mon { font-size: .7rem; color: var(--muted); }
.cal-day.is-today .cal-day-head .num { color: var(--accent); }
.cal-day-body { display: flex; flex-direction: column; gap: var(--sp-1); padding: var(--sp-2); min-height: 5rem; }
.cal-none { font-size: .75rem; color: var(--muted); opacity: .6; }

.cal-event {
  display: flex;
  flex-direction: column;
  gap: .1rem;
  padding: .35rem .5rem;
  border-radius: var(--radius-sm);
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  color: var(--text);
  font-size: .8rem;
  line-height: 1.25;
  min-width: 0;
}
.cal-event:hover { text-decoration: none; background: color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 12%); }
.cal-event .time { font-weight: 700; color: var(--accent); font-size: .72rem; }
.cal-event .title { overflow-wrap: anywhere; }
.cal-event.is-cancelled { background: var(--surface-2); border-left-color: var(--danger); }
.cal-event.is-cancelled .title { text-decoration: line-through; opacity: .7; }

/* Monatsraster */
.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
}
.cal-dow {
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2);
  font-size: .72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .04em;
  color: var(--muted);
  text-align: left;
}
.cal-cell {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
  min-height: 6rem;
  padding: var(--sp-2);
  background: var(--surface);
}
.cal-cell.is-weekend { background: color-mix(in srgb, var(--surface-2) 55%, var(--surface)); }
.cal-cell.is-outside { background: var(--bg-soft); }
.cal-cell.is-outside .cal-daynum { color: var(--muted); opacity: .55; }
.cal-cell.is-today { background: color-mix(in srgb, var(--accent-soft) 55%, var(--surface)); }

.cal-daynum {
  align-self: flex-start;
  min-width: 1.6rem;
  height: 1.6rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  font-size: .82rem;
  font-weight: 650;
  color: var(--text-soft);
}
.cal-daynum:hover { background: var(--surface-3); text-decoration: none; }
.cal-cell.is-today .cal-daynum { background: var(--accent); color: var(--on-accent); }

.cal-chips { display: flex; flex-direction: column; gap: .2rem; min-width: 0; }
.cal-event.is-tentative,
.cal-chip.is-tentative {
  border-left-style: dashed;
  border-left-color: var(--warning);
  background: var(--warning-soft);
}

.cal-chip {
  display: block;
  padding: .18rem .4rem;
  border-radius: 6px;
  background: var(--accent-soft);
  border-left: 3px solid var(--accent);
  color: var(--text);
  font-size: .74rem;
  line-height: 1.3;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.cal-chip:hover { text-decoration: none; background: color-mix(in srgb, var(--accent-soft) 70%, var(--accent) 12%); }
.cal-chip .time { font-weight: 700; color: var(--accent); margin-right: .25rem; }
.cal-chip.is-cancelled { background: var(--surface-2); border-left-color: var(--danger); text-decoration: line-through; opacity: .75; }

/* Nur auf dem Handy: statt Titeln ein Punkt pro Event. */
.cal-dots { display: none; gap: .18rem; }
.cal-dots .dot { width: .32rem; height: .32rem; border-radius: 999px; background: var(--accent); }
.cal-dots .dot.is-cancelled { background: var(--danger); }
.cal-dots .dot.is-tentative { background: var(--warning); }

/* Jahresübersicht */
.cal-year { display: grid; grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); gap: var(--sp-4); }
.cal-mini {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  padding: var(--sp-3);
  box-shadow: var(--shadow-xs);
}
.cal-mini-head {
  display: flex;
  align-items: center;
  gap: var(--sp-2);
  margin-bottom: var(--sp-2);
  color: var(--text);
  font-weight: 680;
  font-size: .95rem;
}
.cal-mini-head:hover { color: var(--accent); text-decoration: none; }
.cal-mini-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.cal-mini-grid .dow {
  font-size: .6rem;
  font-weight: 700;
  text-align: center;
  color: var(--muted);
  padding-bottom: .15rem;
}
.cal-mini-grid .day {
  display: grid;
  place-items: center;
  aspect-ratio: 1;
  border-radius: 5px;
  font-size: .68rem;
  color: var(--text-soft);
}
.cal-mini-grid .day.is-outside { visibility: hidden; }
.cal-mini-grid .day:hover { background: var(--surface-3); text-decoration: none; }
.cal-mini-grid .day.has-events { background: var(--accent-soft); color: var(--accent); font-weight: 700; }
.cal-mini-grid .day.is-today { outline: 1.5px solid var(--accent); }

/* --- E-Mail-Bestätigung --------------------------------------------------- */

.verify-wrap { max-width: 30rem; margin: var(--sp-6) auto 0; }
.verify-icon {
  display: grid;
  place-items: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius);
  background: var(--accent-soft);
  color: var(--accent);
  margin-bottom: var(--sp-4);
}
.verify-icon svg { width: 1.5rem; height: 1.5rem; }
.verify-wrap h1 { font-size: 1.5rem; margin-bottom: var(--sp-2); }

.verify-hint {
  padding: var(--sp-3) var(--sp-4);
  border-radius: var(--radius-sm);
  font-size: .875rem;
  margin: var(--sp-4) 0;
}
.verify-hint.is-warning {
  background: var(--warning-soft);
  color: var(--warning);
  border: 1px solid color-mix(in srgb, var(--warning) 25%, transparent);
}

.verify-code { margin-top: var(--sp-5); }
/* Der Code ist zum Abtippen da — grosse Ziffern, weite Sperrung, damit man
   beim Vergleich mit der Mail nicht die Stelle verliert. */
.verify-code input[name="code"] {
  flex: 1;
  min-width: 0;
  font-size: 1.35rem;
  font-weight: 700;
  letter-spacing: .18em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
.verify-code input[name="code"]:disabled { opacity: .5; }

.verify-change { margin-top: var(--sp-4); }
.verify-change summary {
  cursor: pointer;
  font-size: .875rem;
  color: var(--muted);
  list-style: none;
}
.verify-change summary::-webkit-details-marker { display: none; }
.verify-change summary::before { content: "▸ "; }
.verify-change[open] summary::before { content: "▾ "; }
.verify-change summary:hover { color: var(--accent); }

/* --- Responsiv ------------------------------------------------------------ */

/* Grosse Schirme: mehr Luft, nicht mehr Inhalt. */
@media (min-width: 1280px) {
  :root { --content: 68rem; }
  main { padding-top: var(--sp-7); }
}

/* Ab hier wandert die Navigation in die Schublade. 1024px, weil die sechs
   Punkte plus Aktionen darunter anfangen zu drängeln. */
@media (max-width: 1024px) {
  .site-nav { display: none; }
  /* Ohne die Navigationsleiste fehlt das Element mit flex:1, das die Aktionen
     sonst nach rechts drueckt - hier uebernimmt das der Aussenabstand. */
  .header-actions { margin-left: auto; }
  /* Alles, was in der Schublade nochmal auftaucht, verschwindet aus der
     Kopfzeile. Sonst stehen dort fünf Bedienelemente nebeneinander. */
  .hide-mobile { display: none !important; }
  .nav-toggle {
    display: inline-grid;
    place-items: center;
    width: 2.4rem; height: 2.4rem;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text);
    cursor: pointer;
  }
  .nav-toggle:hover { background: var(--surface-2); }
}

@media (min-width: 1025px) {
  /* Über der Bruchstelle darf die Schublade nie auftauchen, auch nicht,
     wenn die Klasse am body noch hängt (Grösse geändert bei offener Schublade). */
  .nav-drawer, .nav-backdrop { display: none; }
}

@media (max-width: 720px) {
  :root { --header-h: 58px; }
  main { padding: var(--sp-5) var(--sp-4) var(--sp-7); }
  .site-header { padding: 0 var(--sp-4); gap: var(--sp-3); }
  .card { padding: var(--sp-4); }
  .hero { border-radius: var(--radius); }
  .gallery-grid { grid-template-columns: repeat(auto-fill, minmax(118px, 1fr)); gap: var(--sp-1); }
  .rsvp-buttons .btn { min-width: 0; padding: .58rem .5rem; }
  .meet-btn { width: 2.9rem; height: 2.9rem; }
  .event-facts { gap: var(--sp-3); }

  /* Ganzes Bild statt Ausschnitt: bei 3:2 entspricht das Band dem
     Seitenverhaeltnis der Vorlage, es wird also nichts weggeschnitten und der
     Titel unten liegt unter den Gesichtern statt darauf. */
  .page-banner { aspect-ratio: 3 / 2; min-height: 0; }
}

/* Event-Karte: dreispaltig geht auf dem Handy nicht auf - der Titel bleibt
   sonst als "Te" uebrig, weil die Badges rechts die Breite fressen. Als Raster
   wandern sie in eine eigene Zeile darunter. */
@media (max-width: 620px) {
  .event-card {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-areas:
      "chip body"
      "side side";
    gap: var(--sp-2) var(--sp-3);
    padding: var(--sp-3);
    align-items: start;
  }
  .event-card > .date-chip { grid-area: chip; }
  .event-card-body { grid-area: body; min-width: 0; }
  .event-card-side {
    grid-area: side;
    flex-direction: row;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--sp-2);
  }
  .event-card-meta { gap: var(--sp-1) var(--sp-4); }

  /* Filterleiste: nebeneinander wuerden die Auswahlfelder unterschiedlich
     breit ausfallen, je nachdem was rechts daneben noch mitlaeuft. */
  .filter-field { flex-basis: 100%; }
  .filter-bar .spacer { flex-basis: 100%; height: 0; }
}

/* Kleine Telefone: Buttons dürfen nicht mehr nebeneinander gequetscht werden. */
@media (max-width: 460px) {
  .brand span:not(.brand-mark) { display: none; }
  .page-head { gap: var(--sp-3); }
  .page-head .btn, .hero-actions .btn { flex: 1; }
  .date-chip { width: 3.1rem; }
  .rsvp-buttons { display: grid; grid-template-columns: 1fr 1fr 1fr; }
  .vote-choice span { font-size: .8rem; padding: .5rem .3rem; }
}

/* Fingerbedienung: kein Anheben beim Zeigen, das gibt es dort nicht. */

/* Kalender auf schmalen Schirmen: die Woche wird zur Liste, im Monatsraster
   verschwinden die Titel zugunsten von Punkten — sieben Spalten mal 47px
   geben keinen lesbaren Titel her, nur Buchstabensalat. Ein Tippen auf den
   Tag führt in die Woche, dort steht alles ausgeschrieben. */
@media (max-width: 900px) {
  .cal-week { grid-template-columns: minmax(0, 1fr); }
  .cal-day-body { min-height: 0; }
  .cal-year { grid-template-columns: repeat(auto-fill, minmax(10.5rem, 1fr)); gap: var(--sp-3); }
}

@media (max-width: 620px) {
  .cal-toolbar { gap: var(--sp-2); }
  .cal-heading { order: -1; flex-basis: 100%; font-size: 1.05rem; }
  /* .album-tabs scrollt waagerecht — es würde also lieber unsichtbar schmal
     werden als umzubrechen. Zusammen mit flex-end rutschte „Woche" nach links
     aus dem Sichtfeld, und dorthin kommt man in einem Scrollcontainer nicht
     zurück. Darum nicht schrumpfen lassen: dann bricht die Leiste sauber in
     die nächste Zeile, sobald sie neben „Heute" nicht mehr hinpasst. */
  .cal-steps { margin-right: auto; }
  .cal-views { flex: 0 0 auto; }

  .cal-grid { border-radius: var(--radius-sm); }
  .cal-dow { padding: var(--sp-1); text-align: center; font-size: .62rem; }
  .cal-cell { min-height: 3.1rem; align-items: center; padding: var(--sp-1) 2px; gap: 2px; }
  .cal-chips { display: none; }
  .cal-dots { display: flex; }
  .cal-daynum { align-self: center; min-width: 1.5rem; height: 1.5rem; font-size: .78rem; }
  /* Ganze Zelle antippbar, nicht nur die Ziffer. */
  .cal-daynum::after { content: ""; position: absolute; inset: 0; }
  .cal-dots { position: relative; z-index: 1; pointer-events: none; }
}
@media (hover: none) {
  .event-card:hover, .card:hover, .gallery-item:hover { transform: none; box-shadow: var(--shadow-xs); }
  .comment .delete { opacity: 1; }
}

@media print {
  .site-header, .nav-drawer, .nav-backdrop, .meet-controls,
  .form-actions, .btn { display: none !important; }
  body { background: #fff; }
  body::before { display: none; }
  main > * { animation: none; }
}

/* Ein [hidden] muss auch dann greifen, wenn die Klasse selbst ein display
   setzt - .btn { display: flex } gewinnt sonst gegen das [hidden] des Browsers,
   und ein per Javascript ausgeblendeter Knopf bleibt sichtbar stehen. Betrifft
   ausser den Gesichtern auch den "Anzeigen"-Knopf der Filterleisten. */
[hidden] { display: none !important; }

/* --- Gesichter markieren ---------------------------------------------------
   Die Vorschaubilder sind Ausschnitte aus dem Originalbild, per
   background-position gesetzt (siehe Face.crop_position) - dadurch braucht es
   keine zweite Datei und keine weitere Anfrage. Das Ziel zum Antippen ist
   immer gleich gross, egal wie klein das Gesicht im Bild ist; auf dem Handy
   wäre ein Rechteck direkt im Bild nur wenige Pixel breit. */

.tag-photo {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr);
  gap: var(--sp-5);
  align-items: start;
  margin-bottom: var(--sp-5);
}

.tag-image { position: relative; line-height: 0; }
.tag-image img {
  width: 100%;
  height: auto;
  border-radius: var(--radius);
  display: block;
}

.tag-box {
  position: absolute;
  border: 2px solid var(--accent);
  border-radius: var(--radius-sm);
  box-shadow: 0 0 0 1px rgb(0 0 0 / .35);
  pointer-events: none;
}
.tag-box.done { border-color: var(--success); }
.tag-box .tag-num {
  position: absolute;
  top: -.55rem;
  left: -.55rem;
}

.tag-num {
  display: grid;
  place-items: center;
  min-width: 1.35rem;
  height: 1.35rem;
  padding: 0 .3rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--on-accent);
  font-size: .72rem;
  font-weight: 640;
  line-height: 1;
}

.tag-side { min-width: 0; }
.tag-faces {
  display: flex;
  flex-direction: column;
  gap: var(--sp-3);
  margin-top: var(--sp-3);
}

.tag-face {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--sp-3);
  min-width: 0;
  transition: opacity var(--dur-2) var(--ease);
}
.tag-face select { flex: 1; min-width: 0; }

/* Rückmeldung beim Speichern im Hintergrund. Die Seite lädt nicht neu, also
   muss man sehen, dass etwas angekommen ist — sonst klickt man zweimal. */
.tag-state {
  flex: none;
  min-width: 1.1rem;
  font-size: .8rem;
  line-height: 1;
  color: var(--muted);
}
.tag-face.saving { opacity: .5; }
.tag-face.saving select { cursor: progress; }
.tag-face.saved .tag-state::before {
  content: "✓";
  color: var(--success);
  font-weight: 700;
}
/* Fehlermeldungen sind ganze Sätze — die bekommen eine eigene Zeile, statt
   das Auswahlfeld zusammenzuquetschen. */
.tag-face.failed .tag-state { flex: 1 1 100%; color: var(--danger); }
.tag-face.done .tag-crop { border-color: var(--success); }

/* Ein Vorschlag ist noch keine Zuordnung: das Feld ist vorausgefüllt, gilt
   aber weiter als offen. Er muss sich darum deutlich von einer bestätigten
   Zuordnung unterscheiden — sonst hält man ihn für erledigt und schaut nicht
   mehr hin, und genau dann rutscht der falsche durch. */
.tag-face.suggested .tag-crop {
  border-color: var(--warning);
  border-style: dashed;
}
.tag-guess {
  display: inline-block;
  padding: .1rem .4rem;
  border-radius: var(--radius-sm);
  background: var(--warning-soft);
  color: var(--text);
  font-size: .7rem;
  font-weight: 560;
  white-space: nowrap;
}

.tag-crop {
  position: relative;
  flex: none;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background-repeat: no-repeat;
  background-color: var(--surface-2);
}
.tag-crop .tag-num {
  position: absolute;
  bottom: -.35rem;
  right: -.35rem;
}

.tag-fixed { flex: 1; min-width: 0; }

/* Unter 900px steht die Seitenspalte unter dem Bild statt daneben - nebendran
   wäre das Bild so schmal, dass man die Gesichter darauf nicht mehr zuordnen
   könnte. */
@media (max-width: 900px) {
  .tag-photo { grid-template-columns: 1fr; gap: var(--sp-4); }
}

/* Auf dem Handy bleibt das Auswahlfeld neben dem Bildchen: nebeneinander ist
   es eine Zeile pro Gesicht statt zwei, und bei sieben Gesichtern auf einem
   Gruppenbild macht das den Unterschied. Nur der Knopf fällt darunter — den
   sieht ohnehin nur, wer kein Javascript hat. */
@media (max-width: 460px) {
  .tag-face { flex-wrap: wrap; }
  .tag-face .btn { flex: 1 1 100%; }
}

/* ---------------------------------------------------------------------------
   Sichere Bereiche (Notch, Statusleiste, Gestenbalken)

   Ab Android 15 zeichnen Apps standardmässig *hinter* den Systemleisten, und
   auf iOS tut das eine installierte PWA schon lange. Ohne die folgenden Regeln
   sitzt die Kopfzeile unter der Uhr und dem Batteriestand.

   `env(safe-area-inset-*)` liefert die nötigen Abstände; im Browser am Desktop
   sind sie 0, die Regeln ändern dort also nichts. Voraussetzung ist
   `viewport-fit=cover` im Viewport-Tag — das steht in base.html.

   Der Block steht bewusst am Dateiende: so gewinnt er gegen die
   Medienabfragen weiter oben, ohne dass dort überall ein calc() hinein muss.
   --------------------------------------------------------------------------- */

/* Die Leiste wächst nach oben und schiebt ihren Inhalt unter die Statusleiste
   heraus. Der milchige Hintergrund reicht weiterhin bis ganz nach oben — so
   bleibt der Übergang zur Systemleiste ruhig. */
.site-header {
  height: calc(var(--header-h) + env(safe-area-inset-top));
  padding-top: env(safe-area-inset-top);
}

/* Was unter der Kopfzeile klebt, muss um denselben Betrag tiefer. */
.detail-grid > .sidebar {
  top: calc(var(--header-h) + env(safe-area-inset-top) + 1.5rem);
}

.nav-drawer {
  padding-top: calc(var(--sp-5) + env(safe-area-inset-top));
  padding-bottom: calc(var(--sp-6) + env(safe-area-inset-bottom));
}

/* Unten der Gestenbalken. */
main {
  padding-bottom: calc(var(--sp-8) + env(safe-area-inset-bottom));
}

/* Vollbild-Ebenen bringen ihre eigenen Bedienelemente an den Rand. */
.lightbox .close { top: calc(1rem + env(safe-area-inset-top)); }
.lightbox .caption { bottom: calc(1.2rem + env(safe-area-inset-bottom)); }
.meet-bar { padding-top: calc(.7rem + env(safe-area-inset-top)); }

/* Der Umschalter auf der Anmeldeseite sitzt frei oben rechts. */
.theme-float {
  position: fixed;
  top: calc(1rem + env(safe-area-inset-top));
  right: calc(1rem + env(safe-area-inset-right));
}


/* ===========================================================================
   Die native Hülle — was es nur in der App gibt.
   =========================================================================== */

/* Eine Mitteilung, die eintrifft, während die App offen ist. Android zeigt
   in dem Fall von sich aus nichts an; ohne diesen Streifen bekäme sie also
   ausgerechnet der nicht zu sehen, der gerade hinschaut. */
.push-toast {
  position: fixed;
  top: calc(var(--sp-3) + env(safe-area-inset-top));
  left: var(--sp-3);
  right: var(--sp-3);
  z-index: 210;
  display: block;
  padding: var(--sp-3) var(--sp-4);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-lg);
  color: var(--text);
  text-decoration: none;
  transform: translateY(-160%);
  transition: transform var(--dur-3) var(--ease-out);
}
.push-toast.is-in { transform: none; }
.push-toast strong { display: block; font-size: .95rem; }
.push-toast span { display: block; font-size: .85rem; color: var(--muted); margin-top: .15rem; }

/* App-Sperre. Die Klasse setzt schon der Kopf der Seite, lange bevor das
   Skript läuft — ein Vorhang, der erst nach dem Inhalt kommt, ist keiner. */
.app-lock-screen { display: none; }
.app-locked .app-lock-screen {
  display: grid;
  place-items: center;
  position: fixed;
  inset: 0;
  z-index: 300;
  background: var(--bg);
}
/* Der Rest bleibt stehen und wird nur unlesbar. Ein display:none risse das
   ganze Bild beim Entsperren neu auf, samt Scrollposition. */
.app-locked body > *:not(.app-lock-screen) { filter: blur(20px); pointer-events: none; }
.app-lock-inner { display: grid; justify-items: center; gap: var(--sp-4); }
.app-lock-inner .brand-mark { width: 56px; height: 56px; border-radius: 16px; font-size: 1.3rem; }
.app-lock-inner p { margin: 0; color: var(--muted); }

/* Die App-Karte in den Einstellungen. Steht im HTML immer da und wird von
   core/static/core/native.js aufgedeckt, sobald sich Capacitor meldet. */
[data-app-only] .form-help { margin-top: var(--sp-2); }
