/* ============================================================================
 * panel.css — Vereinsportal (panel.php). Ergänzt head.css.
 * Desktop: feste linke Sidebar + Inhalt rechts. Mobil: gestapelt.
 * Statusfarben kommen aus den --st-*-Tokens in head.css.
 * ========================================================================== */
body { padding:0; }   /* head.css reserviert Platz für App-Bars — hier keine */

/* ---- Auth (Login/Setup/Kein Zugriff) zentriert ----
 * Dasselbe Foto wie auf der Startseite, damit Login und Registrierung nicht
 * wie eine andere Anwendung wirken. Als fest stehende Ebene statt
 * background-attachment:fixed — das ignoriert iOS, und beim langen
 * Registrierungsformular soll die Karte über das Bild laufen. Gleichmäßig
 * abgedunkelt statt wie dort von links: die Karte steht hier in der Mitte. */
.admin-auth {
  position:relative; isolation:isolate;
  min-height:100dvh; display:flex; flex-direction:column; align-items:center; justify-content:center;
  gap:clamp(18px, 3vw, 28px); padding:24px;
  &::before {
    content:""; position:fixed; inset:0; z-index:-1;
    background:
      linear-gradient(180deg, rgba(27,28,38,.62) 0%, rgba(27,28,38,.78) 100%),
      #1b1c26 url("../assets/hero.webp") center/cover no-repeat;
  }
  &[hidden] { display:none; }   /* sonst überschreibt display:flex das hidden-Attribut */
  & .admin-auth-brand { display:block; flex:0 0 auto; }
  & .admin-auth-brand img { display:block; height:clamp(64px, 9vw, 92px); width:auto; }
  & .card { width:100%; max-width:420px; box-shadow:0 24px 60px rgba(0,0,0,.35); }
  & .card.vp-register-card { max-width:840px; }
  /* Eingabefelder gestapelt statt nebeneinander — nebeneinander sind sie auf
   * 420px zu schmal für eine E-Mail-Adresse. */
  & .card > .row { flex-direction:column; align-items:stretch; gap:12px; }
  & .card > .row + .row { margin-top:18px; }
  & .card > .out { margin-top:10px; }
  & .card > h2 + .out { margin:0 0 16px; }
}

/* ---- Abstände innerhalb der Sektionen ----
 * Der Stapelabstand hängt am Container, nicht an der Karte: eine Regel wie
 * `.admin-section > .card` greift nicht, sobald Karten in einem Raster
 * (.vp-detail-grid) oder in einer Gruppe (.vp-stack) liegen.
 *
 * flex + gap statt `* + *`: der Nachbar-Selektor sieht nur das unmittelbar
 * vorangehende Geschwister — liegt dazwischen ein ausgeblendetes Element
 * (etwa die Nichtmitglied-Karte für Mitglieder), fiel der Abstand aus. `gap` überspringt
 * display:none-Kinder von sich aus. */
.admin-section,
.vp-detail-grid > div,
.vp-stack {
  display:flex; flex-direction:column; gap:14px; align-items:stretch;
}
/* display:flex würde das hidden-Attribut sonst überstimmen. */
.vp-stack[hidden] { display:none; }

.admin-section .card > .row + .row { margin-top:14px; }
.admin-section .card > .out { margin-top:10px; }
.admin-section .card > .row .btn-accent { flex:0 0 auto; }

/* ---- App-Layout ---- */
.admin-app { display:flex; flex-direction:column; min-height:100dvh; }
.admin-app[hidden] { display:none; }
.admin-section[hidden] { display:none; }

/* Die Sidebar ist Markenfläche und bleibt in beiden Themes dunkel. Eigene
 * Tokens statt der globalen: auf --surface würde sie im Light-Theme weiß und
 * das weiße Logo verschwände. */
.admin-side {
  --side-bg:#1b1c26;
  --side-text:#f3f3f6;
  --side-muted:#9a9aa8;
  --side-line:rgba(255,255,255,.10);
  --side-hover:rgba(255,255,255,.07);
  display:flex; flex-direction:column; gap:4px; padding:16px;
  background:var(--side-bg); color:var(--side-text);
}
/* Das Logo ist eine weiße Vektorgrafik im Hochformat (753×980) — die Höhe
 * deckelt, nicht die Breite. */
.admin-brand {
  display:block; padding:6px 8px 14px;
  & img { display:block; height:56px; width:auto; }
}
.admin-nav {
  display:flex; flex-direction:column; gap:2px;
  & button {
    display:flex; align-items:center; gap:10px; width:100%; text-align:left;
    padding:10px 12px; border-radius:10px; border:none; background:none;
    color:var(--side-text); font:inherit; font-size:14.5px; cursor:pointer;
    &:hover { background:var(--side-hover); }
    &.active { background:var(--accent); color:var(--accent-ink); font-weight:600; }
    &[hidden] { display:none; }
  }
  & svg { flex:0 0 auto; width:20px; height:20px; }
}
.admin-foot {
  margin-top:auto; display:flex; align-items:center; gap:10px;
  padding:12px 8px 4px; border-top:1px solid var(--side-line);
  & .admin-foot-user { flex:1; min-width:0; }
  & .admin-foot-email { font-size:13.5px; color:var(--side-text); word-break:break-all; }
  & .admin-foot-role { font-size:12px; color:var(--side-muted); text-transform:uppercase; letter-spacing:.03em; }
}
.admin-logout {
  flex:0 0 auto; display:grid; place-items:center; width:38px; height:38px; border-radius:10px;
  border:1px solid var(--side-line); background:transparent; color:var(--side-text); cursor:pointer;
  &:hover { background:var(--side-hover); }
  &:active { transform:scale(.94); }
  & svg { width:18px; height:18px; }
}
/* min-width:0 ist Pflicht: als Flex-Item schrumpft .admin-content sonst nie
 * unter die Inhaltsbreite — eine breite Tabelle würde die Seite seitlich
 * aufblähen statt in sich zu scrollen. */
.admin-content { flex:1; min-width:0; padding:20px 18px 44px; max-width:1000px; width:100%; }
/* Anmelden und Ansichtswechsel: Menü und Inhalt erst zeigen, wenn die Module
 * fertig geladen haben (umbauen() in panel.js, dort auch die 150 ms). */
.admin-nav, .admin-content { transition:opacity .15s ease; }
.admin-app.is-umbau :is(.admin-nav, .admin-content) { opacity:0; pointer-events:none; }
@media (prefers-reduced-motion: reduce) {
  .admin-nav, .admin-content { transition:none; }
}
/* Overlays hängen an <body>, nicht in .admin-content — beide Scopes brauchen
 * die Größenbremse, sonst zieht ein Inline-SVG den Button auf. */
.admin-content button svg,
.vp-modal button svg { width:16px; height:16px; display:block; flex:0 0 auto; }
.admin-h1 { font-size:22px; font-weight:800; letter-spacing:-.02em; }

/* Listen- und Detailansichten brauchen die volle Breite — die 1000px-Deckelung
 * oben gilt für die schmalen Verwaltungsseiten (Benutzer, Mein Konto). */
.admin-section-wide { width:100%; min-width:0; & > * { max-width:100%; } }

/* ---- Untermenü (z.B. Ausfahrten unter „Fahrten") ---- */
.admin-nav-sub {
  display:flex; flex-direction:column; gap:2px; margin:2px 0 6px 12px;
  padding-left:10px; border-left:1px solid var(--side-line);
  & button {
    display:flex; align-items:center; gap:8px; width:100%; text-align:left;
    padding:7px 10px; border-radius:8px; border:none; background:none;
    color:var(--side-muted); font:inherit; font-size:13.5px; cursor:pointer;
    &:hover { background:var(--side-hover); color:var(--side-text); }
    &.active { background:var(--side-hover); color:#fff; font-weight:600; }
  }
}
.admin-nav-subtext { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.admin-nav-count {
  flex:0 0 auto; font-size:11.5px; font-weight:700; color:var(--side-muted);
  background:var(--side-hover); border-radius:999px; padding:1px 7px;
}

/* ---- Mobilmenü (unter 900px) ----
 * Die Sidebar ist dort ein Slide-in von links; darüber liegt eine schmale
 * Leiste mit Burger, Logo und dem Namen der offenen Seite. Ab 900px gibt es
 * beides nicht — dann steht die Sidebar fest an der Seite. */
.admin-mobilebar {
  display:flex; align-items:center; gap:12px;
  position:sticky; top:0; z-index:60;
  padding:10px 14px calc(10px + env(safe-area-inset-top,0px));
  background:var(--side-bg, #1b1c26); color:#f3f3f6;
  & .admin-mobilebar-logo { height:28px; width:auto; flex:0 0 auto; }
  & .admin-mobilebar-title {
    flex:1; min-width:0; font-size:15px; font-weight:700; letter-spacing:-.01em;
    overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
  }
}
.admin-burger {
  flex:0 0 auto; display:grid; place-items:center; width:40px; height:40px;
  border-radius:10px; border:1px solid rgba(255,255,255,.14);
  background:transparent; color:inherit; cursor:pointer;
  &:active { transform:scale(.94); }
  & svg { width:20px; height:20px; }
}
.admin-side-backdrop {
  position:fixed; inset:0; z-index:70; background:rgba(4,5,8,.55);
  backdrop-filter:blur(4px);
  &[hidden] { display:none; }
}
/* Slide-in. Die Klasse setzt panel.js; ohne sie steht das Panel links außen —
 * mit -110% bleibt auch der Schatten außerhalb des Bildschirms. */
.admin-side {
  position:fixed; top:0; left:0; bottom:0; z-index:80; width:min(280px, 84vw);
  overflow:auto; box-shadow:14px 0 40px rgba(0,0,0,.35);
  transform:translateX(-110%); transition:transform .26s cubic-bezier(.22,.84,.22,1);
  &.open { transform:translateX(0); }
}

@media (min-width:900px) {
  .admin-app { flex-direction:row; }
  /* Wieder feste Spalte: kein Slide-in, keine Leiste, kein Backdrop. */
  .admin-side {
    position:fixed; top:0; left:0; bottom:0; z-index:auto; width:266px;
    overflow:auto; box-shadow:none; transform:none; transition:none;
  }
  .admin-mobilebar, .admin-side-backdrop { display:none; }
  .admin-content { margin-left:266px; padding:30px 36px 60px; }
  .admin-content:has(.admin-section-wide:not([hidden])) { max-width:none; }
}

/* ---- Speicherleiste ----
 * Ein Knopf für die ganze Seite statt eines „Speichern" in jedem Formular.
 * Sie fährt von unten herein, sobald etwas geändert wurde — dadurch ist ohne
 * Suchen zu sehen, dass etwas offen ist, und der Knopf ist überall gleich
 * erreichbar, auch am Ende einer langen Detailansicht. */
.vp-savebar {
  position:fixed; right:16px; bottom:16px; z-index:210;
  display:flex; align-items:center; gap:10px; flex-wrap:wrap;
  max-width:calc(100vw - 32px);
  padding:12px 14px; border-radius:16px;
  background:var(--surface); border:1px solid var(--line);
  box-shadow:0 18px 40px -14px rgba(0,0,0,.45);
  transform:translateY(calc(100% + 24px)); opacity:0;
  transition:transform .26s cubic-bezier(.22,.84,.22,1), opacity .2s;
  &.show { transform:translateY(0); opacity:1; }
  &[hidden] { display:none; }
  & .vp-savebar-text { flex:1; min-width:0; font-size:13.5px; color:var(--muted); }
  & .btn-accent, & .btn-ghost { flex:0 0 auto; }
  & .btn-ghost[hidden] { display:none; }
}
/* Die Kurzmeldungen sitzen an derselben Ecke — sie rücken hoch, solange die
 * Leiste steht, sonst deckt eine die andere zu. */
body.has-savebar .admin-toasts { bottom:88px; }

@media (max-width:640px) {
  .vp-savebar {
    left:12px; right:12px; bottom:12px;
    /* Text über die volle Breite, Knöpfe darunter nebeneinander — nebeneinander
       bleibt auf 390px für „Verwerfen" und „Speichern" kein Platz. */
    & .vp-savebar-text { flex:1 0 100%; }
    & .btn-accent, & .btn-ghost { flex:1; justify-content:center; }
  }
  body.has-savebar .admin-toasts { bottom:132px; }
}

/* ---- Kurzmeldungen (panel.php lädt toast.js nicht) ----
 * Sie blenden nicht von selbst aus, sondern werden weggeklickt — deshalb der
 * ✕-Knopf in jeder Meldung und „Alle schließen" über dem Stapel. */
.admin-toasts {
  position:fixed; right:16px; bottom:16px; z-index:200;
  display:flex; flex-direction:column; gap:8px; align-items:flex-end;
  pointer-events:none; max-height:calc(100dvh - 32px);
}
.admin-toast-list {
  display:flex; flex-direction:column; gap:8px; align-items:flex-end;
  overflow-y:auto; pointer-events:none;
}
.admin-toast-all {
  pointer-events:auto; flex:0 0 auto;
  border:1px solid var(--line); background:var(--surface); color:var(--muted);
  border-radius:999px; padding:4px 12px; font:inherit; font-size:12.5px; cursor:pointer;
  &:hover { color:var(--text); border-color:var(--accent); }
  &[hidden] { display:none; }
}
.admin-toast {
  pointer-events:auto; display:flex; align-items:flex-start; gap:10px;
  max-width:min(420px, calc(100vw - 32px)); cursor:pointer;
  background:var(--surface); color:var(--text);
  border:1px solid var(--line); border-left:4px solid var(--accent);
  border-radius:12px; padding:10px 10px 10px 14px; font-size:14px; line-height:1.35;
  box-shadow:0 10px 30px -12px rgba(0,0,0,.4);
  /* Skalieren statt verschieben: ein translateY(10px) vergrößert den
     scrollbaren Bereich der Liste — beim Schließen blitzte dadurch kurz eine
     Scrollbar am rechten Rand auf. Eine verkleinerte Box überläuft nie. */
  opacity:0; transform:scale(.96); transform-origin:right bottom;
  transition:opacity .2s, transform .2s;
  &.show { opacity:1; transform:scale(1); }
  &.error { border-left-color:var(--st-abgelehnt); }
  & .admin-toast-msg { flex:1; min-width:0; overflow-wrap:anywhere; }
  & .admin-toast-x {
    flex:0 0 auto; border:none; background:none; color:var(--muted);
    font:inherit; font-size:13px; line-height:1; padding:2px 4px; cursor:pointer;
    &:hover { color:var(--text); }
  }
}

/* ---- Stats-Kacheln (Übersicht) ---- */
/* Grid statt flex-wrap: sonst streckt sich die letzte Zeile über die volle
 * Breite, sobald die Kachelzahl nicht aufgeht. */
.admin-stats {
  display:grid; grid-template-columns:repeat(auto-fill, minmax(150px, 1fr));
  gap:12px;
}
.admin-tile {
  background:var(--surface); border:1px solid var(--line);
  border-radius:var(--radius); padding:16px 18px;
  /* Als <button> gerendert (klickbare Kachel) sonst zentriert und mit
     Systemschrift — hier bleibt sie optisch eine Kachel. */
  text-align:left; font:inherit; color:inherit; width:100%;
  & .admin-tile-n { font-size:30px; font-weight:800; letter-spacing:-.02em; }
  /* hyphens:auto lässt das Soft-Hyphen im Label greifen; Text bleibt in den
   * Text-Tokens — die Farbe trägt der Rahmen, nicht die Schrift. */
  & .admin-tile-l { font-size:13px; color:var(--muted); margin-top:2px; overflow-wrap:break-word; hyphens:auto; }
}
/* Statuskacheln: Rahmen in der Statusfarbe, dazu ein zarter Anflug der Farbe
 * in der Fläche, damit der 1px-Rand nicht die ganze Arbeit macht. */
.admin-tile-toned {
  border-color:var(--tile-tone);
  background:color-mix(in srgb, var(--tile-tone) 5%, var(--surface));
}
/* Klickbare Kachel: führt in die zugehörige Liste, dort gleich gefiltert. */
.admin-tile-link {
  cursor:pointer;
  &:hover { border-color:var(--accent); }
  &:active { transform:scale(.99); }
  &:focus-visible { outline:2px solid var(--accent); outline-offset:2px; }
}
.admin-overview-extra:empty { display:none; }

/* ---- Benutzer-Liste ---- */
.admin-users { display:flex; flex-direction:column; gap:8px; margin-top:10px; }
.admin-user {
  display:flex; align-items:center; gap:10px;
  background:var(--surface-2); border:1px solid var(--line); border-radius:12px; padding:10px 13px;
  & .admin-uinfo { flex:1; min-width:0; display:flex; align-items:center; gap:10px; }
  & .admin-uemail { font-size:14.5px; word-break:break-all; }
  & .admin-umember { font-size:13px; color:var(--muted); }
  & .admin-self { font-size:12.5px; color:var(--muted); padding:0 6px; }
}
.admin-role {
  font-size:11px; font-weight:700; text-transform:uppercase; letter-spacing:.03em;
  padding:2px 8px; border-radius:999px; border:1px solid var(--line); color:var(--muted);
  &.admin-role-viewer { background:var(--surface-2); color:var(--muted); }
  &.admin-role-admin { background:var(--accent); color:var(--accent-ink); border-color:transparent; }
  &.admin-role-superadmin { background:var(--text); color:var(--bg); border-color:transparent; }
}
/* Lesemodus (Rolle User in der Verwaltungsansicht): was schreibt, verschwindet.
 * Der Server lehnt Schreibzugriffe ohnehin ab — das hier erspart nur Knöpfe,
 * die garantiert mit einem Fehler enden. */
.is-readonly .vp-write { display:none !important; }

/* Umschalter Verwaltung ↔ Mitgliederbereich, direkt über dem Benutzerblock.
 * Er übernimmt das margin-top:auto des Fußes, sonst teilten sich beide den
 * freien Platz und der Umschalter schwebte mitten in der Sidebar. */
.admin-view-switch {
  display:block; margin-top:auto; padding:12px 8px 10px; color:var(--side-muted); font-size:12px;
  &[hidden] { display:none; }
  & span { display:block; margin-bottom:6px; text-transform:uppercase; letter-spacing:.03em; }
  & select {
    width:100%; padding:8px 34px 8px 11px; font-size:14px; border-radius:10px;
    color:var(--side-text); background-color:rgba(255,255,255,.06); border-color:var(--side-line);
    background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23c8c8d2' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    & option { color:#1b1c26; }
  }
}
.admin-view-switch:not([hidden]) + .admin-foot { margin-top:0; }
.admin-foot-readonly { color:var(--side-muted); font-size:11px; }
/* padding-right lässt Platz für den Chevron aus head.css — sonst liegt er auf
 * dem Text. */
.admin-roasel { width:auto; flex:0 0 auto; padding:5px 26px 5px 9px; font-size:12.5px; }
.del-btn {
  border:1px solid var(--line); background:var(--surface); color:var(--text);
  border-radius:10px; padding:8px 12px; font:inherit; font-size:13px; cursor:pointer;
  &:disabled { opacity:.5; cursor:default; }
  &:not(:disabled):active { transform:scale(.97); }
}

/* ---- Frontend-Fehler-Log ---- */
.admin-logs { display:flex; flex-direction:column; gap:6px; margin-top:10px; }
.admin-log {
  display:flex; align-items:baseline; gap:10px; font-size:12.5px;
  padding:8px 10px; background:var(--surface-2); border:1px solid var(--line); border-radius:10px;
  & .admin-log-date { color:var(--muted); font-variant-numeric:tabular-nums; white-space:nowrap; }
  & .admin-log-ip { color:var(--muted); white-space:nowrap; }
  & .admin-log-msg { flex:1; min-width:0; word-break:break-word; }
  & .admin-log-type {
    font-size:10.5px; font-weight:700; text-transform:uppercase; padding:1px 6px; border-radius:999px;
    border:1px solid var(--line); color:var(--muted); white-space:nowrap;
    &.admin-log-error { background:#c0392b; color:#fff; border-color:transparent; }
    &.admin-log-warn { background:#d68910; color:#fff; border-color:transparent; }
  }
}

/* ============================================================================
 * Bausteine für die Fachmodule (panel-*.js) — Präfix vp- (Vereinsportal).
 * ========================================================================== */

/* ---- Häkchen ----
 * head.css lässt input[type=checkbox] bewusst aus der Feld-Sammelregel heraus,
 * damit es nicht wie ein Textfeld aussieht — dadurch hatte es aber gar kein
 * Styling. Als Grid-Kind in .vp-frow bekam es justify-self:stretch, wurde
 * spaltenbreit und das Häkchen rutschte in die Mitte der Zelle.
 * Deshalb: feste Größe, nie strecken, immer links. */
input[type=checkbox] {
  flex:0 0 auto; width:18px; height:18px; margin:0;
  accent-color:var(--accent); cursor:pointer;
}
.vp-frow > input[type=checkbox] { justify-self:start; }

/* Häkchen-Zeile: Kästchen links, Text rechts, mehrzeiliger Text rückt nicht
 * unter das Kästchen. */
.vp-check {
  display:flex; align-items:flex-start; gap:10px; cursor:pointer; margin:0;
  &[hidden] { display:none; }   /* sonst überschreibt display:flex das hidden-Attribut */
  & > input[type=checkbox] { margin-top:2px; }
  & > span { flex:1; min-width:0; font-size:14.5px; line-height:1.4; color:var(--text); }
}
/* Erläuterung unter einer Häkchen-Zeile — auf Höhe des Textes, nicht des
 * Kästchens, damit erkennbar ist, wozu sie gehört. */
.vp-check-hint { margin-left:28px; }

/* ---- Zahlenfelder ----
 * head.css setzt width:100% auf alle Textfelder. Für Namen und Adressen ist das
 * richtig, für eine Jahreszahl nicht: ein Feld, das zehnmal so breit ist wie
 * sein Inhalt, sieht aus, als gehöre da mehr hinein. Die Zahl im Klassennamen
 * ist die Anzahl der Ziffern; dazu kommt der Innenabstand aus head.css. */
input.vp-num {
  width:auto; flex:0 0 auto; text-align:right; font-variant-numeric:tabular-nums;
  /* Chrome/Firefox blenden die Pfeilchen bei appearance:none nicht überall aus. */
  &::-webkit-outer-spin-button, &::-webkit-inner-spin-button { appearance:none; margin:0; }
  &[type=number] { -moz-appearance:textfield; }
}
input.vp-num-2 { width:calc(2ch + 30px); }
input.vp-num-3 { width:calc(3ch + 30px); }
input.vp-num-4 { width:calc(4ch + 30px); }
input.vp-num-6 { width:calc(6ch + 30px); }
input.vp-num-8 { width:calc(8ch + 30px); }
/* Kurzes Textfeld (Kürzel) in derselben Breitenlogik, aber linksbündig. */
input.vp-num-text { text-align:left; font-variant-numeric:normal; }

/* Datum und Uhrzeit haben eine feste Länge — „07.02.2027" braucht keine halbe
 * Spalte. Der Zuschlag deckt Innenabstand und das eigene Symbol ab. */
/* Der Zuschlag: 13px Innenabstand links, 38px rechts für das Symbol, 2px Rand
 * und etwas Luft — mit 46px schnitt das Symbol „06:00" zu „06:0" ab. */
.admin-content input[data-type=date] { width:calc(10ch + 60px); flex:0 0 auto; }
.admin-content input[data-type=time] { width:calc(5ch + 62px); min-width:calc(5ch + 62px); flex:0 0 auto; }
/* In der Auth-Karte (Registrierung) bleiben die Felder gestapelt und gleich
   breit — dort steht das Datum in einer Spalte mit Name und Adresse. */
.admin-auth input[data-type=date] { width:100%; }
/* In einer Tabellenzelle steht das Feld für sich — links ausgerichtet wirkt es
   sonst wie ein abgeschnittener Text. */
.vp-table td > input.vp-num { display:block; }

/* ---- Schrittfolge (nach der Registrierung) ----
 * Drei nummerierte Sätze statt eines Fließtexts: nach der Registrierung muss
 * unmissverständlich sein, dass es ohne die E-Mail nicht weitergeht. */
ol.vp-steps {
  margin:10px 0 0; padding-left:22px;
  display:flex; flex-direction:column; gap:6px;
  font-size:14px; line-height:1.45;
  & li { padding-left:2px; }
  & li::marker { color:var(--muted); font-variant-numeric:tabular-nums; }
}

/* ---- Feld mit Fehlermeldung (Registrierung) ---- */
.vp-field { display:flex; flex-direction:column; gap:4px; width:100%; }
/* `.card p` aus head.css färbt jeden Absatz in einer Karte grau — mit gleicher
 * Spezifität bliebe die Fehlermeldung unscheinbar. Daher der Tagname davor. */
p.vp-field-err, .vp-field-err {
  color:var(--st-abgelehnt); font-size:13px; line-height:1.35; font-weight:600;
  &[hidden] { display:none; }
}
/* background-color, nicht background: der Shorthand setzte auch das
 * background-image zurück — ein als fehlend markiertes Select verlor dadurch
 * seinen Pfeil (head.css). */
input.is-invalid, select.is-invalid, textarea.is-invalid {
  border-color:var(--st-abgelehnt);
  background-color:color-mix(in srgb, var(--st-abgelehnt) 6%, var(--surface-2));
}

/* ---- Datums- und Zeitauswahl ----
 * Icons liegen wie der Select-Chevron im Hintergrund. Dadurch bleiben sie
 * auch bei einer roten Fehlerfläche sichtbar, ohne zusätzliche Wrapper im DOM. */
input[data-type=date], input[data-type=time] {
  padding-right:38px;
  background-repeat:no-repeat;
  background-position:right 12px center;
  background-size:16px;
}
input[data-type=date] {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23777' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 2v4M16 2v4'/%3E%3Crect width='18' height='18' x='3' y='4' rx='2'/%3E%3Cpath d='M3 10h18'/%3E%3C/svg%3E");
}
input[data-type=time] {
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='%23777' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'/%3E%3Cpath d='M12 6v6l4 2'/%3E%3C/svg%3E");
}
.air-datepicker {
  --adp-font-family:var(--font, inherit);
  --adp-accent-color:var(--accent);
  --adp-cell-background-color-selected:var(--accent);
  --adp-cell-background-color-selected-hover:var(--accent);
  --adp-color-current-date:var(--accent);
  --adp-day-name-color:var(--muted);
  --adp-border-radius:12px;
  --adp-cell-border-radius:8px;
  --adp-background-color:var(--surface);
  --adp-color:var(--text);
  --adp-border-color:var(--line);
  --adp-border-color-inline:var(--line);
  --adp-border-color-inner:var(--line);
  --adp-background-color-hover:var(--surface-2);
  --adp-background-color-active:var(--surface-2);
  --adp-color-secondary:var(--muted);
  --adp-width:272px;
  --adp-z-index:300;
}
.air-datepicker--pointer:after { background:var(--surface); }
.air-datepicker-overlay { --adp-overlay-z-index:299; }

/* ---- Statuspunkt + Pill ---- */
.vp-dot { flex:0 0 auto; width:9px; height:9px; border-radius:50%; background:var(--muted); }
.vp-dot-pending    { background:var(--st-pending); }
.vp-dot-aktiv      { background:var(--st-aktiv); }
.vp-dot-inaktiv    { background:var(--st-inaktiv); }
.vp-dot-abgelehnt  { background:var(--st-abgelehnt); }
.vp-dot-gebucht    { background:var(--st-gebucht); }
.vp-dot-warteliste { background:var(--st-warteliste); }
.vp-dot-storniert  { background:var(--st-abgelehnt); }

.vp-pill {
  display:inline-flex; align-items:center; gap:6px; white-space:nowrap;
  padding:3px 10px; border-radius:999px; font-size:12.5px; font-weight:600;
  background:var(--surface-2); color:var(--text);
}
/* Textfarbe bei Gelb/Grün bewusst abgedunkelt — die Signalfarbe selbst hat auf
 * hellem Grund zu wenig Kontrast für Fließtext. */
.vp-pill-pending    { background:color-mix(in srgb, var(--st-pending) 16%, var(--surface)); color:#a35c04; }
.vp-pill-aktiv      { background:color-mix(in srgb, var(--st-aktiv) 14%, var(--surface)); color:#07785b; }
.vp-pill-nichtmitglied { background:var(--surface-2); color:var(--text); }
.vp-pill-inaktiv    { background:var(--surface-2); color:var(--muted); }
.vp-pill-abgelehnt  { background:color-mix(in srgb, var(--st-abgelehnt) 12%, var(--surface)); color:var(--st-abgelehnt); }
.vp-pill-gebucht    { background:color-mix(in srgb, var(--st-gebucht) 14%, var(--surface)); color:var(--st-gebucht); }
.vp-pill-warteliste { background:color-mix(in srgb, var(--st-warteliste) 14%, var(--surface)); color:var(--st-warteliste); }
.vp-pill-storniert  { background:var(--surface-2); color:var(--muted); text-decoration:line-through; }
.vp-pill-offen      { background:color-mix(in srgb, var(--st-pending) 16%, var(--surface)); color:#a35c04; }
.vp-pill-abgebucht,
.vp-pill-bezahlt    { background:color-mix(in srgb, var(--st-aktiv) 14%, var(--surface)); color:#07785b; }
.vp-pill-erlassen   { background:var(--surface-2); color:var(--muted); }

/* ---- Kopfzeile + Toolbar ---- */
.vp-head {
  display:flex; align-items:center; gap:14px; flex-wrap:wrap;
  & .admin-h1 { margin:0; flex:1; min-width:0; }
  &[hidden] { display:none; }
}
.vp-head-actions { display:flex; align-items:center; gap:8px; }
.vp-head-actions .btn-accent { padding:10px 16px; border-radius:12px; }

.vp-toolbar {
  display:flex; align-items:center; gap:10px; flex-wrap:wrap; justify-content:space-between;
  background:var(--surface); border:1px solid var(--line); border-radius:14px;
  padding:10px 12px;
  &[hidden] { display:none; }
}
.vp-toolbar-left { display:flex; align-items:center; gap:10px; flex:1; min-width:0; flex-wrap:wrap; }
.vp-toolbar-right { display:flex; align-items:center; gap:8px; }
.vp-column-picker { position:relative; }
.vp-column-menu { position:absolute; right:0; top:calc(100% + 6px); z-index:20; min-width:210px; max-height:min(70vh, 430px); overflow:auto; padding:8px; border:1px solid var(--line); border-radius:10px; background:var(--surface); box-shadow:0 10px 30px rgba(0,0,0,.16); }
.vp-column-menu[hidden] { display:none; }
.vp-column-menu label { display:flex; align-items:center; gap:9px; padding:7px; white-space:nowrap; cursor:pointer; }
.vp-filter { width:auto; flex:0 0 auto; padding:8px 32px 8px 12px; font-size:13.5px; }
.vp-search { flex:1; min-width:160px; padding:8px 12px; font-size:13.5px; }
.vp-chip {
  flex:0 0 auto; font-size:12.5px; font-weight:600; color:var(--muted);
  background:var(--surface-2); border-radius:999px; padding:5px 12px; white-space:nowrap;
}

/* ---- Tabelle ---- */
.vp-listwrap {
  background:var(--surface); border:1px solid var(--line); border-radius:14px; overflow-x:auto;
  &[hidden] { display:none; }
}
/* Mitgliederliste: Wrapper scrollt selbst, damit der Kopf kleben bleibt und die
 * horizontale Leiste im Blick ist. Opt-in, andere .vp-table bleiben unberührt. */
.vp-listframe {
  position:relative;
  /* Der Inhaltsbereich lässt unten 44px (ab 900px 60px) Luft; die Liste soll den
   * Bildschirm ausnutzen, ohne dass die Seite zusätzlich scrollt. */
  margin-bottom:-32px;
  @media (min-width:900px) { margin-bottom:-48px; }
}
.vp-listwrap-sticky {
  overflow:auto; max-height:max(320px, calc(100dvh - 190px)); /* Vorgabe; panel-mitglieder.js misst genauer */
  & .vp-table th { position:sticky; top:0; z-index:2; background:var(--surface); border-bottom:none; box-shadow:inset 0 -1px 0 var(--line); }
}
.vp-scrollarrow {
  position:absolute; top:1px; z-index:3; width:30px; height:40px; padding:0; border:0; border-radius:0;
  font-size:24px; line-height:1; color:var(--text); background:color-mix(in srgb, var(--surface) 88%, transparent);
  box-shadow:0 0 12px 6px color-mix(in srgb, var(--surface) 88%, transparent); cursor:pointer;
  &[hidden] { display:none; }
  &:hover { color:var(--accent); }
}
.vp-scrollarrow-l { left:1px; }
.vp-th-tools { display:inline-flex; vertical-align:middle; gap:2px; margin-left:6px; opacity:0; transition:opacity .12s; }
.vp-table th:hover .vp-th-tools, .vp-table th:focus-within .vp-th-tools, .vp-th-tools:has(.is-active) { opacity:1; }
@media (hover:none) { .vp-th-tools { opacity:1; } }
.vp-th-tools button {
  width:22px; height:22px; padding:3px; border:0; border-radius:6px; background:none; color:var(--muted); cursor:pointer;
  & svg { width:100%; height:100%; display:block; }
  &:hover { background:var(--surface-2); color:var(--text); }
  &.is-active { color:var(--accent); opacity:1; }
}
.vp-colfilter {
  position:fixed; z-index:80; min-width:230px; max-width:min(320px, calc(100vw - 16px)); max-height:min(70vh, 420px); overflow:auto;
  padding:10px; display:flex; flex-direction:column; gap:10px;
  border:1px solid var(--line); border-radius:10px; background:var(--surface); box-shadow:0 10px 30px rgba(0,0,0,.16);
  &[hidden] { display:none; }
  & label { display:flex; align-items:center; gap:9px; padding:5px 4px; white-space:nowrap; cursor:pointer; font-size:14px; }
}
.vp-colfilter-opts, .vp-colfilter-dates { display:flex; flex-direction:column; }
.vp-colfilter-dates label { justify-content:space-between; & input { width:auto; } }
.vp-colfilter-foot { display:flex; justify-content:flex-end; }
.vp-colfilter-out { font-size:13px; font-weight:600; font-variant-numeric:tabular-nums; margin-bottom:6px; }
.vp-dualrange {
  position:relative; height:26px; margin:0 8px;
  & input[type=range] {
    position:absolute; left:-8px; top:0; width:calc(100% + 16px); height:26px; margin:0; padding:0; border:0;
    background:none; appearance:none; pointer-events:none;
    &::-webkit-slider-runnable-track { background:none; }
    &::-webkit-slider-thumb { appearance:none; pointer-events:auto; width:16px; height:16px; border-radius:50%; background:var(--accent); border:2px solid var(--surface); box-shadow:0 0 0 1px var(--accent); cursor:pointer; }
    &::-moz-range-thumb { pointer-events:auto; width:12px; height:12px; border-radius:50%; background:var(--accent); border:2px solid var(--surface); cursor:pointer; }
  }
}
.vp-dualrange-track { position:absolute; left:0; right:0; top:50%; height:4px; margin-top:-2px; border-radius:2px; background:var(--line); }
.vp-dualrange-fill { position:absolute; top:0; bottom:0; border-radius:2px; background:var(--accent); }
/* Zwischenüberschrift innerhalb einer Karte (z.B. „Grundpreis" / „Ab 01.11.") */
.vp-hint { margin:0; font-size:13px; color:var(--muted); &[hidden] { display:none; } }
.vp-subhead { font-size:14px; font-weight:700; }
.vp-table {
  width:100%; border-collapse:collapse; font-size:14px;
  & th {
    text-align:left; font-size:12.5px; font-weight:600; color:var(--muted);
    padding:12px 14px; border-bottom:1px solid var(--line); white-space:nowrap;
  }
  & td { padding:11px 14px; border-bottom:1px solid var(--line); white-space:nowrap; }
  & tbody tr:last-child td { border-bottom:none; }
  & .vp-td-name { font-weight:600; }
  & .vp-td-num { text-align:right; font-variant-numeric:tabular-nums; }
  & .vp-td-center { text-align:center; font-variant-numeric:tabular-nums; }
  & input[type=checkbox] { width:16px; height:16px; accent-color:var(--accent); cursor:pointer; }
}
/* Nur klickbare Tabellen bekommen den Zeiger — Preis-Matrizen sind reine
 * Eingaberaster und dürfen nicht so aussehen, als führten sie irgendwohin. */
.vp-table-click tbody tr { cursor:pointer; }
.vp-table-click tbody tr:hover { background:var(--surface-2); }
.vp-table th.vp-sortable { cursor:pointer; user-select:none; }
.vp-table th.vp-sortable:focus-visible { outline:2px solid var(--accent); outline-offset:-3px; }
.vp-table th.vp-sortable::after { content:''; display:inline-block; margin-left:6px; width:0; height:0; vertical-align:middle; }
.vp-table th.vp-sortable[aria-sort="ascending"]::after { border-left:4px solid transparent; border-right:4px solid transparent; border-bottom:6px solid currentColor; }
.vp-table th.vp-sortable[aria-sort="descending"]::after { border-left:4px solid transparent; border-right:4px solid transparent; border-top:6px solid currentColor; }
.vp-family > summary { cursor:pointer; list-style:none; display:flex; align-items:center; gap:10px; font-weight:700; }
.vp-family > summary::-webkit-details-marker { display:none; }
.vp-family > summary::before { content:'›'; color:var(--muted); font-size:22px; transition:transform .15s ease; }
.vp-family[open] > summary::before { transform:rotate(90deg); }
.vp-family > summary .vp-family-meta { margin-left:auto; display:flex; gap:8px; flex-wrap:wrap; }
.vp-family > .vp-family-body { margin-top:16px; display:flex; flex-direction:column; gap:12px; }
.vp-search-results { border:1px solid var(--line); border-radius:10px; overflow:hidden; max-height:260px; overflow-y:auto; }
.vp-search-result { display:block; width:100%; padding:9px 12px; border:0; border-bottom:1px solid var(--line); background:var(--surface); text-align:left; cursor:pointer; }
.vp-search-result:last-child { border-bottom:0; }
.vp-search-result:hover, .vp-search-result:focus-visible { background:var(--surface-2); }
.vp-rl-actions .is-active { box-shadow:0 0 0 2px var(--accent); }
.vp-export-row { gap:8px; margin-top:6px; }
.vp-export-label { flex:1; min-width:140px; font-size:14px; }
.vp-empty { color:var(--muted); font-size:14px; padding:22px 14px; text-align:center; }

/* ---- Detailansicht (ersetzt den Maincontent, kein Popup) ---- */
.vp-detail[hidden] { display:none; }
.vp-detail-head {
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; margin-bottom:18px;
  & .vp-detail-name { font-size:22px; font-weight:800; letter-spacing:-.02em; margin-right:4px; }
  /* Zerstörendes ans andere Ende — nicht direkt neben „Kopieren". */
  & .vp-head-end { margin-left:auto; }
}
.vp-chips { display:flex; align-items:center; gap:8px; margin-left:auto; flex-wrap:wrap; }
.vp-contact {
  display:inline-flex; align-items:center; gap:7px; font-size:13.5px;
  background:var(--surface); border:1px solid var(--line); border-radius:11px; padding:7px 12px;
  color:var(--text); text-decoration:none;
  & svg { width:15px; height:15px; color:var(--muted); flex:0 0 auto; }
}
a.vp-contact {
  &:hover { border-color:var(--accent); color:var(--accent); }
  &:hover svg { color:var(--accent); }
}
/* Zwei Spalten ab Tablet: links Stammdaten, rechts Verlauf/Zusatz. */
/* minmax(0, …) statt bloßem fr: eine fr-Spalte wird nie schmaler als ihr
 * Inhalt, und die Preis-Matrix ist seit der dritten Leistungsspalte so breit,
 * dass sie die linke Spalte zusammendrückte — die Eckdaten-Felder waren
 * dadurch zu schmal für einen Ausfahrtstitel. Mit minmax darf die Spalte
 * schrumpfen und die Tabelle scrollt in ihrem eigenen .vp-listwrap. */
.vp-detail-grid { display:grid; grid-template-columns:minmax(0, 1fr); gap:14px; align-items:start; }
@media (min-width:1000px) {
  .vp-detail-grid { grid-template-columns:minmax(0, 1.15fr) minmax(0, .85fr); }
}

/* Feldraster für Stammdaten — Label links, Wert/Eingabe rechts. */
.vp-fields { display:flex; flex-direction:column; }
.vp-fields[hidden] { display:none; }
.vp-frow {
  display:grid; grid-template-columns:170px 1fr; gap:12px; align-items:center;
  &[hidden] { display:none; }
  padding:8px 0; border-bottom:1px solid var(--line);
  &:last-child { border-bottom:none; }
  & > label { font-size:13px; color:var(--muted); }
  & > .vp-fval { font-size:14px; word-break:break-word; }
}
/* Häkchen als Zeile eines Feldrasters: eine Spalte statt Label + Wert — die
 * Beschriftung steht neben dem Kästchen und braucht die ganze Breite. Muss
 * NACH .vp-frow stehen, sonst gewinnt dessen 170px-Spalte und der Text bricht
 * schon nach zwei Wörtern um. */
.vp-frow-check { grid-template-columns:1fr; }
@media (max-width:560px) { .vp-frow { grid-template-columns:1fr; gap:4px; } }

/* ---- Verlauf im Mitglieder-Detail ----
 * Datum und Urheber bilden eine schmale Kopfzeile, der Eintrag steht darunter.
 * Vorher lagen alle drei nebeneinander (Fehler-Log-Optik): in der schmalen
 * rechten Spalte brach der Text mehrzeilig um und die 6px Abstand zwischen den
 * Kästen verschwanden optisch — zwei Einträge sahen aus wie einer. */
.vp-verlauf { display:flex; flex-direction:column; gap:12px; margin-top:14px; }
.vp-verlauf-item {
  padding:10px 12px; background:var(--surface-2); border:1px solid var(--line); border-radius:10px;
  & .vp-verlauf-meta {
    display:flex; justify-content:space-between; align-items:baseline; gap:10px;
    font-size:11.5px; color:var(--muted); font-variant-numeric:tabular-nums;
  }
  /* p.  schlägt das .card p aus head.css — sonst bleibt der Eintrag grau. */
  & p.vp-verlauf-text {
    margin:4px 0 0; font-size:13.5px; line-height:1.45; color:var(--text); word-break:break-word;
  }
}

/* ---- Auslastungsbalken (Busplätze) ---- */
.vp-bar {
  height:8px; border-radius:999px; background:var(--surface-2); overflow:hidden;
  & > span { display:block; height:100%; background:var(--accent); border-radius:999px; }
  &.full > span { background:var(--st-abgelehnt); }
}
.vp-bar-label { font-size:12.5px; color:var(--muted); margin-top:5px; font-variant-numeric:tabular-nums; }

/* ---- Modal (das <app-modal> aus components.js lädt panel.php nicht, und mit
 *      380px wäre es für Formulare ohnehin zu schmal) ---- */
.vp-overlay {
  position:fixed; inset:0; z-index:150; display:grid; place-items:center; padding:20px;
  background:rgba(0,0,0,.45);
  &[hidden] { display:none; }
}
.vp-modal {
  width:100%; max-width:560px; max-height:calc(100dvh - 40px); overflow:auto;
  background:var(--surface); border:1px solid var(--line); border-radius:var(--radius);
  padding:20px 22px; box-shadow:0 24px 60px -20px rgba(0,0,0,.55);
  & > h2 { font-size:17px; font-weight:700; margin-bottom:14px; }
}
.vp-modal-wide { max-width:820px; }
.vp-modal-actions { display:flex; gap:10px; justify-content:flex-end; margin-top:20px; flex-wrap:wrap; }
.btn-danger {
  border:1px solid var(--st-abgelehnt); background:var(--st-abgelehnt); color:#fff;
  border-radius:12px; padding:10px 16px; font:inherit; font-size:14px; cursor:pointer;
  &:active { transform:scale(.97); }
}

/* ---- Wiederholbare Zeilen (Haltestellen, Betreuer) ---- */
.vp-repeat { display:flex; flex-direction:column; gap:8px; }
.vp-repeat-row {
  display:flex; gap:8px; align-items:center; flex-wrap:wrap;
  & input, & select { flex:1; min-width:120px; }
  & .del-btn { flex:0 0 auto; }
}

/* ---- Personenauswahl beim Buchen ----
 * Das Raster gehört der LISTE, nicht der einzelnen Zeile: jede Zeile für sich
 * auszurichten hieß, dass die 1.3fr-Spalte je Zeile unterschiedlich breit
 * wurde — Altersgruppe, Kurs und Gruppe sprangen dann zwischen einem Kind
 * (mit Gruppenauswahl) und einem Erwachsenen (ohne) hin und her.
 * Mit `subgrid` teilen sich alle Zeilen dieselben Spalten und bleiben
 * trotzdem eigene Elemente mit Rahmen und Abstand.
 *
 * Die Spaltenfolge entspricht der DOM-Reihenfolge in panel-mein-verein.js:
 * Person · Altersgruppe · Kurs · Skigruppe · Leistung · Preis · Status.
 * Kurs- und Gruppenzelle bleiben auch leer im DOM (leeres <span>) — sonst
 * verrutschen die folgenden Spalten. */
.vp-persons {
  display:grid; row-gap:0; column-gap:10px;
  grid-template-columns:minmax(150px,1.3fr) auto auto minmax(110px,auto) minmax(150px,auto) 90px auto;
}
.vp-persons-rl {
  grid-template-columns:minmax(160px,1.4fr) minmax(120px,auto) minmax(110px,auto) 90px auto;
}
/* Alles, was keine Personenzeile ist (etwa „keine Anmeldungen"), über die
   volle Breite — sonst klebte es in der ersten Spalte. */
.vp-persons > :not(.vp-person) { grid-column:1/-1; }
.vp-person {
  grid-column:1/-1; align-items:center; gap:10px;
  /* Erst die eigene Spaltenfolge, dann subgrid: fehlt subgrid im Browser,
     fällt die zweite Zeile weg und die Zeile richtet sich wie früher selbst
     aus — schlechter, aber nicht kaputt. */
  display:grid;
  grid-template-columns:minmax(150px,1.3fr) auto auto minmax(110px,auto) minmax(150px,auto) 90px auto;
  grid-template-columns:subgrid;
  padding:9px 0; border-bottom:1px solid var(--line);
  &:first-of-type { padding-top:0; }
  &:last-of-type { border-bottom:none; padding-bottom:0; }
  & > label { display:flex; align-items:center; gap:8px; margin:0; cursor:pointer; }
  & input[type=checkbox] { width:17px; height:17px; accent-color:var(--accent); flex:0 0 auto; }
  & select { padding:4px 32px 4px 8px; font-size:13px; }
  & .vp-price { text-align:right; font-variant-numeric:tabular-nums; font-weight:600; }
  & .vp-price-free { color:var(--st-aktiv); }
  & .vp-group-full { margin:4px 0 0; font-size:12px; color:var(--st-pending); }
}
.vp-book-sub { font-size:15px; font-weight:700; margin:18px 0 8px; }
.vp-book-sub + select { max-width:420px; }
@media (max-width:1100px) {
  .vp-persons { grid-template-columns:minmax(140px,1fr) auto auto auto; row-gap:6px; }
  .vp-person { grid-template-columns:minmax(140px,1fr) auto auto auto; grid-template-columns:subgrid; }
}
@media (max-width:720px) {
  .vp-persons { grid-template-columns:1fr auto; row-gap:4px; }
  .vp-person { grid-template-columns:1fr auto; grid-template-columns:subgrid; }
}

/* Haltestelle, Summe und der Anmelde-Knopf: sichtbar abgesetzt von der
 * Namensliste darüber, sonst liest sich der Knopf als Teil der letzten Zeile. */
.vp-book-actions {
  margin-top:18px; padding-top:16px; border-top:1px solid var(--line);
  & select { flex:0 1 260px; }
}

/* Reiseleiter-Zeile: eine Person je Zeile mit großem Knopf. Am Bus wird mit
 * Handschuhen bedient, deshalb weniger Spalten und mehr Fläche. Die Spalten
 * stehen an der Liste (.vp-persons-rl), die Zeile erbt sie. */
.vp-person-rl {
  grid-template-columns:minmax(160px,1.4fr) minmax(120px,auto) minmax(110px,auto) 90px auto;
  grid-template-columns:subgrid;
  & button { padding:8px 14px; }
}
@media (max-width:820px) {
  /* Am Handy ist die Zeile kein Raster über fünf Spalten mehr, sondern ein
     kompakter Block je Person — drei Zeilen:

       Josef Aigner · EW                        offen
       Ranshofen                     📞 0664 1162948
       [    Anwesend    ] [        Fehlt        ]

     Fünf Spalten auf 390px ergaben eine Zeile, in der Telefonnummer und Status
     wie Eingabefelder aussahen und die Knöpfe irgendwo dazwischen standen. Und
     jede Angabe auf einer eigenen Zeile machte aus fünf Personen eine
     Bildschirmlänge — am Bus scrollt niemand gern.

     display:block auf der Liste hebt das subgrid auf — die Zeile bekommt hier
     wieder ihr eigenes Raster. Alle Kinder werden ausdrücklich platziert: ohne
     das fiele der Status ans Ende der automatischen Reihenfolge. */
  .vp-persons-rl { display:block; }
  .vp-person-rl {
    grid-template-columns:1fr auto;
    gap:3px 10px; padding:13px 0;
    /* Name und Altersgruppe nebeneinander statt untereinander. */
    & .vp-rl-wer {
      grid-row:1; grid-column:1;
      display:flex; align-items:baseline; gap:8px; flex-wrap:wrap;
      & .vp-bar-label { margin-top:0; }
    }
    & .vp-rl-status { grid-row:1; grid-column:2; justify-self:end; align-self:center; }
    & .vp-rl-stop { grid-row:2; grid-column:1; font-size:13.5px; color:var(--muted); }
    & .vp-rl-tel { grid-row:2; grid-column:2; justify-self:end; padding:4px 10px; font-size:13px; }
    & .vp-rl-actions {
      grid-row:3; grid-column:1 / -1;
      display:flex; gap:8px; margin-top:7px;
      & button { flex:1; padding:12px 14px; font-size:15px; }
    }
  }
}
.vp-chip-ok   { background:var(--st-aktiv); color:#fff; }
.vp-chip-warn { background:var(--st-pending); color:#1b1c26; }

/* Hinweise der Ausfahrt beim Buchen. Abgesetzt vom Rest, weil sie bestätigt
 * werden müssen und im Streitfall die Grundlage sind. */
.vp-terms {
  background:var(--surface-2); border:1px solid var(--line); border-left:4px solid var(--accent);
  border-radius:10px; padding:12px 14px; margin-bottom:10px; font-size:14.5px; line-height:1.5;
  & h3 { font-size:15px; font-weight:700; margin:.5em 0 .2em; }
  & p { margin:.35em 0; }
  & ul { margin:.35em 0; padding-left:1.4em; list-style:disc; }
  /* Leerzeile: ein Absatz ohne Inhalt hätte sonst keine Höhe und wäre für den
     Leser nicht da. */
  & p:empty { min-height:1em; }
}
/* Kleine Überschrift je Hinweiskarte: Ausfahrthinweis und Stornohinweis
 * stehen untereinander und sehen gleich aus — ohne Titel läse man sie als
 * einen Block. */
.vp-terms .vp-terms-title {
  font-size:12px; font-weight:700; text-transform:uppercase; letter-spacing:.04em;
  color:var(--muted); margin:0 0 6px;
}

/* Formatierbares Textfeld für die Ausfahrtsbeschreibung. Kein Editor-Paket —
 * ein contenteditable mit fünf Knöpfen reicht für Hinweise, und das Projekt
 * hat bewusst keinen Build-Schritt. */
.vp-richtext-bar {
  display:flex; flex-wrap:wrap; gap:6px; margin-bottom:6px;
  & button { padding:4px 10px; font-size:13px; }
}
.vp-richtext {
  min-height:120px; padding:10px 12px;
  background:var(--surface-2); border:1px solid var(--line); border-radius:10px;
  font-size:14.5px; line-height:1.5;
  &:focus { outline:2px solid var(--accent); outline-offset:-1px; }
  & h3 { font-size:16px; font-weight:700; margin:.6em 0 .3em; }
  & p { margin:.4em 0; }
  & ul { margin:.4em 0; padding-left:1.4em; list-style:disc; }
  & p:empty { min-height:1em; }
}

/* Preis-Matrix mit zweizeiliger Kopfzeile: sechs gleich aussehende Spalten
 * brauchen die Gruppierung Mitglied/Nichtmitglied, sonst zählt man mit dem
 * Finger mit. Die Trennlinie markiert den Wechsel. */
.vp-matrix {
  & .vp-matrix-head { text-align:center; border-bottom:1px solid var(--line); }
  & .vp-matrix-sub { font-weight:400; font-size:12px; color:var(--muted); white-space:nowrap; }
  /* Die Trennlinie zwischen Mitglied und Nichtmitglied. Kopf und Körper
     brauchen verschiedene Spaltennummern: in der Kopf-Unterzeile stehen genau
     die sechs Preisspalten, in den Datenzeilen kommt links die Altersgruppe
     davor. Mit einem gemeinsamen nth-child(4) saß der Strich im Körper eine
     Spalte zu weit links — mitten in der Mitglied-Gruppe. */
  & th:nth-child(4) { border-left:2px solid var(--line); }
  & td:nth-child(5) { border-left:2px solid var(--line); }
  /* Die Beträge sind vierstellig plus Komma — ein Feld über die ganze Zelle
     täuscht mehr Platz vor, als hineingehört. */
  & input { width:calc(7ch + 30px); min-width:0; text-align:right; font-variant-numeric:tabular-nums; }
}

/* Gruppen-Kontingente: eine Zeile mit fünf Zahlen unter den Gruppennamen.
 * Gleich breite Spalten, damit die Köpfe über den Feldern stehen. */
.vp-grid-caps {
  table-layout:fixed;
  & th { text-align:center; }
  & td { padding:10px 8px; }
  /* margin:auto statt text-align:center — das Feld ist display:block (siehe
     .vp-table td > input.vp-num) und würde sonst links kleben. */
  & input { margin-inline:auto; text-align:center; }
}

/* Skigruppen-Auswahl in der Altersgruppen-Tabelle: fünf kurze Häkchen, die in
 * eine Tabellenzelle passen müssen. */
.vp-skigroups {
  display:flex; flex-wrap:wrap; gap:4px 12px;
  & label { display:flex; align-items:center; gap:5px; margin:0; font-size:13px; cursor:pointer; white-space:nowrap; }
  & input[type=checkbox] { width:15px; height:15px; accent-color:var(--accent); }
}

/* Deaktivierte Aktionen müssen auch deaktiviert aussehen — ein voll gefärbter
 * Button, der nicht reagiert, liest sich als Fehler. */
.btn-accent:disabled, .btn-ghost:disabled, .btn-danger:disabled {
  opacity:.45; cursor:default; filter:saturate(.6);
}

/* Mail-Protokoll für die Testphase. */
.vp-cards {
  display:flex; flex-direction:column; gap:16px;
}

.vp-mail-header {
  display:flex; justify-content:space-between; align-items:flex-start; gap:12px; margin-bottom:12px;
  & .vp-mail-meta {
    flex:1; min-width:0;
    & p { margin:0 0 6px 0; font-size:14px; color:var(--muted); }
    & p:first-child { color:var(--text); font-weight:600; }
    & .vp-mail-subject { font-size:15.5px; font-weight:600; color:var(--text); }
  }
}

.vp-badge {
  flex:0 0 auto; padding:6px 10px; border-radius:6px; font-size:12.5px;
  font-weight:600; text-transform:uppercase; letter-spacing:.04em;
  white-space:nowrap;
  &.is-ok { background:var(--st-aktiv); color:#fff; }
  &.is-preview { background:var(--surface-2); color:var(--muted); border:1px solid var(--line); }
  &.is-error { background:#f5d0d0; color:#8b3333; }
}

.vp-mail-error {
  margin:8px 0 0; padding:8px 10px; background:#fef2f2; border:1px solid #f5d0d0;
  border-radius:6px; font-size:13.5px; color:#8b3333;
}

.vp-mail-body {
  background:var(--surface-2); padding:14px; border-radius:8px;
  border:1px solid var(--line); margin:12px 0; font-size:14px; line-height:1.6;
  word-wrap:break-word; overflow-x:auto;
  & a { color:var(--accent); text-decoration:underline; cursor:pointer; }
  & a:hover { opacity:.85; }
  /* Verbrauchter Zugangslink: sichtbar, aber erkennbar nicht mehr zu gebrauchen. */
  & s { color:var(--muted); text-decoration-color:var(--muted); }
  & br { display:block; content:''; }
  & p, & div { margin:0 0 10px 0; }
  & p:last-child, & div:last-child { margin-bottom:0; }
}

.vp-mail-actions {
  display:flex; gap:8px; flex-wrap:wrap;
  & button { padding:10px 14px; font-size:14px; }
}

.vp-note {
  margin-top:12px; padding:10px 12px; background:var(--surface-2);
  border-radius:8px; border-left:3px solid var(--accent); font-size:13.5px;
  color:var(--muted);
}

.vp-register-form { width:100%; }
.vp-form-heading { flex:1 0 100%; margin:14px 0 2px; font-size:14px; }
.vp-consent-copy { flex:1 0 100%; margin:2px 0; font-size:13.5px; line-height:1.55; color:var(--muted); overflow-wrap:anywhere; }
.vp-fee-list { font-size:14px; line-height:1.55; color:var(--text); & > div { margin:1px 0; } }
.vp-field[hidden] { display:none; }
/* Registrierung: Felder zweispaltig, Straße und Kontoinhaber über die volle
 * Breite. Unter 640px wieder einspaltig — nebeneinander wäre dort eine
 * E-Mail-Adresse nicht mehr lesbar. */
.vp-reg-grid {
  display:grid; grid-template-columns:1fr 1fr; gap:12px 14px;
  &[hidden] { display:none; }
  & > .vp-span { grid-column:1 / -1; }
}
@media (max-width:640px) { .vp-reg-grid { grid-template-columns:1fr; } }
.vp-honeypot { position:absolute; left:-9999px; }
