/* ==========================================================================
   CRM – Oberfläche
   Farbwelt, Knöpfe, Eingabefelder, Seitenleiste, Modale und Hinweise sind
   aus dem Web Agent übernommen, damit beide Anwendungen gleich aussehen und
   sich gleich bedienen lassen. Ergänzt sind die CRM-Bausteine: Tabellen,
   Kontakt-Detailansicht, Formularraster und Blätterleiste.
   ========================================================================== */

:root {
    /* Sagt dem Browser, dass die Oberfläche dunkel ist. Davon leben die
       vom System gemalten Teile: die aufgeklappte Liste eines <select>,
       Bildlaufleisten, der Datumswähler. Ohne das leuchten sie weiß. */
    color-scheme: dark;

    --bg: #0f1420;
    --panel: #171e2e;
    --panel-2: #1e2740;
    --line: #2a3552;
    --text: #e6ecf7;
    --muted: #8b97b3;
    /* Die Signalfarbe trägt zwei Rollen, und eine Farbe kann beide nicht
       gut erfüllen: Was auf dunklem Grund gut lesbar ist, ist zu hell für
       weiße Schrift darauf. Vorher stand hier ein Kompromiss (#4f7cff),
       der beides knapp verfehlte – 4.49 auf der Fläche, 3.71 unter weißer
       Schrift. Deshalb getrennt. */
    --accent: #6f9bff;       /* Vordergrund: Links, Reiter, Chips, Fokus (6.19, AA) */
    --accent-fill: #3a63e0;  /* Fläche mit weißer Schrift darauf (5.20, AA) */
    --accent-2: #2f56d4;     /* dieselbe Fläche beim Überfahren (6.17, AA) */
    --danger: #e5484d;
    --ok: #3dbb7f;
    --warn: #e0a35a;

    /* Die Sperre nach Art. 21 DSGVO. Ein eigener Ton, weil sie keiner der
       vorhandenen ist: Sie ist keine Gefahr (Rot heißt „weg damit"), kein
       Zustand (Grün, Gelb) und keine gewöhnliche Handlung (Blau) – sie ist
       eine Entscheidung über den Kontakt, die stehen bleibt.
       Weiße Schrift darauf liest sich mit 5.39 – wie das Blau daneben
       (5.20), damit die beiden Knöpfe gleich schwer wirken. */
    --sperre: #7b52c9;
    --sperre-2: #6a43b3;  /* dieselbe Fläche beim Überfahren (6.85) */

    /* Herkunft statt Zustand. Die gesättigten Farben oben sind vergeben –
       Rot heißt überfällig, Gelb heißt fällig, Grün heißt erledigt, Blau
       heißt Aktion. Woher eine Angabe stammt, ist kein Zustand, deshalb
       zwei Tönungen von Weiß: Sie unterscheiden sich nur in der
       Farbtemperatur, fallen einzeln nicht auf und nebeneinander sofort.
       Siehe PLANUNG.md, Abschnitt 9. */
    --meta: #d6ecdd;       /* Wert aus den Metadaten */
    --meta-link: #f0e3b4;  /* dasselbe, aber anklickbar */

    /* Der gewählte Tag im Kalender. Ein Grau und kein zweites Blau: In
       der hellen Fassung sind `--accent` und `--accent-fill` derselbe
       Wert, zwei Blautöne wären dort nicht zu unterscheiden – und heute
       UND gewählt fällt oft zusammen, beim Öffnen sogar immer.
       Hier heller als das Gitter (`--line`), damit er auf dem dunklen
       Feld überhaupt zu sehen ist, aber leiser als das Blau: „heute" ist
       die Angabe, die man nicht selbst gesetzt hat. */
    --wahl: #55648c;

    --radius: 10px;
}

/* ---------- Helles Thema ----------
   Aktiviert durch data-theme="light" auf <html> (JavaScript, gespeichert
   unter localStorage 'crm.theme'). Dieselben Variablen, helle Werte. */
/* `.thema-hell`: dieselben Werte für EINEN Bereich, egal wie die Seite
   steht – das Blatt des Schreibdialogs, den Signatur- und den Vorlageneditor. Eine
   Mail ist für weißen Grund geschrieben; wer im dunklen Thema schreibt,
   sah seinen eigenen Text und das Zitat darunter auf dunklem Grund, mit
   Farben, die für Weiß gemeint waren. Das ist keine Geschmacksfrage,
   sondern eine des Kontrasts – dieselbe, die den Anzeigerahmen der
   Nachricht hell hält. */
html[data-theme="light"], .thema-hell {
    color-scheme: light;

    --bg: #f2f4f9;          /* Seitenhintergrund (hellbläulich) */
    --panel: #ffffff;       /* Karten, Listen, Eingabefelder */
    --panel-2: #eef1f7;     /* Hover, Kopfzeilen, Badge-Grund */
    --line: #d6dce8;        /* Trennlinien, Rahmen */
    --text: #1c2436;        /* Grundschrift */
    --muted: #5b667e;       /* Sekundärtext, weiterhin AA auf weiß */

    /* Signalfarbe neu abgestimmt: auf hellem Grund braucht sie mehr
       Tiefe, sonst wirkt sie ausgewaschen. */
    --accent: #2453d6;      /* Vordergrund: Links, Reiter, Chips (6.0 AA) */
    --accent-fill: #2453d6; /* Fläche mit weißer Schrift (7.0 AA auf weiß) */
    --accent-2: #1c42ac;    /* Hover, etwas dunkler */

    --danger: #c9333a;
    --ok: #1f8f5f;
    --warn: #a96f18;

    /* Auf hellem Grund braucht auch das Lila mehr Tiefe – 7.10 unter
       weißer Schrift, wie das Blau daneben (6.40). */
    --sperre: #6d28d9;
    --sperre-2: #5b21b6;

    /* Herkunft: die gleichen zwei Farbtemperatur-Tönungen, aber dunkel
       statt hell – auf weißem Grund mit AA lesbar. */
    --meta: #2d6a4f;        /* grünlich */
    --meta-link: #8a6a1f;   /* gelblich */
    /* Hier andersherum: DUNKLER als das Gitter (#d6dce8), sonst wäre der
       Rahmen auf Weiß nicht zu sehen. `--muted` (#5b667e) wäre so schwer
       wie das Blau und stritte mit ihm. */
    --wahl: #7a8496;
}

/*
 * Die Farben der SEITE, ein zweites Mal unter eigenem Namen.
 *
 * Gebraucht von `.thema-seite`: einem Stück INNERHALB eines hellen
 * Bereichs (`.thema-hell`), das trotzdem aussehen soll wie die Seite –
 * die Werkzeugleiste über der Nachricht. Ein `var(--panel)` dort sähe
 * nur den hellen Wert des Bereichs; die Werte der Seite sind von innen
 * nicht mehr zu erreichen. Deshalb werden sie HIER, am Wurzelelement,
 * unter zweitem Namen festgehalten: `var()` in einem Wert wird auf dem
 * Element ausgerechnet, das ihn setzt – auf `html` also mit den Farben
 * der Seite –, und das Ergebnis erbt jedes Kind, unangetastet von dem,
 * was ein Bereich dazwischen an `--panel` ändert.
 */
html {
    --seite-bg: var(--bg); --seite-panel: var(--panel); --seite-panel-2: var(--panel-2);
    --seite-line: var(--line); --seite-text: var(--text); --seite-muted: var(--muted);
    --seite-accent: var(--accent); --seite-accent-fill: var(--accent-fill); --seite-accent-2: var(--accent-2);
    --seite-danger: var(--danger); --seite-ok: var(--ok); --seite-warn: var(--warn);
    --seite-meta: var(--meta); --seite-meta-link: var(--meta-link); --seite-wahl: var(--wahl);
}
.thema-seite {
    --bg: var(--seite-bg); --panel: var(--seite-panel); --panel-2: var(--seite-panel-2);
    --line: var(--seite-line); --text: var(--seite-text); --muted: var(--seite-muted);
    --accent: var(--seite-accent); --accent-fill: var(--seite-accent-fill); --accent-2: var(--seite-accent-2);
    --danger: var(--seite-danger); --ok: var(--seite-ok); --warn: var(--seite-warn);
    --meta: var(--seite-meta); --meta-link: var(--seite-meta-link); --wahl: var(--seite-wahl);
    color: var(--text); background: var(--panel);
}

* { box-sizing: border-box; }
[x-cloak] { display: none !important; }

html, body {
    margin: 0;
    height: 100%;
    /* Nur der Inhaltsbereich scrollt, nicht die ganze Seite. */
    overflow: hidden;
    background: var(--panel);
    color: var(--text);
    font: 15px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
}

/* `--ueberschrift` ist eine Wahl des Anwenders (Einstellungen → Darstellung).
   Ohne sie `inherit` – also der Text, wie bisher. */
h1, h2, h3, h4 { margin: 0; font-weight: 600; color: var(--ueberschrift, inherit); }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
code { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: .9em; }

.muted { color: var(--muted); }
.tiny { font-size: 12px; }
.error { color: var(--danger); }
.warn { color: var(--warn); }
.ok { color: var(--ok); }
.spacer { flex: 1; }
.nowrap { white-space: nowrap; }
.right { text-align: right; }

/* ---------- Knöpfe ---------- */

button {
    background: var(--accent-fill);
    color: #fff;
    border: 0;
    border-radius: 8px;
    padding: 8px 14px;
    font: inherit;
    font-size: 14px;
    cursor: pointer;
}
button:hover { background: var(--accent-2); }
button:disabled { opacity: .5; cursor: not-allowed; }
button.ghost { background: transparent; border: 1px solid var(--line); color: var(--text); }
button.ghost:hover { background: var(--panel-2); }
button.mini { padding: 3px 8px; font-size: 12px; }
button.danger { background: var(--danger); }
button.danger:hover { background: #c73b40; }
/* Die Sperre: eine Entscheidung über den Kontakt, die stehen bleibt –
   und deshalb weder rot (das hieße „weg damit") noch blau wie das
   Bearbeiten daneben. */
button.sperre { background: var(--sperre); }
button.sperre:hover { background: var(--sperre-2); }
/* Drei Knöpfe mit eigener Farbe (Einstellungen → Darstellung): E-Mail
   schreiben, Neuer Termin, Kontakt bearbeiten. Die Ausnahme von „Farbe
   bedeutet Rolle" – ausdrücklich gewünscht. Ohne Wahl der Akzent, wie
   bisher. Weiße Schrift bleibt: Die Wahl wird abgedunkelt, bis sie trägt. */
button.knopf-mail { background: var(--knopf-mail, var(--accent-fill)); }
button.knopf-mail:hover { background: var(--knopf-mail-2, var(--accent-2)); }
button.knopf-termin { background: var(--knopf-termin, var(--accent-fill)); }
button.knopf-termin:hover { background: var(--knopf-termin-2, var(--accent-2)); }
button.knopf-kontakt { background: var(--knopf-kontakt, var(--accent-fill)); }
button.knopf-kontakt:hover { background: var(--knopf-kontakt-2, var(--accent-2)); }
button.icon-btn { padding: 6px 8px; line-height: 0; }
button.icon-btn svg { display: block; }
/* Werkzeugknopf für etwas Unwiderrufliches: erst beim Zeigen rot, damit er
   in der Leiste nicht dauernd Alarm schlägt. */
button.danger-icon:hover:not(:disabled) { color: var(--danger); }
button.link-btn {
    background: none; border: 0; color: var(--accent); padding: 0;
    font: inherit; font-size: inherit; cursor: pointer;
}
button.link-btn:hover { background: none; text-decoration: underline; }

/* ---------- Eingabefelder ---------- */

input, textarea, select {
    width: 100%;
    /* Schrumpfen erlauben. Ein Flex- oder Rasterkind bekommt sonst als
       Mindestbreite seine MIN-CONTENT-Breite, und die ist bei
       `type="date"` und `type="datetime-local"` die des fertig
       formatierten Datums samt Bedienglied – auf einem iPhone breiter
       als das Feld daneben. Der Dialog scrollte dadurch waagerecht.
       `width: 100%` allein hilft nicht: Es setzt die gewünschte Breite,
       nicht die kleinstmögliche. */
    min-width: 0;
    background: var(--panel);
    border: 1px solid var(--line);
    color: var(--text);
    border-radius: 8px;
    padding: 9px 11px;
    font: inherit;
    /* iOS zoomt bei < 16px beim Fokus automatisch hinein -> mind. 16px */
    font-size: 16px;
}
input:focus, textarea:focus, select:focus { outline: 2px solid var(--accent); outline-offset: -1px; }
textarea { resize: vertical; min-height: 80px; }
/* Der Platzhalter im Feld: bislang die Vorgabe des Browsers – im dunklen
   Thema ein Grau, das kaum zu lesen war. Jetzt der Nebentext (AA auf der
   Karte), und einstellbar über `--platzhalter`. `opacity: 1`, weil einige
   Browser ihn sonst zusätzlich dämpfen. */
input::placeholder, textarea::placeholder { color: var(--platzhalter, var(--muted)); opacity: 1; }

/* Auswahlfelder sehen sonst aus wie vom Betriebssystem gemalt: kleiner,
   mit eigenem Rahmen und eigener Höhe – die Regel oben greift bei ihnen
   nur halb. `appearance: none` schaltet das ab; dafür muss der Pfeil
   selbst kommen, als eingebettetes SVG (kein zusätzlicher Netzzugriff,
   und die Farbe steht im Bild statt in einer zweiten Regel). */
select {
    cursor: pointer;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8' fill='none' stroke='%238b97b3' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='1,1.5 6,6.5 11,1.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
    background-size: 11px 8px;
    /* Platz für den Pfeil, damit langer Text nicht darunter läuft. */
    padding-right: 34px;
}
select:hover { border-color: var(--muted); }
/* Ohne Optionen (noch nicht geladen) sieht ein leeres Feld sonst kaputt aus. */
select:disabled { opacity: .5; cursor: not-allowed; }
input[type="checkbox"], input[type="radio"] { width: auto; }
input[type="file"] { padding: 8px; }

/* Datums- und Zeitfelder in Safari.
 *
 * iOS malt `date`, `time` und `datetime-local` mit eigenem Innenleben:
 * Der Wert steht MITTIG statt links wie in jedem anderen Feld, und das
 * Bedienglied bringt eine eigene Breite mit, die sich auf den Kasten
 * nicht einlässt – die Seitenränder verschwinden, und das Feld sieht
 * breiter aus als das darunter.
 *
 * `appearance: none` schaltet das ab, dieselbe Behandlung wie bei
 * `select` weiter oben und aus demselben Grund. Der Wert bekommt seine
 * Ausrichtung über das Pseudoelement zurück, das WebKit dafür anbietet.
 *
 * In Chrome ändern die Regeln nichts – nachgemessen: Feld für Feld
 * gleich, der Kalenderknopf bleibt. Sie sind für Safari da, und dort
 * kann dieser Prüfstand sie nicht nachmessen.
 */
input[type="date"], input[type="time"], input[type="datetime-local"] {
    appearance: none;
    -webkit-appearance: none;
}
input[type="date"]::-webkit-date-and-time-value,
input[type="time"]::-webkit-date-and-time-value,
input[type="datetime-local"]::-webkit-date-and-time-value {
    text-align: left;
    margin: 0;
    /* Ein LEERES Feld hat in Safari keinen Text und damit keine Zeile –
       es fiel auf ein paar Pixel Höhe zusammen, bis ein Datum drin
       stand. Die Zeilenhöhe eines Textfelds als Mindestmaß hält es
       gleich hoch wie die Felder daneben. */
    min-height: 1.4em;
    line-height: 1.4;
}

label { display: block; margin: 0 0 12px; font-size: 13px; color: var(--muted); }
label > input, label > textarea, label > select { margin-top: 5px; color: var(--text); }
label.row, label.toggle { display: flex; align-items: center; gap: 8px; margin: 0; }
/* Überschrift und ein Knopf dazu, der nicht zum Feld gehört, sondern
   neben ihm steht – etwa „Gruppe anlegen" über der Gruppenliste. */
label.label-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
label.row input, label.toggle input { width: auto; margin: 0; }
label .req { color: var(--danger); }

/* Datumsfeld mit Knopf daneben. Der Knopf schrumpft nicht, das Feld
   nimmt den Rest. */
.date-row { display: flex; align-items: center; gap: 8px; margin-top: 5px; }
.date-row input { margin-top: 0; }
.date-row button { flex: 0 0 auto; white-space: nowrap; }

/* ---------- Anmeldung ---------- */

.center {
    min-height: 100vh;
    min-height: 100dvh;
    background: var(--bg);
    display: grid; place-items: center; padding: 20px;
}

/* Hintergrundbild der Anmeldung.
   Zwei Bilder, nicht eines mit `cover`: Das Motiv ist quer aufgebaut und
   verliert im Hochformat seine Mitte. `login.jpg` ist 1376×768,
   `login_mobile.jpg` 768×1376 – umgeschaltet wird nach der **Ausrichtung**
   und nicht nach der Breite, denn ein liegendes Telefon braucht das
   Querbild und ein schmales Fenster am Rechner das hohe. */
.login-bg {
    position: relative;
    background-image: url("img/login.jpg");
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    /* Der Farbwert bleibt darunter stehen: Solange das Bild lädt – oder
       wenn es fehlt – ist der Hintergrund dunkel und nicht weiß. */
    background-color: var(--bg);
}
@media (orientation: portrait) {
    .login-bg { background-image: url("img/login_mobile.jpg"); }
}

/* Ein Schleier zwischen Bild und Karte. Ohne ihn hängt die Lesbarkeit
   des Formulars davon ab, was zufällig hinter ihm liegt. */
.login-bg::before {
    content: "";
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(15,20,32,.55), rgba(15,20,32,.78));
}
.login-bg > * { position: relative; }

/* Die Kopfleiste der Website vor der Anmeldung: Sie liegt oben auf der
   Fotofläche, die Karte bleibt in der Mitte. Maße und Aufteilung wie in
   layout/assets/css/site.css (.nav, .nav-in: 60px hoch, Inhalt mittig
   in 1200px mit 24px Rand), die Farben sind die der Anwendung. */
.login-nav {
    position: absolute; top: 0; left: 0; right: 0;
    height: 60px;
    background: color-mix(in srgb, var(--bg) 72%, transparent);
    border-bottom: 1px solid color-mix(in srgb, var(--line) 60%, transparent);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
}
.login-nav-in {
    max-width: 1200px; margin: 0 auto; padding: 0 24px; height: 100%;
    display: flex; align-items: center; gap: 28px;
}
.login-nav-brand {
    display: inline-flex; align-items: center; gap: 10px;
    color: var(--text); text-decoration: none;
    font-size: 16px; font-weight: 600; letter-spacing: -0.01em;
}
.login-nav-brand img { width: 28px; height: 28px; border-radius: 8px; }
.login-nav-links { display: flex; align-items: center; gap: 4px; margin-right: auto; }
.login-nav-links a {
    padding: 6px 10px; border-radius: 8px;
    font-size: 14px; color: var(--muted); text-decoration: none;
}
.login-nav-links a:hover { color: var(--text); background: var(--panel-2); }
.login-nav-actions { display: flex; align-items: center; gap: 8px; margin-left: auto; }
.login-nav-cta {
    display: inline-flex; align-items: center;
    height: 30px; padding: 0 12px; border-radius: 8px;
    background: var(--accent-fill); color: #fff;
    font-size: 13px; font-weight: 600; text-decoration: none;
}
.login-nav-cta:hover { background: var(--accent-2); }
/* Schmal bleiben Marke, Themenwechsel und Knopf; die Verweise verschwinden. */
@media (max-width: 520px) {
    .login-nav-links { display: none; }
}

/* Die Karte selbst wird etwas undurchsichtiger und bekommt einen
   Schatten – sonst schwimmt sie auf dem Bild. */
.login-bg .card {
    background: rgba(23, 30, 46, .92);
    box-shadow: 0 18px 50px rgba(0, 0, 0, .55);
    backdrop-filter: blur(2px);
}
.card { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; }
.login { width: 340px; max-width: 100%; }
.login h1 { margin: 0 0 4px; font-size: 20px; display: flex; align-items: center; gap: 10px; }
.login-logo { width: 40px; height: 40px; border-radius: 10px; flex: none; }
.login p { margin: 0 0 18px; }
.login button[type="submit"] { width: 100%; margin-top: 8px; }
.hint { margin-top: 14px; }

.spinner {
    width: 34px; height: 34px; border-radius: 50%;
    border: 3px solid var(--line); border-top-color: var(--accent);
    animation: spin 1s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ---------- Grundgerüst ---------- */

.app {
    display: flex; flex-direction: column;
    background: var(--bg);
    height: 100vh;   /* Fallback für ältere Browser */
    height: 100dvh;  /* füllt den Bildschirm inkl. Safe-Areas */
}
@supports not (height: 100dvh) {
    .app { height: var(--app-height, 100vh); }
}

/* „Die Anwendung wurde aktualisiert": ein Streifen über der Kopfleiste,
   in der Flex-Spalte der Anwendung – er schiebt alles nach unten, statt
   etwas zu verdecken. Ein Hinweis, keine Warnung: Akzent, nicht Rot. Die
   Safe-Area oben nimmt er der Kopfleiste ab. */
.aktualisierung {
    display: flex; align-items: center; gap: 10px; flex: none;
    padding: 8px 16px; padding-top: calc(8px + env(safe-area-inset-top));
    background: var(--accent-fill); color: #fff; font-size: 13.5px;
}
.aktualisierung button.mini { background: #fff; color: var(--accent-fill); border-color: transparent; font-weight: 600; }
/* Nur wenn der Streifen WIRKLICH steht, gibt die Kopfleiste die Safe-Area
   an ihn ab. Ein Nachbar-Selektor („Streifen plus Kopfleiste") griff auch
   beim unsichtbaren Streifen – der steht mit `x-show` weiter im Baum –,
   und die Anwendung begann auf dem iPhone in der Notch. */
.app.mit-streifen .topbar { padding-top: 10px; }

.topbar {
    display: flex; align-items: center; gap: 10px;
    padding: 10px 16px; border-bottom: 1px solid var(--line); background: var(--panel);
    /* Safe-Area im iOS-Standalone-Modus (Notch/Statusleiste) */
    padding-top: calc(10px + env(safe-area-inset-top));
    padding-left: calc(16px + env(safe-area-inset-left));
    padding-right: calc(16px + env(safe-area-inset-right));
}
.brand { font-weight: 700; letter-spacing: .3px; white-space: nowrap; display: inline-flex; align-items: center; gap: 8px; }
/* So hoch wie der Knopf daneben (gemessen 38 × 34) und mit derselben
   Ecke: Zwei Dinge nebeneinander, von denen eines halb so groß ist,
   sehen aus wie ein Fehler – und schmal ist das Zeichen das Einzige,
   was von der Marke übrig bleibt. */
.brand-logo { width: 34px; height: 34px; border-radius: 8px; flex: none; }
/* Zeichen und Schriftzug als Knopf zum Dashboard – ohne die Zeichnung
   eines Knopfs, auch beim Überfahren nicht (`button:hover`). */
.brand-home {
    display: inline-flex; align-items: center; gap: 8px; padding: 0; margin: 0;
    background: none; border: 0; color: inherit; font: inherit; letter-spacing: inherit; cursor: pointer;
}
.brand-home:hover { background: none; }
.brand-user { font-weight: 400; font-size: 12.5px; color: var(--muted); letter-spacing: 0; }
/* Schmal weicht erst der Benutzername, dann der Schriftzug: Das Zeichen
   daneben sagt dasselbe, und der Platz gehört dem, was sich ändert.
   Dieselbe Schwelle wie für den Namen – eine Zahl, nicht zwei. */
/* Was nur auf schmalen Schirmen steht – etwa die Hilfe im Profilmenü,
   die dort das Zeichen in der Leiste ersetzt. */
.nur-schmal { display: none; }

@media (max-width: 560px) {
    .brand-user { display: none; }
    .brand-name { display: none; }
    /* Ohne Schriftzug braucht das Zeichen keinen Abstand nach rechts. */
    .brand { gap: 0; }
    /* Und umgekehrt: Was nur breit Platz hat, weicht hier. */
    .nur-breit { display: none; }
    .profile-dropdown li.nur-schmal { display: flex; }
}

/* Profil-Aufklappmenü */
.profile-menu { position: relative; }
.profile-dropdown {
    position: absolute; right: 0; top: calc(100% + 4px);
    margin: 0; padding: 4px; list-style: none; z-index: 80;
    background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
    min-width: 180px; box-shadow: 0 8px 24px rgba(0,0,0,.4);
}
/* Jeder Punkt trägt sein Sinnbild links: In einer Liste aus dreizehn
   Wörtern findet das Auge den gesuchten Punkt über das Bild schneller
   als über den Text – und in der Kopfleiste stehen dieselben Zeichen. */
.profile-dropdown li {
    display: flex; align-items: center; gap: 9px;
    padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 14px; white-space: nowrap;
}
/* Gedämpft, solange die Zeile ruhig ist: Dreizehn Bilder in voller
   Schriftfarbe wären eine Wand. Unter dem Zeiger nimmt das Bild die
   Farbe der Zeile an. */
.profile-dropdown li > svg { flex: none; color: var(--muted); }
.profile-dropdown li:hover > svg { color: inherit; }
.profile-dropdown li.return > svg,
.profile-dropdown li.danger:hover > svg { color: inherit; }
.profile-dropdown li:hover { background: var(--accent-fill); color: #fff; }
.profile-dropdown li.danger:hover { background: var(--danger); }
.profile-dropdown li.return { color: var(--accent); font-weight: 600; }

/* Die Rechte-Maske im Selbst-Modus: dieselbe Ansicht wie beim
   Administrator, aber ohne Stift – nichts klickbar, leicht gedimmt. */
.perm-readonly { pointer-events: none; opacity: .75; }

/* Der Vergleichsdialog Pool ↔ Kontakt: Der Zustand einer Zeile ist ihre
   Farbe, der Titel sagt ihn in Worten, die Legende darunter erklärt ihn. */
.diff-table tr.diff-fuellen td { color: var(--ok); }
.diff-table tr.diff-bleibt td { color: var(--warn); }
.diff-table tr.diff-gleich td { color: var(--muted); }
.diff-dir { text-align: center; white-space: nowrap; }
.diff-dir-btn { min-width: 34px; font-size: 15px; line-height: 1; padding: 3px 6px; }
.diff-dir-btn.ist-aktion { color: var(--accent); border-color: var(--accent); }
.diff-dot { display: inline-block; width: 9px; height: 9px; border-radius: 50%; vertical-align: baseline; }
.diff-dot.diff-fuellen { background: var(--ok); }
.diff-dot.diff-bleibt { background: var(--warn); }

/* Auswahlliste in einem Dialog (Anruf zuordnen): eine Zeile je Treffer,
   die ganze Zeile ist der Knopf. */
.pick-list { list-style: none; margin: 0; padding: 0; }
.pick-list li {
    display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 8px;
    padding: 8px 10px; border-radius: 6px; cursor: pointer; border: 1px solid transparent;
}
.pick-list li:hover { background: var(--panel-2); border-color: var(--line); }
.pick-list li.is-busy { opacity: .6; cursor: progress; }
.pick-list li .row-sub { flex-basis: 100%; }
.call-unknown-actions { display: inline-flex; gap: 6px; margin-left: 8px; }

/* Aufklappmenü an einem Knopf – das Muster des Profilmenüs als
   eigenes Bauteil, für die Auswahlleiste und künftig anderswo. Die
   Zeilen tragen ihre Bedeutung als Farbe (Punkt und Schrift) und beim
   Überfahren als Fläche; `.is-off` ist eine Zeile, die gerade nichts
   träfe. */
.menu { position: relative; display: inline-block; }
.menu .caret { font-size: 11px; margin-left: 2px; opacity: .7; }
.menu-list {
    position: absolute; right: 0; top: calc(100% + 4px);
    margin: 0; padding: 4px; list-style: none; z-index: 80;
    background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
    min-width: 260px; box-shadow: 0 8px 24px rgba(0,0,0,.4);
}
.menu-list li {
    display: flex; align-items: center; gap: 9px;
    padding: 8px 12px; border-radius: 6px; cursor: pointer; font-size: 14px; white-space: nowrap;
}
.menu-list li::before {
    content: ""; width: 8px; height: 8px; border-radius: 50%; flex: none; background: currentColor;
}
.menu-list li.menu-ok { color: var(--ok); }
.menu-list li.menu-warn { color: var(--warn); }
.menu-list li.menu-danger { color: var(--danger); }
.menu-list li.menu-ok:hover { background: var(--ok); color: #fff; }
.menu-list li.menu-warn:hover { background: var(--warn); color: #fff; }
.menu-list li.menu-danger:hover { background: var(--danger); color: #fff; }
.menu-list li.is-off, .menu-list li.is-off:hover {
    color: var(--muted); background: transparent; cursor: default; opacity: .7;
}
/* Einträge ohne Farbpunkt – Aufgaben, keine Stufen. */
.menu-list li.menu-plain::before { display: none; }
.menu-list li.menu-plain:hover { background: var(--panel-2); }
@media (max-width: 700px) { .menu-list { right: auto; left: 0; } }

/* Ein Menü an einem Knopf, der weder links noch rechts am Rand sitzt.
   Von diesem Knopf aus gerechnet zeichnet es schmal in jedem Fall über
   einen der beiden Ränder: nach rechts hinaus (`left: 0`, die Regel
   darüber) oder, rechtsbündig, nach links – wie weit, hängt daran, was
   sonst noch in der Zeile steht.

   Also misst es sich schmal nicht am Knopf, sondern an seiner Zeile:
   `position: static` an der Hülle gibt den Bezugspunkt an die Kopfzeile
   ab, und deren beide Ränder SIND die Ränder der Karte. Gerechnet wird
   dabei nichts – ein Menü, dessen Platz das Programm ausrechnet, steht
   beim Drehen des Geräts falsch. Was nicht in eine Zeile passt, bricht
   um, statt abgeschnitten zu werden. */
@media (max-width: 700px) {
    .menue-halter { position: relative; }
    .menue-halter > .menu { position: static; }
    .menue-halter > .menu > .menu-list {
        left: 0; right: 0; width: auto; min-width: 0; max-width: none;
    }
    .menue-halter > .menu > .menu-list li { white-space: normal; }
}

/* Stellvertretung: Untermenü mit den Konten. Das Hauptmenü hängt am rechten
   Rand, also klappt das Untermenü nach links auf. */
.profile-dropdown li.has-sub { position: relative; display: flex; align-items: center; gap: 8px; }
.profile-dropdown li.has-sub .sub-arrow { margin-left: auto; opacity: .6; transform: rotate(180deg); }
.profile-submenu {
    position: absolute; right: calc(100% + 4px); top: -4px;
    margin: 0; padding: 4px; list-style: none; z-index: 81;
    background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
    min-width: 180px; max-height: 60vh; overflow-y: auto;
    box-shadow: 0 8px 24px rgba(0,0,0,.4); color: var(--text);
}
.profile-submenu li { display: flex; align-items: center; gap: 8px; }
.profile-submenu li .sub { margin-left: auto; font-size: 11px; opacity: .7; }
.profile-submenu li.hint { color: var(--muted); cursor: default; font-size: 12.5px; }
.profile-submenu li.hint:hover { background: transparent; color: var(--muted); }
/* Mobil ist rechts wie links kein Platz: Das Untermenü klappt im Menü auf. */
@media (max-width: 560px) {
    .profile-dropdown li.has-sub { flex-wrap: wrap; }
    .profile-dropdown li.has-sub.open { background: transparent; color: inherit; }
    .profile-dropdown li.has-sub .sub-arrow { transform: rotate(90deg); }
    .profile-submenu {
        position: static; flex-basis: 100%; margin-top: 6px; box-shadow: none;
        max-height: 40vh;
    }
}

/* Der Hinweis in der Kopfleiste, dass ein Administrator ein fremdes Konto
   vertritt – ein Klick führt zurück. */
.impersonation-badge {
    margin-left: 8px; padding: 2px 9px; border-radius: 999px; cursor: pointer;
    font-size: 11.5px; font-weight: 600; letter-spacing: 0; white-space: nowrap;
    background: var(--warn, #d97706); color: #fff; border: 0; font-family: inherit;
}
.impersonation-badge:hover { filter: brightness(1.1); }
@media (max-width: 560px) { .impersonation-badge span { display: none; } .impersonation-badge { padding: 0; width: 10px; height: 10px; margin-left: 6px; vertical-align: middle; } }

.layout { flex: 1; display: flex; min-height: 0; position: relative; }

/* ---------- Seitenleiste ---------- */

.sidebar {
    width: 240px; flex: none; border-right: 1px solid var(--line);
    display: flex; flex-direction: column; background: var(--panel); min-height: 0;
    transition: margin-left .25s ease;
    margin-left: 0;
    padding-bottom: env(safe-area-inset-bottom);
}
.sidebar:not(.open) { margin-left: -240px; }

.sidebar-backdrop { position: absolute; inset: 0; background: rgba(0,0,0,.5); z-index: 20; }

/* Die Grundregeln oben SIND der Schreibtisch: Die Leiste steht im Fluss
   und schiebt den Inhalt. Ein eigener Block dafür stand hier einmal, mit
   `.sidebar-backdrop { display: none !important }` – der Schleier hängt
   ohnehin an `x-show="sidebarOpen && isMobile"`, und ein `!important`
   auf etwas, das die Komponente schaltet, ist ein zweiter Schalter, den
   man beim nächsten Umbau vergisst.

   Telefon: Seitenleiste als Overlay darüberlegen. Dieselbe Bedingung wie
   `CRM_TELEFON` in app.js und wie der Mailbereich – ein iPhone im
   Querformat ist 769 Pixel breit und mehr, und nach der Breite allein
   bekam es die feste Spalte von 240 Pixeln: ein Drittel des Schirms. */
@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    .sidebar { position: absolute; top: 0; bottom: 0; left: 0; z-index: 30; box-shadow: 2px 0 12px rgba(0,0,0,.3); }
    .sidebar:not(.open) { margin-left: -250px; }
    /* Die Suche in der Kopfleiste nimmt die Breite zwischen Marke und
       Zahnrad; der Benutzername in der Marke weicht ihr. (Hier und nicht
       in einem eigenen Block: Die Telefonbedingung steht im Stilblatt
       genau zweimal – ein Wächter zählt sie.) */
    .topbar .suche { flex: 1 1 auto; min-width: 0; }
    .topbar .suche input, .topbar .suche input:focus { width: 100%; }
    /*
     * Die Trefferliste über die ganze Schirmbreite, mit acht Pixeln Rand.
     *
     * Sie hing vorher am Suchfeld (`right: 0`) und war mindestens 360
     * Pixel breit – auf einem 390er Schirm lief sie damit 82 Pixel nach
     * links aus dem Bild. Gemessen: x−82 bis x278.
     *
     * Der Trick ist `position: static` am Feld: Damit ist der nächste
     * positionierte Vorfahr die Kopfleiste, und `left`/`right` messen
     * gegen den Schirm statt gegen ein 160 Pixel breites Feld. `top:
     * 100%` bleibt „unter der Leiste" – auch wenn der
     * Aktualisierungsstreifen sie nach unten schiebt.
     *
     * `.app` davor, weil die breite Regel weiter unten im Stilblatt
     * steht: Bei gleicher Gewichtung gewönne die spätere, und genau das
     * war der Fehler.
     */
    .topbar { position: relative; }
    .app .topbar .suche { position: static; }
    .topbar .suche-feld { flex: 1 1 auto; min-width: 0; }
    .app .topbar .suche-liste {
        left: 8px; right: 8px; width: auto; min-width: 0; max-width: none;
    }
    .topbar .brand-user { display: none; }
    /* Die Akte als Dialog randlos (siehe „Die Akte als Dialog" weiter
       unten); der Kopf rückt unter die Statusleiste. `.modal.akte-modal`
       davor, weil die breiten Regeln der Akte weiter unten im Stilblatt
       stehen: Bei gleicher Gewichtung gewönne die spätere. */
    .modal.akte-modal { padding: 0; }
    .modal.akte-modal .modal-box.akte-dialog {
        width: 100vw; height: 100vh; height: 100dvh; max-height: none;
        border: 0; border-radius: 0;
    }
    .modal.akte-modal .akte-kopf { padding-top: calc(8px + env(safe-area-inset-top)); }
    .modal.akte-modal .akte-inhalt { --inhalt-rand: 12px; }
    /* Das KI-Ergebnis ebenso randlos. `.modal` davor aus demselben Grund:
       Die Regel für die Größe steht weiter unten. */
    .modal:has(> .ki-vorschau-dialog) { padding: 0; }
    .modal .modal-box.ki-vorschau-dialog {
        width: 100vw; height: 100vh; height: 100dvh; max-height: none; border: 0; border-radius: 0;
        padding: calc(12px + env(safe-area-inset-top)) 12px calc(12px + env(safe-area-inset-bottom));
    }
    /* Die Einstellungen ebenso randlos. */
    .modal:has(> .einst-dialog) { padding: 0; }
    .modal .modal-box.einst-dialog {
        width: 100vw; height: 100vh; height: 100dvh; max-height: none; border: 0; border-radius: 0;
    }
    .einst-dialog .einst-kopf { padding-top: calc(10px + env(safe-area-inset-top)); }
    .einst-dialog .modal-actions.einst-fuss { padding-bottom: calc(10px + env(safe-area-inset-bottom)); }
    /*
     * Der Lesedialog ebenso randlos.
     *
     * Zentriert stand er weder oben noch unten richtig: Auf dem Telefon
     * blieb unten eine Zeile Luft, und der Inhalt hatte seitlich Rand,
     * während die Nachricht im E-Mail-Bereich bis an die Kanten läuft –
     * schmale Mails wurden dadurch rechts abgeschnitten. Randlos gibt es
     * keine Lücke, die man gegen eine andere justieren müsste.
     *
     * `.modal` davor, wie bei den Nachbarn: Die allgemeinen Regeln des
     * Dialogs stehen weiter unten im Stilblatt und gewönnen sonst.
     */
    .modal:has(> .mail-leser-dialog) { padding: 0; }
    .modal .modal-box.mail-leser-dialog {
        width: 100vw; height: 100vh; height: 100dvh; max-height: none;
        border: 0; border-radius: 0;
    }
    /* Die Leiste rückt unter die Statusleiste, der Inhalt endet über dem
       Home-Balken. Der Rand gehört an die LEISTE, nicht an den rollenden
       Bereich: Sie klebt oben (`position: sticky`), und ein Innenrand am
       Bereich schöbe nur den Inhalt, nicht sie. */
    /*
     * Schwerer gewichtet, und das ist hier kein Geschmack: Weiter unten
     * steht `.mail-reader > .mail-werkzeuge.thema-seite { padding: 12px 0
     * 10px; }` – gleich schwer (0,3,0), aber später, und als
     * Kurzschreibweise nimmt sie den Notch-Abstand wieder mit. Gemessen
     * mit ersetzter Notch-Angabe: Der Knopf stand bei 15 statt bei 59
     * Pixeln, also mitten unter der Notch. `.modal` davor hebt die Regel
     * auf (0,4,0) – derselbe Kunstgriff wie bei den Nachbardialogen.
     */
    .modal .mail-leser-dialog .mail-reader > .mail-werkzeuge.thema-seite {
        padding-top: calc(12px + env(safe-area-inset-top));
    }
    .modal .mail-leser-dialog .mail-reader { padding-bottom: calc(16px + env(safe-area-inset-bottom)); }
}

.nav { padding: 10px 8px; overflow-y: auto; flex: 1; }
.nav-item {
    display: flex; align-items: center; gap: 10px; width: 100%;
    padding: 9px 12px; margin-bottom: 2px; border-radius: 8px;
    background: transparent; border: 0; color: var(--muted);
    font-size: 14px; text-align: left; cursor: pointer;
}
.nav-item svg { flex: none; }
.nav-item:hover { background: var(--panel-2); color: var(--text); }
.nav-item.active { background: var(--accent-fill); color: #fff; }
.nav-count {
    margin-left: auto; font-size: 11px; font-weight: 600;
    background: var(--danger); color: #fff; border-radius: 20px; padding: 1px 7px;
}
.nav-item.active .nav-count { background: rgba(0,0,0,.3); }
.nav-sep { margin: 10px 12px 6px; font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }

.sidebar-foot {
    border-top: 1px solid var(--line); padding: 10px 14px;
    font-size: 12px; color: var(--muted);
    display: flex; align-items: center; gap: 8px;
}

/* ---------- Inhaltsbereich ---------- */

/* Die Polsterung steht als Variablen da, weil etwas sie zurücknehmen
   muss: Die gelesene Nachricht tritt auf dem Telefon randlos daraus
   hervor (siehe „Telefon: Liste ODER Nachricht"). Zweimal dieselbe Zahl –
   einmal als Polsterung, einmal als negativer Rand – ginge beim ersten
   Ändern auseinander. */
.content {
    --inhalt-rand: 20px;
    --inhalt-oben: 18px;
    --inhalt-unten: calc(28px + env(safe-area-inset-bottom));
    flex: 1; min-width: 0; overflow-y: auto;
    padding: var(--inhalt-oben) var(--inhalt-rand) var(--inhalt-unten);
}
/* Der sichere Bereich gilt hier ERST RECHT: Diese Regel greift auf dem
   Telefon, und dort liegt der Streifen für den Startbalken. Er fehlte –
   die Zeile setzte glatte 28 Pixel und nahm ihn damit zurück. */
@media (max-width: 640px) {
    .content { --inhalt-rand: 12px; --inhalt-oben: 14px; }
}

.page-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 16px;
}
.page-head h1 { font-size: 20px; }
/* Der Zusatz steht IM Titel, nicht darunter: eine Zeile weniger, und die
   Zahl liest sich als das, was sie ist – eine Angabe zum Titel, keine
   eigene Überschrift. `font-weight: normal`, damit sie nicht mitschreit. */
.page-head .sub { font-size: 12.5px; color: var(--muted); font-weight: normal; }
.head-actions { display: flex; gap: 8px; flex-wrap: wrap; }
/* Ein Knopf aus Sinnbild und Wort. Schmal weicht das Wort (`nur-breit`),
   und der Rand wird gleichmäßig: Sonst stünde das Zeichen in einem Knopf,
   der noch die Breite seiner Beschriftung hätte. */
.head-actions button, .kopf-knopf { display: inline-flex; align-items: center; gap: 7px; }
.head-actions button > svg, .kopf-knopf > svg { flex: none; }
@media (max-width: 560px) {
    .head-actions button { padding: 8px 10px; }
}

/* Das Schloss am Sperrknopf: geschlossen, solange der Kontakt es nicht
   ist – offen, sobald er gesperrt ist. Über die CSS und nicht über
   `x-show`, damit im Knopf nichts springt, während Alpine hochfährt.
   Dasselbe Muster wie der Schalter kompakt/ausführlich in der Liste. */
.sperr-schalter .sperr-auf { display: none; }
.sperr-schalter.ist-gesperrt .sperr-zu { display: none; }
.sperr-schalter.ist-gesperrt .sperr-auf { display: inline-flex; }

.panel-card {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 16px; margin-bottom: 16px;
}
.panel-card > h3 {
    font-size: 12px; text-transform: uppercase; letter-spacing: .5px;
    color: var(--muted); margin-bottom: 12px;
}
.panel-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.panel-head h3 { font-size: 12px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted); }

.empty {
    padding: 26px 16px; text-align: center; color: var(--muted); font-size: 13.5px;
}

/* ---------- Kennzahlen ---------- */

.stat-tiles {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 10px; margin-bottom: 18px;
}
.stat-tile {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 12px 14px;
}
.stat-tile.alert { border-color: var(--danger); }
/* Anklickbar: Der Rahmen hebt sich beim Zeigen, mehr braucht es nicht –
   eine Kachel, die aussieht wie ein Knopf, wäre eine Kachel zu viel. */
.stat-tile.clickable { cursor: pointer; }
.stat-tile.clickable:hover { border-color: var(--accent); background: var(--panel-2); }
.stat-label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.stat-value { font-size: 26px; font-weight: 600; line-height: 1.25; }
.stat-tile.alert .stat-value { color: var(--danger); }

/* ---------- Such- und Filterleiste ---------- */

.toolbar {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin-bottom: 12px;
}
.toolbar .search { flex: 1 1 240px; min-width: 180px; position: relative; }
/* Feld und Auswahl standen hier 1,5 Pixel auseinander: verschiedene
   Schriftgrößen bei gleichem Polster. Gleiche Schrift, und der Unterschied
   ist weg; der Pfeil braucht rechts weiterhin seinen Platz. */
.toolbar select {
    width: auto; min-width: 150px;
    font-size: 15px; padding: 8px 32px 8px 10px;
    background-position: right 10px center;
}
/* Platz links für die Lupe, rechts für das Kreuz – dieselbe Anordnung
   wie in der Kopfleiste. Die Höhe bleibt: Nur die seitliche Polsterung
   wächst, und der Feldknopf daneben misst sich weiter an ihr. */
.toolbar .search input { font-size: 15px; padding: 8px 32px 8px 34px; }
.toolbar .search .suche-lupe {
    position: absolute; left: 11px; top: 50%; transform: translateY(-50%);
    width: 16px; height: 16px; color: var(--muted); pointer-events: none;
}
/* Erscheint nur, wo aus Zeilen Karten werden. Die Schwelle steht damit
   einmal im Stilblatt und nicht ein zweites Mal in der Anwendung. */
.nur-karten { display: none; }
/* Und das Gegenstück: was es NUR als Tabelle gibt. Die Spaltenansicht
   braucht Breite; unter der Schwelle gäbe es nichts umzuschalten. */
.nur-tabelle { display: inline-flex; }

/* Worin die Suche sucht – das Menü vor dem Suchfeld.
   Es steht dort und nicht in den Einstellungen, weil die Frage beim
   Tippen aufkommt und nicht beim Einrichten. Die Zahl am Knopf
   erscheint nur, solange eingeschränkt ist: Ein Zähler, der immer
   dasteht, sagt nichts. */
.such-felder { position: relative; flex: 0 0 auto; }
/* Er steht in der Suchleiste, also sieht er aus wie sie: derselbe
   Untergrund, derselbe Rahmen, dieselbe Höhe wie Suchfeld und
   Auswahlfelder daneben. Blau wäre der Ton der Handlungen über der
   Liste – hier steht kein Handgriff, sondern ein Filter.

   Die Zahl daneben steht nur da, solange eingeschränkt ist; ein Zähler,
   der immer dasteht, sagt nichts. */
.toolbar .such-felder-knopf {
    display: inline-flex; align-items: center; gap: 6px;
    background: var(--panel); color: var(--muted);
    border: 1px solid var(--line); border-radius: 8px;
    /* Dieselben Werte wie `.toolbar .search input`, dazu die Zeilenhöhe
       eines Feldes: Ohne sie ist der Knopf fünf Pixel flacher als das
       Suchfeld daneben, und das sieht man. */
    padding: 8px 11px; font-size: 15px; line-height: 1.5;
}
.toolbar .such-felder-knopf:hover:not(:disabled) { border-color: var(--muted); color: var(--text); }
/* Das Bild ist so hoch wie eine Zeile: Ohne Text im Knopf bestimmt es
   allein die Höhe, und ein 18 Pixel hohes Bild machte ihn fünf Pixel
   flacher als das Suchfeld daneben. `1.5em` ist dieselbe Zeilenhöhe,
   die auch das Feld hat – keine Zahl, die beim nächsten Umbau daneben
   liegt. */
.toolbar .such-felder-knopf svg { display: block; height: 1.5em; width: 1.5em; }
/* Ein gesetzter Filter färbt sich – der Knopf der Feldauswahl wie die
   Auswahlfelder für Gruppe und Branche. Eine Liste mit wenigen Zeilen
   sieht sonst aus wie ein leerer Bestand, und niemand sucht den Grund
   in einer Zeile darüber. Bei den Auswahlfeldern bleibt es beim Rahmen:
   Ihre Schrift zu färben färbte in manchen Browsern die aufgeklappte
   Liste gleich mit. */
.toolbar .such-felder-knopf.eng { color: var(--accent); border-color: var(--accent); }
.toolbar select.eng { border-color: var(--accent); }
.toolbar select.eng:hover { border-color: var(--accent); }
.such-felder-menue {
    /* Rechtsbündig, seit der Knopf hinter dem Suchfeld steht: linksbündig
       liefe das Menü auf einem 390 Pixel breiten Schirm über den Rand. */
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
    width: 260px; max-height: 60vh; overflow: auto;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 10px 12px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.such-felder-menue .check { margin: 0; }
.such-felder-menue .mail-setting-sep { margin: 8px 0; }
/* Der Kopf trägt den Rückweg: derselbe Haken wie über der Liste, nur
   kräftiger gesetzt – er gilt für alle Zeilen darunter. Ist er
   abgeschaltet, weil ohnehin alles sucht, bleibt er lesbar statt grau
   zu verblassen: Er ist dann eine Aussage, keine tote Schaltfläche. */
.such-felder-menue .such-felder-kopf { margin: 0; font-weight: 600; }
/* Der Hinweis, wenn nichts gewählt ist: Er steht unter der Liste der
   Felder, also dort, wo man gerade das letzte Kreuz weggenommen hat. */
.such-felder-menue .such-felder-leer { margin: 8px 0 0; }

/* ---------- Tabellen ---------- */

.table-wrap {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    overflow-x: auto;
}
table.data {
    width: 100%; border-collapse: collapse; font-size: 13.5px;
}
table.data th, table.data td {
    padding: 9px 12px; text-align: left; border-bottom: 1px solid var(--line);
    vertical-align: top;
}
table.data thead th {
    font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;
    color: var(--muted); font-weight: 600; white-space: nowrap;
    background: var(--panel-2); position: sticky; top: 0; z-index: 1;
}
table.data thead th.sortable { cursor: pointer; user-select: none; }
table.data thead th.sortable:hover { color: var(--text); }
table.data thead th .arrow { color: var(--accent); font-size: 10px; margin-left: 3px; }
table.data tbody tr { cursor: default; }
table.data tbody tr.clickable { cursor: pointer; }
table.data tbody tr:hover { background: var(--panel-2); }
table.data tbody tr:last-child td { border-bottom: 0; }
table.data td.actions { white-space: nowrap; text-align: right; }
table.data .row-title { font-weight: 600; color: var(--text); }
table.data .row-sub { font-size: 12px; color: var(--muted); }
/* Die Adresse zweizeilig: Straße oben, PLZ und Ort darunter. Als
   Stylesheet-Regel, nicht als style-Attribut – Alpines x-show räumt
   beim Einblenden die display-Eigenschaft am Element ab und hätte ein
   Inline-block gleich mit entfernt. */
table.data .addr-street { display: block; }

/* Die Zuordnung im Import: feste Spaltenbreiten.
   Ohne `table-layout: fixed` bestimmt die längste Beispielzeile die
   Breite der Tabelle, und die Auswahl „Wird zu" schrumpft auf ein paar
   Pixel – ausgerechnet das Feld, das man hier bedient. Die Beispiele
   sind ein Hinweis, kein Inhalt: Sie werden abgeschnitten, der volle
   Text steht im Titel. */
table.data.mapping-table { table-layout: fixed; }
table.data.mapping-table td.beispiele {
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Auf schmalen Geräten werden Tabellenzeilen zu Karten – nebeneinander
   passen acht Spalten dort nicht, und waagerechtes Scrollen liest sich
   schlecht. Die Überschriften stehen dann als data-label vor dem Wert. */
@media (max-width: 700px) {
    table.data thead { display: none; }
    table.data, table.data tbody, table.data tr, table.data td { display: block; width: 100%; }
    table.data tr { border-bottom: 1px solid var(--line); padding: 8px 4px; }
    table.data tr:last-child { border-bottom: 0; }
    table.data td { border: 0; padding: 3px 12px; }
    table.data td::before {
        content: attr(data-label) ": "; color: var(--muted); font-size: 11.5px;
    }
    table.data td:empty { display: none; }

    /* ---------- Die Kontaktliste hochkant ----------

       Aus acht Spalten wurden acht Zeilen „Beschriftung: Wert" – zehn
       je Kontakt, drei Kontakte auf einem iPhone. Zum Suchen einer
       Nummer ist das die falsche Form.

       Dieselbe Tabelle wird deshalb hier zur Karte, über ein Raster:
       Es ordnet die vorhandenen Zellen neu, statt daneben ein zweites
       Markup zu stellen. Zwei Abschriften derselben Zeile liefen beim
       nächsten Umbau auseinander, und die eine, die niemand ansieht,
       wäre die auf dem Telefon. */
    table.data.kontakt-tabelle tr {
        display: grid;
        grid-template-columns: auto minmax(0, 1fr) auto;
        grid-template-areas:
            "check firma    firma"
            ".     person   branche"
            ".     adresse  adresse"
            ".     telefon  telefon"
            ".     web      karte"
            ".     gruppen  gruppen";
        column-gap: 8px;
        align-items: start;
        padding: 10px 6px;
    }
    table.data.kontakt-tabelle td { width: auto; padding: 1px 0; }
    /* Die Beschriftungen fallen weg: In dieser Ordnung sagt der Platz,
       was ein Wert ist – „Firma:" vor dem Firmennamen ist eine Zeile
       für nichts. */
    table.data.kontakt-tabelle td::before { content: none; }
    table.data.kontakt-tabelle td.col-check { grid-area: check; padding-top: 2px; }
    table.data.kontakt-tabelle td[data-label="Firma"] { grid-area: firma; }
    table.data.kontakt-tabelle td[data-label="Ansprechpartner"] { grid-area: person; }
    table.data.kontakt-tabelle td[data-label="Branche"] {
        grid-area: branche; color: var(--muted); text-align: right; white-space: nowrap;
    }
    table.data.kontakt-tabelle td[data-label="Adresse"] { grid-area: adresse; color: var(--muted); }
    table.data.kontakt-tabelle td[data-label="Telefon"] { grid-area: telefon; padding-top: 4px; }
    table.data.kontakt-tabelle td[data-label="E-Mail / Web"] { grid-area: web; }
    table.data.kontakt-tabelle td.col-icon { grid-area: karte; }
    table.data.kontakt-tabelle td[data-label="Gruppen"] { grid-area: gruppen; padding-top: 4px; }
    /* Die Firma trägt die Zeile – sie ist der Name, unter dem man sucht. */
    table.data.kontakt-tabelle .row-title { font-size: 15px; }
    /* Zwei Adressen untereinander brauchen hier keine Breitenbremse
       mehr; die Karte ist so breit wie der Schirm. */
    table.data.kontakt-tabelle td.stacked a { max-width: none; }

    /* Kompakt: Name, Person und Nummer – mehr braucht niemand, der eine
       lange Liste nach dem richtigen Betrieb durchsieht. Die Anschrift
       fällt zuerst weg: Sie ist das, was man am wenigsten braucht,
       während man zum Hörer greift. */
    table.data.kontakt-tabelle.kompakt tr {
        grid-template-areas:
            "check firma   firma"
            ".     person  branche"
            ".     telefon telefon";
    }
    table.data.kontakt-tabelle.kompakt td[data-label="Adresse"],
    table.data.kontakt-tabelle.kompakt td[data-label="E-Mail / Web"],
    table.data.kontakt-tabelle.kompakt td[data-label="Gruppen"],
    table.data.kontakt-tabelle.kompakt td.col-icon { display: none; }

    /* ---------- Die Anrufliste hochkant ----------

       Dieselbe Idee wie bei der Kontaktliste: die Zeile als Karte über
       ein Raster, ohne Beschriftungen. Oben Richtung, Kontakt und Status,
       darunter die Nummer der Gegenseite und der Zeitpunkt. Die eigene
       Seite des Anrufs – die eigene Nummer, wer ihn annahm – steht in der
       aufgeklappten Zeile; die ganze Karte klappt auf, der Pfeil entfällt. */
    table.data.anruf-tabelle tr.call-row {
        display: grid;
        grid-template-columns: auto auto minmax(0, 1fr) auto;
        grid-template-areas:
            "check richtung kontakt status"
            ".     .        nummer  zeit";
        column-gap: 8px; row-gap: 3px;
        align-items: center;
        padding: 9px 6px;
    }
    table.data.anruf-tabelle tr.call-row td { width: auto; padding: 0; }
    table.data.anruf-tabelle tr.call-row td::before { content: none; }
    table.data.anruf-tabelle td.col-check { grid-area: check; }
    table.data.anruf-tabelle td.call-richtung { grid-area: richtung; }
    table.data.anruf-tabelle td[data-label="Kontakt"] { grid-area: kontakt; min-width: 0; }
    table.data.anruf-tabelle td[data-label="Status"] { grid-area: status; text-align: right; white-space: nowrap; }
    table.data.anruf-tabelle td[data-label="Zeitpunkt"] {
        grid-area: zeit; color: var(--muted); font-size: 12.5px; text-align: right; white-space: nowrap;
    }
    /* Die Nummer der Gegenseite: ausgehend „An", eingehend „Von". */
    table.data.anruf-tabelle tr.aus td[data-label="An"],
    table.data.anruf-tabelle tr.ein td[data-label="Von"] { grid-area: nummer; }
    table.data.anruf-tabelle tr.aus td[data-label="Von"],
    table.data.anruf-tabelle tr.ein td[data-label="An"],
    table.data.anruf-tabelle td.call-auf { display: none; }
    table.data.anruf-tabelle .row-title { font-size: 15px; }
    .nur-karten { display: inline-flex; }
    .nur-tabelle { display: none; }
    /* In der Karte gibt es keine Spaltenbreite, die zu halten wäre –
       und ein abgeschnittenes Beispiel hilft dort niemandem. */
    table.data.mapping-table td.beispiele { white-space: normal; overflow: visible; }
    table.data td.actions { text-align: left; padding-top: 8px; }
    table.data td.actions::before { content: ""; }
    /* Symbolspalten haben keine Überschrift, die vorangestellt werden
       könnte – und eine leere Symbolzelle nimmt in der Karte nur Platz. */
    table.data td.col-icon { text-align: left; }
    table.data td.col-icon::before { content: ""; }
    table.data td.col-icon.is-leer { display: none; }
    /* Die Post in der Akte am Telefon: „Korrespondenz" ist zu breit für
       die Zeile mit den drei Knöpfen – die Knöpfe sagen selbst, was hier
       steht. */
    .panel-card.mail-akte > .panel-head h3 { display: none; }
    .ki-vorschau { grid-template-columns: 1fr; }
    /* Im Ergebnisdialog untereinander, ohne Griff. Schwerer gewichtet:
       Die Regel für nebeneinander steht weiter unten und gewönne sonst. */
    .ki-vorschau-dialog .ki-vorschau, .ki-vorschau-dialog .ki-vorschau.einzeln { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    .ki-vorschau-dialog .ki-splitter { display: none; }
    .mail-spaltenwahl.mail-kimenue { width: calc(100vw - 16px); }
    /* „Termine heute" auf der Startseite bleibt eine Zeile je Termin:
       Zeit, Punkt, Titel – und ein Kopf, wenn ein Kontakt dranhängt.
       Ort und Kontaktchips fallen weg; sie stehen im Termin selbst. */
    table.kal-heute-tabelle tr { display: flex; align-items: center; gap: 6px; padding: 6px 4px; }
    table.kal-heute-tabelle td { display: block; width: auto; padding: 0; }
    table.kal-heute-tabelle td::before { content: none; }
    table.kal-heute-tabelle td.kal-heute-zeit { flex: 0 0 auto; }
    /* Der Titel wird mit „…" gekürzt statt umzubrechen – der Kopf dahinter
       bleibt stehen, darum kürzt der Titel und nicht die Zelle. */
    table.kal-heute-tabelle td[data-label="Termin"] { flex: 1; min-width: 0; display: flex; align-items: center; }
    table.kal-heute-tabelle td[data-label="Termin"] .kal-heute-titel {
        flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    table.kal-heute-tabelle td[data-label="Termin"] .kal-punkt { flex: none; }
    /* Mit der Tabelle davor, weil die Regel »versteckt« weiter unten steht
       und sonst gewänne. */
    table.kal-heute-tabelle .kal-heute-person { display: inline-block; flex: none; }
    table.kal-heute-tabelle td[data-label="Ort"],
    table.kal-heute-tabelle td[data-label="Kontakt"] { display: none; }
    /* Die Ungelesenen auf der Startseite: vier Textspalten passen in
       keine Zeile. Zweizeilig wie die Postfachliste – Absender und Postfach
       oben, Betreff und Datum darunter, rechts bündig, alles mit „…" statt
       Umbruch. */
    table.mail-heute-tabelle tr {
        display: grid; grid-template-columns: minmax(0, 1fr) auto;
        column-gap: 10px; row-gap: 2px; align-items: baseline; padding: 8px 4px;
    }
    table.mail-heute-tabelle td {
        display: block; width: auto; min-width: 0; padding: 0;
        overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    }
    table.mail-heute-tabelle td::before { content: none; }
    table.mail-heute-tabelle td[data-label="Absender"] { grid-column: 1; grid-row: 1; font-weight: 600; }
    table.mail-heute-tabelle td[data-label="Postfach"] { grid-column: 2; grid-row: 1; font-size: 11.5px; max-width: 42vw; text-align: right; }
    table.mail-heute-tabelle td[data-label="Betreff"] { grid-column: 1; grid-row: 2; }
    table.mail-heute-tabelle td[data-label="Datum"] { grid-column: 2; grid-row: 2; font-size: 11.5px; text-align: right; }
}

/* Blätterleiste: « ‹ Seitenzahlen › » – die Pfeile als Sinnbilder.
   Die Zahlen sind eine Reihe aus `seitenFenster()` (app.js); die Lücke
   darin ist ein „…". Gleich breite Knöpfe, damit die Reihe beim
   Blättern nicht wandert. Die Pfeilknöpfe haben dasselbe Maß wie die
   Zahlen: Ein `<svg>` ist `inline` und stünde sonst auf der Grundlinie,
   mit einem Rand darunter, der den Knopf höher macht als seine Nachbarn. */
.pager {
    display: flex; align-items: center; gap: 6px; justify-content: flex-end; flex-wrap: wrap;
    margin-top: 12px; font-size: 13px; color: var(--muted);
}
.pager button { padding: 5px 10px; font-size: 13px; }
.pager button.pfeil { min-width: 34px; padding: 5px 6px; display: inline-flex; align-items: center; justify-content: center; }
.pager button.pfeil svg { display: block; width: 1.2em; height: 1.2em; }
/* Die Seitengröße sitzt links in der Leiste, die Blätterknöpfe rechts:
   Sie sagt „wie viel", die anderen „welche". */
.pager .seitengroesse { position: relative; margin-right: auto; }
.pager .seitengroesse > button { display: inline-flex; align-items: center; gap: 5px; }
.pager .seitengroesse > button svg { display: block; width: 1.2em; height: 1.2em; }
/* Nach OBEN: Unter der Leiste ist nichts mehr, ein Menü nach unten hinge
   im Leeren und schöbe die Seite länger. */
.seitengroesse-menue {
    position: absolute; bottom: calc(100% + 6px); left: 0; z-index: 40;
    min-width: 120px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.seitengroesse-menue button {
    display: block; width: 100%; text-align: left; border: 0; padding: 6px 10px;
    font-variant-numeric: tabular-nums;
}
.seitengroesse-menue button.active { background: var(--accent-fill); color: #fff; }
.pager .seite { display: inline-flex; }
.pager .seite button { min-width: 34px; padding: 5px 6px; font-variant-numeric: tabular-nums; }
.pager .seite button.active {
    background: var(--accent-fill); border-color: var(--accent-fill); color: #fff; cursor: default;
}
.pager .dots { min-width: 20px; text-align: center; user-select: none; }

/* ---------- Kontakt-Detailansicht ---------- */

.detail-head {
    display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap; margin-bottom: 16px;
}
.detail-head h1 { font-size: 22px; }
.detail-head .sub { font-size: 13px; color: var(--muted); margin-top: 2px; }

.field-grid {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 12px 20px;
}
.field { min-width: 0; }
.field .label {
    font-size: 11px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
}
.field .value { font-size: 14px; word-break: break-word; }
/* Was in der Überschrift NACH dem Feldnamen steht – die Bezeichnung eines
   Fundes, „E-Mail · Geschäftlich". Der Feldname ist versal, sie nicht:
   Sie ist ein Eigenname und keine Rubrik. */
.field .label .zusatz { text-transform: none; letter-spacing: 0; }
/* Die Bezeichnung eines gefundenen Werts – „Geschäftsführer" hinter dem
   Namen. Steht daneben, nicht darunter: eine Zeile je Feld. */
.field .value .row-sub { font-size: 12px; color: var(--muted); margin-left: 6px; }
/* Brief, Erdkugel und Hörer wie in der Kontaktliste: Sie ordnen ein,
   was in der Zeile steht, ohne dass eine Beschriftung es sagen muss.
   Gedämpft, nicht bunt – der Verweis selbst trägt die Farbe. */
.field .value a { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; }
.field .value a > span { min-width: 0; overflow-wrap: anywhere; }
.field .value a > svg { flex: none; color: var(--muted); }
.field .value a:hover > svg { color: inherit; }
.field .value.empty-value { color: var(--muted); padding: 0; text-align: left; }

.phone-list { list-style: none; margin: 0; padding: 0; }
.phone-item {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 8px 0; border-bottom: 1px solid var(--line);
}
.phone-item:last-child { border-bottom: 0; }
.phone-label { font-size: 12px; color: var(--muted); min-width: 100px; }
.phone-number { font-size: 15px; font-variant-numeric: tabular-nums; }

/* Reiter in der Detailansicht */
/* Sieben Reiter passen auf dem Telefon hochkant nicht nebeneinander.
   Umbrechen dürfen sie nicht – zwei Reihen Reiter sind keine Reiter mehr –
   also schieben sie sich seitlich, und der Rand bleibt der Rand.
   `flex: none` an den Reitern selbst: Ohne das quetschte flex sie in die
   vorhandene Breite, und es gäbe nichts zu schieben. */
.tabs {
    display: flex; gap: 2px; border-bottom: 1px solid var(--line); margin-bottom: 14px;
    overflow-x: auto; overflow-y: hidden; scrollbar-width: thin;
}
.tab { flex: none; white-space: nowrap; display: inline-flex; align-items: center; gap: 6px; }
.tab > svg { flex: none; }
/* Ohne Wort wird der Rand knapp – sonst behielte der Reiter die Breite
   seiner Beschriftung. Die Zahl bleibt: Sie ist der Grund, warum man
   hersieht, und ein Reiter ohne sie sagt nur, dass es die Rubrik gibt.
   So knapp, dass die sechs auf ein Telefon hochkant passen und gar nicht
   erst geschoben werden müssen – gemessen sind es 340 von 351 Pixeln. */
@media (max-width: 560px) {
    .tabs { gap: 0; }
    .tabs .tab { padding: 8px 9px; gap: 5px; }
}
.tab {
    background: transparent; border: 0; border-bottom: 2px solid transparent;
    color: var(--muted); padding: 8px 14px; cursor: pointer; font-size: 14px; border-radius: 0;
}
.tab:hover { color: var(--text); background: var(--panel-2); }
.tab.active { color: var(--accent); border-bottom-color: var(--accent); background: transparent; }
.tab .count { font-size: 11px; color: var(--muted); margin-left: 4px; }

/* Notizen und Aufgaben */
.entry {
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    padding: 12px 14px; margin-bottom: 10px;
}
.entry-head {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    font-size: 12px; color: var(--muted); margin-bottom: 6px;
}
.entry-body { white-space: pre-wrap; word-break: break-word; font-size: 14px; }
.entry-actions { display: flex; gap: 6px; margin-left: auto; }
.entry.done .entry-title { text-decoration: line-through; color: var(--muted); }
.entry-title { font-size: 15px; font-weight: 600; }
.entry-check { display: flex; align-items: center; gap: 10px; }

/* ---------- Kennzeichnungen ---------- */

.badge {
    display: inline-block; font-size: 11px; padding: 2px 8px; border-radius: 20px;
    letter-spacing: .3px; background: var(--panel-2); border: 1px solid var(--line); color: var(--muted);
}
.badge.admin { background: #2a4a8a; border-color: #3a63e0; color: #dbe4ff; }
/* Gruppen ohne Kennfarbe bleiben grau; mit Farbe setzt groupBadgeStyle()
   Hintergrund (halbtransparent), Rand und Schriftfarbe als Inline-Style. */
.badge.group { background: var(--panel-2); margin: 1px 4px 1px 0; }
/* Der Zähler für abgekürzte Gruppen („+2“) in der Kontaktliste. */
.badge.group.more { cursor: help; }
.badge.todo { background: #2a4a8a; border-color: #3a63e0; color: #dbe4ff; }
.badge.note { background: #3a3060; border-color: #5a3a8a; color: #e3daff; }
.badge.done { background: #143d2a; border-color: #1f6b46; color: #b7f0d4; }
.badge.open { background: var(--panel-2); }
/* Gesperrt: dieselbe Farbe wie der Kontaktwiderspruch – beides heißt
   „hier geht nichts mehr". */
.badge.blocked { background: #4a1f24; border-color: #8a3a44; color: #ffd7dc; }

/* Farbpunkt vor Gruppennamen in Auswahllisten (Kontaktformular,
   CSV-Import, Benutzerformular). */
.group-dot {
    display: inline-block; width: 10px; height: 10px; border-radius: 50%;
    flex: none; margin-right: 2px;
}
/* Die Gruppen-Spalte darf in die Breite gehen, die Badges brechen um. */
.groups-cell { min-width: 140px; }

/* Farbwahl im Gruppenformular: Systempicker, Häkchen, Vorschau. */
.color-row { display: flex; align-items: center; gap: 12px; }
.color-input {
    width: 44px; height: 30px; padding: 0; border: 1px solid var(--line);
    border-radius: 6px; background: var(--panel-2); cursor: pointer;
}
.color-input:disabled { opacity: .35; cursor: default; }
/* Die Probe neben dem Farbwähler: weiße Schrift auf der Fläche – genau die
   Paarung, die überall sonst fest verdrahtet ist (15 Stellen). Deshalb wird
   eine zu helle Wunschfarbe abgedunkelt, und deshalb zeigt die Probe das
   Ergebnis und nicht die Eingabe. */
.akzent-probe {
    padding: 4px 10px; border-radius: 6px; font-size: 12px; font-weight: 600;
}
/* Die Farbtabelle in den Einstellungen: Wähler und Probe auf einer Höhe
   mit der Beschriftung; die Spalten so schmal wie ihr Inhalt, damit die
   Beschriftung die Breite bekommt. */
.farben-tabelle td { vertical-align: middle; }
.farben-tabelle .color-row { gap: 8px; }
.farben-tabelle th:nth-child(2), .farben-tabelle td:nth-child(2),
.farben-tabelle th:nth-child(3), .farben-tabelle td:nth-child(3) { width: 1%; white-space: nowrap; }

/* Rechte im Benutzerformular: nach Bereichen gegliedert, damit man beim
   Durchsehen weiß, worüber man gerade entscheidet. */
.perm-templates { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin-bottom: 10px; }
.perm-group { margin-bottom: 12px; }
.perm-group-head {
    font-size: 11.5px; font-weight: 700; letter-spacing: .4px;
    color: var(--muted); text-transform: uppercase; margin-bottom: 4px;
}
.perm-row {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    padding: 4px 0; border-top: 1px solid var(--line);
}
.perm-row:first-of-type { border-top: 0; }
.perm-row .check-item { flex: 1; min-width: 0; flex-wrap: nowrap; align-items: flex-start; }
/* Der Text neben der Checkbox schrumpft und bricht in sich um – nie als
   Ganzes unter die Checkbox: [x] Bezeichnung, darunter eingerückt der
   Hinweis. */
.perm-row .check-item > span { flex: 1 1 0; min-width: 0; }
.perm-hint { display: block; font-size: 11.5px; color: var(--muted); }
/* Die Unterreiter der Rechtegruppen samt Häkchen-Zahl. Auf dem
   Desktop eine Zeile – umbrechende Reiter sehen aus wie zwei Leisten.
   Wird es doch enger als gedacht, rollt die Leiste waagerecht, statt
   zu brechen; erst auf schmalen Geräten darf sie umbrechen. */
.perm-seg { margin: 0 0 10px; flex-wrap: nowrap; max-width: 100%; overflow-x: auto; }
.perm-seg button { white-space: nowrap; flex: none; }
@media (max-width: 640px) {
    .perm-seg { flex-wrap: wrap; overflow-x: visible; }
}
.perm-seg button { display: inline-flex; align-items: center; gap: 5px; padding: 5px 9px; font-size: 12.5px; }
.perm-seg .perm-seg-count {
    background: var(--panel-2); color: var(--text); border-radius: 10px;
    padding: 0 6px; font-size: 11px; line-height: 16px;
}
.perm-seg button.active .perm-seg-count { background: rgba(255,255,255,.25); color: #fff; }
/* Die Zahl steht unter ihrem Recht, nicht daneben: Neben der
   Bezeichnung blieb für Platzhalter und Einheit kein Platz mehr, und
   beides wurde abgeschnitten. Eingerückt bis unter den Text, damit
   erkennbar bleibt, wozu sie gehört. */
.perm-value {
    display: flex; align-items: center; gap: 8px;
    /* 100 % **minus** der Einrückung: Sonst ist die Zeile breiter als der
       Kasten, und der Dialog bekommt eine waagerechte Bildlaufleiste. */
    flex: 0 0 calc(100% - 28px); margin: 2px 0 4px 28px; white-space: nowrap;
}
.perm-value input { width: 132px; }

/* Die Sperre im Benutzerformular steht abgesetzt: Sie ist keine
   Eigenschaft wie Name oder Rufnummer, sondern ein Eingriff. */
.block-box {
    margin-top: 16px; padding: 12px 14px; border: 1px solid var(--line);
    border-radius: 8px; background: var(--panel-2);
}

/* Fälligkeiten: rot überfällig, gelb heute, sonst unauffällig */
.due { font-variant-numeric: tabular-nums; white-space: nowrap; }
.due.overdue { color: var(--danger); font-weight: 600; }
.due.today { color: var(--warn); font-weight: 600; }

.chip-list { display: flex; flex-wrap: wrap; gap: 6px; }

/* Mehrfachauswahl (Gruppen, Zuweisungen) */
.check-list {
    max-height: 220px; overflow-y: auto;
    border: 1px solid var(--line); border-radius: 8px; padding: 4px 0;
}
.check-item {
    display: flex; align-items: center; gap: 8px; padding: 5px 10px;
    margin: 0; font-size: 13.5px; color: var(--text); cursor: pointer;
}
.check-item:hover { background: var(--panel-2); }
.check-item input { flex: none; }
.check-item .sub { color: var(--muted); font-size: 12px; }

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

/* `minmax(0, 1fr)` und nicht `1fr`: Ein `1fr`-Gleis ist `minmax(auto,
   1fr)`, und `auto` heisst „mindestens so breit wie der Inhalt". Ein
   Datumsfeld darin macht die Spalte so breit, wie es selbst gern wäre,
   und das Raster sprengt den Dialog. Dieselbe Falle wie beim
   Monatsraster des Kalenders. */
.form-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 14px; }
.form-grid .full { grid-column: 1 / -1; }
@media (max-width: 640px) { .form-grid { grid-template-columns: minmax(0, 1fr); } }

/* Telefonnummern im Formular: Bezeichnung, Nummer, Entfernen */
.phone-row { display: flex; gap: 8px; margin-bottom: 8px; align-items: center; }
.phone-row .label-input { flex: 0 0 34%; }
.phone-row .number-input { flex: 1; }
.phone-row input { margin: 0; font-size: 15px; padding: 8px 10px; }

/* ---------- Modale Dialoge ---------- */

.modal {
    position: fixed; inset: 0; background: rgba(0,0,0,.55);
    display: grid; place-items: center; padding: 20px; z-index: 50;
}
/* Der Rahmen in der Signalfarbe, dünn wie der einer gesetzten Auswahl
   (`.toolbar select.eng`): Auf dem abgedunkelten Grund verschwamm die
   dunkle Fläche eines Dialogs sonst mit ihrer Umgebung. Die Farbe der
   SEITE (`--seite-accent`), nicht `--accent` – ein heller Dialog
   (`thema-hell`) trüge sonst ein anderes Blau als die übrigen. Ein
   Dialog für Unwiderrufliches bleibt rot (`.danger-box`). */
.modal-box {
    background: var(--panel); border: 1px solid var(--seite-accent); border-radius: var(--radius);
    padding: 22px; width: min(460px, 92vw);
    /* `dvh` neben `vh` wie bei `.app`: Auf einem Telefon zaehlt `vh` die
       Leiste des Browsers mit, die beim Scrollen verschwindet – ein
       Dialog mit 90vh ragt dort unten heraus. `dvh` misst, was gerade
       wirklich da ist; ältere Browser nehmen die Zeile darüber. */
    max-height: 90vh;
    max-height: 90dvh;
    display: flex; flex-direction: column;
}
.modal-box.large { width: min(820px, 94vw); }
.modal-box.mittel { width: min(660px, 94vw); }
/* Zwischenbreite für den Benutzer-/Einstellungsdialog: 460px sind zu
   schmal für die fünf Rechte-Unterreiter in einer Zeile, 820px zu leer
   für ein Benutzerformular. */
.modal-box.medium { width: min(620px, 94vw); }
/* Die Auftragsmaske: Eine Position ist eine Zeile aus vier Feldern, und
   die braucht Breite – sonst steht jedes Feld untereinander und drei
   Positionen füllen zwei Bildschirme. */
.modal-box.wide { width: min(1020px, 96vw); }
.modal-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; flex: none; }
.modal-head h2 { font-size: 17px; }
.modal-body { overflow-y: auto; flex: 1 1 auto; min-height: 0; padding-right: 2px; }
/* Umbruch, nicht Überlauf: Die Warteschlange trägt drei breite Knöpfe und
   „Schließen"; schmal stand das Schließen außerhalb des Bildes. Ein Dialog,
   aus dem man nicht mehr herausfindet, ist schlimmer als einer mit zwei
   Knopfzeilen. */
.modal-actions { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 16px; flex: none; }
.modal-actions .spacer { flex: 1; }

/* Dialog für einen Vorgang, der sich nicht zurücknehmen lässt. Die rote
   Umrandung ist die Ansage, bevor der Text gelesen wird. */
.modal-box.danger-box { border-color: var(--danger); box-shadow: 0 0 0 1px var(--danger) inset; }
.danger-title { color: var(--danger); }

/* Das Abtippfeld. Es sitzt abgesetzt unter dem Text, damit es als eigene
   Handlung gelesen wird und nicht als Teil der Erklärung. Das verlangte
   Wort steht als Code – so ist zu sehen, dass es wörtlich gemeint ist. */
/* Die Aufzählung im Bestätigungsdialog: was genau verschwindet. Ruhig
   gesetzt – sie ist eine Angabe, keine zweite Warnung; das Rot trägt
   schon der Rahmen. */
.confirm-list {
    margin: 10px 0 0; padding-left: 18px; color: var(--muted);
    line-height: 1.55;
}
.confirm-list li { margin: 2px 0; }

.confirm-word {
    margin: 16px 0 0; padding-top: 14px; border-top: 1px solid var(--line);
    color: var(--text);
}
.confirm-word code {
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 4px;
    padding: 1px 6px; color: var(--danger); font-weight: 600; letter-spacing: .04em;
}
.confirm-word input { text-transform: uppercase; letter-spacing: .04em; }

/* Die Wahl beim Klick auf eine Adresse. `position: fixed`, weil sie am
   Zeiger hängt und nicht an einem Element: Adressen stehen in Zeilen,
   Karten und Dialogen, und ein Anker an jedem davon bräuchte eine eigene
   Regel. Der Stil kommt als OBJEKT aus `mailWahlStil` – eine
   Zeichenkette nähme `x-show` das `display: none`. */
.mail-wahl {
    position: fixed; z-index: 90; width: 240px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.mail-wahl .label-like {
    padding: 4px 10px 6px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    text-transform: none; letter-spacing: 0;
}
.mail-wahl button {
    display: flex; align-items: center; gap: 8px; width: 100%;
    justify-content: flex-start; text-align: left; border: 0; padding: 8px 10px;
}
.mail-wahl button svg { flex: none; color: var(--muted); }
.mail-wahl button:hover svg { color: inherit; }

/* ---------- Hinweise ---------- */

.toast {
    position: fixed; bottom: 20px; left: 50%; transform: translateX(-50%);
    background: var(--panel-2); border: 1px solid var(--line);
    padding: 10px 16px; border-radius: 8px; z-index: 60; max-width: 90vw;
    box-shadow: 0 6px 20px rgba(0,0,0,.45);
}
.toast.error { border-color: var(--danger); }

.notice {
    display: flex; align-items: flex-start; gap: 8px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 10px 12px; margin-bottom: 14px; font-size: 13px; line-height: 1.5;
}
.notice.warn-notice { border-color: var(--warn); }
.notice.error-notice { border-color: var(--danger); }

/* ---------- Import ---------- */

.import-steps { display: flex; gap: 8px; margin-bottom: 16px; font-size: 12.5px; color: var(--muted); }
.import-step { display: flex; align-items: center; gap: 6px; }
.import-step .num {
    width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center;
    background: var(--panel-2); border: 1px solid var(--line); font-size: 11px; font-weight: 700;
}
.import-step.active { color: var(--text); }
.import-step.active .num { background: var(--accent-fill); border-color: var(--accent-fill); color: #fff; }
.preview-wrap { overflow: auto; }
.preview-wrap table.data thead th { top: 0; }

/* Der Import füllt den Inhaltsbereich – in der Höhe wie in der Breite.
   `48vh` und `46vh` waren Anteile des BILDSCHIRMS: Kopfleiste,
   Schrittanzeige und Knopfzeile zählten sie nicht mit, und auf einem
   hohen Fenster stand die Hälfte des Platzes leer, während die Tabelle
   scrollte. Jetzt bekommt die Tabelle, was übrig bleibt.

   `min-height: 0` an jeder Stufe: Ein Flex-Kind ist von Haus aus so
   hoch wie sein Inhalt und schrumpft nicht – ohne diese Zeile wächst
   die Tabelle nach unten aus dem Bild, statt zu scrollen. */
/* `height`, nicht `min-height`: Nur eine feste Höhe zwingt die Tabelle
   zum Scrollen. Bei `min-height` wächst der Rahmen mit seinem Inhalt,
   und `flex: 1` verteilt dann Platz, den es gar nicht gibt – gemessen:
   Karte 2136 px in einem 942 px hohen Inhaltsbereich.

   Nur auf dem Schreibtisch. Auf dem Telefon ist eine Tabelle in einem
   Rahmen mit eigenem Scrollbalken die schlechtere Antwort als eine
   Seite, die man am Stück durchzieht. */
@media (min-width: 701px) {
    /* `height: 100%` half nicht: Der Inhaltsbereich ist ein Block, seine
       Höhe für eine Prozentangabe also nicht bestimmt – gemessen kam 0
       heraus. Er muss selbst zum Flex-Behälter werden, und das nur für
       die Ansichten, die es brauchen (`content-fuellt`). */
    .content.content-fuellt { display: flex; flex-direction: column; }
    /* `1 0 auto`, nicht `1`: Wächst, wo Platz ist – schrumpft aber nie
       unter das, was hineingehört. Sonst quetscht ein kurzes Fenster die
       Karte auf 218 Pixel zusammen, und Überschrift, Haken und Knöpfe
       stehen unten heraus. So scrollt in diesem Fall die Seite, und die
       Knöpfe bleiben erreichbar. */
    .import-view { display: flex; flex-direction: column; flex: 1 0 auto; }
    .import-schritt { display: flex; flex-direction: column; flex: 1; min-height: 0; }
    /* Nicht `> .table-wrap`: In Schritt 3 steht sie neben einer Karte und
       einem Kopf – die nehmen ihre eigene Höhe, die Tabelle den Rest. */
    /* Grundmaß 0, nicht `auto`: Sonst zählt die volle Tabellenhöhe als
       „das, was hineingehört", und die Karte oben wüchse auf 2000 Pixel.
       Was die Tabelle mindestens braucht, sagt `min-height`. */
    .import-schritt .table-wrap { flex: 1 1 0; min-height: 160px; overflow: auto; }
}

/* ---------- Recherche ---------- */

/* Eine Zeile auf dem Desktop, gestapelt auf dem Handy. Die Branche bekommt
   den meisten Platz – dort steht der längste Text. */
.search-bar {
    display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
}
.search-bar label { margin: 0; flex: 1 1 140px; min-width: 0; }
.search-bar label:nth-child(2) { flex: 2 1 200px; }
.search-bar button {
    flex: 0 0 auto;
    /* Der Knopf steht in einer Reihe mit den Feldern und soll so hoch sein
       wie sie: Schriftgröße 16 + 2×9 Polster + 2×1 Rahmen = 44 Pixel. Ohne
       das ist er sieben Pixel niedriger, was in genau dieser Zeile auffällt
       – anderswo steht er allein und bleibt bei seiner eigenen Größe. */
    min-height: 44px;
    padding: 8px 18px;
}

@media (max-width: 700px) {
    .search-bar { flex-direction: column; align-items: stretch; }
    /* Das zweite Feld ausdrücklich mit: `label:nth-child(2)` wiegt schwerer
       als `label` und behielt sonst `flex: 2 1 200px` – in der Spalte ist das
       eine HÖHE, und unter „Branche" klaffte bis „Ort" eine Lücke von
       zweihundert Pixeln (gesehen auf dem iPhone hochkant). */
    .search-bar label, .search-bar label:nth-child(2), .search-bar button { flex: 1 1 auto; width: 100%; }
}

/* Die Auftragszeile unter der Suchleiste. */
.job-bar {
    display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
    margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line);
}
.job-bar label { margin: 0; }
.job-bar .job-pick { flex: 0 1 260px; min-width: 160px; }
.job-bar button { flex: 0 0 auto; }
.job-bar > .muted { align-self: center; }

/* Der laufende Auftrag – eine Zeile über dem Fortschrittsbalken. */
.job-progress {
    background: var(--panel-2); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 12px 14px; margin-bottom: 12px;
}

/* Eine Position in der Auftragsmaske: eine Zeile, die auf schmalen
   Fenstern umbricht. */
.job-item {
    display: flex; align-items: flex-end; gap: 10px; flex-wrap: wrap;
    padding: 10px; margin-bottom: 8px;
    background: var(--panel); border: 1px solid var(--line); border-radius: 8px;
}
.job-item.inaktiv { opacity: .55; }
.job-item label { margin: 0; }
.job-item .combo { flex: 1 1 200px; min-width: 160px; }
.job-item-no { color: var(--muted); font-size: 13px; padding-bottom: 10px; min-width: 20px; }
.job-item-hint { display: block; margin-top: 3px; }
.job-item-tools { display: flex; gap: 4px; margin-left: auto; }
tr.inaktiv td { opacity: .55; }

/* Die Zeile unter der Suchleiste: Kostenhinweis links, Schalter rechts. */
.search-note { display: flex; align-items: center; gap: 12px; margin-top: 8px; flex-wrap: wrap; }

/* Woraus die Trefferliste besteht – erst ab dem zweiten Lauf sichtbar. */
.collection-age {
    display: flex; flex-wrap: wrap; gap: 6px 14px;
    margin: -4px 0 10px; font-size: 12px; color: var(--muted);
}
/* Älter als die Wiederholungssperre: Treffer, die man nicht mehr für
   frisch halten sollte. */
.collection-age .alt { color: var(--warn); }

/* Eigene Vorschlagsliste. Ein <datalist> zeigt so viele Zeilen, wie der
   Browser für richtig hält – in Chrome sechs, ohne jede Möglichkeit,
   das zu ändern. Bei 208 Branchen ist das zu wenig, also steht hier
   eine eigene Liste: vierzehn Zeilen sichtbar, der Rest rollt. */
.combo { position: relative; }
.combo-liste {
    position: absolute; top: 100%; left: 0; z-index: 40;
    margin-top: 4px;
    /* Mindestens so breit wie das Feld, sonst so breit wie ihr Inhalt:
       Das Ortfeld ist schmal, „2 Suchen" stand darin abgeschnitten als
       „2 S…". Eine Liste darf über ihr Feld hinausragen – abgeschnittene
       Wörter sind schlimmer als eine breite Liste. */
    min-width: 100%;
    width: max-content;
    max-width: min(460px, 90vw);
    max-height: 462px;              /* 14 Zeilen à 33 Pixel */
    overflow-y: auto;
    background: var(--panel-2);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 12px 28px rgba(0, 0, 0, .45);
}
.combo-zeile {
    display: flex; align-items: baseline; gap: 8px;
    padding: 5px 11px; cursor: pointer;
    font-size: 14px; line-height: 21px;
    white-space: nowrap;
}
/* Tastatur und Maus zeigen dieselbe Zeile an – zwei verschiedene
   Hervorhebungen gleichzeitig verwirren mehr, als sie helfen. */
.combo-zeile.aktiv { background: var(--accent); color: #fff; }
/* Der Wert gibt nach, nicht der Hinweis: Wohin ein Synonym führt, ist
   die halbe Auskunft der Zeile. */
.combo-zeile > span:first-child { overflow: hidden; text-overflow: ellipsis; }
.combo-hinweis {
    flex: 0 0 auto;
    margin-left: auto; padding-left: 12px;
    font-size: 12px; color: var(--muted);
}
.combo-zeile.aktiv .combo-hinweis { color: rgba(255, 255, 255, .75); }

/* Geteilte Ansicht: Liste links, Karte rechts. Die Karte bleibt beim
   Blättern durch die Liste stehen. */
.research-split {
    display: grid; grid-template-columns: minmax(0, 1fr) minmax(320px, 420px);
    gap: 16px; align-items: start;
}
.research-split.map-hidden { grid-template-columns: minmax(0, 1fr); }
.research-list { margin-bottom: 0; }
.research-map-card { margin-bottom: 0; position: sticky; top: 0; }

.map-canvas {
    height: 460px; border-radius: 8px; overflow: hidden;
    background: var(--panel-2); border: 1px solid var(--line);
}

/* Leaflet bringt eine helle Grundfarbe mit – die passt nicht zum Theme. */
.map-canvas .leaflet-container { background: var(--panel-2); font: inherit; }
.map-canvas .leaflet-control-attribution {
    background: rgba(15, 20, 32, .78); color: var(--muted); font-size: 10.5px;
}
.map-canvas .leaflet-control-attribution a { color: var(--muted); }
.map-canvas .leaflet-bar a {
    background: var(--panel); color: var(--text); border-bottom-color: var(--line);
}
.map-canvas .leaflet-bar a:hover { background: var(--panel-2); }
.map-canvas .leaflet-tooltip {
    background: var(--panel); color: var(--text);
    border: 1px solid var(--line); box-shadow: none;
}
.map-canvas .leaflet-tooltip-top::before { border-top-color: var(--line); }

.map-legend { display: flex; align-items: center; gap: 6px; font-size: 11.5px; color: var(--muted); }
.map-legend .dot { width: 9px; height: 9px; border-radius: 50%; display: inline-block; margin-left: 6px; }
.map-legend .dot:first-child { margin-left: 0; }
.dot-new     { background: var(--accent); }
.dot-contact { background: var(--ok); }
.dot-maybe   { background: var(--warn); }
.dot-pool    { background: var(--muted); }

/* Zeile, auf die gerade gezeigt wird oder deren Marker angeklickt wurde. */
table.data tr.row-hot td { background: var(--panel-2); }

@media (max-width: 900px) {
    /* Karte über die Liste, nicht daneben – nebeneinander bliebe für beide
       zu wenig Platz. */
    .research-split { grid-template-columns: minmax(0, 1fr); }
    .research-map-card { position: static; order: -1; }
    .map-canvas { height: 300px; }
}

/* Auswahlleiste über Treffer- und Poolliste */
.select-bar {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    padding: 8px 10px; margin-bottom: 12px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
}
/* Die Sinnbilder der Leiste stehen auf einer Höhe, auch wenn sie
   verschieden viel Rand haben – `icon-btn` bringt seinen eigenen mit. */
.select-bar > button, .auswahl-menue-halter > button { align-self: center; }

/* Der Schalter kompakt/ausführlich zeigt die Form, die GERADE GILT –
   eingerastet wie ein Schalter, und `aria-pressed` sagt dasselbe noch
   einmal für den Vorleser. Wohin ein Druck führt, steht im Titel.

   Zwei Bilder im Knopf, eines davon versteckt – wie Sonne und Mond beim
   Thema: über die CSS und nicht über `x-show`, damit im Knopf nichts
   springt, während Alpine hochfährt. */
.ansicht-schalter .ist-kompakt-bild { display: none; }
.ansicht-schalter.ist-kompakt .ist-ausfuehrlich-bild { display: none; }
.ansicht-schalter.ist-kompakt .ist-kompakt-bild { display: block; }
/* Dasselbe für Zeilen/Spalten: das Bild zeigt, was gerade gilt. */
.ansicht-schalter .ist-spalten-bild { display: none; }
.ansicht-schalter.ist-spalten .ist-zeilen-bild { display: none; }
.ansicht-schalter.ist-spalten .ist-spalten-bild { display: block; }

/* Das Menü hinter den drei Punkten. Wie das Suchfeld-Menü über der
   Liste: über die Stellung im Fluss, nicht über eine gerechnete
   Position – ein Menü, dessen Platz das Programm ausrechnet, steht beim
   Drehen des Geräts falsch. */
.auswahl-menue-halter { position: relative; display: inline-flex; }
.auswahl-menue {
    position: absolute; top: calc(100% + 6px); right: 0; z-index: 40;
    min-width: 220px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: 8px;
    padding: 6px; box-shadow: 0 8px 24px rgba(0,0,0,.35);
}
.auswahl-menue button {
    display: flex; align-items: center; gap: 8px; width: 100%;
    justify-content: flex-start; text-align: left; border: 0; padding: 8px 10px;
}
.auswahl-menue button svg { flex: 0 0 auto; color: var(--muted); }
.auswahl-menue button:hover svg { color: inherit; }
/* Angaben aus den Metadaten. Der Farbton sagt: gefunden, nicht gepflegt.
   In der Spalte Ansprechpartner steht er nur beim Rückfall – dieselbe
   Spalte zeigt dann Handarbeit kühlweiß und Maschinenarbeit grünlich. */
.from-meta { color: var(--meta); }
.from-meta a { color: var(--meta-link); }
.from-meta .row-sub { color: var(--muted); }

/* Zwei Angaben in einer Zelle, untereinander statt nebeneinander.
   Bewusst nur an den Verweisen: Ein `display` an der Zelle selbst hätte
   höhere Spezifität als die Kartenregel weiter unten und würde sie auf
   schmalen Fenstern aushebeln – dann stünde genau diese eine Zelle quer,
   während alle anderen umbrechen. */
/* Zeichen und Text auf einer Zeile, der Text darf kürzen. `flex` und
   nicht `block`: Mit dem Bild darin griffe `text-overflow` sonst am
   ganzen Verweis statt am Text – und schnitte das Bild mit ab. */
table.data td.stacked a {
    display: flex; align-items: center; gap: 6px;
    max-width: 26ch;
}
table.data td.stacked a > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Gedämpft, nicht bunt: Sie sollen einordnen, nicht rufen. Der Verweis
   selbst trägt die Farbe. */
table.data td.stacked a > svg { flex: none; color: var(--muted); }
table.data td.stacked a:hover > svg { color: inherit; }

/* ---------- Eine Spalte je Feld (PLANUNG-SPALTEN.md) ----------

   `table-layout: fixed`: Ohne das entscheidet der Inhalt über die
   Breite, und eine gezogene Breite wäre nur ein Vorschlag. Die Breite
   der Tabelle setzt die Anwendung als Summe ihrer Spalten – sonst
   verteilte `fixed` den Rest auf die letzte Spalte, statt die Tabelle
   enden zu lassen, wo die Spalten enden. Was nicht hineinpasst, schiebt
   `.table-wrap` zur Seite. */
table.data.feld-tabelle { table-layout: fixed; }
/* Eine Zeile je Kontakt, immer gleich hoch: In der Zelle steht der
   maßgebliche Wert, der Rest steht in der Akte. Zu langes wird gekürzt,
   der volle Wert hängt im `title` der Zelle. */
table.data.feld-tabelle td {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
table.data.feld-tabelle td a { color: var(--meta-link); }

/* Der Kopf ist zweierlei: Griff zum Umordnen und Schalter zum Sortieren.
   `relative`, weil der Ziehstreifen an seinem rechten Rand hängt. */
table.data.feld-tabelle th.spalten-kopf {
    position: relative; overflow: hidden; white-space: nowrap;
    padding-right: 14px;
}
.spalten-kopf .spalten-name { overflow: hidden; text-overflow: ellipsis; }
/* Die gezogene Spalte tritt zurück, die Zielspalte bekommt einen Strich
   an der Kante, an der sie landet. Ohne den zieht man ins Ungewisse. */
.spalten-kopf.wird-gezogen { opacity: .45; }
.spalten-kopf.zug-ziel { box-shadow: inset 2px 0 0 var(--accent); }

/* Der Streifen am rechten Rand. Schmal, aber nicht unsichtbar: Der
   Zeiger sagt, was er kann, und beim Überfahren zeigt sich die Kante. */
.spalten-griff {
    position: absolute; top: 0; right: 0; bottom: 0; width: 9px;
    cursor: col-resize; user-select: none;
}
.spalten-griff:hover { background: var(--accent); opacity: .5; }

/* Der Knopf der Spaltenwahl steht neben dem Umschalter und sieht aus wie
   er – nicht wie das Feldmenü der Suchleiste, das sich an einem
   Eingabefeld misst. */
.such-felder.spalten-wahl { display: inline-flex; align-self: center; }

/* Spalte, in der nur ein Symbol steht – so schmal wie möglich.
   `vertical-align: middle` gegen die Vorgabe `top` der übrigen Zellen:
   Zeilen können zweizeilig werden (E-Mail über Web-Adresse, Name über
   Bezeichnung), und ein einzelnes Symbol am oberen Rand sähe verrutscht
   aus. Text bleibt oben ausgerichtet, ein Symbol gehört in die Mitte. */
table.data th.col-icon, table.data td.col-icon {
    width: 28px; text-align: center; padding: 0 4px; vertical-align: middle;
    /* Ohne das bliebe der Zeilenabstand der Zelle unter dem Symbol stehen
       und schöbe es um zwei, drei Pixel nach oben. Es steht ohnehin kein
       Text darin. */
    line-height: 0;
}
.map-link { display: inline-flex; color: var(--muted); }
.map-link:hover { color: var(--meta-link); }
.map-link svg { display: block; }

table.data th.col-check, table.data td.col-check { width: 32px; text-align: center; padding-right: 0; }
table.data td.col-check input { margin: 0; }

@media (max-width: 700px) {
    /* In der Kartenansicht schmaler Fenster hat die Spaltenbezeichnung
       vor dem Kästchen keinen Sinn. */
    table.data td.col-check { text-align: left; }
    table.data td.col-check::before { content: ""; }
}

/* Bilanz über der Trefferliste: wie viel davon ist wirklich neu? */
.match-summary {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    margin-bottom: 12px; font-size: 13px;
}
.inline-check {
    display: flex; align-items: center; gap: 6px; margin: 0;
    font-size: 12.5px; white-space: nowrap;
}
.inline-check input { margin: 0; }
/* Mehrzeilige Variante für den Auftragsdialog: Name und Beschreibung
   dürfen umbrechen. */
.inline-check.block {
    display: flex; align-items: flex-start; gap: 8px;
    white-space: normal; font-size: 13.5px; padding: 5px 0;
}

/* Stand der Warteschlange. Fest am unteren Rand, damit er beim Wechsel
   der Ansicht stehen bleibt – die Arbeit läuft ja auch weiter. */
.queue-bar {
    position: fixed; bottom: 20px; right: 20px; z-index: 55;
    display: flex; align-items: center; gap: 8px;
    padding: 8px 14px; border-radius: 8px; font-size: 13px;
    background: var(--panel-2); border: 1px solid var(--line);
    box-shadow: 0 6px 20px rgba(0,0,0,.45);
}
.spinner-dot {
    width: 8px; height: 8px; border-radius: 50%;
    background: var(--accent); animation: pulse 1.4s ease-in-out infinite;
}
@keyframes pulse { 0%, 100% { opacity: .35; } 50% { opacity: 1; } }

@media (max-width: 700px) {
    /* Auf schmalen Fenstern kollidiert die Leiste mit der Meldung. */
    .queue-bar { bottom: 70px; right: 10px; left: 10px; justify-content: center; }
}

.chip {
    display: inline-block; padding: 2px 8px; border-radius: 999px;
    font-size: 11.5px; font-weight: 600; white-space: nowrap;
    border: 1px solid var(--line); background: var(--panel-2); color: var(--muted);
}
.chip-new     { border-color: var(--accent); color: var(--accent); }
.chip-contact { border-color: var(--ok);     color: var(--ok); }
.chip-maybe   { border-color: var(--warn);   color: var(--warn); }
.chip-pool    { border-color: var(--muted);  color: var(--muted); }
/* Widerspruch nach Art. 21 – muss vor einem Anruf sofort ins Auge fallen. */
.chip-blocked { border-color: var(--danger); color: var(--danger); }
/* Ein Zeichen statt eines Wortes. Schriftgröße und Innenabstand bleiben
   die der übrigen Marken – sonst stünde der Haken zwei Pixel höher als
   seine Nachbarn in derselben Zeile. Die Bedeutung steht im Titel. */
.chip-icon { padding-left: 0; padding-right: 0; width: 20px; text-align: center; }
/* Trägt die Marke eine Zeichnung statt eines Zeichens, muss die auf die
   Schriftlinie gesetzt werden – sonst sitzt sie oben im Ring. */
.chip-icon svg { display: inline-block; vertical-align: -1px; }

/* Zwischenüberschrift in einem längeren Dialog. */
.modal-section {
    margin: 22px 0 12px; padding-top: 16px;
    border-top: 1px solid var(--line);
    font-size: 14px;
}
/* Die Zeile für den Plesk-Zeitplan: lang, zum Kopieren, darf umbrechen. */
.cron-line {
    display: block; margin-top: 8px; padding: 6px 8px;
    background: var(--panel); border: 1px solid var(--line); border-radius: 6px;
    font-size: 11.5px; word-break: break-all; user-select: all;
}

/* Die Plesk-Anleitung: Feldname links, Wert rechts. Eine Tabelle und
   keine Liste, weil genau das die Maske drüben auch ist – wer abtippt,
   soll Zeile für Zeile vergleichen können. */
table.cron-plesk { width: 100%; border-collapse: collapse; font-size: 12.5px; }
table.cron-plesk th {
    width: 110px; padding: 4px 10px 4px 0; text-align: left; vertical-align: top;
    font-weight: 600; color: var(--muted); white-space: nowrap;
}
table.cron-plesk td { padding: 4px 0; vertical-align: top; }
/* Innerhalb der Tabelle sitzt die Zeile schon in ihrer Zelle. */
table.cron-plesk .cron-line { margin-top: 0; }

/* Bereits erfasste Betriebe treten zurück, bleiben aber lesbar. */
table.data tr.row-muted td { opacity: .62; }

/* Ein gesperrter Kontakt – Widerspruch nach Art. 21 DSGVO.
   Die ganze Zeile trägt es, nicht ein Zeichen am Namen: Wer eine Liste
   überfliegt, um jemanden anzurufen, sieht die Farbe und liest das
   Zeichen nicht. Und ein Anruf gegen einen Widerspruch ist der Fehler,
   den man nicht machen darf.
   Deutlich rot, aber nicht deckend: Die Zeile muss lesbar bleiben. Der
   Hover bleibt eine Spur kräftiger, damit sichtbar bleibt, welche Zeile
   unter dem Zeiger liegt. */
table.data tbody tr.row-blocked { background: color-mix(in srgb, var(--danger) 40%, transparent); }
table.data tbody tr.row-blocked:hover { background: color-mix(in srgb, var(--danger) 55%, transparent); }

/* ---------- Auf den Home-Bildschirm ----------

   Der Willkommensschirm auf dem iPhone. Kein `.modal`: Der liegt über
   einer Ansicht, die man wiederhaben will – dieser hier ist das Erste,
   was jemand sieht, und deckt deshalb den ganzen Schirm.

   `100dvh` statt `100vh`: In Safari zählt `vh` die Adressleiste mit,
   die beim Rollen verschwindet – der Knopf unten stünde außerhalb des
   Bildes, und gerade er soll erreichbar sein. Der Rand unten hält sich
   zusätzlich vom Balken des Geräts fern (`safe-area`). */
.pwa-blatt {
    position: fixed; inset: 0; z-index: 200;
    display: flex; align-items: center; justify-content: center;
    padding: 24px 20px calc(24px + env(safe-area-inset-bottom));
    min-height: 100dvh;
    background: var(--bg);
    overflow-y: auto;
}
.pwa-karte {
    width: 100%; max-width: 360px; text-align: center;
    display: flex; flex-direction: column; align-items: center; gap: 10px;
}
.pwa-logo { border-radius: 18px; }
.pwa-karte h1 { font-size: 30px; letter-spacing: -.01em; margin: 4px 0 0; }
/* Der Satz der Website, wortgleich – zwei Versprechen wären eines zu viel. */
.pwa-spruch { color: var(--accent); font-size: 15px; margin: 0; }
.pwa-lead { color: var(--muted); font-size: 13.5px; margin: 0 0 4px; }

/* Drei Schritte, nummeriert. Die eigene Nummer statt `list-style`, weil
   sie eine Marke ist und keine Aufzählung: Sie steht in ihrem Kreis auf
   gleicher Höhe mit der Zeile, auch wenn die zweizeilig wird. */
.pwa-schritte {
    list-style: none; margin: 6px 0 4px; padding: 14px 16px; width: 100%;
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    text-align: left;
}
.pwa-schritte li {
    display: flex; align-items: flex-start; gap: 10px;
    font-size: 14px; padding: 7px 0;
}
.pwa-schritte li + li { border-top: 1px solid var(--line); }
.pwa-nr {
    flex: none; width: 22px; height: 22px; border-radius: 50%;
    background: var(--accent-fill); color: #fff;
    font-size: 12px; line-height: 22px; text-align: center;
}
/* Das Teilen-Zeichen steht IM Satz, an der Stelle, an der es gemeint
   ist – daneben wäre es ein zweites Bild ohne Bezug. */
.pwa-schritte svg { vertical-align: -4px; margin-left: 6px; color: var(--accent); }

.pwa-nichtmehr {
    display: flex; align-items: center; gap: 8px;
    font-size: 13.5px; color: var(--muted); margin-top: 2px;
}
.pwa-nichtmehr input { width: 17px; height: 17px; }
.pwa-fertig { width: 100%; padding: 11px 14px; margin-top: 6px; }

/* ---------- Metadaten ---------- */

.meta-block { margin-bottom: 14px; }
.meta-block:last-child { margin-bottom: 0; }
.meta-block-head {
    font-size: 11px; text-transform: uppercase; letter-spacing: .5px;
    color: var(--muted); margin-bottom: 6px;
}
/* Nach Fund gegliedert ist die Überschrift kein Rubrikname, sondern ein
   Wert aus den Metadaten – der Name der gefundenen Person. Sie bekommt
   deshalb dieselbe Farbe wie die Werte darunter. „Einzelne Angaben"
   bleibt grau: Das ist eine Rubrik, keine Angabe. */
.meta-block-head.from-data { color: var(--meta); }
.meta-block-head.from-data .meta-block-sub { color: var(--muted); }
.meta-row {
    display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
    padding: 7px 0; border-top: 1px solid var(--line); font-size: 14px;
}
.meta-label { color: var(--muted); flex: 0 0 auto; min-width: 130px; }
/* Wie in der Kontaktliste: der Farbton sagt, woher der Wert kommt.
   Die Verweise sind warm statt blau – Blau bleibt den Aktionen. */
.meta-value { flex: 1 1 220px; min-width: 0; word-break: break-word; color: var(--meta); }
.meta-value a { color: var(--meta-link); }
/* Wie in den Stammdaten und in der Liste: das Zeichen sagt, was für ein
   Wert das ist – bei „Fund" steht die Art sonst nur in der Beschriftung
   ganz links, und die ist bei drei Werten hintereinander weit weg. */
.meta-value a { display: inline-flex; align-items: center; gap: 6px; max-width: 100%; }
.meta-value a > span { min-width: 0; overflow-wrap: anywhere; }
.meta-value a > svg { flex: none; color: var(--muted); }
.meta-value a:hover > svg { color: inherit; }
.meta-value .meta-text { white-space: pre-wrap; }
/* Langtext mit der Darstellung „Code": feste Schrift, Zeilen wie gespeichert */
.meta-value .meta-code {
    margin: 0; max-width: 100%; overflow-x: auto; white-space: pre;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px;
}
.meta-source { color: var(--muted); font-size: 11.5px; white-space: nowrap; }
/* Sie steht IN der Bezeichnung: „Website · Anreicherung". Beides
   beschreibt den Eintrag – das eine, wofür er steht, das andere, woher er
   kommt. Der Punkt gehört zum Text und nicht ins Stilblatt: Er soll mit
   verschwinden, wenn die Quelle nichts hergibt. */

/* Umschalter mit zwei Stellungen. Kein Auswahlfeld: Bei genau zwei
   Möglichkeiten ist ein Aufklappen ein Klick zu viel. */
.seg { display: inline-flex; border: 1px solid var(--line); border-radius: 8px; overflow: hidden; }
.seg button {
    background: transparent; color: var(--muted); border: 0; border-radius: 0;
    padding: 4px 10px; font-size: 12px;
}
.seg button:hover { background: var(--panel-2); color: var(--text); }
.seg button.active { background: var(--accent-fill); color: #fff; }
.seg.mini button { padding: 2px 9px; font-size: 12px; }
/* „weg" wird rot, wenn es gewählt ist – dieselbe Ansage wie überall,
   bevor etwas wegfällt. Ungewählt bleibt es unauffällig: Es ist eine
   Möglichkeit, keine Warnung. */
.seg.mini button.weg.active { background: var(--danger); }

/* Gruppen einer Auswahl ändern: je Zeile eine Entscheidung. */
.group-choice-row {
    display: flex; align-items: center; gap: 8px;
    padding: 6px 10px; border-bottom: 1px solid var(--line);
}
.group-choice-row:last-child { border-bottom: 0; }
.group-choice-row .spacer { flex: 1; }
.group-choice-name { font-size: 13px; }
/* Die berührten Zeilen heben sich ab – man soll auf einen Blick sehen,
   wie viel man angefasst hat, ohne die Vorschau zu lesen. */
.group-choice-row.is-add { background: rgba(58, 99, 224, .10); }
.group-choice-row.is-remove { background: rgba(229, 72, 77, .10); }

.bulk-preview { margin: 0; padding: 0; list-style: none; font-size: 13px; }
.bulk-preview li {
    display: flex; align-items: baseline; gap: 7px; padding: 3px 0;
    border-left: 2px solid transparent; padding-left: 8px;
}
.bulk-preview li.add { border-left-color: var(--accent-fill); }
.bulk-preview li.remove { border-left-color: var(--danger); }

/* Die Art des Werts, wenn nach Fund gegliedert ist – „Einkauf" allein
   sagt nicht, ob Name oder E-Mail gemeint ist. */
.meta-type { color: var(--muted); opacity: .8; }
.meta-type::after { content: " ·"; }
.meta-block-sub { color: var(--muted); font-weight: 400; margin-left: 8px; }

/* Zu welchem Fund ein Wert gehört. Zurückhaltend: Es ist eine Zutat zum
   Wert, keine eigene Angabe – deshalb kein Chip, sondern nur der Name mit
   einem Pfeil davor. */
.meta-group {
    font-size: 12px; color: var(--muted); white-space: nowrap;
    overflow: hidden; text-overflow: ellipsis; max-width: 180px;
}
.meta-group::before { content: "↳ "; }

/* Der maßgebliche Wert seines Typs – der, den Liste und Suche zeigen.
   Er steht vor der Bezeichnung, nicht hinter dem Wert: Er sagt etwas über
   den Eintrag aus und ist keine Handlung an seinem Inhalt. Links kein
   Rand, damit er am Rand der Karte steht wie eine Aufzählungsmarke. */
.meta-star { color: var(--line); padding: 2px 6px 2px 0; line-height: 1; flex: 0 0 auto; }
.meta-star:hover { color: var(--muted); }
.meta-star.is-primary { color: var(--warn); }

/* „Ändern" und „Löschen" an einem Metadatum: Zeichen immer, Wort nur, wo
   Platz ist (`nur-breit`) – dieselbe Aufteilung wie im Kopf der Akte. */
.meta-row .entry-actions button { display: inline-flex; align-items: center; gap: 5px; }
.meta-row .entry-actions button > svg { flex: none; }

/* Schmal steht die Bezeichnung in einer eigenen Zeile – und die beiden
   Knöpfe standen ganz unten, hinter Wert, Fund, Stern und Quelle: vier
   Angaben zwischen der Zeile und dem Knopf, der sie ändert. Sie rücken
   zu der Bezeichnung hoch, an den rechten Rand.

   Über `order` und nicht über eine zweite Anordnung im HTML: Die Reihen-
   folge im Quelltext ist die, in der ein Vorleser sie nennt – erst was
   dasteht, dann was man damit tun kann. `flex: 1 0 100%` am Wert bricht
   danach die Zeile.

   `align-items: center` an den Knöpfen: Die Zeile richtet sich an der
   Schriftlinie aus, und ein Knopf, in dem nur eine Zeichnung steht, hat
   keine – er hinge sonst unter der Bezeichnung. */
@media (max-width: 700px) {
    .meta-label { min-width: 0; flex: 1 0 100%; }
    .meta-row { gap: 6px; }
    /* Nur die gepflegte Liste, nicht die Vorschläge: Dort sind es andere
       Kinder (Stufe, „schon vorhanden", „Übernehmen"), und die stünden
       ohne eigenes `order` mit an der Bezeichnung. */
    .meta-block .meta-row > .meta-label { flex: 1 1 auto; order: 0; }
    .meta-block .meta-row > .entry-actions { order: 1; flex: 0 0 auto; align-self: center; }
    .meta-block .meta-row > .meta-value { flex: 1 0 100%; order: 2; }
    .meta-block .meta-row > .meta-group { order: 3; }
}

/* ---------- Anrufe ---------- */

/* Der Hörer steht neben „Ändern" und „Löschen". Etwas größer als die
   Nachbarn, weil ein Symbol allein sonst kleiner wirkt als Text. */
/* Der Hörer ist eine Zeichnung wie alle anderen, kein Schriftzeichen:
   `☎` wird auf manchen Systemen als buntes Bildchen gesetzt, und in
   einer Zeile aus gedämpften Zeichen fiele es an der falschen Stelle
   auf. */
.call-btn { font-size: 15px; line-height: 1; padding: 3px 8px; margin-right: 6px; }

/* In der Kontaktliste ohne Rahmen: Dort steht er neben Brief und
   Erdkugel, und die tragen keinen. Ein Knopf mit Kasten daneben sähe
   aus, als täte er etwas anderes – dabei ist auch die Nummer daneben
   ein Auslöser. Anrufen bleibt es trotzdem, deshalb der Zeiger und die
   Farbe unter ihm. */
table.data.kontakt-tabelle .call-btn {
    background: none; border: 0; padding: 0; margin-right: 6px;
    line-height: 0; color: var(--muted);
}
table.data.kontakt-tabelle .call-btn svg { display: block; width: 14px; height: 14px; }
table.data.kontakt-tabelle .call-btn:hover:not(:disabled) { color: var(--ok); background: none; }
table.data.kontakt-tabelle .call-btn:disabled { color: var(--line); }
.call-btn:not(:disabled) { color: var(--ok); }
.call-btn:disabled { color: var(--line); }

/* In der Akte gilt dasselbe wie in der Liste: Neben Brief und Erdkugel
   trüge ein Kasten um den Hörer den Anschein, er täte etwas anderes.
   Steht hinter den beiden Regeln oben, nicht davor – gleiche Gewichtung
   entscheidet die Reihenfolge, und die Farbe soll hier gelten. */
.field .value .call-btn, .meta-value .call-btn {
    background: none; border: 0; padding: 0; margin-right: 6px;
    line-height: 0; color: var(--muted); vertical-align: middle;
}
.field .value .call-btn svg, .meta-value .call-btn svg { display: block; }
.field .value .call-btn:hover:not(:disabled),
.meta-value .call-btn:hover:not(:disabled) { color: var(--ok); background: none; }
.field .value .call-btn:disabled, .meta-value .call-btn:disabled { color: var(--line); }
/* In der Anrufliste ebenso: der Hörer einfarbig wie in der Akte, ohne
   Rahmen – `☎` setzte das iPhone als rotes Bildchen. */
table.data.anruf-tabelle .call-btn {
    background: none; border: 0; padding: 0; margin-right: 6px;
    line-height: 0; color: var(--muted); vertical-align: middle;
}
table.data.anruf-tabelle .call-btn svg { display: block; width: 14px; height: 14px; }
table.data.anruf-tabelle .call-btn:hover:not(:disabled) { color: var(--ok); background: none; }
table.data.anruf-tabelle .call-btn:disabled { color: var(--line); }

/* Zeigt beim Tippen, was bei der Anlage ankommt. */
.call-bulk { margin-top: -6px; }

/* Richtung eines Anrufs: ↗ hinaus, ↙ herein, rot = herein und verpasst. */
.call-dir { display: inline-block; font-weight: 700; font-size: 15px; line-height: 1; min-width: 14px; text-align: center; }
.call-dir.out { color: var(--meta); }
.call-dir.in { color: var(--ok, #2e9e5b); }
.call-dir.in.missed { color: var(--danger, #b3261e); }
.call-dir-tabs { margin-top: -4px; }
.call-dir-tabs .call-dir { margin-right: 2px; }

/* Der Anruf im Aufbau: vier Schritte, einer davon läuft. */
.call-steps { list-style: none; margin: 0 0 14px; padding: 0; }
.call-steps li { display: flex; align-items: center; gap: 10px; padding: 6px 0; color: var(--muted); }
.call-steps li.done { color: var(--text); }
.call-steps li.active { color: var(--text); font-weight: 600; }
.call-step-mark { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--border); flex: none; }
.call-steps li.done .call-step-mark { background: var(--ok, #2e9e5b); border-color: var(--ok, #2e9e5b); }
.call-steps li.active .call-step-mark { border-color: var(--meta); animation: call-pulse 1.2s ease-in-out infinite; }
@keyframes call-pulse { 0%, 100% { box-shadow: 0 0 0 0 rgba(0,0,0,.15); } 50% { box-shadow: 0 0 0 5px rgba(0,0,0,0); } }
.call-outcome { margin: 0 0 10px; padding: 10px 12px; border-radius: 8px; font-weight: 600; }
.call-outcome.ok { background: rgba(46,158,91,.12); color: var(--ok, #2e9e5b); }
.call-outcome.bad { background: rgba(200,50,50,.1); color: var(--danger, #b3261e); }
.call-preview { min-height: 16px; }
.call-preview strong { color: var(--meta); font-weight: 600; letter-spacing: .3px; }

/* Fremdes HTML bringt eigene Vorstellungen von Schriftgröße und Abstand
   mit. Der Rahmen setzt sie zurück – und lässt breite Tabellen in sich
   rollen, statt die Detailansicht zu sprengen. */
.transcript {
    margin-top: 10px; padding: 10px 12px;
    background: var(--panel-2); border: 1px solid var(--line);
    border-radius: var(--radius);
    font-size: 14px; line-height: 1.55; overflow-x: auto;
}
.transcript > *:first-child { margin-top: 0; }
.transcript > *:last-child { margin-bottom: 0; }
.transcript p { margin: 0 0 8px; }
.transcript ul, .transcript ol { margin: 0 0 8px; padding-left: 20px; }
.transcript li { margin: 2px 0; }
.transcript h3, .transcript h4 { font-size: 14px; margin: 10px 0 6px; }
.transcript a { color: var(--meta-link); }
.transcript table { border-collapse: collapse; font-size: 13px; }
.transcript td, .transcript th { border: 1px solid var(--line); padding: 4px 8px; text-align: left; }
.transcript pre { white-space: pre-wrap; word-break: break-word; }

/* Das strukturierte Protokoll: ein Satz oben, Angaben darunter. */
.transcript-summary { margin: 0 0 10px; }
.transcript-facts {
    display: grid; grid-template-columns: auto 1fr; gap: 2px 12px;
    margin: 0; font-size: 13px;
}
.transcript-facts > div { display: contents; }
.transcript-facts dt { color: var(--muted); white-space: nowrap; }
.transcript-facts dd { margin: 0; color: var(--meta); }

.transcript-todos { margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--line); }
.transcript-todos-head { font-size: 12px; color: var(--muted); margin-bottom: 6px; }
.transcript-todo {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    font-size: 13px; padding: 2px 0;
}
.transcript-todo::before { content: "→"; color: var(--muted); }
/* Erledigt: durchgestrichen wie in der Aufgabenliste. Der Punkt bleibt
   stehen – er gehört zum Beleg und verschwindet nicht, nur weil jemand
   ihn abgehakt hat. */
.transcript-todo.is-done > span:first-of-type {
    text-decoration: line-through; color: var(--muted);
}
.transcript-todo.is-gone > span:first-of-type { color: var(--muted); }

@media (max-width: 700px) {
    .transcript-facts { grid-template-columns: 1fr; gap: 0 0; }
    .transcript-facts dt { margin-top: 6px; }
}

/* ---------- Kosten ---------- */

.cost-days { margin-top: 8px; }
.cost-day {
    display: flex; align-items: center; gap: 10px;
    padding: 3px 0; font-size: 13px;
}
.cost-date { flex: 0 0 110px; color: var(--muted); }
/* Der Balken ist Größenvergleich, keine Messung – deshalb ohne Achse und
   ohne Zahlen daran. Der Betrag steht daneben. */
.cost-bar { flex: 1 1 auto; height: 8px; background: var(--panel-2); border-radius: 4px; overflow: hidden; }
.cost-bar span { display: block; height: 100%; background: var(--accent); }
.cost-value { flex: 0 0 72px; text-align: right; color: var(--meta); }
.cost-calls { flex: 0 0 44px; text-align: right; color: var(--muted); font-size: 12px; }

/* ---------- Warteschlange ---------- */

.queue-summary {
    display: flex; flex-wrap: wrap; gap: 6px 18px;
    font-size: 13px; color: var(--muted);
}
.queue-summary strong { color: var(--text); font-size: 15px; margin-right: 3px; }

.queue-section { margin-top: 18px; }
.queue-job {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 8px 0; border-top: 1px solid var(--line);
}
.queue-job-main { min-width: 0; flex: 1; display: flex; flex-direction: column; gap: 2px; }
.queue-job .row-title { font-size: 14px; }
.queue-job .row-sub { font-size: 12px; color: var(--muted); }
.queue-job .entry-actions { margin-left: auto; flex: 0 0 auto; }

.queue-bar.clickable { cursor: pointer; }
.queue-bar.clickable:hover { border-color: var(--accent); }

/* ---------- Anrufliste ---------- */

/* Vier Zahlen in einer Kachel: „heute" groß, der Rest als Maßstab.
   „Termine heute" trägt dieselbe Unterzeile. */
.stat-calls .stat-sub, .stat-termine .stat-sub, .stat-mail .stat-sub {
    display: flex; flex-wrap: wrap; gap: 2px 10px;
    margin-top: 4px; font-size: 11.5px; color: var(--muted);
}
.stat-calls .stat-sub span span, .stat-termine .stat-sub strong, .stat-mail .stat-sub strong { color: var(--text); font-weight: 600; }

.call-row td { vertical-align: middle; }
/* Rufnummer und Hörer gehören auf eine Zeile. Bricht die Spalte um, steht
   das Symbol unter der Nummer und die Zeile wird doppelt so hoch. */
.call-target { white-space: nowrap; }
.call-target .call-btn { margin-right: 6px; vertical-align: middle; }
/* Der Firmenname ist ein Verweis, soll aber nicht wie einer schreien –
   die ganze Zeile ist ohnehin anklickbar. Erst beim Zeigen wird es
   deutlich. */
.call-row a.row-title { color: inherit; }
.call-row a.row-title:hover { color: var(--accent); text-decoration: underline; }
.call-row .suggest-toggle { color: var(--muted); }
.call-detail-row td { background: var(--bg); border-top: 0; padding: 0; }
.call-detail { padding: 12px 14px 14px; }
.call-detail-actions { margin-top: 12px; }

@media (max-width: 700px) {
    /* In der Kartenansicht hat das Dreieck keine eigene Zelle mehr. */
    .call-detail-row td { padding: 0; }
}

/* Zwei bis drei Marken nebeneinander, aber nie untereinander: Umgebrochen
   sieht der Stand aus wie zwei Zeilen und die Tabelle wird unruhig. */
.pool-status { white-space: nowrap; }

/* Ein Vorschlag im aufgeklappten Pool-Eintrag. Die Zeile trägt viel:
   Bezeichnung, Wert, Sicherheit, Fundstelle und die Entscheidung. Was
   ausgeschrieben werden kann, ohne den Wert zu verdrängen, bleibt Wort;
   der Rest ist Zeichen mit Titel. */
/* Sechs feste Spalten: Bezeichnung, Wert, Sicherheit, Fundstelle und
   zwei für die Entscheidung. Jedes Stück bekommt seine Spalte
   ausdrücklich zugewiesen – x-show blendet aus, was gerade nicht gilt,
   und ein ausgeblendetes Element belegt keine Spalte mehr. Ohne die
   Zuweisung rückte in einer Zeile mit nur einer Marke alles um zwei
   Stellen nach rechts, und die Tabelle stünde treppenförmig da. */
.find-row {
    display: grid;
    grid-template-columns: minmax(96px, 150px) minmax(0, 1fr) 62px 26px 30px 30px;
    align-items: center;
    column-gap: 10px;
}
.find-row > .meta-label { grid-column: 1; min-width: 0; }
.find-row > .meta-value { grid-column: 2; min-width: 0; overflow-wrap: anywhere; }
/* Die Sicherheit steht links in ihrer Spalte, damit „hoch", „mittel"
   und „niedrig" an derselben Kante beginnen. */
.find-row > .chip:not(.chip-icon) { grid-column: 3; justify-self: start; }
.find-row > .find-icon { grid-column: 4; justify-self: center; }
.find-row > .find-yes,
.find-row > .chip-icon { grid-column: 5; justify-self: center; }
.find-row > .find-no,
.find-row > .find-undo { grid-column: 6; justify-self: center; }

.find-icon {
    display: inline-flex; align-items: center; color: var(--muted);
    line-height: 0; padding: 2px; border-radius: 6px;
}
.find-icon:hover { color: var(--accent); background: var(--panel-2); }
/* Ein Wert von einer fremden Seite ist weniger wert als einer aus dem
   eigenen Impressum. Vorher stand das als „fremde Quelle" daneben. */
.find-icon.is-foreign { color: var(--warn); }

/* Die beiden Winkel neben der Auswahl. Sie stehen dicht beieinander –
   zwei Griffe für dieselbe Sache, nicht zwei getrennte Befehle. */
.fold-all { display: inline-flex; gap: 4px; margin-left: 4px; }
.fold-btn { padding: 3px 8px; line-height: 0; color: var(--muted); }
.fold-btn:not(:disabled):hover { color: var(--accent); }

/* Warnfarben und nicht rot: Verwerfen nimmt nichts weg, es legt beiseite.
   Rot bleibt dem Unwiederbringlichen vorbehalten. */
.dismiss-rest:not(:disabled) { color: var(--warn); }
.dismiss-rest:not(:disabled):hover { border-color: var(--warn); }

.find-yes, .find-no, .find-undo {
    font-size: 15px; line-height: 1; padding: 2px 0; width: 100%; min-width: 0;
}
.find-yes:not(:disabled) { color: var(--ok); }
.find-no:not(:disabled)  { color: var(--danger); }
.find-yes:not(:disabled):hover { border-color: var(--ok); }
.find-no:not(:disabled):hover  { border-color: var(--danger); }

/* Verworfen heißt nicht weg: Der Wert bleibt lesbar, aber erkennbar
   beiseitegelegt – sonst wüsste beim Zurückholen niemand mehr, was er
   zurückholt. */
.find-row.is-dismissed .meta-value,
.find-row.is-dismissed .meta-label { text-decoration: line-through; opacity: .55; }
.find-row.is-dismissed .chip { opacity: .55; }

@media (max-width: 700px) {
    /* Sechs Spalten sind auf dem Telefon vier zu viel: Dort fällt die
       Zeile auf den Umbruch zurück, wie die übrigen Metadatenzeilen. */
    .find-row { display: flex; flex-wrap: wrap; align-items: center; }
    .find-row > * { grid-column: auto; }
    .find-yes, .find-no, .find-undo { width: auto; padding: 2px 8px; }
}

/* Was aus der gewählten Branche tatsächlich hinausgeht. Ohne diese Zeile
   ist nicht nachvollziehbar, warum zwei Quellen verschiedene Treffer
   liefern. */
.branche-hinweis {
    display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
    margin: -4px 0 14px; font-size: 12.5px; color: var(--muted);
}
.branche-hinweis strong { color: var(--text); font-weight: 600; }
.branche-hinweis code { color: var(--meta-link); }

/* Die Probe in der Pflegemaske: erst ausprobieren, dann speichern. */
.probe-box {
    margin-top: 16px; padding: 12px 14px; border: 1px solid var(--line);
    border-radius: 8px; background: var(--panel-2);
}

/* Fortschritt eines Suchlaufs. Kein Zappelbalken ohne Zahlen: Die
   Beschriftung sagt, was gerade geholt wird und wie viel davon. */
.search-progress {
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 12px 14px; margin-bottom: 14px;
}
.search-progress-head { display: flex; align-items: baseline; gap: 10px; font-size: 13.5px; }
.progress-track {
    margin-top: 8px; height: 8px; border-radius: 999px;
    background: var(--panel-2); overflow: hidden;
}
.progress-fill {
    height: 100%; background: var(--accent-fill); border-radius: 999px;
    transition: width .3s ease;
}
/* In der Warteschlange steht der Balken in einer Zeile und nicht in
   einer Karte – etwas schmaler, mit Luft nach oben. */
.queue-job .progress-track { margin-top: 6px; height: 5px; max-width: 320px; }
/* Was nicht läuft, tritt zurück: Ein voller Balken an einem
   abgebrochenen Auftrag hat schon manchen glauben lassen, es sei alles
   erledigt. */
.queue-job .progress-track.ruht { opacity: .45; }

/* Der aufgeklappte Pool-Eintrag: dieselbe Machart wie beim Anruf. */
.pool-detail-row td { background: var(--bg); border-top: 0; padding: 0; }
.pool-detail { padding: 12px 14px 14px; }
.pool-detail .panel-head { margin: 0 0 8px; }
.pool-detail .meta-block:first-of-type { margin-top: 0; }
/* Das Dreieck steht vor dem Firmennamen, nicht davor und darunter. */
.data .suggest-toggle { padding: 0 6px 0 0; line-height: 1; }

/* Die beiden Listen der Startseite – die ganze Kopfzeile klappt auf. */
.later-head { cursor: pointer; }
.later-head + .table-wrap + .later-head,
.table-wrap + .later-head { margin-top: 22px; }
.later-head .suggest-toggle { padding: 0 4px; line-height: 1; }

/* Die Kopfzeile klappt auf und zu. Ein Protokoll kostet sonst eine
   Bildschirmhöhe, und gelesen wird fast immer nur das letzte. */
.transcript-head { cursor: pointer; margin-bottom: 0; }
.transcript-head .suggest-toggle { padding: 0 4px; line-height: 1; }
.transcript-teaser {
    margin: 6px 0 0; font-size: 13px; color: var(--muted); cursor: pointer;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
}

/* Die wörtliche Mitschrift. Eingeklappt, weil die Zusammenfassung darüber
   in aller Regel genügt. */
.transcript-words { margin-top: 12px; font-size: 13px; }
.transcript-words summary { color: var(--accent); cursor: pointer; }
.transcript-words > div {
    margin-top: 8px; padding: 8px; max-height: 420px; overflow: auto;
    background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
}
.transcript-words table { border-collapse: collapse; width: 100%; }
.transcript-words td, .transcript-words th {
    border: 1px solid var(--line); padding: 5px 8px;
    text-align: left; vertical-align: top;
}
.transcript-words th { color: var(--muted); font-weight: 600; }
/* Die erste Spalte trägt nur den Sprecher – sie darf nicht mitwachsen. */
.transcript-words td:first-child { width: 1%; white-space: nowrap; color: var(--muted); }

/* Die Rohmeldung – die Antwort auf „wo ist der Rest hin?". */
.transcript-raw { margin-top: 8px; font-size: 12px; }
.transcript-raw summary { color: var(--muted); cursor: pointer; }
.transcript-raw pre {
    margin: 8px 0 0; padding: 8px; max-height: 240px; overflow: auto;
    background: var(--bg); border: 1px solid var(--line); border-radius: 6px;
    white-space: pre-wrap; word-break: break-all; color: var(--muted);
}

/* ---------- Anreicherung: Vorschläge ---------- */

.inline-select {
    width: auto; min-width: 150px; max-width: 220px;
    font-size: 13px; padding: 4px 26px 4px 8px; margin: 0;
    background-position: right 8px center;
}
.suggest-box {
    background: var(--panel-2); border: 1px solid var(--line);
    border-radius: 8px; padding: 10px 12px; margin-bottom: 14px;
}
/* Ein durchgesehener Lauf tritt zurück, verschwindet aber nicht: Was
   dort steht, ist bezahlt und bleibt greifbar. */
.suggest-box.is-done { opacity: .72; }
.suggest-box.is-done:hover { opacity: 1; }

.suggest-head {
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 4px;
}
.suggest-box .meta-row:first-of-type { border-top: 0; }
.suggest-box .meta-source { text-decoration: underline; }

/* Der Auf-/Zuklapper trägt den Auftragsnamen – die ganze Zeile ist
   damit die Schaltfläche, nicht nur ein kleines Dreieck. */
.suggest-toggle {
    display: inline-flex; align-items: center; gap: 6px;
    color: var(--text); font-size: 13.5px;
}
.suggest-toggle:hover { text-decoration: none; color: var(--accent); }
.suggest-toggle span:first-child { color: var(--muted); font-size: 11px; }

/* Zeile über allen Läufen: wie viel ist insgesamt noch zu tun? */
.suggest-summary {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    font-size: 12.5px; margin: 4px 0 10px;
}

/* Ein Fund aus mehreren zusammengehörigen Werten – Name, Durchwahl und
   E-Mail einer Person – wird als ein Block gezeigt, damit erkennbar
   bleibt, wen man unter welcher Nummer verlangt. */
.suggest-group.is-block {
    border-left: 3px solid var(--accent);
    padding-left: 10px;
    margin: 6px 0;
}
.suggest-group.is-block .meta-row:first-of-type { border-top: 0; }

/* ---------- Herkunft aus der Recherche ---------- */

.source-line {
    display: flex; align-items: center; flex-wrap: wrap; gap: 10px;
    font-size: 13px; margin-bottom: 6px;
}
.source-line:last-child { margin-bottom: 0; }

/* ---------- Platzhalterseite ---------- */

.placeholder {
    max-width: 620px; background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 26px;
}
.placeholder h2 { font-size: 17px; margin-bottom: 8px; }
.placeholder p { color: var(--muted); font-size: 14px; margin: 0 0 10px; }
.placeholder ul { color: var(--muted); font-size: 14px; margin: 0; padding-left: 20px; }
.placeholder li { margin-bottom: 6px; }

/* ==========================================================================
   Helles Thema – Feinschliff
   Die Variablen oben tragen schon das meiste. Hier folgen nur die Stellen,
   deren Farben fest im dunklen Thema stehen und die für das helle Thema
   neu abgemischt werden müssen. Alles hängt an `html[data-theme="light"]`.
   ========================================================================== */

html[data-theme="light"] .modal,
html[data-theme="light"] .sidebar-backdrop { background: rgba(28, 36, 54, .4); }

/* Die Login-Karte liegt auf einem Foto; hell heißt: heller Schleier,
   halbtransparente weiße Karte. */
html[data-theme="light"] .login-bg::before {
    background: linear-gradient(180deg, rgba(242,244,249,.45), rgba(242,244,249,.72));
}
html[data-theme="light"] .login-bg .card {
    background: rgba(255, 255, 255, .93);
    box-shadow: 0 18px 50px rgba(28, 36, 54, .28);
}

/* Weiße Schrift auf gefüllten Flächen bleibt weiß – aber bei den
   Kennzeichnungen stehen die dunklen Töne so, dass weiß auf dunkel
   gewählt war. Für hell: getönte Fläche, dunkle Schrift in derselben
   Farbfamilie. */
html[data-theme="light"] .badge.admin,
html[data-theme="light"] .badge.todo { background: #e2e9fc; border-color: #9fb3ec; color: #21377e; }
html[data-theme="light"] .badge.note { background: #ece4f8; border-color: #c5aee2; color: #553d80; }
html[data-theme="light"] .badge.done { background: #d9efe4; border-color: #8ac7a8; color: #1e5d3c; }
html[data-theme="light"] .badge.blocked { background: #fadfdf; border-color: #e59aa2; color: #8c2430; }

/* Leaflet-Attribution ist auf Dunkel zugeschnitten. */
html[data-theme="light"] .map-canvas .leaflet-control-attribution {
    background: rgba(255, 255, 255, .82); color: var(--muted);
}

/* Schlagschatten sollen im hellen Thema weicher fallen. */
html[data-theme="light"] .profile-dropdown,
html[data-theme="light"] .profile-submenu,
html[data-theme="light"] .combo-liste,
.thema-hell .combo-liste { box-shadow: 0 12px 28px rgba(28, 36, 54, .18); }
html[data-theme="light"] .toast { box-shadow: 0 6px 20px rgba(28, 36, 54, .18); }

/* ==========================================================================
   Theme-Umschalter
   Kleiner Bildschirmknopf unten in der Seitenleiste, rechts neben dem
   eigenen Namen. Zeigt das Gegenstück an: Im dunklen Thema die Sonne,
   im hellen der Mond.
   ========================================================================== */
.sidebar-user {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 6px;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.theme-toggle {
    flex: none; width: 28px; height: 28px; padding: 0;
    display: grid; place-items: center; border-radius: 7px;
    background: transparent; border: 1px solid var(--line); color: var(--muted);
    cursor: pointer;
}
/* Der Umschalter auf der Anmelde- und Passwortwechsel-Maske sitzt oben
   rechts auf der Fotofläche – die Karte selbst bleibt frei davon. */
.theme-toggle.login-theme {
    position: absolute; top: 14px; right: 14px;
    background: var(--panel); color: var(--text);
}
.center { position: relative; }
.theme-toggle:hover { background: var(--panel-2); color: var(--text); }
.theme-toggle .icon-sun { display: none; }
html[data-theme="light"] .theme-toggle .icon-sun { display: block; }
html[data-theme="light"] .theme-toggle .icon-moon { display: none; }

/* ---------- E-Mail ---------- */

/* Zwei bzw. drei feste Spalten. `field-grid` allein ordnet nach Platz um;
   bei Server/Port/Verschlüsselung soll die Reihenfolge aber stehen –
   ein Port, der unter seinen Server rutscht, liest sich falsch. */
.field-grid.two { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.field-grid.three { grid-template-columns: 2fr 1fr 1.4fr; }
@media (max-width: 640px) {
    .field-grid.three { grid-template-columns: 1fr; }
}

.mail-sub {
    margin: 18px 0 6px; font-size: 12px; text-transform: uppercase;
    letter-spacing: .5px; color: var(--muted);
}

/* Ein Zustand in einem Wort, neben dem Namen des Kontos. */
.tag {
    display: inline-block; margin-left: 8px; padding: 1px 7px; border-radius: 999px;
    font-size: 11px; border: 1px solid currentColor; vertical-align: middle;
}

.mail-account-list { display: flex; flex-direction: column; gap: 10px; }
.mail-account {
    display: flex; align-items: flex-start; gap: 14px;
    background: var(--panel); border: 1px solid var(--line);
    border-radius: var(--radius); padding: 14px 16px;
}
.mail-account.inactive { opacity: .6; }
.mail-account-main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.mail-account-name { font-size: 15px; }
.mail-account-actions { display: flex; gap: 6px; flex: none; }
/* Die Knöpfe am Konto sind Sinnbilder: gleich groß, das Bild mittig.
   Der Signaturknopf färbt sich, sobald eine hinterlegt ist. */
.mail-account-actions button.symbol {
    display: inline-flex; align-items: center; justify-content: center;
    width: 32px; height: 30px; padding: 0;
}
.mail-account-actions button.symbol svg { width: 16px; height: 16px; }
.mail-account-actions button.symbol.aktiv { color: var(--accent); }
/* Das Schreibfeld der Signatur: dasselbe wie in der Nachricht, nur nicht so
   hoch – eine Unterschrift hat vier Zeilen, kein Brief. */
.compose-text.signatur-text { min-height: 140px; max-height: 40vh; }
/* Die Vorlage: ein Brief, aber die Zeilen darüber brauchen Platz. */
.compose-text.vorlage-text { min-height: 180px; max-height: 38vh; }
.vorlage-sichtbar { gap: 18px; }
/* Das Platzhaltermenü ist länger als die anderen: zwanzig Einträge in drei
   Gruppen. Breiter, damit „Vor- und Nachname {{name}}" in eine Zeile passt. */
/* Mit `.mail-spaltenwahl` davor, weil dessen Regel (260 px) weiter unten
   im Stilblatt steht und bei gleicher Gewichtung gewönne. */
.mail-spaltenwahl.mail-platzhaltermenue { width: 320px; }
.mail-spaltenwahl.mail-vorlagenmenue { width: 320px; }
/* Das Menü der KI-Aufträge: breiter, weil ein Eingabefeld in der Zeile
   steht; der Bereich (Markierung oder Text) oben als zwei Haken. */
/* 600 Pixel: Ein Auftrag mit Eingabe („Wann?", „Grund") braucht Platz zum
   Ausformulieren. Die Obergrenze hier, nicht in der Telefonregel – die
   steht weiter oben und verlöre gegen diese. */
.mail-spaltenwahl.mail-kimenue { width: 600px; max-width: calc(100vw - 16px); }
.ki-bereich { display: flex; gap: 14px; flex-wrap: wrap; margin: 4px 0 8px; }
.ki-bereich .check { margin: 0; }
.ki-eintrag { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
/* Name und Eingabe teilen sich die Zeile, die Eingabe bekommt den größeren
   Teil; wird es eng, rutscht sie unter den Namen. */
.ki-eintrag > button.ghost { flex: 1 1 180px; min-width: 0; }
.ki-eintrag.gesperrt > button.ghost { opacity: .45; }
/* Die Aufträge stießen Rahmen an Rahmen aneinander. */
.ki-eintrag + .ki-eintrag { margin-top: 5px; }
/* Der dünne Rahmen in der Farbe der Seite wie bei den Dialogen – das Menü
   trägt Reiter, Wahl und Eingaben, es ist mehr als eine Liste. */
.mail-spaltenwahl.mail-kimenue { border-color: var(--seite-accent); }
.mail-kimenue .tabs.ki-tabs { margin: 2px 0 8px; }
/* „(für alle)" nur für den Administrator – leise hinter dem Namen. */
.ki-fuer-alle { margin-left: 4px; font-size: 12px; font-weight: normal; color: var(--muted); opacity: .7; }
.ki-eingabe { flex: 2 1 260px; min-width: 0; margin: 0; padding: 4px 8px; font-size: 12.5px; }
/* Der KI-Knopf in der Werkzeugleiste: gefüllt in der Signalfarbe, nicht
   als Geist – er ist der eine Knopf, der etwas Neues anbietet. */
.ki-knopf { font-weight: 600; }
button.ghost.ki-knopf { background: #dbe8ff; color: #1d3fa8; border-color: #b9cfff; display: inline-flex; align-items: center; gap: 4px; }
button.ghost.ki-knopf svg { flex: none; }
button.ghost.ki-knopf:hover { background: #c7dbff; color: #1d3fa8; }
/* Die Vorschau: Vorher und Nachher nebeneinander, am Telefon untereinander. */
/* Die Teilung (`--ki-links`, in Prozent) verschiebt der Griff dazwischen. */
.ki-vorschau { display: grid; grid-template-columns: minmax(0, var(--ki-links, 50%)) 6px minmax(0, 1fr); gap: 0 8px; }
.ki-vorschau.einzeln { grid-template-columns: minmax(0, 1fr); }
.ki-splitter { border-radius: 3px; }
.ki-vorschau.zieht { user-select: none; }
.ki-vorschau.zieht .ki-splitter { background: var(--accent); }
.ki-vorschau .ki-spalte:only-child { grid-column: 1 / -1; }
/* Nachschärfen: der Hinweis und sein Knopf in einer Zeile. */
.ki-nachschaerfen { display: flex; gap: 8px; margin-top: 10px; }
.ki-nachschaerfen input { flex: 1 1 auto; min-width: 0; }
.ki-vorschau-text {
    font-size: 14px; line-height: 1.5; padding: 10px 12px; border-radius: var(--radius);
    background: var(--panel-2); border: 1px solid var(--line); max-height: 50vh; overflow: auto;
}
.ki-anweisung { white-space: pre-wrap; max-height: 3.2em; overflow: hidden; }
/* Das Ergebnis groß wie der Schreibdialog: Zwei Texte nebeneinander
   brauchen die Breite. Die Höhe steht fest – die Texte füllen sie und
   rollen für sich, der Dialog springt nicht, wenn der Vorschlag kommt.
   Hinweiszeile und gesendeter Prompt nehmen ihre Höhe, den Rest die Texte. */
.modal-box.ki-vorschau-dialog { width: min(1200px, calc(100vw - 40px)); height: 90vh; height: 90dvh; }
.ki-vorschau-dialog .modal-body { display: flex; flex-direction: column; }
.ki-vorschau-dialog .modal-body > * { flex: none; }
.ki-vorschau-dialog .ki-vorschau { flex: 1 1 auto; min-height: 200px; }
.ki-vorschau-dialog .ki-spalte { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.ki-vorschau-dialog .ki-vorschau-text { flex: 1 1 auto; min-height: 0; max-height: none; }

/* Eigene Platzhalter: die Kennung im Editor als Code, die festen in der
   Liste knapp und grau – zum Nachschlagen, nicht zum Anfassen. */
/* Der Dialog „Vorlage anwenden" (PLANUNG-PLATZHALTER-DIALOG.md): die Liste
   in Schritt 1 wie das frühere Menü, die Fragen in Schritt 2 als Zeilen –
   Beschriftung links, Feld rechts, Beschreibung darunter. */
.vorlage-kontaktzeile { margin: 0 0 10px; }
.vorlage-zum-an { margin-top: 8px; }
.vorlage-suche { margin-bottom: 8px; }
.vorlage-wahl { display: flex; flex-direction: column; gap: 4px; max-height: 50vh; overflow-y: auto; }
.vorlage-wahl > button.ghost { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; width: 100%; text-align: left; }
.vorlage-wahl > button.ghost .sub { display: block; font-size: 12px; color: var(--muted); font-weight: normal; }
.vorlage-frage { align-items: flex-start; margin-bottom: 10px; }
.vorlage-frage .compose-label { padding-top: 9px; }
.vorlage-frage-feld { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 4px; }
.vorlage-frage-feld > div > input, .vorlage-frage-feld input, .vorlage-frage-feld select, .vorlage-frage-feld textarea { width: 100%; margin: 0; box-sizing: border-box; }
.vorlage-fuss, .vorlage-betreff { margin-top: 10px; }
/* Das Platzhaltermenü steht außerhalb der Dialoge und über jedem von ihnen
   (Stufe 2 und 3), unter `modal-oben`. */
.mail-spaltenwahl.mail-platzhaltermenue { z-index: 53; }
.platzhalter-kennung { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; text-transform: uppercase; max-width: 260px; }
.platzhalter-kennung[readonly] { opacity: .7; cursor: not-allowed; }
.platzhalter-einheit { max-width: 140px; }
/* Der Editor als Tabelle: die Bezeichner in einer Spalte gleicher Breite,
   oben ausgerichtet, damit sie auch neben einem mehrzeiligen Feld an der
   ersten Zeile stehen. */
.platzhalter-editor .compose-zeile { align-items: flex-start; }
.platzhalter-editor .compose-label { flex: 0 0 140px; padding-top: 9px; }
.platzhalter-editor .compose-zeile > .check { padding-top: 7px; }
.platzhalter-editor .compose-zeile > .muted { padding-top: 8px; }
.platzhalter-editor .compose-zeile > span.muted { padding-top: 9px; }
.vorlage-zahl { display: flex; align-items: center; gap: 8px; }
/* Der Zeitwähler (`x-zeitwahl`): Feld und Uhr-Knopf in einer Reihe, die
   Liste als schwebendes Feld unter dem Knopf, über jedem Dialog. */
.zeitwahl { display: flex; align-items: center; gap: 6px; width: 100%; max-width: 100%; }
.zeitwahl > input { flex: 1 1 0; min-width: 0; width: auto; margin: 0; }
.zeitwahl-knopf { flex: none; }
.zeitwahl-menue {
    position: fixed; z-index: 57; padding: 6px; max-height: 280px; overflow-y: auto;
    display: grid; grid-template-columns: repeat(4, auto); gap: 2px;
    background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
    box-shadow: 0 10px 30px rgba(0, 0, 0, .35);
}
.zeitwahl-menue button.ghost { padding: 4px 8px; font-size: 13px; font-variant-numeric: tabular-nums; }
.zeitwahl-menue button.ghost.aktiv { background: var(--accent-fill); color: #fff; border-color: transparent; }
.vorlage-zahl input { flex: 1; min-width: 0; }
.mail-account-name code { font-size: 12px; margin-left: 4px; }
/* In den Platzhalterlisten: die Beschriftung hell, Kennung und Chips im
   helleren Grau der Nebentexte – die Beschriftung ist das, was man liest. */
.platzhalter-liste .mail-account-name code, .platzhalter-liste .mail-account-name .tag { color: var(--muted); }
.platzhalter-fest { gap: 2px; }
.platzhalter-fest .mail-account { padding: 4px 10px; }
.platzhalter-fest .mail-account-name { font-size: 14px; }
.ki-prompt { width: 100%; min-height: 120px; font: inherit; font-size: 13.5px; line-height: 1.5; margin: 0 0 8px; }
.ki-prompt-vorschau {
    white-space: pre-wrap; font-size: 12px; line-height: 1.45; padding: 10px 12px; margin: 0 0 8px;
    background: var(--panel-2); border: 1px solid var(--line); border-radius: var(--radius); max-height: 40vh; overflow: auto;
}
.mail-spaltenwahl.mail-signaturmenue { width: 320px; }
/* Ein leerer Platzhalter im Schreibfeld: gelb, mit dem Namen darin. Für
   den Schreibenden – der Versand entfernt das Span samt Inhalt. */
.crm-leer { background: #5a4a00; color: #ffe680; border-radius: 3px; padding: 0 3px; cursor: help; }
html[data-theme="light"] .crm-leer, .thema-hell .crm-leer { background: #fff3a8; color: #6b5200; }
/* In der Vorschau des Vorlageneditors: eine ersetzte Stelle in leichtem
   Grün; eine eingesetzte Vorgabe dazu mit gepunktetem Strich – ein Wert,
   nur ein vorläufiger. */
.crm-ersetzt { background: #1f4a2a; color: #c6f2d0; border-radius: 3px; padding: 0 3px; cursor: help; }
html[data-theme="light"] .crm-ersetzt, .thema-hell .crm-ersetzt { background: #dff5e3; color: #1d5a2a; }
.crm-vorgabe { border-bottom: 1px dotted currentColor; }
/* Die Vorschau im Vorlageneditor: sieht aus wie der Text, ist aber keiner. */
.vorlage-vorschau {
    border: 1px solid var(--line); border-radius: 8px; padding: 10px 12px;
    background: var(--bg); display: flex; flex-direction: column; gap: 6px;
}
.vorlage-vorschau-text { font-size: 14px; line-height: 1.5; overflow-x: auto; }
/* Beide stehen mittig (`menueMittig`) und sind damit kleine Dialoge: eine
   Kopfzeile mit Titel und Kreuz, damit man sie auch ohne „daneben tippen"
   zumacht – auf dem Telefon füllen sie fast den Schirm. Nie breiter als
   der Schirm. */
.mail-spaltenwahl.mail-platzhaltermenue, .mail-spaltenwahl.mail-vorlagenmenue, .mail-spaltenwahl.mail-signaturmenue { max-width: calc(100vw - 16px); }
.menue-kopf { display: flex; align-items: center; justify-content: space-between; gap: 8px; margin-bottom: 4px; }
.menue-kopf .label-like { margin: 0; }
.menue-kopf button.symbol { width: 28px; height: 28px; padding: 0; font-size: 18px; line-height: 1; }
@media (max-width: 640px) {
    .mail-account { flex-direction: column; }
    .mail-account-actions { width: 100%; }
}

/* Das Ergebnis des Verbindungstests. Zwei Zeilen, weil es zwei Wege gibt:
   Ein Postfach, das sich lesen, aber nicht beschicken lässt, ist ein
   häufiger Zustand – und einer, den eine einzelne Ampel verschweigen
   würde. Siehe PLANUNG-WEBMAIL.md, Abschnitt 2.6. */
.mail-probe {
    margin-top: 14px; padding: 12px 14px; border-radius: var(--radius);
    background: var(--panel-2); border: 1px solid var(--line);
    display: flex; flex-direction: column; gap: 8px;
}
.mail-probe-row { display: flex; gap: 10px; align-items: flex-start; font-size: 13px; }
.mail-probe-row.ok .mail-probe-mark { color: var(--ok); }
.mail-probe-row.bad .mail-probe-mark { color: var(--danger); }
.mail-probe-mark { font-weight: 700; flex: none; width: 1em; }

.modal-actions.inline { margin-top: 12px; align-items: center; flex-wrap: wrap; }

.mail-key-hint { border-color: var(--warn); }
.mail-key-example {
    margin: 10px 0 0; padding: 10px 12px; overflow-x: auto;
    background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
    font-size: 12px;
}

/* ---------- E-Mail: die drei Spalten ---------- */

/* ---------- Das Seitengerüst ----------
   Aufgebaut wie `.kal-seite`: eine Spalte, in der die Werkzeugzeile ihre
   Höhe behält und das Raster den Rest bekommt.

   Vorher stand am Raster `height: calc(100dvh - 190px)`. Die 190 waren
   geraten und stimmten nur, solange die Kopfzeile genau so hoch blieb wie
   an dem Tag, an dem die Zahl entstand – jeder Hinweis darüber (der
   fehlende Schlüssel, eine Störung im Postfach) schob das Raster unter
   den Rand. Eine Flex-Kette misst, statt zu raten. */
.mail-seite { display: flex; flex-direction: column; height: 100%; min-height: 0; }

.mail-seitenkopf {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    flex: none; padding: 0 0 12px;
}
.mail-titel { font-size: 18px; white-space: nowrap; }
/* Zahnrad und sein Menü stehen zusammen, wie Knopf und Menü beim Kontakt:
   Das Menü hängt am Fenster, aber `click.outside` braucht seinen Knopf
   in der Nähe – sonst zählte der Klick auf das Zahnrad als „außerhalb"
   und schlösse, was er gerade öffnen soll. */
.mail-adminknopf { display: inline-flex; position: relative; }
/* Dieselben Einträge wie im Kontaktmenü: Wort und Erklärung darunter.
   Schmaler als jenes – hier stehen zwei Zeilen, dort ganze Sätze. */
.mail-adminmenue { width: 268px; display: flex; flex-direction: column; gap: 2px; }
.mail-adminmenue > button {
    display: block; width: 100%; text-align: left; border: 0;
    padding: 8px 10px; border-radius: 8px; line-height: 1.35;
}
.mail-adminmenue > button:hover { background: var(--panel-2); }
.mail-adminmenue .sub { display: block; color: var(--muted); font-size: 12px; margin-top: 3px; }

/* Kein Postfach eingebunden: Der Knopf zum Anlegen steht in der leeren
   Fläche selbst. Ein Satz, der auf einen Knopf zeigt, während der Knopf
   danebenstehen könnte, ist ein Umweg. */
.mail-leer-tat {
    display: flex; flex-direction: column; align-items: center; gap: 8px;
    margin-top: 10px;
}
/* Ein Schalter, der zeigt, dass er steht – dieselbe Regel wie am
   Kalender. */
.mail-spalte-schalter.aktiv, .mail-seitenkopf .ghost.aktiv { color: var(--accent); }

/* Ordner | Liste | Nachricht. Die Ordnerspalte lässt sich ausblenden –
   zusammen mit der CRM-Navigation wären es sonst vier, und vier passen
   auf kein Notebook. Siehe PLANUNG-WEBMAIL.md, Abschnitt 7.1. */
.mail-layout {
    display: grid;
    /* Fünf Spalten: Ordner, Griff, Liste, Griff, Nachricht. Die Breiten
       kommen als Variablen aus der Komponente (siehe `rasterStil`), die
       Vorgaben stehen hier – so bleibt die Anzeige auch dann richtig,
       wenn nichts gesetzt ist. */
    grid-template-columns:
        var(--ordner-breite, 210px) var(--ordner-griff, 6px)
        var(--liste-breite, 320px) 6px
        1fr;
    /*
     * Die Ordnerspalte SCHIEBT, sie verschwindet nicht – wie die
     * Kalenderspalte, nur mit ziehbarer Breite und deshalb über die
     * Spurgröße statt über einen festen Rand.
     *
     * Der Uebergang setzt voraus, dass die Spurzahl gleich bleibt: Ein
     * Raster mit fünf Spuren lässt sich auf fünf Spuren überblenden,
     * auf drei nicht. Genau deshalb bleiben Ordnerspalte und Griff im
     * Baum und gehen nur auf null (`rasterStil` in mail.js).
     */
    transition: grid-template-columns .25s ease;
    gap: 0;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    flex: 1 1 auto;
    min-height: 380px;
}

/*
 * Während am Griff gezogen wird: kein Uebergang. Sonst liefe die Spalte
 * der Hand eine Viertelsekunde hinterher, und das Ziehen fühlte sich an,
 * als hänge es.
 */
.mail-layout.zieht { transition: none; }

/*
 * Zugeklappte Ordnerspalte. Die Breiten stehen in `rasterStil`; hier
 * bleiben die zwei Dinge, die eine Spalte von null Pixeln sonst noch
 * verrieten:
 *
 * 1. Die Polsterung. `box-sizing: border-box` kann eine Breite nicht
 *    unter Polsterung und Rahmen drücken – aus null wären 16 Pixel
 *    geworden, die über die Spur hinausragen.
 * 2. Der Tabulatorlauf. Von `overflow: hidden` abgeschnittene Knöpfe
 *    bleiben anspringbar – wer taktet, landete in einer Ordnerliste, die
 *    er nicht sieht. Und der Griff trägt `tabindex="0"`: Auf ihm hätten
 *    die Pfeiltasten eine Breite verschoben, die auf null festliegt –
 *    nichts bewegt sich, aber das Mass wird gemerkt.
 *
 *    `visibility: hidden` nimmt beide heraus, und zwar erst NACH dem
 *    Wegschieben (die Verzögerung von .25s), damit man das Zuklappen
 *    noch sieht. Beim Aufklappen greifen die Regeln an den Elementen
 *    selbst und schalten ohne Verzögerung zurück.
 *
 *    Es nimmt zugleich die Trefferfläche des Griffs weg. Die reicht drei
 *    Pixel nach jeder Seite und läge sonst als unsichtbarer Streifen am
 *    Rand der Liste, wo sie den Zeiger auf `col-resize` stellt, ohne dass
 *    da etwas zu ziehen wäre.
 *
 * Nicht `inert`: Alpine führt es nicht in seiner Liste der Ja/Nein-
 * Attribute und schriebe bei `false` ein `inert="false"` – und das sperrt
 * genauso, weil der Browser nur auf das Dasein des Attributs sieht.
 */
.mail-layout.ohne-ordner > .mail-folders {
    padding-left: 0; padding-right: 0;
    visibility: hidden;
    transition: padding .25s ease, visibility 0s linear .25s;
}
.mail-layout.ohne-ordner > .mail-splitter-ordner {
    visibility: hidden;
    transition: visibility 0s linear .25s;
}

/*
 * Nachricht UNTER der Liste.
 *
 * Aus fünf Spalten werden drei, und die dritte teilt sich in drei Reihen:
 * Liste, Griff, Nachricht. Die Ordner bleiben daneben stehen und reichen
 * über alle drei – sie gehören zu keiner der beiden Hälften.
 *
 * Die Zuordnung steht ausdrücklich (`grid-row`/`grid-column`) statt über
 * die Reihenfolge: Drei Spalten und drei Reihen ergeben neun Plätze, und
 * welcher davon der richtige ist, sagt keine Reihenfolge von selbst.
 *
 * Einen Sonderfall für die eingeklappte Ordnerspalte gibt es hier nicht
 * mehr. Sie steht dann auf null und bleibt an ihrem Platz – vorher
 * verschwand sie mit `display: none` aus dem Raster, und alles rutschte
 * um zwei Plätze, was mit vier weiteren Zeilen wieder eingefangen werden
 * musste.
 *
 * Das Ganze steht bewusst in einem `min-width`-Block: Darunter wird
 * ohnehin gestapelt, und dort dürfen weder die Reihen noch die feste
 * Höhe der Liste gelten. Ein `@media`-Block, der eine Regel gar nicht
 * erst aufstellt, ist verlässlicher als einer, der sie hinterher wieder
 * einfangen muss – zumal `.mail-layout.unten` schwerer wiegt als
 * `.mail-layout`.
 */
@media (min-width: 769px) {
    .mail-layout.unten {
        grid-template-columns: var(--ordner-breite, 210px) var(--ordner-griff, 6px) minmax(0, 1fr);
        /* `minmax(0, …)`, damit die Liste ihren Inhalt nicht als
           Mindesthöhe durchsetzt und die Reihe aufbläht. Dieselbe Regel
           wie `min-height: 0` in der Flex-Kette. */
        grid-template-rows: minmax(0, var(--liste-hoehe, 320px)) 6px minmax(0, 1fr);
    }
    .mail-layout.unten > .mail-folders         { grid-column: 1; grid-row: 1 / -1; }
    .mail-layout.unten > .mail-splitter-ordner { grid-column: 2; grid-row: 1 / -1; }
    .mail-layout.unten > .mail-list            { grid-column: 3; grid-row: 1; }
    .mail-layout.unten > .mail-splitter-liste  { grid-column: 3; grid-row: 2; }
    .mail-layout.unten > .mail-reader          { grid-column: 3; grid-row: 3; }
}

/*
 * Der Griff zwischen zwei Spalten.
 *
 * Er IST die Trennlinie – deshalb steht die Rasterfuge auf 0. Sechs
 * Pixel sind schmal genug, um wie eine Linie zu wirken, und breit genug,
 * um ihn zu treffen; die Kontaktfläche wächst über die Pseudo-Elemente
 * noch einmal nach beiden Seiten, ohne dass man das sieht.
 */
.mail-splitter {
    position: relative;
    background: var(--line);
    cursor: col-resize;
    touch-action: none;   /* sonst scrollt das Tablet, statt zu ziehen */
}
.mail-splitter::before {
    content: ''; position: absolute; top: 0; bottom: 0; left: -3px; right: -3px;
}
/* Waagerecht liegend: anderer Zeiger, andere Richtung für die
   unsichtbare Kontaktfläche. Die 6 Pixel sind hier eine Höhe. */
.mail-splitter.quer { cursor: row-resize; }
.mail-splitter.quer::before { left: 0; right: 0; top: -3px; bottom: -3px; }
.mail-splitter:hover, .mail-splitter:focus-visible { background: var(--accent); outline: none; }
/* Ohne Verzögerung zurück ins Bild – sonst bliebe der Griff nach dem
   Aufklappen eine Viertelsekunde unsichtbar. */
.mail-splitter-ordner { transition: visibility 0s; }
.mail-layout.zieht .mail-splitter { background: var(--accent); }

/*
 * Während des Ziehens: keine Textauswahl, und der Anzeigerahmen nimmt
 * keine Zeigerereignisse an.
 *
 * Das zweite ist der Punkt, an dem ein Spaltengriff sonst hakt: Ein
 * `iframe` ist ein eigenes Dokument. Wandert der Zeiger darüber, gingen
 * die Bewegungen dorthin und die Leiste bliebe stehen. `setPointerCapture`
 * fängt das ab, aber zusammen mit dieser Zeile ist es zuverlässig.
 */
.mail-layout.zieht { user-select: none; }
.mail-layout.zieht .mail-frame { pointer-events: none; }
.mail-folders, .mail-list, .mail-reader { background: var(--panel); min-width: 0; }
/* `overflow: hidden auto` und nicht nur `auto` für die Höhe: Zugeklappt
   ist die Spalte null breit, und was darin steht, muss waagerecht sauber
   abgeschnitten werden. Die Polsterung fährt im selben Takt wie die
   Spurbreite (siehe `.ohne-ordner` weiter oben). */
.mail-folders {
    padding: 10px 8px; overflow: hidden auto;
    transition: padding .25s ease, visibility 0s;
}
/* Dieselbe Regel wie beim Lesebereich: Nur EIN Teil scrollt – die Zeilen.
   Kopfzeile und Blätterleiste bleiben stehen. Mit `overflow-y: auto`
   hier UND an `.mail-rows` scrollte beides ineinander, und die
   Blätterleiste rutschte aus dem Blick. */
.mail-list { display: flex; flex-direction: column; padding: 0; overflow: hidden; }

/* Der Lesebereich ist eine Spalte, in der genau EIN Teil wächst: die
   Nachricht. Kopfzeile, Bildstreifen und Anhänge behalten ihre Höhe.

   `min-height: 0` steht hier nicht zur Zierde – ohne die Angabe nimmt ein
   Flex-Element als kleinste Höhe den Inhalt, und dann wächst die Spalte
   über ihren Behälter hinaus, statt innen zu scrollen. Das ist die
   Regel, die man an dieser Stelle einmal vergisst. */
/* Der Lesebereich SCROLLT – am Tisch wie auf dem Telefon. Die Nachricht ist
   ein Block: Werkzeuge, Betreff, Absender, Inhalt, Anhänge, am Stück wie ein
   Blatt Papier. Der Rahmen des Inhalts bekommt seine Höhe von der Messung
   (`rahmenStil`) und scrollt nicht in sich. Vorher scrollte am Tisch nur der
   Rahmen, und die Anhänge klemmten in einem Drittel darunter. Oben ohne
   Rand: Die Werkzeugleiste klebt an der Kante, ein Rand darüber wäre ein
   Schlitz, durch den der Inhalt durchscheint. */
.mail-reader {
    padding: 0 20px 18px;
    display: flex; flex-direction: column;
    min-height: 0; overflow-y: auto; overflow-x: hidden;
}
.mail-message { display: block; flex: none; }
/* Die Nachricht als helle Karte: innen ein Rand, damit Betreff und Kopf
   nicht an der Kante kleben. Die Werkzeugleiste darüber (`thema-seite`)
   bleibt bei der Seite und läuft über die volle Breite – deshalb hebt sie
   den Rand mit negativen Rändern wieder auf. */
.mail-message.thema-hell { padding: 0 14px 14px; border-radius: 10px; }
/* Die Werkzeugleiste steht über der Karte, nicht darin; die Knöpfe der
   Nachricht sind eine Gruppe darin (`display: contents` – sie reihen sich
   wie direkte Kinder). Ohne offene Nachricht ist die Leiste weg – am
   Tisch stünde sonst ein leerer Streifen über „Keine Nachricht
   ausgewählt". Im Nachrichtenfenster gibt es die Klasse `liest` nicht;
   dort steht die Leiste immer. */
/* `flex: none`: Die Leiste ist ein Flex-Kind der Leserspalte und würde
   sonst auf ihre Mindesthöhe gestaucht, sobald die Nachricht länger ist
   als die Spalte – umgebrochene Knöpfe ragten dann unten heraus, statt
   dass die Leiste zweizeilig würde. Gemessen. */
.mail-reader > .mail-werkzeuge.thema-seite { flex: none; margin: 0 0 12px; padding: 12px 0 10px; }
.mail-werkzeuge-nachricht { display: contents; }
body:not(.nachrichtenfenster) .mail-seite:not(.liest) .mail-reader > .mail-werkzeuge { display: none; }
/* Die Werkzeuge bleiben oben stehen, wenn die Nachricht darunter
   wegrollt – Antworten und Weiterleiten sind immer in Reichweite. Der
   Grund ist die Seitenfarbe, sonst schiene der Inhalt durch. */
/* Der Grund der Leiste ist der der Leseansicht (`--panel`), nicht der
   Seitengrund (`--bg`): Als klebende Leiste braucht sie einen eigenen
   Grund, damit die Nachricht darunter durchrollt – aber denselben wie die
   Fläche, auf der sie liegt, sonst steht ein dunkler Balken über dem
   helleren Bereich. */
.mail-werkzeuge.thema-seite { position: sticky; top: 0; z-index: 3; background: var(--panel); }

.mail-folder-group { margin-bottom: 10px; }
/* Vertretene Postfächer (PLANUNG-MAIL-VERTRETER.md): die Überschrift vor
   dem ersten, eine Linie darüber wie unter den Sammelordnern; der Inhaber
   klein hinter dem Kontonamen. */
.mail-account-group {
    margin: 12px 0 4px; padding: 8px 8px 0; border-top: 1px solid var(--line);
    color: var(--muted); font-size: 10px; text-transform: uppercase; letter-spacing: .6px;
}
.mail-account-inhaber { text-transform: none; letter-spacing: 0; opacity: .75; white-space: nowrap; }
/* Der Streifen über einer Nachricht aus einem vertretenen Postfach: ein
   Hinweis, keine Warnung – es ist gewollt. */
.mail-vertreten-hinweis {
    margin: 4px 0 6px; padding: 4px 8px; border-left: 3px solid var(--accent);
    background: var(--accent-soft, rgba(68, 98, 216, .08)); color: var(--muted); font-size: 12px;
}
.mail-vertreten-titel { margin-top: 16px; }
/* Der Block „Alle Postfächer" über den Konten: derselbe Bau wie ein
   Konto, ohne Pfeil – und eine Linie darunter, die ihn absetzt. */
.mail-sammel { padding-bottom: 8px; border-bottom: 1px solid var(--line); margin-bottom: 12px; }
.mail-sammel .mail-ordner-zeile { padding-left: 8px; }
/* Zweizeilig im Sammelordner: das Konto klein hinter dem Absender. */
.mail-konto { flex: none; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--muted); }
.mail-row.active .mail-konto { color: rgba(255,255,255,.75); }
.mail-zelle.sp-postfach { color: var(--muted); font-size: 12px; }
.mail-account-head {
    display: flex; align-items: center; gap: 6px; width: 100%;
    background: none; border: 0; padding: 5px 8px; cursor: pointer;
    color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .5px;
}
.mail-account-head:hover { color: var(--text); background: none; }
/* Der Winkel vor dem Konto: dasselbe Zeichen wie vor dem Ordner, damit
   „hier klappt etwas auf" überall gleich aussieht. Zugeklappt zeigt er
   nach rechts, aufgeklappt nach unten. */
.mail-caret { flex: none; width: 16px; height: 16px; display: inline-flex; align-items: center; justify-content: center; }
.mail-caret svg { width: 16px; height: 16px; transition: transform .15s ease; }
.mail-caret.offen svg { transform: rotate(90deg); }
/*
 * Eine Zeile im Ordnerbaum: Pfeil, dann der Ordner. Die Zeile trägt
 * Hintergrund und Auswahl – nicht der Knopf –, damit Pfeil und Name wie
 * EIN Eintrag aussehen. Die Einrückung kommt aus `--tiefe`, die die
 * Vorlage je Zeile setzt: 14 Pixel je Ebene, beliebig tief.
 */
.mail-ordner-zeile {
    display: flex; align-items: center; border-radius: 7px;
    padding-left: calc(4px + var(--tiefe, 0) * 14px);
}
.mail-ordner-zeile:hover { background: var(--panel-2); }
.mail-ordner-zeile.active { background: var(--accent-fill); color: #fff; }
/* Die Knöpfe darin färben sich nie selbst ein. `button:hover` (Zeile oben
   im Stilblatt, die Signalfarbe) wiegt mehr als `background: none` an der
   Klasse – beim Überfahren und auf dem Tablet nach dem Tippen standen
   Einrückung und Name dann als zwei eigene Blöcke da, im hellen Thema
   dunkel und mit unlesbarer Schrift. Die Zeile trägt die Markierung. */
.mail-folder:hover, .mail-ordner-pfeil:hover { background: none; }
/* Der Pfeil: ein Winkel nach rechts, aufgeklappt nach unten gedreht.
   Ohne Kinder bleibt sein Platz, der Winkel nicht – so stehen die Namen
   einer Ebene untereinander, ob mit Unterordnern oder ohne. */
.mail-ordner-pfeil {
    flex: none; width: 24px; height: 30px; padding: 0; margin: 0;
    display: inline-flex; align-items: center; justify-content: center;
    background: none; border: 0; border-radius: 6px; color: var(--muted); cursor: pointer;
}
.mail-ordner-pfeil svg { width: 16px; height: 16px; transition: transform .15s ease; }
.mail-ordner-pfeil.offen svg { transform: rotate(90deg); }
.mail-ordner-pfeil.leer { cursor: default; }
.mail-ordner-pfeil.leer svg { visibility: hidden; }
.mail-ordner-pfeil:not(.leer):hover { color: var(--text); background: rgba(0,0,0,.06); }
.mail-ordner-zeile.active .mail-ordner-pfeil { color: #fff; }
.mail-folder {
    display: flex; align-items: center; gap: 8px; flex: 1 1 auto; min-width: 0;
    background: none; border: 0; padding: 6px 10px 6px 0; cursor: pointer;
    color: inherit; font-size: 13.5px; text-align: left;
}
.mail-folder-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail-folder-count {
    flex: none; font-size: 11px; padding: 0 6px; border-radius: 999px;
    background: var(--panel-2); color: var(--muted);
}
/* Die Zahl schließt Verborgenes ein: gedämpft, denn sie ist eine Summe,
   keine Angabe zu diesem Ordner allein. */
.mail-folder-count.unten { border: 1px dashed var(--muted); background: none; }
.mail-ordner-zeile.active .mail-folder-count { background: rgba(0,0,0,.3); color: #fff; border-color: transparent; }
.mail-folder-empty { padding: 4px 22px; }

.mail-list-head {
    display: flex; align-items: center; gap: 10px; flex: none;
    padding: 10px 12px; border-bottom: 1px solid var(--line);
}
/*
 * Was nachgibt, wenn es eng wird – und was nie.
 *
 * Die Zeile trägt vier Knöpfe, seit das Spaltenmenü hier steht. Bei der
 * Vorgabebreite der Liste (320 Pixel) passten drei gerade so; der vierte
 * wurde von `.mail-list { overflow: hidden }` abgeschnitten, ohne dass
 * etwas darauf hinwies. Ein Knopf, der nicht da ist, ist kein Knopf.
 *
 * Deshalb: Die Knöpfe behalten ihr Maß. Der Zähler gibt zuerst nach
 * (`flex-shrink: 100`, er ist die entbehrlichste Angabe), danach der
 * Ordnername – beide mit Auslassung statt Umbruch, sonst wüchse die
 * Zeile in die Höhe und die Liste rutschte darunter weg.
 */
/* Ordner und Anzahl oben, das Postfach darunter – der Block gibt nach,
   wenn es eng wird, die Knöpfe daneben nicht. */
.mail-list-titel { flex: 0 1 auto; min-width: 0; }
.mail-list-titelzeile { display: flex; align-items: baseline; gap: 10px; min-width: 0; }
.mail-list-titelzeile > strong {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mail-list-titelzeile > .muted {
    flex: 0 100 auto; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mail-list-konto { margin-top: 1px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mail-list-head > button, .mail-list-head > .mail-kopf-menue { flex: none; }
/* `0 1 auto`, nicht `1 1 auto`: Die Zeilen dürfen SCHRUMPFEN (dann
   scrollen sie innen), aber nicht wachsen. Mit `1` nahmen sie die ganze
   Resthöhe, und auf einer halbvollen Seite – der letzten, meist – stand
   die Blätterleiste am unteren Rand, mit einem leeren Block zwischen ihr
   und der letzten Zeile. Jetzt folgt sie der letzten Zeile; was darunter
   frei bleibt, ist einfach Fläche. */
.mail-rows { flex: 0 1 auto; min-height: 0; overflow-y: auto; }
/* Die Zeilen kommen aus dem Speicher, der Server ist gefragt: leicht
   zurückgenommen, bis seine Antwort sie ersetzt. */
.mail-rows.prueft { opacity: .7; transition: opacity .15s; }

/* Zwei Zeilen je Eintrag, wie in Apple Mail: Absender und Datum oben,
   Betreff darunter. Ungelesen bekommt Punkt und fetteren Absender. */
.mail-row {
    padding: 10px var(--mail-rand); border-bottom: 1px solid var(--line); cursor: pointer;
    display: flex; flex-direction: column; gap: 3px;
    /* Doppelklick öffnet das Fenster – und markierte sonst ein Wort im
       Betreff. Eine Zeile ist ein Knopf, kein Text zum Kopieren. */
    user-select: none;
}
.mail-row:hover { background: var(--panel-2); }
.mail-row.active { background: var(--accent-fill); color: #fff; }
.mail-row.active .mail-date, .mail-row.active .mail-subject { color: rgba(255,255,255,.85); }
.mail-row-top { display: flex; align-items: center; gap: 8px; }
.mail-from { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13.5px; }
.mail-row.unseen .mail-from { font-weight: 700; }
.mail-date { flex: none; font-size: 11.5px; color: var(--muted); }
.mail-subject {
    font-size: 13px; color: var(--muted);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.mail-row.unseen .mail-subject { color: var(--text); }
/* Der Punkt ist zugleich der Schalter für gelesen/ungelesen – derselbe
   Griff wie in Apple Mail, und er erspart ein Menü. */
.mail-dot {
    flex: none; width: 9px; height: 9px; border-radius: 50%;
    background: var(--accent); cursor: pointer;
}
.mail-row.active .mail-dot { background: #fff; }
/* An gelesenen Zeilen bleibt der Punkt unsichtbar und tritt erst beim
   Überfahren hervor: Er ist dort ein Angebot, kein Zustand. Der Platz
   bleibt trotzdem belegt, damit die Zeilen nicht springen. */
.mail-dot.gelesen { background: transparent; box-shadow: inset 0 0 0 1px var(--muted); opacity: 0; }
.mail-row:hover .mail-dot.gelesen { opacity: .7; }
.mail-dot.gelesen:hover { opacity: 1; }
/* Beantwortet: der Pfeil an der Stelle des Punkts, immer sichtbar – in
   beiden Ansichten. Ungelesen UND beantwortet (selten, nach „als
   ungelesen markieren") zeigt der Pfeil in der Signalfarbe. */
.mail-dot.beantwortet {
    width: 13px; height: 13px; border-radius: 0; background: transparent; box-shadow: none;
    opacity: 1; color: var(--muted); display: inline-flex; align-items: center; justify-content: center;
}
.mail-dot-svg { width: 13px; height: 13px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round; }
.mail-dot.beantwortet:not(.gelesen) { color: var(--accent); }
.mail-row.active .mail-dot.beantwortet { background: transparent; color: rgba(255,255,255,.9); }
.mail-dot.beantwortet:hover { opacity: 1; color: var(--text); }

.mail-reader-head {
    flex: none;
    border-bottom: 1px solid var(--line); padding-bottom: 12px; margin-bottom: 14px;
}
.mail-reader-head h2 { font-size: 18px; margin-bottom: 6px; }
/* Reiner Text in Etappe 2: umbrechen, aber Absätze und Einrückung
   erhalten – ein Angebot mit Tabelle wird sonst unlesbar. */
.mail-body {
    flex: none; min-height: 0; overflow-y: visible;
    white-space: pre-wrap; word-break: break-word; margin: 0;
    font: inherit; font-size: 13.5px; line-height: 1.6;
}
.mail-html-hint, .mail-attach-hint {
    margin-top: 16px; padding: 10px 12px; border-radius: 8px;
    background: var(--panel-2); border: 1px solid var(--line); font-size: 12.5px;
}


/* Eine Störung im Postfach – bleibt stehen, bis sie behoben ist. Der
   Wortlaut der Gegenstelle steht darunter zum Aufklappen: Er ist für die
   Fehlersuche das Wertvollste, was es gibt, und in der Hauptmeldung wäre
   er im Weg. */
.mail-trouble { border-color: var(--danger); margin-bottom: 12px; }
.mail-trouble h3 { color: var(--danger); }
.mail-trouble p { margin: 6px 0 10px; }
.mail-trouble-detail {
    margin: 10px 0 0; padding: 10px 12px; overflow-x: auto;
    background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
    font-size: 12px; white-space: pre-wrap; word-break: break-word;
}

/* ---------- E-Mail: die Nachricht selbst ---------- */

/* Der Anzeigerahmen für fremdes HTML. Feste Höhe mit eigenem Bildlauf:
   Ein iframe weiß nicht, wie groß sein Inhalt ist, und ohne Skript darin
   – das ist ja der Punkt – kann er es auch nicht melden. */
/* Der Anzeigerahmen füllt, was übrig bleibt.

   Vorher stand hier `height: 60vh` – eine Zahl, die zur Fensterhöhe
   passte und nicht zum Behälter. Je größer das Fenster, desto mehr
   Leerraum blieb darunter stehen. Ein iframe weiß nicht, wie hoch sein
   Inhalt ist, und ohne Skript darin – das ist ja der Punkt – kann er es
   auch nicht melden; also bekommt er den Platz zugeteilt und scrollt
   innen. Genauso hält es Apple Mail. */
.mail-frame {
    flex: none;
    /* Ohne Messung ein festes Maß mit eigenem Bildlauf – die Messung
       (`rahmenStil`) ersetzt es durch die Höhe des Inhalts. */
    width: 100%; height: 60vh; min-height: 0;
    /* Ohne Rand: Die gemessene Inhaltshöhe wird zur RAHMENhöhe
       (`box-sizing: border-box`), und zwei Pixel Rand wären zwei Pixel
       Bildlauf im Rahmen. Die weiße Karte darum herum trennt genug. */
    border: 0; border-radius: 0;
    background: #fff;
}

/* Fremde Post im Nachrichtenfenster: die Zeile über der Nachricht, die
   sagt, aus welchem Postfach sie kommt und was hier geht. Warnfarbe wie
   der Bilderstreifen – eine Entscheidung des Inhabers, kein Fehler. */
.mail-fremd-hinweis {
    margin-top: 8px; padding: 6px 10px; border-radius: 8px; font-size: 12.5px;
    background: var(--panel-2); border: 1px solid var(--warn); color: var(--text);
}
.mail-antwort-als { max-width: 240px; font-size: 12.5px; padding: 3px 6px; }
.compose-vertretung { font-size: 12.5px; color: var(--warn); }
.mail-vertretung.aus { opacity: .55; }

/* Der Streifen über gesperrten Bildern. Warnfarbe, aber kein Alarm: Es
   ist kein Fehler, sondern eine Entscheidung, die dem Anwender gehört. */
.mail-images-bar {
    flex: none;
    display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
    margin-bottom: 10px; padding: 8px 12px; border-radius: 8px;
    background: var(--panel-2); border: 1px solid var(--warn);
    font-size: 12.5px;
}

/* Anhänge stehen unter der Nachricht und nehmen ihr keinen Platz weg:
   feste Höhe nach Bedarf, aber nie mehr als ein Drittel. */
/* Die Anhänge über der Nachricht, unter den Werkzeugen: ein Kopf zum
   Klappen, darunter die Zeilen. Zugeklappt bleibt der Kopf eine Zeile mit
   den Namen. */
.mail-attachments { flex: none; margin: 0 0 12px; }
.mail-attach-head {
    display: flex; align-items: center; gap: 6px; width: 100%; min-width: 0;
    background: none; border: 0; padding: 4px 0; margin-bottom: 6px; cursor: pointer;
    font-size: 11px; text-transform: uppercase; letter-spacing: .5px; color: var(--muted);
    text-align: left;
}
/* Kein Farbwechsel beim Überfahren oder Antippen: Die allgemeine Regel
   `button:hover` malte den Kopf blau – und auf dem iPhone bleibt :hover
   nach dem Tippen stehen. In der hellen Karte war die Schrift damit
   unlesbar. Der Winkel sagt, dass hier etwas klappt. */
.mail-attach-head:hover, .mail-attach-head:active, .mail-attach-head:focus {
    background: none; color: var(--muted);
}
.mail-attach-head { -webkit-tap-highlight-color: transparent; }
.mail-attach-head:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.mail-attach-winkel { width: 14px; height: 14px; flex: none; transform: rotate(90deg); transition: transform .15s ease; }
.mail-attachments.zu .mail-attach-winkel { transform: none; }
.mail-attachments.zu .mail-attach-head { margin-bottom: 0; }
.mail-attach-kurz {
    flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    text-transform: none; letter-spacing: 0; font-size: 12px; margin-left: 4px;
}
.mail-attach {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 12px; margin-bottom: 6px; border-radius: 8px;
    background: var(--panel-2); border: 1px solid var(--line);
    color: var(--text); text-decoration: none; font-size: 13px;
}
.mail-attach:hover { border-color: var(--accent); }
/* Zwei Wege in einer Zeile: der Name (ansehen oder laden) und der Pfeil
   (immer laden). Der Name füllt die Zeile, der Pfeil steht am Rand. */
.mail-attach-name-link { display: flex; align-items: center; gap: 8px; flex: 1; min-width: 0; color: inherit; text-decoration: none; }
.mail-attach-download { flex: none; width: 28px; height: 28px; padding: 0; margin-left: 4px; }

/* Der Betrachter der installierten App (PLANUNG-MAIL-ANHAENGE.md, B):
   Vollbild über allem, eine Leiste oben – mit der Safe-Area des
   Telefons, wie die Kopfleiste –, darunter der Anhang. Der Inhalt
   scrollt in beide Richtungen und lässt sich mit zwei Fingern zoomen. */
.mail-anhang-vollbild {
    position: fixed; inset: 0; z-index: 90;
    display: flex; flex-direction: column;
    background: var(--bg); color: var(--text);
}
.mail-anhang-leiste {
    flex: none; display: flex; align-items: center; gap: 8px;
    padding: 8px 12px; border-bottom: 1px solid var(--line); background: var(--panel);
    padding-top: calc(8px + env(safe-area-inset-top));
}
.mail-anhang-leiste .rueckweg { width: auto; padding: 0 10px; white-space: nowrap; }
.mail-anhang-titel { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; }
.mail-anhang-inhalt {
    flex: 1; min-height: 0; overflow: auto; -webkit-overflow-scrolling: touch;
    touch-action: pan-x pan-y pinch-zoom;
    padding-bottom: env(safe-area-inset-bottom);
}
.mail-anhang-inhalt.art-bild { display: flex; align-items: center; justify-content: center; background: #111; }
.mail-anhang-inhalt img { max-width: 100%; max-height: 100%; object-fit: contain; }
.mail-anhang-pdf { padding: 8px; display: flex; flex-direction: column; align-items: center; gap: 8px; min-width: min-content; }
.mail-anhang-seite { background: #fff; box-shadow: 0 1px 4px rgba(0,0,0,.35); flex: none; }
.mail-anhang-seite canvas { display: block; }
.mail-anhang-pdf-werkzeuge { display: inline-flex; align-items: center; gap: 4px; }
.mail-anhang-pdf-werkzeuge .icon-btn { width: 30px; height: 30px; font-size: 18px; line-height: 1; }
.mail-anhang-text { padding: 12px; }
.mail-anhang-text pre { white-space: pre-wrap; word-break: break-word; font-size: 13px; margin: 0; }
.mail-anhang-tabelle th, .mail-anhang-tabelle td { white-space: nowrap; }
/* Die CSV bleibt auf dem Telefon eine Tabelle – die Kartenansicht der
   Datentabellen (data-label vor dem Wert) wäre hier eine Liste ohne
   Überschriften. Sie scrollt waagerecht in ihrem Rahmen. */
@media (max-width: 700px) {
    table.data.mail-anhang-tabelle thead { display: table-header-group; }
    table.data.mail-anhang-tabelle { display: table; width: auto; min-width: 100%; }
    table.data.mail-anhang-tabelle tbody { display: table-row-group; }
    table.data.mail-anhang-tabelle tr { display: table-row; padding: 0; border-bottom: 0; }
    table.data.mail-anhang-tabelle td { display: table-cell; width: auto; padding: 6px 10px; border-bottom: 1px solid var(--line); }
    table.data.mail-anhang-tabelle td::before { content: none; }
    table.data.mail-anhang-tabelle td:empty { display: table-cell; }
}
.mail-attach-icon { flex: none; }
.mail-attach-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Die Blätterleiste der Nachrichtenliste steht unter der letzten Zeile
   (bei einer vollen Seite ist das der untere Rand) und scrollt nicht mit. Mittig,
   nicht rechtsbündig wie unter der Kontakttabelle: Die Spalte ist 320
   Pixel breit, die Leiste bricht dort in zwei Zeilen – rechtsbündig
   stünde die zweite Zeile versetzt unter der ersten. */
.mail-list .pager {
    flex: none; border-top: 1px solid var(--line); padding: 8px 12px; margin: 0;
    justify-content: center;
}

/* Die Erläuterungen im Einstellungsdialog stehen unter ihrer Wahl und
   eingerückt: Sie gehören zur Zeile darüber, nicht zur nächsten. */
.mail-setting-hint { margin: 2px 0 12px 26px; line-height: 1.5; }

/* Die Post in der Akte sieht aus wie die Postfachliste: derselbe Kopf,
   dieselben Zeilen (`.mail-kopf`, `.mail-row`, `.mail-zelle` – siehe den
   Mailabschnitt). Nur die Maße stehen hier noch einmal, weil sie dort an
   `.mail-list` hängen: Vorne steht statt Kästchen und Punkt der Pfeil.
   Die Karte außen wie im Reiter „Gruppen", innen bündig. */
.panel-card.mail-akte {
    --mail-rand: 14px;
    --mail-luecke: 10px;
    --mail-richtung: 16px;
    --mail-vorspann: calc(var(--mail-richtung) + var(--mail-luecke));
    padding: 0; overflow: hidden;
}
.panel-card.mail-akte > .panel-head { padding: 14px 16px 12px; margin-bottom: 0; }
.panel-card.mail-akte .empty { padding: 22px 16px; }
.mail-akte .mail-richtung {
    flex: 0 0 var(--mail-richtung); text-align: center;
    color: var(--muted); font-size: 12px; line-height: 1.5;
}
.mail-akte .mail-zelle.sp-postfach { color: var(--muted); font-size: 12px; }
/* Die Adresse des Kontakts – in welcher Spalte sie auch steht. */
.mail-akte .ist-kontakt { font-weight: 600; }
.mail-akte .mail-anhang { flex: none; font-size: 12px; }
.mail-akte .mail-postfach { color: var(--muted); font-size: 12px; }
/* Post aus einem anderen Postfach lässt sich nicht öffnen – die Zeile
   ist dann kein Knopf, und der Tooltip sagt, warum. */
.mail-akte .mail-row.nicht-offen { cursor: default; color: var(--muted); }
.mail-akte .mail-row.nicht-offen:hover { background: none; }
/* Ein Eintrag ist Zeile plus aufgeklappte Nachricht. Der Trennstrich
   sitzt am Eintrag: An der Zeile liefe er quer durch den Leser. */
.mail-akte-eintrag { border-bottom: 1px solid var(--line); }
.mail-akte-eintrag:last-child { border-bottom: 0; }
.mail-akte .mail-row { border-bottom: 0; }
.mail-akte-eintrag.offen > .mail-row { background: var(--panel-2); }

/*
 * Die Nachricht in der Akte: ein Schirm hoch, unter ihrer Zeile.
 *
 * Kopf und Knöpfe stehen fest, gescrollt wird nur der Inhalt – wer eine
 * lange Mail liest, verliert sonst den Betreff und den Weg zurück.
 */
.post-leser {
    display: flex; flex-direction: column;
    /*
     * So hoch wie die Nachricht – und nie höher als der Schirm.
     *
     * Ein festes Maß ließ unter einer kurzen Mail den Rest der Box grau
     * stehen: Drei Zeilen Text, darunter ein halber Bildschirm Nichts.
     * Als Deckel statt als Maß wächst der Kasten mit seinem Inhalt und
     * hört am Schirmrand auf – erst dort beginnt der Inhalt zu rollen
     * (weiter unten `flex: 1 1 auto` und `min-height` null).
     *
     * `dvh` und nicht `vh`: Auf dem Telefon zählt der Schirm ohne die
     * Leisten des Browsers, sonst stünde das untere Ende darunter.
     */
    max-height: 100dvh;
    border-top: 1px solid var(--line);
    background: var(--panel-2);
}
/* Wer es so eingestellt hat, nimmt den Deckel ab: Der Kasten wächst mit
   der Nachricht, auch über den Schirm hinaus, und gerollt wird die Liste.
   Der Inhalt rollt dann nicht mehr für sich – es gibt nichts zu rollen. */
.post-leser.waechst { max-height: none; }
.post-leser-kopf {
    flex: none; padding: 10px var(--mail-rand) 8px;
    border-bottom: 1px solid var(--line);
}
.post-leser-titel { display: flex; align-items: flex-start; gap: 8px; }
/* Der Betreff darf umbrechen – anders als in der Zeile, wo er kürzt:
   Hier ist er die Überschrift dessen, was man gerade liest. Er gibt nach,
   die Knöpfe nicht: Sie sind der einzige Weg zu Antwort und Rückweg. */
.post-leser-betreff { flex: 1; min-width: 0; font-weight: 600; line-height: 1.35; }
/* Die Handlungen in der Kopfzeile, links vom Kreuz – eng gesetzt, damit
   auf dem Telefon vier Sinnbilder und das Kreuz nebeneinander Platz
   haben, ohne dem Betreff die Zeile zu nehmen. */
.post-leser-knoepfe { flex: none; display: flex; align-items: center; gap: 2px; }
.post-leser-knoepfe .icon-btn { padding: 4px 5px; }

/*
 * Auf der Startseite steht der Leser in einer Tabellenzeile über alle vier
 * Spalten – in einer Tabelle gibt es keinen anderen Platz dafür. Die Zelle
 * gibt ihren Innenrand ab, der Leser bringt seinen eigenen mit.
 */
/*
 * Der Lesebereich des Postfachs als Dialog (Suche über alles).
 *
 * Er ist als Spalte eines Rasters gestaltet; in einer Hülle braucht er
 * deshalb zweierlei. Erstens muss er sich der Hülle fügen, statt eine
 * eigene Höhe zu setzen: `.modal-box` deckelt schon auf 90dvh und ist
 * selbst eine Flex-Spalte – dieselbe Lehre wie beim aufgeklappten Leser.
 *
 * Zweitens muss er hier IMMER innen rollen. Im Telefonblock steht
 * `.mail-reader { overflow: visible }`, weil dort die Seite rollt und
 * nicht der Bereich; in einem Dialog gibt es keine Seite, die das
 * übernähme – der Inhalt liefe unten aus der Hülle heraus. Zwei Klassen
 * wiegen schwerer als eine, deshalb greift das unabhängig davon, wo im
 * Stilblatt die Regeln stehen.
 */
.modal-box.mail-leser-dialog {
    padding: 0; overflow: hidden;
    width: min(1000px, calc(100vw - 40px));
}
.mail-leser-dialog .mail-reader {
    flex: 1 1 auto; min-height: 0;
    max-height: none; overflow-y: auto;
    padding: 0 16px 16px;
}

/*
 * Als Dialog: Der Kasten bringt seinen Rand selbst mit, die Hülle gibt
 * ihren ab. Breit wie der Schreibdialog, damit eine Nachricht nicht in
 * einer Spalte steht.
 */
.modal-box.post-leser-dialog {
    padding: 0; overflow: hidden;
    width: min(900px, calc(100vw - 40px));
}
/*
 * Der Leser FÜLLT die Hülle – er bekommt hier KEINE eigene Höhe.
 *
 * `.modal-box` deckelt bereits auf 90dvh und ist selbst eine Flex-Spalte.
 * Eine zweite Zahl daneben rechnet an dieser Grenze vorbei: Gemessen ragte
 * der Leser 36 Pixel über den Kasten hinaus, und dessen `overflow: hidden`
 * schnitt ihm unten die Nachricht ab – lautlos.
 *
 * Damit gilt auch „so hoch wie die Nachricht" hier nicht, und das ist
 * richtig so: Im Dialog gibt es keine Liste, die rollen könnte; was über
 * den Schirm hinauswüchse, wäre nicht mehr erreichbar. Die Einstellung
 * wirkt dort, wo sie kann – in Akte und Startseite.
 */
.post-leser-dialog .post-leser,
.post-leser-dialog .post-leser.waechst {
    max-height: none; flex: 1 1 auto; min-height: 0; border-top: 0;
}

.post-leser-zeile > td { padding: 0; }
.mail-heute-tabelle tbody.offen > tr.clickable > td { background: var(--panel-2); }
@media (max-width: 700px) {
    /* Der Telefonblock weiter oben macht aus jeder Zeile dieser Tabelle ein
       Raster mit zwei Spalten und aus jeder Zelle eine Zeile mit
       „…"-Kürzung. Für die Leserzeile gilt beides nicht: Sie ist EINE Zelle
       mit einer ganzen Nachricht darin. Schwerer gewichtet statt später –
       so hängt es nicht an der Reihenfolge im Stilblatt. */
    table.mail-heute-tabelle tr.post-leser-zeile { display: block; padding: 0; }
    table.mail-heute-tabelle tr.post-leser-zeile > td {
        display: block; width: auto;
        white-space: normal; overflow: visible; text-overflow: clip;
    }
}
.post-leser-inhalt {
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    padding: 10px var(--mail-rand) 14px;
}
/* Die Nachricht selbst ist hell – sie ist für weißen Grund geschrieben.
   Das gilt für den Rahmen wie für den reinen Text daneben. */
.post-leser .mail-frame, .post-leser .mail-body {
    display: block; width: 100%; border: 0; border-radius: 8px; background: #fff;
}
/*
 * Nur der Platzhalter, bis die Höhe gemessen ist (`postRahmenGemessen`
 * setzt sie als Stil am Rahmen und schlägt diese Regel).
 *
 * Ohne ihn gälte das Maß aus dem Postfach – dort 60vh, am Telefon 70vh –,
 * und der Kasten ginge bei JEDER Nachricht über drei Viertel Schirm auf,
 * um danach auf ihre wahre Höhe zusammenzufallen. Klein anfangen und
 * wachsen ist das ruhigere von beidem.
 */
.post-leser .mail-frame { height: 220px; }
.post-leser .mail-body { color: #000; padding: 12px; margin: 0; }
.post-leser-anhaenge { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 8px; }
.post-leser-anhang {
    display: inline-flex; align-items: center; gap: 6px;
    padding: 4px 8px; border: 1px solid var(--line); border-radius: 999px;
    color: inherit; text-decoration: none; max-width: 100%;
}
.post-leser-anhang:hover { background: var(--panel); }
.post-leser-anhang-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Der Punkt vor dem Absender auf der Startseite: derselbe Griff wie in
   der Postfachliste, hier immer sichtbar – eine gelesene Zeile bleibt
   grau stehen, damit sich der Klick zurücknehmen lässt. */
.mail-heute-tabelle .mail-dot { display: inline-block; vertical-align: middle; margin-right: 8px; }
.mail-heute-tabelle .mail-dot.gelesen { opacity: .7; }
.mail-heute-tabelle tr.gelesen td { opacity: .55; }
.mail-heute-tabelle tr.gelesen td .mail-dot { opacity: 1; }
/* Zweizeilig steht „Sortiert nach" in einer breiten Karte, nicht in der
   schmalen Liste des Postfachs: Das Feld nimmt nur, was es braucht. */
.mail-akte .mail-kopf-einfach .tiny { white-space: nowrap; }
.mail-akte .mail-kopf-einfach select.mini { flex: none; width: auto; margin: 0; }
.mail-akte .pager {
    border-top: 1px solid var(--line); padding: 8px 12px; margin: 0;
    justify-content: center;
}
.mail-akte .mail-filter button { display: inline-flex; align-items: center; gap: 5px; }
.mail-akte .mail-filter svg { display: block; }
.mail-akte-je-seite select { margin: 0; padding: 4px 8px; font-size: 12.5px; }
.panel-card.mail-akte > .panel-head { gap: 8px; flex-wrap: wrap; }

/* Empfangen/Gesendet: eine Reihe kleiner Knöpfe in der Kopfzeile. */
.mail-filter { display: flex; gap: 6px; flex-wrap: wrap; }
.mail-filter .count { opacity: .65; margin-left: 4px; font-variant-numeric: tabular-nums; }
.mail-filter .aktiv {
    background: var(--panel-2); border-color: var(--accent); color: var(--text);
}

/* Der Dublettenhinweis im Kontaktdialog: eine Feststellung, keine Warnung.
   „Den gibt es schon" ist kein Fehler des Anwenders. */
/* Ein Knopf mit Pfeilchen – beide Wege stehen im Menü, keiner am Klick. */
.mail-kontakt-knopf { display: inline-flex; align-items: stretch; position: relative; }
.mail-kontakt-pfeil { opacity: .6; margin-left: 1px; }
/* Der Verweis in eine vorhandene Akte. Er trägt einen Namen und darf
   deshalb länger werden als die übrigen Knöpfe – aber nicht beliebig. */
/* Breit genug für „Firma · Vorname Nachname" (`mailContactLabel()`) –
   bei 220 Pixeln fiel der Ansprechpartner meist dem Kürzen zum Opfer. */
.mail-zur-akte { max-width: 360px; }
.mail-zur-akte > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Dasselbe Aufklappmenü wie bei den Spalten – und aus demselben Grund am
   Fenster statt am Lesebereich: Der schneidet ab, was über seinen Rand
   hinausragt. */
.mail-kontakt-menue { width: 320px; display: flex; flex-direction: column; gap: 2px; }
.mail-kontakt-menue > button {
    display: block; width: 100%; text-align: left;
    padding: 8px 10px; border-radius: 8px; line-height: 1.35;
}
.mail-kontakt-menue > button:hover { background: var(--panel-2); }
.mail-kontakt-menue .sub { display: block; color: var(--muted); font-size: 12px; margin-top: 3px; }

/* Eine Angabe, die durchgefallen ist: sichtbar mit Grund, nicht still weg. */
.check-item.mit-grund { opacity: .75; }
/* Der Grund steht unter der Zeile, nicht daneben: `.check-item` ist eine
   Flex-Zeile, und `flex-wrap` plus volle Breite ist der Umbruch.
   Bewusst auf `.check-list` beschränkt: Global gestellt riss die Regel
   anderswo die Zeile auseinander – in der Rechtemaske stand die Checkbox
   allein oben und Bezeichnung samt Hinweis rutschten darunter. */
.check-list .check-item { flex-wrap: wrap; }

/* Doppelgänger gesperrter Kontakte: eine Zeile je Fund */
.twin-list { max-height: 360px; overflow-y: auto; }
.twin-row { display: flex; gap: 10px; align-items: flex-start; padding: 8px 0; }
.twin-row + .twin-row { border-top: 1px solid var(--line); }
.twin-row input { margin-top: 3px; }
.twin-text { min-width: 0; }
.check-item .warn { color: var(--warn); flex: 0 0 100%; margin-left: 26px; }

/* Der ausgewertete Text zum Nachsehen: eingeklappt, damit er den Dialog
   nicht beherrscht, aber jederzeit erreichbar. */
.mail-grundlage { margin-top: 14px; }
.mail-grundlage > summary { cursor: pointer; color: var(--muted); font-size: 12px; }
.mail-grundlage > pre {
    margin: 8px 0 0; padding: 10px 12px; max-height: 260px; overflow: auto;
    background: var(--bg); border: 1px solid var(--line); border-radius: 8px;
    font-size: 12px; line-height: 1.5; white-space: pre-wrap; word-break: break-word;
}

.mail-dublette { border-color: var(--accent); margin-bottom: 14px; }
.mail-dublette p { margin-bottom: 10px; }
/* Die Wertfelder der gefundenen Angaben füllen die Zeile aus. */
.check-item input[type="text"].grow { flex: 1; min-width: 0; }
.mail-setting-sep { height: 1px; background: var(--line); margin: 16px 0; }
/* Das Sekundenfeld sitzt mitten im Satz und soll ihn nicht sprengen. */
.mail-delay { width: 4.5em; margin: 0 4px; padding: 2px 6px; font-size: inherit; }
.label-like {
    font-size: 11px; text-transform: uppercase; letter-spacing: .04em;
    color: var(--muted); margin-bottom: 8px;
}


/* ---------- E-Mail: schreiben ---------- */

/* Antworten steht ÜBER dem Betreff, nicht darunter: Es ist die Handlung,
   die man nach dem Lesen sucht, und sie soll ohne Scrollen erreichbar
   sein – auch bei einer langen Nachricht. */
/* Die Leiste über der Nachricht: antworten, allen antworten, weiterleiten –
   Trennstrich – löschen, Spam, markieren. Alles davon nur als Sinnbild;
   beschriftet bleiben allein die zwei Knöpfe zum Kontakt. */
.mail-werkzeuge {
    display: flex; gap: 6px; flex-wrap: wrap; align-items: center;
    margin-bottom: 12px; padding-bottom: 10px;
    border-bottom: 1px solid var(--line);
}
/* `gap` gilt nur noch den beschrifteten zwei – bei den übrigen steht
   nichts neben dem Bild, was einen Abstand bräuchte. */
.mail-werkzeuge button { display: inline-flex; align-items: center; gap: 6px; }
/* Das Wort neben dem Sinnbild – nur, wenn der Lesebereich breit genug ist.
   Gemessen wird der LESEBEREICH, nicht das Fenster: Am Tisch mit drei
   Spalten ist er schmal, obwohl das Fenster breit ist; das iPhone quer
   ist breit genug, obwohl es ein Telefon ist. Der Lesebereich ist dafür
   ein Behälter (`container-type`). Ein Browser ohne Behälterabfragen
   zeigt die Wörter immer – das ist der ältere Zustand, kein Schaden. */
.mail-reader { container-type: inline-size; }
@container (max-width: 639px) {
    .mail-werkzeuge .beschriftung { display: none; }
}
/* Strich-Sinnbilder wie in Apple Mail: keine Fläche, Linie in der Farbe
   des Knopfs, runde Enden. Etwas größer als die gefüllten (`mail-akt-icon`),
   weil eine Linie weniger Gewicht hat als eine Fläche. */
.mail-strich-icon {
    width: 17px; height: 17px; flex: none;
    fill: none; stroke: currentColor; stroke-width: 1.6;
    stroke-linecap: round; stroke-linejoin: round;
}
/* Die Farbe kommt vom Knopf – so gilt sie auch beim Überfahren und im
   hellen wie im dunklen Thema, ohne dass irgendwo ein zweiter Wert steht. */
.mail-akt-icon { width: 14px; height: 14px; flex: none; fill: currentColor; }
/* Markiert: Das Sinnbild trägt die Auskunft. Der Titel wechselt dazu die
   Richtung („Markieren" / „Markierung entfernen"), und `aria-pressed`
   sagt dasselbe dem Vorlesegerät – Farbe allein ist keine Auskunft. */
.mail-werkzeuge button.aktiv { color: var(--accent); }

/* Betreff mit dem Knopf davor, der die Nachricht in ein eigenes Fenster
   holt. `baseline` und nicht `center`: Bei einem zweizeiligen Betreff
   stünde der Knopf sonst in der Mitte zwischen den Zeilen. */
.mail-betreff { display: flex; align-items: baseline; gap: 8px; }
.mail-eigenes-fenster {
    flex: none; padding: 3px; line-height: 0;
    align-self: center; color: var(--muted);
}
.mail-eigenes-fenster:hover { color: var(--accent); }
.mail-eigenes-fenster svg { width: 15px; height: 15px; display: block; }

/*
 * Ein einzelnes Nachrichtenfenster: dieselbe Seite, nur ohne alles, was
 * einen zweiten Ort zum Hingehen anbietet. Es gibt hier keinen zweiten Ort
 * – das Fenster zeigt eine Nachricht und schließt sich, wenn sie erledigt
 * ist.
 */
body.nachrichtenfenster .topbar,
body.nachrichtenfenster .sidebar,
body.nachrichtenfenster .sidebar-backdrop { display: none; }
/* Die Höhe wird verteilt, nicht gesetzt: Über dem Raster kann ein
   Störungsstreifen stehen, und mit einer festen Höhe von 100dvh schöbe der
   die Nachricht aus dem Fenster. Die Kette reicht von `.content` über die
   Wurzel der Mailkomponente bis zum Raster – reißt sie an einer Stelle,
   fällt das Raster auf seinen Inhalt zusammen. */
body.nachrichtenfenster .content {
    /* Ohne Polsterung – und damit auch ohne etwas, das ein negativer Rand
       zurücknehmen dürfte. Stünden hier die 20 Pixel von oben, zöge die
       Regel für die gelesene Nachricht das Fenster seitlich aus dem Bild. */
    --inhalt-rand: 0px; --inhalt-oben: 0px; --inhalt-unten: 0px;
    padding: 0; overflow: hidden;
    display: flex; flex-direction: column;
}
body.nachrichtenfenster .content > div {
    flex: 1 1 auto; min-height: 0;
    display: flex; flex-direction: column;
}
body.nachrichtenfenster .mail-layout {
    flex: 1 1 auto; height: auto; min-height: 0;
    border: 0; border-radius: 0;
}
/* Nur die Nachricht – eine Spalte, eine Reihe. Steht NACH den Regeln für
   „untereinander", weil beide gleich schwer wiegen und dann die spätere
   gewinnt. Im Fenster werden `unten` und `ohne-ordner` ohnehin nicht
   gesetzt; die Zeilen hier sind der Gürtel zum Hosenträger. */
.mail-layout.nur-nachricht {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
}
.mail-layout.nur-nachricht > .mail-reader { grid-column: 1; grid-row: 1; }

/* „Erledigt" – steht da, wenn das Fenster sich nicht selbst schließen darf. */
.mail-fenster-fertig {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 8px; height: 100%; text-align: center; color: var(--muted);
}

.compose-box { display: flex; flex-direction: column; max-height: 90vh; }
/* Der Schreibdialog wächst mit dem Fenster: so breit wie der Platz, bis
   1200 Pixel – breiter liest sich eine Zeile nicht mehr, und ein
   Newsletter im Zitat (600 bis 700 Pixel) hat seinen Raum schon lange
   vorher. Die Höhe steht fest bei 90 % des Fensters: Das Blatt nimmt,
   was Kopfzeilen und Leiste übrig lassen, und der Dialog springt nicht,
   wenn der Text wächst. Die Breite hängt am FENSTER (abzüglich der 20
   Pixel Rand von `.modal` je Seite), nicht an `100%`: Der Dialog steht
   in einem Raster, dessen Spalte sich nach dem Inhalt richtet. Was sich
   nicht umbrechen lässt – eine eingefügte Tabelle, ein langer Verweis –
   machte ihn mit `100%` breiter als das Fenster; so rollt es im Blatt. */
.modal-box.compose-dialog { width: min(1200px, calc(100vw - 40px)); height: 90vh; height: 90dvh; }

/* Die Akte als Dialog (index.php, „Die Akte als Dialog"). Groß mit
   schmalem Rand wie der Schreibdialog; eine Ebene UNTER den übrigen
   Dialogen, damit alles, was aus der Akte aufgeht, über ihr liegt. Der
   Kopf steht, der Inhalt scrollt für sich – die Seite darunter bleibt
   dabei, wo sie war. Die Abstände heißen wie die von `.content`, weil
   der Inhalt der Akte früher dort stand und mit ihnen rechnet. */
/* ---------- Die Einstellungen (PLANUNG-EINSTELLUNGEN.md) ----------
   Ein Dialog, links die Leiste der Bereiche, rechts der Bereich. Groß
   wie die Akte. Die Leiste klappt über den Schalter im Kopf ein – auf
   jeder Breite, damit man sie immer zurückholen kann (wie beim
   Kalenderschalter); schmal liegt sie aufgeklappt über dem Bereich. */
.modal-box.einst-dialog {
    width: min(1100px, calc(100vw - 40px));
    height: 90vh; height: 90dvh;
    padding: 0; overflow: hidden;
}
.einst-kopf { display: flex; align-items: center; gap: 8px; flex: none; padding: 10px 14px; border-bottom: 1px solid var(--line); }
.einst-titel { margin: 0; font-size: 17px; min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.einst-leiste-schalter.aktiv { color: var(--accent); }
.einst-rumpf { flex: 1 1 auto; min-height: 0; display: flex; position: relative; }
.einst-leiste {
    flex: 0 0 220px; overflow-y: auto; padding: 10px 8px;
    border-right: 1px solid var(--line); background: var(--panel);
}
.einst-dialog.leiste-zu .einst-leiste { display: none; }
.einst-gruppe + .einst-gruppe { margin-top: 14px; }
.einst-gruppe-titel {
    padding: 4px 10px; font-size: 11px; color: var(--muted);
    text-transform: uppercase; letter-spacing: .5px;
}
/* `.einst-eintrag` vor `:hover` der Knöpfe: Sonst färbte `button:hover`
   den Eintrag in der Signalfarbe (wie früher die Ordnerzeilen). */
.einst-eintrag {
    display: block; width: 100%; margin: 1px 0; padding: 7px 10px; border: 0; border-radius: 7px;
    background: none; color: var(--text); font-size: 14px; font-weight: normal; text-align: left; cursor: pointer;
}
.einst-eintrag:hover { background: var(--panel-2); }
.einst-eintrag.aktiv { background: var(--accent-fill); color: #fff; }
.einst-inhalt { flex: 1 1 auto; min-width: 0; overflow-y: auto; padding: 16px 20px 20px; }
/* Eine Liste in den Einstellungen: oben ihre Knöpfe (anlegen …), darunter die Einträge. */
.einst-liste-kopf { display: flex; gap: 8px; flex-wrap: wrap; margin: 0 0 12px; }
.modal-actions.einst-fuss { margin-top: 0; padding: 10px 14px; border-top: 1px solid var(--line); }
@media (max-width: 900px) {
    .einst-leiste {
        position: absolute; top: 0; bottom: 0; left: 0; z-index: 2;
        width: min(260px, 80vw); box-shadow: 4px 0 18px rgba(0, 0, 0, .3);
    }
}

.modal.akte-modal { z-index: 49; }
.modal-box.akte-dialog {
    width: min(1200px, calc(100vw - 40px));
    height: 90vh; height: 90dvh;
    padding: 0; overflow: hidden;
}
/* Zwei Zeilen: Name mit Kreuz, darunter die Knöpfe – auf dem Grund der
   Seite (`--bg`, wie hinter der Kontaktliste), und zwar dem des JEWEILIGEN
   Themas: hell im Hellen, dunkel im Dunkeln.

   Vorher stand hier der dunkle Grund fest, samt Schrift, Linien und
   Flächen des dunklen Themas, „in beiden Themen". Im hellen Thema war das
   ein schwarzer Block über der Akte – und seit der Grund einstellbar ist,
   passte er auch im dunklen nicht mehr zur Seite. Mit dem Grund fallen die
   erzwungenen Werte und `color-scheme` weg: Sie folgen jetzt dem Thema,
   sonst stünde im Hellen helle Schrift auf hellem Grund. */
.akte-kopf {
    display: flex; flex-direction: column; gap: 10px; flex: none;
    padding: 10px 12px; border-bottom: 1px solid var(--line);
    background: var(--bg); color: var(--text);
}
/* Im Hellen liegen Grund (#f2f4f9) und Karte (#ffffff) fast gleichauf – die
   Knopfleiste setzte sich nicht vom Inhalt ab, anders als im Dunkeln, wo
   der Grund deutlich unter der Karte liegt. Deshalb hier ein Grau: der
   Grund, um 7 % zur Schrift gemischt – aus den Variablen gerechnet, damit
   es auch mit einem eigenen hellen Grundton stimmt. */
html[data-theme="light"] .akte-kopf { background: color-mix(in srgb, var(--bg) 93%, var(--text)); }
/* Das Kreuz auf der Höhe des Namens, nicht mittig neben Name und Branche. */
.akte-kopfzeile { display: flex; align-items: flex-start; gap: 8px; }
/* Der Name darf kürzen, nicht Zurück und Kreuz aus der Zeile drängen. */
.akte-titelblock { flex: 0 1 auto; min-width: 0; }
.akte-titel {
    margin: 0; font-size: 18px; line-height: 1.35; font-weight: 700;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.akte-untertitel {
    font-size: 13px; color: var(--muted); margin-top: 1px;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.akte-inhalt {
    --inhalt-rand: 20px;
    --inhalt-oben: 14px;
    --inhalt-unten: calc(24px + env(safe-area-inset-bottom));
    flex: 1 1 auto; min-height: 0; overflow-y: auto;
    padding: var(--inhalt-oben) var(--inhalt-rand) var(--inhalt-unten);
}
/* Auf dem Telefon randlos: steht im Telefon-Block oben bei `.sidebar` –
   die Telefonbedingung gibt es im Stilblatt nur zweimal. */
/* Senden, Entwurf und Verwerfen in der Kopfzeile, rechtsbündig über dem
   Blatt: `margin-right: 2px`, weil `.modal-body` rechts 2 Pixel freihält –
   so schließt das Kreuz außen rechts genau mit dem Rand des Blatts ab. Wird die Zeile zu
   eng (der Hinweis der Vertretung ist lang), rutscht die Gruppe darunter. */
.compose-kopf { flex-wrap: wrap; }
.compose-aktionen { display: flex; align-items: center; gap: 8px; margin-left: auto; margin-right: 2px; }
/* Der gefüllte Knopf hat keinen Rand, die hellen einen – ohne den
   durchsichtigen stünde Senden zwei Pixel niedriger als die beiden
   daneben, und die Zeichen säßen nicht auf einer Höhe. */
.compose-aktionen button:not(.ghost) { border: 1px solid transparent; }
@media (max-width: 560px) {
    /* Hochkant nur das Zeichen (`nur-breit` weicht) – mit gleichmäßigem
       Rand, wie die Knöpfe im Kopf der Akte. */
    .compose-aktionen button { padding: 8px 10px; }
    /* Hochkant gehört dem Schreiben fast der ganze Schirm: 5 Pixel Abstand
       zum Rand links und rechts, 60 oben, unten keiner – der Dialog steht
       auf dem unteren Rand, seine unteren Ecken sind deshalb eckig. Breite
       und Höhe am Fenster (`vw`, `dvh` – aus demselben Grund wie oben nicht
       `100%`); die Obergrenze von 90 % fällt, sonst bliebe unten Platz.
       Innen 2 Pixel seitlich und 5 oben und unten. `.modal-body` hält hier
       rechts nichts frei, also braucht auch die Knopfgruppe keinen
       Ausgleich. */
    .modal:has(> .compose-dialog) { padding: 60px 5px 0; }
    .modal-box.compose-dialog {
        width: calc(100vw - 10px); height: calc(100vh - 60px); height: calc(100dvh - 60px);
        max-height: none; padding: 5px 2px; border-radius: var(--radius) var(--radius) 0 0;
    }
    .compose-dialog .modal-body { padding-right: 0; }
    .compose-dialog .compose-aktionen { margin-right: 0; }
    /* Der obere Block – Titel mit den Knöpfen, An, Von, Kopie, Betreff –
       rückt innen auf 10 Pixel vom Rahmen (2 vom Dialog, 8 hier). Leiste
       und Blatt darunter bleiben bei 2: Dort gehört die Breite dem Text. */
    .compose-dialog .compose-kopf,
    .compose-dialog .compose-body > .compose-zeile { padding-left: 8px; padding-right: 8px; }
    /* Die Vorschläge unter An, Kopie und Blindkopie über die ganze
       Breite: Ab dem Feld liefen sie rechts aus dem Bild – das Feld
       beginnt erst hinter der Beschriftung. Bezugspunkt ist hier die
       Zeile, nicht das Feld; das Kreuz hängt an seiner eigenen Hülle. */
    .compose-dialog .compose-body > .compose-zeile { position: relative; }
    .compose-dialog .compose-feld.combo { position: static; }
    .compose-dialog .compose-vorschlaege { left: 0; right: 0; width: auto; min-width: 0; max-width: none; }
}
/* Die Schrift ausdrücklich: Der Dialog erbt sie sonst vom dunklen `body`
   und stünde hell auf seinem hellen Grund. */
.thema-hell { color: var(--text); background: var(--panel); }
.compose-body { display: flex; flex-direction: column; min-height: 0; gap: 8px; }

.compose-zeile { display: flex; align-items: center; gap: 10px; }
.compose-zeile input[type="text"] { flex: 1; min-width: 0; margin: 0; }
.compose-zeile select.compose-von { flex: 1; min-width: 0; margin: 0; }
/* Ein Empfängerfeld: das Feld füllt die Zeile, das Kreuz sitzt rechts IM
   Feld (deshalb der rechte Innenabstand), die Vorschlagsliste hängt
   darunter – `.combo` gibt den Bezugspunkt. */
.compose-feld { flex: 1; min-width: 0; display: flex; align-items: center; }
/* Die Hülle um Feld und Kreuz – der Bezugspunkt des Kreuzes. */
.compose-eingabe { position: relative; flex: 1; min-width: 0; display: flex; align-items: center; }
.compose-feld input[type="text"] { width: 100%; padding-right: 30px; }
.compose-leeren {
    position: absolute; right: 4px; top: 50%; transform: translateY(-50%);
    width: 24px; height: 24px; padding: 0; border: 0; border-radius: 50%;
    background: none; color: var(--muted); font-size: 18px; line-height: 1; cursor: pointer;
}
.compose-leeren:hover { color: var(--text); background: var(--panel-2); }
/* Die Liste zeigt Adressen, nicht Branchen: kein Umbruch, aber die Adresse
   darf lang sein – dann rollt die Zeile, statt das Fenster zu sprengen. */
.compose-vorschlaege { max-width: min(560px, 90vw); max-height: 264px; }
/* Der Aufklappknopf neben „An": ein doppelter Winkel, der sich aufgeklappt
   umdreht. Als Knopf so hoch wie das Feld daneben, damit die Zeile nicht
   wackelt, wenn er den Text verliert. */
.compose-mehr { display: inline-flex; align-items: center; justify-content: center; padding: 5px 8px; }
.compose-mehr svg { width: 14px; height: 14px; transition: transform .15s ease; }
.compose-mehr.offen svg { transform: rotate(180deg); }
.compose-label {
    flex: 0 0 90px; font-size: 12px; color: var(--muted);
    text-transform: uppercase; letter-spacing: .04em;
}

.compose-werkzeuge {
    display: flex; align-items: center; gap: 4px; flex-wrap: wrap;
    padding: 6px; border: 1px solid var(--line); border-radius: 8px 8px 0 0;
    border-bottom: 0; background: var(--panel-2);
}
.compose-trenner { width: 1px; align-self: stretch; background: var(--line); margin: 2px 4px; }

/* Ein Dateifeld sieht in jedem Browser anders aus. Also versteckt und die
   Beschriftung als Knopf – so passt es zu den übrigen. */
.compose-anhang-knopf { position: relative; overflow: hidden; cursor: pointer; }
.compose-anhang-knopf input[type="file"] { position: absolute; inset: 0; opacity: 0; cursor: pointer; }
/* Im Schreibdialog gezeichnet wie die Knöpfe daneben: `button.ghost` und
   `button.mini` gelten nur für Knöpfe, und die Grundregel für `label`
   machte den Anhang zu einer grauen Beschriftung. Zeichen und Wort wie
   beim KI-Knopf; schmal weicht das Wort (`nur-breit`). Das Zeichen nimmt
   mit seinem Rand die Höhe einer Textzeile ein – ohne Wort stünde der
   Knopf sonst vier Pixel niedriger als seine Nachbarn. */
.compose-dialog .compose-anhang-knopf {
    display: inline-flex; align-items: center; gap: 4px; margin: 0;
    padding: 3px 8px; border: 1px solid var(--line); border-radius: 8px;
    background: transparent; color: var(--text); font-size: 12px;
}
.compose-dialog .compose-anhang-knopf:hover { background: var(--panel-2); }
.compose-dialog .compose-anhang-knopf > svg { flex: none; margin: 2px 0; }
.compose-dialog .compose-anhang-knopf input[type="file"] { margin: 0; }

.compose-text {
    flex: 1 1 auto; min-height: 220px; max-height: 45vh; overflow-y: auto;
    padding: 12px 14px; border: 1px solid var(--line); border-radius: 0 0 8px 8px;
    background: var(--bg); color: var(--text);
    font: inherit; font-size: 14px; line-height: 1.6;
}
.compose-text:focus { outline: none; border-color: var(--accent); }
.compose-text blockquote {
    margin: 8px 0 8px 4px; padding-left: 12px;
    border-left: 3px solid var(--line); color: var(--muted);
}
.compose-text a { color: var(--accent); }
/* Das Blatt des Schreibdialogs: oben die Antwort, darunter das Zitat in
   seinem eigenen Rahmen, auf dem hellen Grund einer Mail (`thema-hell` am
   Blatt, nicht am Dialog – der folgt dem Thema). EIN Bildlauf für beides;
   der Rahmen bekommt die Höhe seines Inhalts (`quoteStyle`). Den Rand
   trägt das Blatt, die Antwort darin ist randlos. Es füllt, was der
   Dialog übrig lässt – der steht fest bei 90 % des Fensters
   (`.compose-dialog`). */
.compose-blatt {
    flex: 1 1 auto; min-height: 220px; overflow-y: auto;
    display: flex; flex-direction: column;
    border: 1px solid var(--line); border-radius: 0 0 8px 8px;
}
.compose-blatt:focus-within { border-color: var(--accent); }
.compose-blatt > .compose-text {
    flex: none; min-height: 120px; max-height: none; overflow: visible;
    border: 0; border-radius: 0; background: transparent;
}
/* Ohne Zitat ist das ganze Blatt Schreibfläche – ein Klick ins Weiß
   darunter landet im Text, nicht im Nichts. */
.compose-blatt:has(> .compose-zitat[hidden]) > .compose-text { flex: 1 0 auto; }
/* Ohne Messung ein festes Maß, die Messung ersetzt es. Ohne Rand: Die
   gemessene Inhaltshöhe wird zur Rahmenhöhe – wie beim `.mail-frame`. */
.compose-zitat { display: block; flex: none; width: 100%; height: 30vh; border: 0; background: #fff; }
/* `hidden` statt `x-show`: Alpine blendet mit `x-show` erst beim nächsten
   Bildaufbau ein. Bis dahin misst der Rahmen 0, und Befehle wirken in
   seinem Dokument nicht – das Attribut gilt sofort. */
.compose-zitat[hidden] { display: none; }

.compose-anhaenge { display: flex; flex-wrap: wrap; gap: 6px; }
.compose-anhang {
    display: inline-flex; align-items: center; gap: 8px;
    padding: 4px 6px 4px 10px; border-radius: 999px;
    background: var(--panel-2); border: 1px solid var(--line); font-size: 12.5px;
}

/* ---------- E-Mail: suchen und aufräumen ---------- */

.mail-suche { display: flex; gap: 6px; padding: 8px 12px; border-bottom: 1px solid var(--line); flex: none; }
.mail-suche input { flex: 1; min-width: 0; margin: 0; font-size: 13px; padding: 5px 9px; }

/* Die Auswahlleiste erscheint erst mit einer Auswahl – ohne sie hätten
   die Knöpfe nichts, worauf sie sich beziehen. */
.mail-auswahl {
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: none;
    padding: 6px 12px; border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.mail-auswahl select.mini { padding: 3px 6px; font-size: 12px; min-width: 0; }

/* Die Zeile: Kästchen links, Inhalt daneben. */
.mail-row { flex-direction: row; align-items: flex-start; gap: var(--mail-luecke); }
.mail-row-inhalt { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }

/* Unsichtbar, bis man die Zeile überfährt oder etwas gewählt ist: In
   einer Liste, die man meistens nur liest, wäre eine Spalte Kästchen
   ständiges Rauschen. Der Platz bleibt belegt, damit nichts springt. */
.mail-pick { flex: 0 0 var(--mail-pick); width: var(--mail-pick); margin: 3px 0 0;
             opacity: 0; transition: opacity .12s; }
.mail-row:hover .mail-pick, .mail-pick.sichtbar, .mail-pick:checked { opacity: 1; }
.mail-row.gewaehlt { background: var(--panel-2); }
.mail-row.gewaehlt.active { background: var(--accent-fill); }

.mail-flag { flex: none; color: var(--warn); font-size: 12px; }
.mail-row.active .mail-flag { color: rgba(255,255,255,.9); }
/* Markieren in Farbe – die sieben Farben von Apple Mail. Der Stern und der
   Punkt im Menü tragen die Farbe voll, die Zeile einen zarten Grund
   davon; die gewählte Zeile behält ihre Signalfarbe. */
:root {
    --markier-rot: #ff5b57; --markier-orange: #ff9f2e; --markier-gelb: #f2c53d; --markier-gruen: #4cc76b;
    --markier-blau: #4f8cff; --markier-lila: #b47cff; --markier-grau: #9aa3b5;
}
html[data-theme="light"] {
    --markier-rot: #e0383e; --markier-orange: #e8850f; --markier-gelb: #c9a300; --markier-gruen: #2f9e4f;
    --markier-blau: #2a68e6; --markier-lila: #8a4fe0; --markier-grau: #7d8797;
}
.farbe-rot { --markier: var(--markier-rot); } .farbe-orange { --markier: var(--markier-orange); }
.farbe-gelb { --markier: var(--markier-gelb); } .farbe-gruen { --markier: var(--markier-gruen); }
.farbe-blau { --markier: var(--markier-blau); } .farbe-lila { --markier: var(--markier-lila); }
.farbe-grau { --markier: var(--markier-grau); }
.mail-flag[class*="farbe-"] { color: var(--markier); }
/* Die Zeile selbst trägt keine Farbe – ein Grund oder Streifen war zu
   aufdringlich. Die Farbe zeigt allein der Stern: zweizeilig neben dem
   Absender, einzeilig in einer festen Spalte direkt hinter dem Punkt. */
.mail-werkzeuge button.mail-markieren.aktiv { color: var(--markier); }
.mail-markieren.aktiv .mail-strich-icon { color: var(--markier); fill: var(--markier); }
.mail-markier-knopf { position: relative; display: inline-flex; }
.mail-markieren .mail-kontakt-pfeil { margin-left: 2px; }
.mail-markier-menue { width: 210px; }
.mail-markier-menue button.ghost { display: flex; align-items: center; gap: 10px; }
.mail-markier-menue button.ghost:disabled { opacity: .45; cursor: default; }
.markier-punkt { width: 12px; height: 12px; border-radius: 50%; background: var(--markier); flex: none; }
.markier-punkt.markier-weg { background: transparent; color: var(--muted); font-size: 12px; line-height: 12px; text-align: center; }


/* Neue Post, während man mitten in etwas steckt. Ein Hinweis zum
   Anklicken – keine Warnung, deshalb die Akzentfarbe und nicht Rot. */
.mail-neu { cursor: pointer; border-bottom-color: var(--accent); }
.mail-neu:hover { background: var(--accent-fill); color: #fff; }

/* ---------- E-Mail: Überschriften und Spalten ---------- */

/*
 * Kopf und Zeile müssen an derselben Stelle beginnen.
 *
 * Das ist die Falle bei Spaltenüberschriften: Links vor der ersten Spalte
 * stehen in der Zeile das Auswahlkästchen und der Gelesen-Punkt. Wird die
 * Überschrift nicht um genau dieselbe Breite eingerückt, steht jede
 * Beschriftung versetzt über ihrer Spalte – und eine Überschriftenzeile,
 * die daneben steht, ist schlimmer als gar keine.
 *
 * Deshalb stehen alle beteiligten Maße HIER, an einer Stelle, und beide
 * Seiten rechnen mit denselben Werten. Wer eines ändert, ändert beide.
 */
.mail-list {
    --mail-rand: 14px;    /* seitlicher Rand von Kopf und Zeile   */
    --mail-pick: 14px;    /* Breite des Auswahlkästchens          */
    --mail-luecke: 10px;  /* Abstand Kästchen → Inhalt            */
    --mail-punkt: 9px;    /* Breite des Gelesen-Punkts            */
    --mail-stern: 18px;   /* Breite der Sternspalte (einzeilig)  */
    --mail-punkt-abstand: 8px;
    /* Was links vor der ersten Spalte steht: */
    --mail-vorspann: calc(var(--mail-pick) + var(--mail-luecke)
                          + var(--mail-punkt) + var(--mail-punkt-abstand));
}

.mail-kopf {
    display: flex; align-items: stretch; flex: none;
    padding: 0 var(--mail-rand);
    border-bottom: 1px solid var(--line); background: var(--panel-2);
}
.mail-kopf-spalten { flex: 1; min-width: 0; display: flex; align-items: stretch; }
.mail-kopf-einfach {
    flex: 1; min-width: 0; display: flex; align-items: center; gap: 8px; padding: 5px 10px;
}
.mail-kopf-einfach select.mini { padding: 3px 6px; font-size: 12px; }

/* Die Lücke über dem Auswahlkästchen und dem Punkt: Ohne sie stünde die
   erste Überschrift um deren Breite versetzt über ihrer Spalte – genau
   der Fehler, den eine Überschriftenzeile nicht machen darf. */
.mail-kopf-luecke { flex: 0 0 var(--mail-vorspann); display: flex; align-items: center; justify-content: center; }
/* Der Menüknopf in der Lücke: schmal, damit er in den Vorspann passt. */
.mail-kopf-luecke button, .mail-kopf-einfach > button:first-child { padding: 1px 6px; font-size: 13px; }

.mail-kopf-zelle { position: relative; display: flex; align-items: stretch; min-width: 0; }
.mail-kopf-spalte {
    flex: 1; min-width: 0;
    display: flex; align-items: center; gap: 4px;
    background: none; border: 0; padding: 6px 8px; cursor: pointer;
    color: var(--muted); font-size: 11px; text-transform: uppercase;
    letter-spacing: .04em; white-space: nowrap; overflow: hidden;
}
.mail-kopf-spalte:hover { color: var(--text); }
.mail-kopf-spalte.aktiv { color: var(--accent); }
.mail-pfeil { flex: none; font-size: 9px; }

/* Der Griff zwischen zwei Spalten – am LINKEN Rand jeder außer der
   ersten, damit jede Grenze einen bekommt (auch die neben der
   mitwachsenden Betreff-Spalte). Schmal, aber mit breiterer
   Kontaktfläche über das Pseudo-Element, wie bei den Bereichsgriffen.

   Der negative Rand links zieht ihn über die Zellgrenze, damit er
   optisch genau auf der Trennlinie sitzt und nicht daneben. */
.mail-kopf-griff {
    flex: 0 0 5px; cursor: col-resize; position: relative;
    background: var(--line); margin: 4px 0 4px -3px;
    touch-action: none;
}
.mail-kopf-griff::before {
    content: ''; position: absolute; top: -4px; bottom: -4px; left: -3px; right: -3px;
}
.mail-kopf-griff:hover { background: var(--accent); }
.mail-kopf.zieht { user-select: none; }
.mail-kopf.zieht .mail-kopf-griff { background: var(--accent); }
/* Während eines Spaltenzugs nimmt auch der Anzeigerahmen keine
   Zeigerereignisse an – sonst verschluckt das eingebettete Dokument die
   Bewegungen, sobald der Zeiger darüber wandert. Die Klasse sitzt am
   Raster, nicht an der Kopfzeile: Der Rahmen ist kein Geschwister von ihr.
   (Die erste Fassung schrieb `.mail-kopf.zieht ~ * .mail-frame` – ein
   Ausdruck, der nie zutrifft.) */
.mail-layout.zieht .mail-frame { pointer-events: none; }
/* Steht in der Kopfzeile der LISTE, bei „Neu laden" und der Anordnung –
   die Zeile hat ihren eigenen Abstand (`gap`), ein Polster obendrauf
   rückte ihn aus der Reihe. `relative`, damit das Menü seinen Knopf
   kennt: Es hängt am Fenster, aber `click.outside` braucht ihn in der
   Nähe. */
.mail-kopf-menue { position: relative; display: flex; align-items: center; }
/*
 * Am FENSTER, nicht an der Liste.
 *
 * `absolute` unter dem Knopf war das Naheliegende und falsch: `.mail-list`
 * und `.mail-layout` schneiden beide ab, was über ihren Rand hinausragt,
 * und beide müssen das – sonst scrollte die Liste als Ganzes statt nur
 * ihrer Zeilen, und Zeileninhalt liefe über die Trennlinie. Ein
 * aufgeklapptes Menü ragt aber genau dorthin, über die Trennlinie in den
 * Lesebereich; es wurde an der Kante halbiert.
 *
 * `fixed` steht außerhalb dieser Rahmen. Die Stelle rechnet die Komponente
 * aus (`spaltenMenue`), weil sie nicht mehr aus dem Fluss kommt.
 *
 * Der Stapelwert liegt über dem Lesebereich und unter den Dialogen (50):
 * Öffnet einer, gehört er darüber. `translateZ(0)` gibt dem Menü eine
 * eigene Ebene beim Zeichnen – ohne das kann es unter dem eingebetteten
 * Rahmen der Nachricht landen, der als fremdes Dokument seine eigene hat.
 */
.mail-spaltenwahl {
    position: fixed; z-index: 45; width: 260px;
    padding: 12px 14px; border-radius: var(--radius);
    background: var(--panel); border: 1px solid var(--line);
    box-shadow: 0 8px 24px rgba(0,0,0,.35);
    transform: translateZ(0);
    max-height: calc(100vh - 16px); overflow-y: auto;
}

/* Der Umschalter für die Anordnung: Rahmen als Strich, die Liste darin
   als Fläche. Beide Farben kommen vom Knopf. */
.mail-anordnung { display: inline-flex; align-items: center; padding: 4px 6px; }
.mail-anordnung svg { width: 17px; height: 17px; display: block; }
.mail-anordnung .rahmen { fill: none; stroke: currentColor; stroke-width: 1.5; }
.mail-anordnung .fuellung { fill: currentColor; opacity: .35; }

/* Einzeilig: die Spalten teilen sich die Breite. `subject` bekommt den
   Rest, die übrigen ihr Maß – sonst drängt ein langer Betreff das Datum
   aus dem Blick. */
/* Die Breiten kommen aus der Komponente (`spaltenStil`) – Kopf und Zelle
   bekommen dieselbe. Hier steht nur, was sich nicht ziehen lässt. */
.mail-row-tabelle { flex: 1; min-width: 0; display: flex; align-items: center; }
.mail-zelle {
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 13px; padding: 0 8px;
}
.mail-zelle.sp-size { text-align: right; }
.mail-zelle.sp-date, .mail-zelle.sp-size { color: var(--muted); font-size: 12px; }
.mail-row.active .mail-zelle.sp-date, .mail-row.active .mail-zelle.sp-size { color: rgba(255,255,255,.85); }
.mail-row.unseen .mail-zelle.sp-from, .mail-row.unseen .mail-zelle.sp-subject { font-weight: 700; }
/* Einzeilig: die Sternspalte, fest und schmal, direkt hinter dem Punkt –
   im Kopf ein gleich breiter Platzhalter, damit die Spalten darunter
   bündig bleiben. */
.mail-zelle.sp-flag { flex: 0 0 var(--mail-stern); width: var(--mail-stern); padding: 0; text-align: center; line-height: 1; }
.mail-kopf-stern { flex: 0 0 var(--mail-stern); }
/* Die Zeilen scrollen, der Kopf nicht: Ohne festen Rollbalken-Platz
   drängt der Balken die Zeilen um seine Breite zusammen, und ab der
   mitwachsenden Betreffspalte stehen die Zellen links von ihren
   Überschriften. `scrollbar-gutter: stable` hält auf beiden Seiten
   denselben Platz frei. */
.mail-rows, .mail-kopf { scrollbar-gutter: stable; }
.mail-kopf { overflow: hidden; }
/* Einzeilig sitzen Kästchen und Punkt nebeneinander vor der ersten
   Spalte – zusammen die 33 Pixel, die `.mail-kopf-luecke` freihält. */
.mail-row-tabelle { align-items: center; }
.mail-row-tabelle .mail-dot { flex: 0 0 var(--mail-punkt); margin-right: var(--mail-punkt-abstand); }
/* Einzeilig sitzt alles auf einer Höhe – das Kästchen darf nicht wie im
   zweizeiligen Fall nach oben gerückt sein. */
.sicht-tabelle .mail-pick { margin-top: 0; align-self: center; }

/* Der Telefon-Block steht am ENDE des Mailabschnitts, nicht mittendrin.
   Ein `@media` erhöht die Gewichtung nicht: Eine Grundregel gleicher
   Gewichtung, die WEITER UNTEN steht, schlägt ihn. Genau das ist
   passiert – `.mail-kopf-menue` wird fünfhundert Zeilen später noch
   einmal auf `display: flex` gesetzt und stand auf dem Telefon weiter da,
   obwohl der Block es ausblendet. Am Ende gibt es kein „weiter unten"
   mehr. */

/* Rückweg und Kreuz stehen IN der Werkzeugleiste – links der Rückweg
   (wenn es einen gibt), rechts das Kreuz. Der Zurück-Balken darüber war
   eine Zeile nur für das Kreuz; auf dem Telefon ist das Platz, den der
   Schirm nicht hat. Das Kreuz gehört zum Telefon und steht deshalb hier
   auf `none` – eingeschaltet wird es unten im Telefon-Block. Auf dem
   Schreibtisch stehen Liste und Nachricht nebeneinander; ein Weg zurück
   führte dort nirgendwohin. */
/* Der Rückweg: so hoch wie die Knöpfe daneben (`icon-btn`), mit Winkel
   und dem Wort „Zurück" – wohin, sagt der Tooltip. */
.mail-werkzeuge .rueckweg { width: auto; padding: 0 10px; height: 31px; line-height: 1; white-space: nowrap; font-size: 13px; gap: 4px; }
.mail-werkzeuge .rueckweg-pfeil { font-size: 18px; line-height: 1; position: relative; top: -1px; }
.mail-werkzeuge .nur-telefon { display: none; }
.modal-head .rueckweg { margin-right: 10px; flex: none; }
/* Das Kreuz: rechtsbündig (der `spacer` schiebt es), quadratisch, ohne Text. */
.mail-werkzeuge .mail-schliessen { align-items: center; justify-content: center; width: 34px; height: 32px; padding: 0; }
/* Beim Laden ist die Leiste schon da – dieselbe Höhe, damit nichts springt. */
.mail-werkzeuge { min-height: 54px; }

/* ==========================================================================
   Telefon: Liste ODER Nachricht

   Zwei Bedingungen, und die zweite ist der Grund, warum hier nicht die
   Hausgrenze allein steht: Ein iPhone im QUERFORMAT ist je nach Modell
   568 bis 932 Pixel breit und nur 320 bis 430 hoch. Nach der Breite wäre
   das ein Schreibtisch – und die drei Spalten lägen auf einem Streifen
   von vier Zentimetern Höhe.

   `pointer: coarse` hält den Schreibtisch draußen: Ein niedriges
   Browserfenster auf einem Rechner meldet einen feinen Zeiger und behält
   die gewohnte Ansicht.

   Wortgleich in mail.js (`TELEFON`), weil dort dieselbe Frage beantwortet
   werden muss – ob der Stand der Liste zu merken ist. Ein Wächter hält
   beide Fassungen zusammen.

   Angetippt nimmt die Nachricht den ganzen Schirm, mit einem Pfeil oben
   links zurück zur Liste. Vorher standen Ordner, Liste und Nachricht
   untereinander: Man tippte eine Nachricht an und musste an der ganzen
   Liste vorbeiscrollen, um sie zu lesen.
   ========================================================================== */
@media (max-width: 768px), (max-height: 500px) and (pointer: coarse) {
    /*
     * Ordner | Liste – die Ordnerspalte SCHIEBT von links, wie die
     * Kalenderspalte. Sie stand hier eine Fassung lang als Block ÜBER der
     * Liste und drückte die Zeilen nach unten: Wer ein Postfach suchte,
     * sah erst einmal keine Post mehr.
     *
     * Zwei Spuren: die Ordnerspalte (ihre Breite kommt aus `rasterStil`,
     * zugeklappt null) und die Liste mit HUNDERT PROZENT – nicht `1fr`.
     * `1fr` gäbe der Liste, was neben den Ordnern übrig bleibt, 180
     * Pixel auf einem Schirm von 390: gequetscht. Mit 100 % behält sie
     * ihre Breite und rückt nach rechts; das Raster wird breiter als
     * sein Behälter, und der scrollt waagerecht – man zieht zur Liste.
     * Derselbe Gedanke wie `.kal-flaeche { flex: 0 0 100% }`.
     *
     * Der Übergang bleibt der vom Schreibtisch: Die Spur geht auf null,
     * die Spalte bleibt im Baum. Beim Antippen eines Postfachs schließt
     * die Komponente sie (`openFolder`), und die Liste gleitet zurück.
     *
     * Die Plätze stehen ausdrücklich: Die Griffe sind hier `display:
     * none`, und ein so ausgeblendetes Kind ist für das Raster nicht da –
     * ohne feste Zuordnung rutschte die Liste in die Ordnerspur.
     */
    .mail-layout {
        grid-template-columns: var(--ordner-breite, 210px) 100%;
        overflow-x: auto; overflow-y: hidden;
    }
    .mail-layout > .mail-folders { grid-column: 1; grid-row: 1; border-right: 1px solid var(--line); }
    .mail-layout > .mail-list    { grid-column: 2; grid-row: 1; }
    /* Mit dem Finger gibt es nichts zu ziehen. */
    .mail-splitter { display: none; }
    /* Gestapelt wird gescrollt, nicht verteilt: Die Seite gibt ihre feste
       Höhe auf, sonst müssten drei Bereiche sich einen Schirm teilen. */
    .mail-seite { height: auto; }
    .mail-layout { flex: none; height: auto; }
    .mail-list, .mail-reader { max-height: none; }
    /* Gestapelt gibt es keine Resthöhe zu verteilen – dann wieder ein
       festes Maß, sonst fiele der Rahmen auf seine Mindesthöhe zusammen. */
    .mail-reader { overflow: visible; }
    /* Die Karte darf nicht schrumpfen: Als Flex-Kind des Lesers mit
       `min-height: 0` endete sie bei Bildschirmhöhe, und der Text lief
       auf dunklem Grund darunter weiter (gesehen auf dem iPhone). */
    .mail-message { display: block; flex: none; min-height: auto; }
    .mail-frame { height: 70vh; }

    /* Das Spaltenmenü BLEIBT. Zweizeilig ist auf dem Telefon nur die
       Vorgabe (siehe `initMail()`), nicht der Zwang – und eine
       Einstellung, die sich nicht einstellen lässt, ist keine. Hier war
       das Menü einmal ausgeblendet; damit war der Schalter „Einzeilig"
       auf dem Gerät unerreichbar, für das er am ehesten gebraucht wird. */

    /* „Wo steht die Nachricht" hat hier dagegen nichts zu schalten: Sie
       steht immer im ganzen Schirm, nie neben oder unter der Liste. Der
       Schalter böte eine Wahl zwischen zwei Zuständen, von denen es nur
       einen gibt. */
    .mail-anordnung { display: none; }

    /* „In eigenem Fenster öffnen" ebenso: Ein zweites Browserfenster ist
       auf dem Telefon kein zweites Fenster, sondern ein Tab, den man erst
       wiederfinden muss. Der Knopf verspräche etwas, das das Gerät nicht
       hergibt. */
    .mail-eigenes-fenster { display: none; }

    /*
     * Die Anordnung „Nachricht unten" gibt es hier nicht – und sie darf
     * auch nicht durchschlagen. Ihre Regeln stehen unter `min-width:
     * 769px`, und ein iPhone im Querformat IST 769 Pixel breit und mehr.
     * Ohne diese Zeilen galten dort beide Blöcke zugleich: drei Spalten
     * und drei Reihen vom Schreibtisch, darüber das Stapeln vom Telefon.
     *
     * Gemessen bei 844×390 mit `anordnung = 'unten'`: In der Liste blieb
     * Reihe 3 leer (93 Pixel unter der Liste), und beim Lesen stand die
     * Nachricht in Reihe 3 – hinter 285 Pixeln fester, leerer Reihen für
     * eine Liste, die gar nicht mehr da war. Sie bekam 62 Pixel Höhe.
     *
     * Gleiche Gewichtung wie die Schreibtischregeln, später in der Datei:
     * Deshalb steht dieser Block am Ende des Abschnitts.
     */
    .mail-layout.unten {
        grid-template-columns: var(--ordner-breite, 210px) 100%;
        grid-template-rows: none;
    }
    .mail-layout.unten > .mail-splitter-ordner,
    .mail-layout.unten > .mail-splitter-liste { grid-column: auto; grid-row: auto; }
    .mail-layout.unten > .mail-folders { grid-column: 1; grid-row: 1; }
    .mail-layout.unten > .mail-list,
    .mail-layout.unten > .mail-reader { grid-column: 2; grid-row: 1; }

    /* ---------- Zustand LISTE ----------
       Ohne offene Nachricht gibt es keinen Lesebereich zu zeigen. Vorher
       stand dort „Keine Nachricht ausgewählt." als leerer Kasten unter der
       Liste – eine Auskunft über etwas, das man gerade nicht sucht.

       `body:not(.nachrichtenfenster)`: Im Fenster für eine einzelne
       Nachricht IST der Lesebereich der ganze Inhalt. Dort ist `liest`
       nie gesetzt (es gibt keine Liste), und ohne diese Bedingung bliebe
       das Fenster auf dem Telefon leer. */
    body:not(.nachrichtenfenster) .mail-seite:not(.liest) .mail-reader { display: none; }

    /* Die Winkel im Ordnerbaum: ein Fingerziel, kein Nadelstich. */
    .mail-ordner-pfeil { width: 32px; height: 36px; }
    .mail-ordner-pfeil svg, .mail-caret svg { width: 20px; height: 20px; }
    .mail-caret { width: 20px; height: 20px; }
    .mail-account-head { padding: 8px 8px; }

    /* ---------- Zustand NACHRICHT ---------- */
    .mail-werkzeuge .nur-telefon { display: inline-flex; }

    /* Die Werkzeugzeile der Seite weicht: Sie führt zu Postfächern,
       Einstellungen und einer neuen Nachricht – lauter Dinge, die man
       gerade nicht tut. Der Zurück-Balken ersetzt sie, und im Querformat
       sind die gewonnenen 44 Pixel ein Zehntel der Höhe. */
    .mail-seite.liest .mail-seitenkopf,
    /* Der Hinweis auf den fehlenden Schlüssel ebenso: Er steht sonst
       dauerhaft ÜBER der Nachricht und nimmt auf 390 Pixeln Höhe ein
       Drittel. Eine Störung (`.mail-trouble`) bleibt dagegen stehen – sie
       kann der Grund sein, warum die Nachricht leer ist. */
    .mail-seite.liest > .mail-key-hint,
    .mail-seite.liest > .empty,
    .mail-seite.liest .mail-folders,
    .mail-seite.liest .mail-splitter,
    .mail-seite.liest .mail-list { display: none; }

    /*
     * Randlos: Die Nachricht nimmt sich die Polsterung des Inhaltsbereichs
     * zurück. Auf 375 Pixeln sind das 24 in der Breite – ein ganzes Wort
     * je Zeile. Die Zahlen kommen als Variablen von `.content`, damit
     * Polsterung und Rücknahme nicht auseinanderlaufen können.
     */
    .mail-seite.liest { height: 100%; }
    .mail-seite.liest .mail-layout {
        flex: 1 1 auto; height: auto; min-height: 0;
        border: 0; border-radius: 0;
        /* Eine Spur, kein Ziehen: Beim Lesen gibt es keine Liste, die
           nach rechts rücken könnte, und nichts, wozu man scrollen müsste. */
        grid-template-columns: 1fr; overflow: hidden;
        margin: calc(-1 * var(--inhalt-oben))
                calc(-1 * var(--inhalt-rand))
                calc(-1 * var(--inhalt-unten));
    }

    /*
     * Gescrollt wird IM Lesebereich, nicht auf der Seite. Sonst wanderte
     * der Zurück-Balken beim Lesen mit nach oben aus dem Bild, und der
     * Weg zurück wäre eine Scrollstrecke weit weg.
     */
    .mail-seite.liest .mail-layout > .mail-reader { grid-column: 1; grid-row: 1; }
    .mail-seite.liest .mail-reader {
        overflow-y: auto;
        padding: 0 var(--inhalt-rand) calc(16px + env(safe-area-inset-bottom));
    }

    /*
     * EINE Leiste bleibt oben stehen: die Werkzeuge, mit dem Kreuz zum
     * Schließen ganz rechts – eine Zeile, weil unter 640 Pixeln
     * Lesebreite nur die Sinnbilder stehen. Betreff, Absender, Anhänge
     * und Inhalt sind ein Block und scrollen am Stück, wie ein Blatt
     * Papier unter der Leiste. (Vorher stand das Kreuz in einem eigenen
     * Balken darüber – 42 Pixel für einen Knopf.)
     */
    .mail-seite.liest .mail-werkzeuge { padding-top: 10px; top: 0; z-index: 2; }

    /*
     * Die Fälle auf dem Telefon hochkant, weil dort nicht alles in eine
     * Zeile passt:
     *  – kein Kontakt: eine Zeile. Gibt es einen Rückweg, wird er zum
     *    breiten „‹" ohne Wort; so bleibt die Zeile eine.
     *  – ein verknüpfter Kontakt: zwei Zeilen. Oben der Kontakt in der
     *    Mitte und rechts das Kreuz – und links der Rückweg, wenn es
     *    einen gibt; darunter immer die Knöpfe der Nachricht. So sieht
     *    die Leiste mit Kontakt immer gleich aus, ob mit Rückweg oder
     *    ohne. Die Reihenfolge macht `order`, den Zeilenwechsel ein
     *    Element mit voller Breite dazwischen.
     */
    .mail-werkzeuge.mit-rueckweg:not(.mit-kontakt) .rueckweg .rueckweg-text { display: none; }
    .mail-werkzeuge.mit-rueckweg:not(.mit-kontakt) .rueckweg { width: 44px; padding: 0; justify-content: center; }
    .mail-werkzeuge.mit-kontakt .rueckweg { order: 0; }
    .mail-werkzeuge.mit-kontakt .spacer { display: none; }
    .mail-werkzeuge.mit-kontakt .mail-schliessen { order: 2; }
    .mail-werkzeuge.mit-kontakt::after { content: ""; flex: 0 0 100%; height: 0; order: 3; }
    .mail-werkzeuge.mit-kontakt .mail-werkzeuge-nachricht > * { order: 4; }
    .mail-werkzeuge.mit-kontakt .mail-zur-akte { order: 1; margin: 0 auto; max-width: calc(100% - 140px); }

    /* Der Rahmen bekommt seine Höhe von der Messung (`rahmenStil`) und
       scrollt dann nicht mehr in sich. `min-height: 0`, damit eine kurze
       Nachricht nicht auf die 180 Pixel der Grundregel aufgeblasen wird –
       das wären bei weißem Grund zwei Zentimeter leeres Papier.

       Ohne Messung greift weiter `height: 70vh` von oben: ein Rahmen mit
       eigenem Bildlauf ist unschön, aber lesbar. Nichts zu setzen wäre es
       nicht – ein iframe ohne Höhe ist 150 Pixel hoch. */
    .mail-seite.liest .mail-frame {
        flex: none; min-height: 0;
        /*
         * Ohne Rand – und das ist nicht nur Geschmack. `box-sizing:
         * border-box` gilt im ganzen Haus: Die gemessene Inhaltshöhe steht
         * dann als RAHMENhöhe da, und die zwei Pixel Rand fehlen innen.
         * Gemessen: zwei Pixel Bildlauf im Rahmen, also genau die
         * Bildlaufleiste, die hier verschwinden sollte.
         *
         * Ihn stattdessen mitzurechnen hieße, in der Komponente eine Zahl
         * aus dem Stilblatt nachzuhalten. Auf dem Telefon steht die
         * Nachricht ohnehin randlos – ein Kasten um den Inhalt trennt dort
         * nichts von nichts.
         */
        border: 0; border-radius: 0;
    }
}

/* Hochkant wie der Schreibdialog (siehe `.compose-dialog`): Die Karte der
   Nachricht steht 5 Pixel vom Rand des Schirms, die klebende Leiste mit
   den Knöpfen darüber ist genauso breit – schmaler sah man beim Scrollen
   links und rechts neben ihr den Inhalt vorbeiziehen. Ihre Knöpfe stehen
   10 Pixel vom Rand, auf einer Linie mit dem Betreff. In der Karte stehen
   Anhänge, Betreff, Kopfzeilen und Hinweise 10 Pixel vom Rand der Karte,
   der Inhalt der Mail 2 Pixel – den seitlichen Rand im Rahmen nimmt
   `mailRahmenInhalt()` dafür zurück. Hinter dem Telefon-Block: Bei
   gleicher Gewichtung gewinnt, was weiter unten steht. */
/* Dieselben Maße gelten im Lesedialog (Suche über alles): Dort ist es
   dieselbe Nachricht in demselben Leser, und sie soll nicht schmaler
   stehen, nur weil eine Hülle darum liegt. Die Zeilen sind deshalb um den
   Dialog erweitert und nicht ein zweites Mal geschrieben – zwei Fassungen
   derselben Maße laufen beim nächsten Mal auseinander. */
@media (max-width: 560px) {
    .mail-seite.liest .mail-reader,
    .mail-leser-dialog .mail-reader { padding-left: 5px; padding-right: 5px; }
    .mail-seite.liest .mail-reader > .mail-werkzeuge.thema-seite,
    .mail-leser-dialog .mail-reader > .mail-werkzeuge.thema-seite {
        margin-left: 0; margin-right: 0; padding-left: 10px; padding-right: 10px;
    }
    .mail-seite.liest .mail-message.thema-hell,
    .mail-leser-dialog .mail-message.thema-hell { padding-left: 2px; padding-right: 2px; }
    .mail-seite.liest .mail-reader-head,
    .mail-leser-dialog .mail-reader-head { padding-left: 8px; padding-right: 8px; }
    .mail-seite.liest .mail-message > .mail-attachments,
    .mail-seite.liest .mail-message > .mail-images-bar,
    .mail-seite.liest .mail-message > .tiny,
    .mail-leser-dialog .mail-message > .mail-attachments,
    .mail-leser-dialog .mail-message > .mail-images-bar,
    .mail-leser-dialog .mail-message > .tiny { margin-left: 8px; margin-right: 8px; }
}

/* ==========================================================================
   Kalender
   Etappe 2: der Dialog „Apple-Konten & Kalender". Die Ansicht selbst
   (Monat/Woche/Tag) kommt in Etappe 3 – siehe PLANUNG-KALENDER.md, 8.5.

   Bewusst nur zwei Klassen und alles aus den Variablen des Hauses: Die
   TermineApp bringt eine eigene Farbwelt mit; wer die mitkopiert, hat
   einen Kalender, der im hellen Thema unlesbar ist.
   ========================================================================== */

/* Der Farbpunkt eines Kalenders. Die Farbe kommt aus Apple oder aus der
   eigenen Wahl des Benutzers und wird deshalb inline gesetzt; hier steht
   nur die Form. Der Rahmen trennt einen dunklen Punkt vom dunklen Grund –
   ohne ihn verschwindet Schwarz auf Schwarz. */
.kal-punkt {
    flex: none;
    width: 10px; height: 10px;
    border-radius: 50%;
    border: 1px solid var(--line);
    display: inline-block;
}

/* Eine Zeile in der Kalenderauswahl. */
.kal-wahl {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 8px;
    border-radius: 8px;
    cursor: pointer;
}
.kal-wahl:hover { background: var(--panel-2); }

/* Ein Kalender ohne Termine (eine Erinnerungsliste) lässt sich nicht
   ankreuzen. Ausgegraut und nicht versteckt: Wer ihn bei Apple sieht und
   hier sucht, soll erfahren, warum er fehlt – statt ihn zu vermissen. */
.kal-wahl-aus { opacity: .55; cursor: not-allowed; }
.kal-wahl-aus:hover { background: transparent; }

/* ==========================================================================
   Kalender – die Ansicht (Etappe 3)

   Übersetzt aus der TermineApp, nicht kopiert: Sie bringt eine eigene
   Farbwelt mit; wer die mitnimmt, hat einen Kalender, der im hellen Thema
   unlesbar ist. Hier steht keine feste Farbe außer den zwei, die aus der
   Kalenderfarbe berechnet werden (Schrift auf farbigem Grund, in app.js).
   Siehe PLANUNG-KALENDER.md, Abschnitt 8.5.
   ========================================================================== */

.kal-seite { display: flex; flex-direction: column; height: 100%; min-height: 0; }

/* ---------- Kopfzeile ---------- */
.kal-kopf {
    display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
    padding: 0 0 12px;
}
.kal-titel { font-size: 18px; white-space: nowrap; }
.kal-sichten { margin: 0; }
/* Der Schalter für die Kalenderliste – dauerhaft sichtbar, auf jeder
   Breite. Er stand hier lange auf `display: none` und kam erst unter
   900 Pixeln dazu; wer schmal startete und dann breit zog, hatte die
   Liste weg und nichts, womit er sie zurückholen konnte. */
.kal-spalte-schalter.aktiv { color: var(--accent); }

/* `overflow: hidden` schneidet die weggeschobene Spalte sauber ab. Ohne
   das bliebe von ihr ein Streifen in der Polsterung des Inhalts stehen:
   `.content` polstert 20 Pixel, die Spalte schiebt sich um genau ihre
   eigene Breite hinaus – und käme damit 20 Pixel zu kurz. */
.kal-rumpf { flex: 1; display: flex; gap: 12px; min-height: 0; overflow: hidden; }

/* ---------- Die Kalenderspalte ---------- */
/*
 * Sie SCHIEBT, sie überlagert nicht – auf jeder Breite dieselbe
 * Darstellung, wie die Seitenleiste des CRM. Vorher wurde sie unter
 * 900 Pixeln zu `position: absolute` und lag über dem Kalender: dieselbe
 * Einstellung, zwei Bilder, je nachdem wie breit das Fenster gerade war.
 *
 * `margin-left` und nicht `x-show`: Das schiebt weich statt zu springen,
 * und die Spalte bleibt im Baum – ihr Inhalt muss nach dem Aufklappen
 * nicht neu aufgebaut werden.
 */
.kal-spalte {
    flex: 0 0 210px;
    overflow-y: auto;
    padding-right: 4px;
    border-right: 1px solid var(--line);
    transition: margin-left .25s ease;
}
/* Genau die eigene Breite – `box-sizing: border-box` gilt im ganzen Haus,
   die 210 enthalten Polsterung und Linie. Und die Lücke dazu: `gap`
   zählt auch für eine weggeschobene Spalte, und auf dem Telefon wären
   das zwölf Pixel Scrollweg ins Leere. */
.kal-spalte:not(.offen) { margin-left: -210px; margin-right: -12px; }
.kal-eintrag {
    display: flex; align-items: center; gap: 7px;
    padding: 6px 6px; border-radius: 8px; cursor: pointer;
    font-size: 13px;
}
.kal-eintrag:hover { background: var(--panel-2); }
.kal-eintrag input { flex: none; }
.kal-eintrag-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kal-eintrag-zeichen { flex: none; font-size: 11px; opacity: .8; display: flex; gap: 2px; }
.kal-spalte-fuss { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--line); }

/* ---------- Die Fläche ---------- */
.kal-flaeche { flex: 1; min-width: 0; overflow: auto; }

/* ---------- Monat ---------- */
.kal-monat {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    /* Die Kopfzeile so hoch, wie sie sein muss; die sechs Wochen teilen
       sich den Rest zu gleichen Teilen. Ohne das wachsen Zellen mit vielen
       Terminen und das Raster wird schief. */
    grid-template-rows: auto repeat(6, minmax(84px, 1fr));
    gap: 1px;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    overflow: hidden;
    min-height: 100%;
}
.kal-wochentag {
    background: var(--panel-2); color: var(--muted);
    padding: 6px 8px; font-size: 12px; font-weight: 600; text-align: center;
}
.kal-zelle {
    background: var(--panel);
    padding: 4px; min-width: 0;
    display: flex; flex-direction: column; gap: 2px;
    overflow: hidden;
    /* Anklickbar: Ein Klick waehlt den Tag – daran haengen „+ Termin"
       und der Wechsel auf Woche oder Tag. */
    cursor: pointer;
}
/* Tage des Vor- und Folgemonats: zurückgenommen, aber nicht unsichtbar –
   sie tragen echte Termine. */
.kal-fremd { background: var(--bg); }
.kal-fremd .kal-zellkopf { color: var(--muted); }
/* Zwei Rahmen INNEN, keine Flächen: Eine farbige Zelle stritte mit den
   Terminfarben darin.

   Heute trägt das kräftigere Blau (`--accent-fill`, nicht das hellere
   `--accent`) – auf dem dunklen Feld ist es das ruhigere von beiden und
   in der hellen Fassung ohnehin derselbe Wert.

   Beides zugleich kommt oft vor und beim Öffnen immer: Dann steht das
   Blau außen und das Grau als zweiter Ring dahinter. Ohne diese Regel
   gewänne eine der beiden, und die andere Angabe wäre stillschweigend
   weg. */
.kal-heute { box-shadow: inset 0 0 0 2px var(--accent-fill); }
.kal-gewaehlt { box-shadow: inset 0 0 0 2px var(--wahl); }
.kal-heute.kal-gewaehlt {
    box-shadow: inset 0 0 0 2px var(--accent-fill), inset 0 0 0 4px var(--wahl);
}
.kal-zellkopf {
    display: flex; align-items: center; justify-content: space-between;
    font-size: 12px; font-weight: 600; padding: 1px 3px;
}
.kal-zellinhalt { flex: 1; min-height: 0; overflow-y: auto; display: flex; flex-direction: column; gap: 2px; }

/* ---------- Ein Termin ---------- */
.kal-pille {
    display: flex; align-items: center; gap: 4px;
    padding: 2px 6px; border-radius: 5px;
    font-size: 12px; line-height: 1.35;
    cursor: pointer;
    overflow: hidden; white-space: nowrap;
}
.kal-pille:hover { filter: brightness(1.12); }
.kal-pille-zeit { flex: none; opacity: .85; font-variant-numeric: tabular-nums; }
.kal-pille-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }

/* Ein abgesagter Termin bleibt stehen und ist durchgestrichen: Dass er
   abgesagt ist, ist die Auskunft – ihn zu entfernen wäre keine. */
.kal-abgesagt { text-decoration: line-through; opacity: .6; }
.kal-vorlaeufig { opacity: .75; border: 1px dashed currentColor; }
/* Über Mitternacht: die Kanten laufen weiter, statt zu schließen. */
.kal-laeuft-weiter { border-top-right-radius: 0; border-bottom-right-radius: 0; }
.kal-kam-von { border-top-left-radius: 0; border-bottom-left-radius: 0; }
/* Zustand des Abgleichs – der ehrliche Teil. */
.kal-wartet { opacity: .7; }
.kal-kaputt { box-shadow: inset 0 0 0 2px var(--danger); }

/* Stufe „belegt": Die Zeit ist weg, der Titel geht niemanden an. Ein
   schraffierter Block und kein Loch – der Anwender soll SEHEN, dass hier
   etwas ist, sonst plant er darüber hinweg. */
.kal-gesperrt {
    cursor: default;
    color: var(--muted);
    background: repeating-linear-gradient(
        135deg, var(--panel-2), var(--panel-2) 5px, var(--line) 5px, var(--line) 10px);
}
.kal-gesperrt:hover { filter: none; }

/* ---------- Woche und Tag ---------- */
.kal-zeitraster { display: flex; flex-direction: column; min-height: 100%; }
.kal-zeitkopf, .kal-ganztags { display: flex; position: sticky; top: 0; z-index: 2; background: var(--panel); }
.kal-ganztags { top: 44px; border-bottom: 1px solid var(--line); }
.kal-uhrspalte { flex: 0 0 54px; }
.kal-ganztags-titel {
    color: var(--muted); font-size: 11px; padding: 4px 6px; text-align: right;
}
.kal-tagesspalten { flex: 1; display: flex; min-width: 0; }
.kal-tageskopf {
    flex: 1; min-width: 0; text-align: center;
    padding: 5px 2px; border-left: 1px solid var(--line);
}
.kal-tagname { font-size: 11px; color: var(--muted); }
.kal-tagdatum { font-size: 14px; font-weight: 600; }
.kal-ganztags-zelle {
    flex: 1; min-width: 0; min-height: 24px;
    border-left: 1px solid var(--line); padding: 2px;
    display: flex; flex-direction: column; gap: 2px;
}
.kal-zeitrumpf { display: flex; flex: 1; }
/* 48 px je Stunde – derselbe Wert steht in app.js (kalAnordnen). Ändert
   sich einer, sitzen die Blöcke auf falscher Höhe. */
.kal-stundenzeile {
    height: 48px; font-size: 11px; color: var(--muted);
    text-align: right; padding-right: 6px;
    transform: translateY(-6px);
}
.kal-tagesspalte {
    flex: 1; min-width: 0; position: relative;
    border-left: 1px solid var(--line);
}
.kal-stundenfeld { height: 48px; border-bottom: 1px solid var(--line); }
/* Außerhalb des Arbeitstags (Einstellungen → Kalender · Ansicht): gedämpft,
   nicht weg – ein früher Termin soll sichtbar bleiben. */
.kal-stundenfeld.kal-ausserhalb { background: var(--panel-2); }
.kal-stundenzeile.kal-ausserhalb { opacity: .6; }
.kal-block {
    position: absolute; overflow: hidden;
    border-radius: 6px; padding: 2px 5px;
    font-size: 11px; line-height: 1.3; cursor: pointer;
}
.kal-block:hover { filter: brightness(1.12); }
.kal-block-titel { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.kal-block-zeit, .kal-block-ort { opacity: .85; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ---------- Die Agenda unter dem Kalender ----------
   Sie steht UNTER dem Rumpf und nicht darin: Das Raster behält seinen
   Platz (`.kal-rumpf` ist `flex: 1`), die Agenda nimmt nur, was sie
   braucht, und scrollt in sich. Ein Monat mit sechzig Terminen darf den
   Kalender nicht aus dem Bild schieben. */
.kal-agenda {
    flex: none; min-height: 0;
    display: flex; flex-direction: column;
    margin-top: 10px; border-top: 1px solid var(--line);
}
/* Der Kopf ist der Schalter – eine ganze Zeile und kein kleines Dreieck:
   Wer die Agenda zuklappen will, trifft so auch auf einem Tastfeld. */
.kal-agenda-kopf {
    display: flex; align-items: baseline; gap: 8px;
    background: none; border: 0; padding: 8px 2px;
    color: var(--text); font-size: 13px; font-weight: 600;
    cursor: pointer; text-align: left;
}
.kal-agenda-kopf:hover { background: none; color: var(--accent); }
.kal-agenda-pfeil { display: inline-block; transition: transform .15s ease; color: var(--muted); }
.kal-agenda-pfeil.offen { transform: rotate(90deg); }
/* Die Höhe gedeckelt, damit unter dem Kalender noch Kalender bleibt. */
.kal-agenda-liste { overflow-y: auto; max-height: min(34vh, 300px); padding-bottom: 4px; }
/* Die Tagesüberschrift bleibt beim Scrollen stehen – in einer Liste über
   sechs Wochen weiß man sonst nach zwei Umdrehungen nicht mehr, welcher
   Tag gerade läuft. */
.kal-agenda-tag {
    position: sticky; top: 0; z-index: 1;
    background: var(--bg);
    font-size: 12px; font-weight: 600; color: var(--muted);
    padding: 6px 0 3px;
}

/* ---------- Liste ---------- */
.kal-liste { display: flex; gap: 16px; align-items: flex-start; }
.kal-mini { flex: 0 0 280px; }
.kal-monat-mini { grid-template-rows: auto repeat(6, 46px); min-height: 0; }
.kal-minizelle { align-items: center; justify-content: center; cursor: pointer; font-size: 12px; }
.kal-minizelle:hover { background: var(--panel-2); }
.kal-minipunkte { display: flex; gap: 2px; }
.kal-minipunkt { width: 5px; height: 5px; border-radius: 50%; }
.kal-tagesliste { flex: 1; min-width: 0; }
.kal-listenkopf { margin-bottom: 10px; }
.kal-listeneintraege { list-style: none; margin: 0; padding: 0; }
.kal-listeneintrag {
    display: flex; align-items: center; gap: 10px;
    padding: 8px 6px; border-bottom: 1px solid var(--line); cursor: pointer;
}
.kal-listeneintrag:hover { background: var(--panel-2); }
.kal-listenzeit { flex: 0 0 62px; font-variant-numeric: tabular-nums; font-size: 13px; }
.kal-listenstreifen { flex: 0 0 3px; align-self: stretch; border-radius: 2px; }
.kal-listentext { flex: 1; min-width: 0; }
/* Der schraffierte Block ist in der Liste eine Zeile – dieselbe Aussage,
   andere Form. Ohne Zeiger, weil es nichts zu öffnen gibt. */
.kal-listeneintrag.kal-gesperrt { background: none; cursor: default; color: var(--muted); }

/* ---------- Die Übersicht im Termin-Dialog ----------
   Gleitet links neben dem Dialog heraus: der kleine Monat wie unter
   „Liste", darunter die Termine des gewählten Tages – nur zum Ansehen,
   deshalb ohne Zeiger und ohne Hervorhebung beim Überfahren. Der Dialog
   ist die Bezugsbox (`:has`), damit die Übersicht an seiner Kante hängt.
   Mit offener Übersicht rückt der Dialog um die halbe Breite nach
   rechts – beide zusammen stehen dann in der Mitte. */
.modal-box:has(.kal-planer) { position: relative; transition: transform .18s ease; }
.modal-box:has(.kal-planer.offen) { transform: translateX(156px); }
.kal-planer {
    position: absolute; top: 0; right: calc(100% + 12px); width: 300px;
    max-height: 90vh; max-height: 90dvh; overflow-y: auto; box-sizing: border-box; padding: 12px;
    background: var(--panel); border: 1px solid var(--seite-accent); border-radius: var(--radius);
    box-shadow: 0 8px 28px rgba(0, 0, 0, .3);
    opacity: 0; visibility: hidden; pointer-events: none; transform: translateX(40px);
    transition: opacity .18s ease, transform .18s ease, visibility 0s linear .18s;
}
.kal-planer.offen {
    opacity: 1; visibility: visible; pointer-events: auto; transform: none;
    transition: opacity .18s ease, transform .18s ease, visibility 0s;
}
.kal-planer-kopf { display: flex; align-items: center; gap: 4px; margin-bottom: 8px; }
.kal-planer-kopf strong { flex: 1; text-align: center; }
.kal-planer .kal-monat-mini { grid-template-rows: auto repeat(6, 36px); }
.kal-planer-tag { margin-top: 12px; }
/* Nie seitlich scrollen: Ein Ort wie „Jitsi: https://meet…/PMG" hat
   keine Stelle zum Umbrechen und machte die Zeile breiter als die
   Übersicht – `overflow-y: auto` oben zog dann auch waagerecht einen
   Balken auf. Jetzt bricht der Text, wo er muss, und bleibt ganz lesbar. */
.kal-planer { overflow-x: hidden; }
.kal-planer .kal-listentext { overflow-wrap: anywhere; }
.kal-planer-liste .kal-listeneintrag { cursor: default; }
.kal-planer-liste .kal-listeneintrag:hover { background: none; }
.kal-planer-knopf.aktiv { color: var(--accent); }
/* Ist neben dem Dialog kein Platz, liegt die Übersicht ÜBER ihm – von
   links hereingeschoben, mit dem Kreuz oben zum Schließen. */
@media (max-width: 1080px) {
    .modal-box:has(.kal-planer.offen) { transform: none; }
    .kal-planer {
        right: auto; left: 0; bottom: 0; max-height: none; width: min(320px, 100%); z-index: 2;
        border-radius: var(--radius) 0 0 var(--radius); transform: translateX(-100%);
    }
    .kal-planer.offen { transform: none; }
}

/* ---------- Schmale Bildschirme ----------
   Sieben Spalten auf 380 Pixeln sind unlesbar. Die Wochenansicht bleibt
   erreichbar (der Kopf scrollt waagerecht mit), aber die Kalenderliste
   klappt weg und die Liste wird einspaltig. */
@media (max-width: 900px) {
    .kal-liste { flex-direction: column; }
    .kal-mini { flex: none; width: 100%; max-width: 340px; }
    /* Gestapelt braucht auch die Tagesliste eine Breite: `align-items:
       flex-start` lässt Kinder in einer Spalte auf ihre INHALTSbreite
       schrumpfen. Ein Tag mit einem kurzen Termin war damit 425 Pixel
       breit, während daneben 435 leer blieben. */
    .kal-tagesliste { width: 100%; }
    .kal-titel { font-size: 15px; }
}

/* Auf einem Telefon nimmt die Spalte 210 von 380 Pixeln. Statt den
   Kalender daneben zu quetschen, behält er seine Breite und rückt nach
   rechts – man scrollt zu ihm. Wer die Liste aufmacht, will die Liste;
   wer den Kalender will, macht sie zu (der Schalter steht daneben).

   Die Grenze ist 768 wie im ganzen Haus, nicht 900 wie vorher hier. */
@media (max-width: 768px) {
    .kal-rumpf { overflow-x: auto; }
    /*
     * `flex: 0 0 100%` und NICHT `1 0 auto`: Bei `flex-basis: auto` ist
     * die Grundbreite die INHALTSBREITE, und ein Raster aus `1fr`-Spalten
     * meldet als solche seine Max-Content-Breite – sieben Spalten so
     * breit wie ihr längster Termintitel. Der Monat wurde damit auf dem
     * Telefon mehrere Bildschirme breit.
     *
     * Mit 100 % ist die Grundbreite fest, `min-width: 0` hält die
     * selbsttätige Mindestbreite von Flex-Kindern draußen, und `1fr`
     * teilt eine bekannte Breite auf, statt sie zu bestimmen.
     */
    .kal-flaeche { flex: 0 0 100%; min-width: 0; }

    /*
     * Der Mini-Kalender nimmt die volle Breite. Die 340 aus dem Block
     * darüber sind für ein Tablet gedacht – dort stünde ein über die
     * ganze Breite gezogener Monat allein und verloren. Auf einem Telefon
     * ist die ganze Breite genau richtig: Die Zellen werden anfassbar,
     * statt dass rechts ein Streifen leer bleibt.
     */
    .kal-mini { max-width: none; }
    /*
     * Mit der vollen Breite wachsen die Zellen in die Breite – die Zeilen
     * müssen mit, sonst wird aus dem Monat ein flaches Band. Eine Zelle
     * ist rund ein Siebtel der Breite; `12vw` hält sie annähernd
     * quadratisch, und die 46 aus der Grundregel bleiben die Untergrenze
     * für die schmalsten Geräte. Auf dieser Breite liegt die
     * CRM-Seitenleiste als Overlay, nimmt also keine Breite weg – `vw`
     * beschreibt hier wirklich den Platz, den der Kalender hat.
     */
    .kal-monat-mini { grid-template-rows: auto repeat(6, max(46px, 12vw)); }
}

/* Der Termin-Dialog. */
.kal-detail { display: flex; align-items: center; gap: 7px; margin-bottom: 6px; }
.kal-detail-zeit { font-size: 15px; font-weight: 600; margin: 0 0 10px; }

/* Das Plus in einer Monatszelle. Erscheint beim Überfahren – ein Plus in
   jeder der 42 Zellen wäre Lärm, und Doppelklick findet nicht jeder. */
.kal-plus {
    background: none; border: 0; color: var(--muted);
    padding: 0 3px; line-height: 1; font-size: 14px; cursor: pointer;
    opacity: 0; transition: opacity .1s;
}
.kal-zelle:hover .kal-plus { opacity: 1; }
.kal-plus:hover { background: none; color: var(--accent); }
/* Auf einem Tastfeld gibt es kein Überfahren – dort steht es immer da. */
@media (hover: none) { .kal-plus { opacity: .6; } }

.kal-listenkopf { display: flex; align-items: center; justify-content: space-between; }
/* Ein leeres Stundenfeld ist anklickbar – der Zeiger sagt es. */
.kal-stundenfeld { cursor: pointer; }
.kal-stundenfeld:hover { background: var(--panel-2); }

/* Die Freigabemaske. Eine Tabelle und keine Kartenliste: Es geht um den
   Vergleich Zeile für Zeile – wer darf was –, und den liest man in
   Spalten. */
.kal-freigaben { width: 100%; border-collapse: collapse; }
.kal-freigaben th {
    text-align: left; font-size: 12px; font-weight: 600; color: var(--muted);
    padding: 4px 8px 8px; border-bottom: 1px solid var(--line);
}
.kal-freigaben td { padding: 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.kal-freigaben select { width: 100%; }
/* Wer den Kalenderbereich nicht benutzen darf, bekommt keine Freigabe:
   Ausgegraut statt versteckt, damit die Frage „warum steht der nicht in
   der Liste?" gar nicht erst entsteht. */
.kal-frg-aus { opacity: .55; }

/* Das Abgleichprotokoll. Schmal gesetzt – es wird überflogen, nicht
   gelesen: Man sucht die eine Zeile, in der etwas schieflief. */
.kal-laeufe { width: 100%; border-collapse: collapse; font-size: 12px; }
.kal-laeufe th {
    text-align: left; font-weight: 600; color: var(--muted);
    padding: 4px 8px; border-bottom: 1px solid var(--line);
}
.kal-laeufe td { padding: 5px 8px; border-bottom: 1px solid var(--line); vertical-align: top; }
.kal-lauf-fehler td { color: var(--danger); }

/* „Termine heute" auf der Startseite: dieselbe Tabelle wie „Wiedervorlage"
   und „Später fällig" – nur Zeit, Termin, Ort, Kontakt statt Art und Fällig. */
.kal-heute-feld { margin-bottom: 22px; }
.kal-heute-tabelle .kal-heute-zeit { color: var(--muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.kal-heute-tabelle .kal-punkt { display: inline-block; vertical-align: middle; margin-right: 6px; }
.kal-heute-titel { vertical-align: middle; }
/* Vergangene Termine grau, der nächste hervorgehoben; eine Zeile mit
   Termin öffnet ihn im Kalender. Die Kontakte als Chips in die Akte. */
.kal-heute-tabelle tr.vorbei td { opacity: .5; }
.kal-heute-tabelle tr.naechster .kal-heute-titel { font-weight: 600; color: var(--accent); }
.kal-heute-kontakte { display: inline-flex; gap: 4px; flex-wrap: wrap; }
.kal-heute-kontakte .kal-kontakt-chip { text-decoration: none; color: var(--text); padding: 1px 8px; font-size: 11.5px; }
.kal-heute-morgen { margin-top: 14px; }
.kal-heute-morgen .label-like { margin-bottom: 4px; }
/* Der Kopf am Zeilenende ist nur für das Telefon da – siehe den Block
   für schmale Geräte bei den Datentabellen. */
.kal-heute-person { display: none; color: var(--muted); vertical-align: middle; margin-left: 6px; }
.kal-heute-person:hover { color: var(--accent); }

/* ---------- Termine in der Kontaktakte ---------- */
.kal-akte { list-style: none; margin: 0; padding: 0; }
.kal-akte li {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 6px; border-bottom: 1px solid var(--line);
    font-size: 13px; cursor: pointer;
}
.kal-akte li:hover { background: var(--panel-2); }
.kal-akte-zeit {
    flex: 0 0 120px; color: var(--muted);
    font-variant-numeric: tabular-nums; font-size: 12px;
}
.kal-akte-titel { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
/* Gewesene zurückgenommen, aber lesbar: Sie sind Beleg, nicht Aufgabe. */
.kal-akte-alt li { opacity: .72; }
/* Ein Termin, dessen Titel die Stufe verbirgt, ist nicht anklickbar –
   es gibt nichts zu öffnen. */
.kal-akte-gesperrt { cursor: default !important; color: var(--muted); }
.kal-akte-gesperrt:hover { background: none !important; }

/* ---------- Kontakte am Termin ---------- */
.kal-kontaktfeld { margin-top: 14px; padding-top: 12px; border-top: 1px solid var(--line); }
/* Im Formular steht der Block zwischen Titel und Kalender – dort ist er ein
   Feld unter Feldern, keine Fußzeile: ohne Trennlinie, mit dem Abstand der
   Felder. */
label + .kal-kontaktfeld { margin: 0 0 12px; padding-top: 0; border-top: 0; }
.kal-kontakt-chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 8px; }
.kal-kontakt-chip {
    display: inline-flex; align-items: center; gap: 5px;
    background: var(--panel-2); border: 1px solid var(--line);
    border-radius: 999px; padding: 3px 6px 3px 10px; font-size: 12px;
}
.kal-chip-weg {
    background: none; border: 0; color: var(--muted);
    padding: 0 3px; line-height: 1; font-size: 14px; cursor: pointer;
}
.kal-chip-weg:hover { background: none; color: var(--danger); }
/* Die Trefferliste der Suche. Kurz gehalten – sie ist ein Vorschlag,
   keine Ansicht: Wer blättern will, geht in die Kontaktliste. */
.kal-treffer {
    list-style: none; margin: 4px 0 0; padding: 0;
    border: 1px solid var(--line); border-radius: var(--radius);
    background: var(--panel); max-height: 200px; overflow-y: auto;
}
.kal-treffer li {
    display: flex; justify-content: space-between; gap: 10px;
    padding: 6px 10px; cursor: pointer; font-size: 13px;
}
.kal-treffer li:hover { background: var(--panel-2); }
/* Tastatur und Maus zeigen dieselbe Zeile an – wie in der Branchenauswahl. */
.kal-treffer li.aktiv { background: var(--accent); color: #fff; }
.kal-treffer li.aktiv .muted { color: rgba(255, 255, 255, .75); }

/* Rote Schrift statt roter Fläche.
   Für Stellen, an denen etwas endgültig ist oder schiefsteht, aber nicht
   die Hauptaussage der Zeile: „Konto trennen" neben „Kalender wählen",
   „Endgültig löschen" im Pool, die Zahl fehlgeschlagener Aufträge.

   **Die Klasse wurde an fünf Stellen benutzt und war nie definiert** –
   auf Knöpfen wie auf `<span>`. Sie sahen deshalb aus wie gewöhnlicher
   Text, und zwar seit jeher, nicht erst seit dem Kalender.

   Wo Rot die Hauptaussage ist, steht weiter `button.danger` mit voller
   Fläche – etwa „Löschen" im Termin-Dialog: Der Termin verschwindet auch
   bei Apple, auf allen Geräten, ohne Papierkorb. */
.danger-text { color: var(--danger); }
button.ghost.danger-text:hover { background: var(--panel-2); color: var(--danger); }

/* ---------- Gestapelte Dialoge ----------

   Das Haus kannte bisher nur einen Dialog zur Zeit: Alle `.modal` liegen
   auf `z-index: 50`, und welcher oben liegt, entschiede die Reihenfolge
   im Markup – also der Zufall.

   Der Kalender braucht den Stapel: „Konflikte & Fehler" wird aus dem
   Konten-Dialog heraus geöffnet, und wer einen Termin aus der Liste
   ansieht, will danach zur Liste zurück und nicht wieder von vorn
   suchen.

   Stapeln braucht DREI Dinge, und ohne alle drei wird es eine Falle:

     1. die Höhe – sonst öffnet der zweite hinter dem ersten,
     2. die Escape-Taste – sonst schließt sie alle auf einmal,
     3. den Hintergrundklick – der obere Schleier muss ihn fangen.

   Die Stufe steht am Dialog und nicht in einem Stapelzähler: Welcher
   über welchem liegt, ist eine Eigenschaft des Dialogs (ein Termin liegt
   immer über einer Liste, nie umgekehrt) und keine der Reihenfolge, in
   der jemand geklickt hat. Punkt 2 steht in index.php an den
   `@keydown.escape`-Bedingungen, Punkt 3 ergibt sich aus 1. */
.modal-stufe-2 { z-index: 51; }
.modal-stufe-3 { z-index: 52; }
/* Zwei Schleier übereinander wären doppelt so dunkel. Der obere ist
   deshalb dünner – er soll Tiefe zeigen, nicht das Darunterliegende
   auslöschen. */
.modal-stufe-2 { background: rgba(0,0,0,.35); }
.modal-stufe-3 { background: rgba(0,0,0,.3); }

/* Die Rückfrage liegt über allem.
   (`-oben` und nicht `-frage`: Es geht um die Höhe, nicht um die Art.
   Die Art steckt in `confirmBox.art` und entscheidet über die Farbe.)
   Sie ist eine Frage ZU dem, was gerade offen ist – „diesen Termin
   löschen?" über dem Termin, „ohne Betreff senden?" über dem
   Schreibfenster. Bisher lag sie nur deshalb oben, weil sie zufällig
   später im Markup steht; das ist keine Zusage, sondern ein Zustand.
   56, weil der Streifen (60) darüber bleiben muss: Eine Meldung, die
   hinter einem Dialog verschwindet, ist keine. */
.modal-oben { z-index: 56; }

/* ---------- Nie zoomen ----------
 * iOS Safari zoomt beim Fokus in jedes Feld hinein, dessen Schrift kleiner
 * als 16 Pixel ist – auch in ein Schreibfeld (`contenteditable`). Die
 * Grundregel oben setzt 16 Pixel; an ein Dutzend Stellen wird sie danach
 * unterschritten (Mailsuche 13, Schreibfeld 14, kleine Auswahlfelder 12),
 * und jede davon zoomte den Dialog auf dem Telefon aus dem Bild. Deshalb
 * EINE Regel am Ende, für alle: Auf Tastgeräten haben Felder mindestens
 * 16 Pixel, und `!important` steht hier mit Absicht – es ist eine
 * Zusicherung, keine Gestaltung. Am Schreibtisch (`pointer: fine`)
 * bleibt alles, wie es war. */
@media (pointer: coarse) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
    select, textarea, [contenteditable="true"] {
        font-size: 16px !important;
    }
}

/* Das Kreuz zum Leeren – in beiden Suchfeldern dasselbe: rechts im Feld,
   erst da, wenn etwas drinsteht. Gedämpft, damit es nicht mit dem Inhalt
   um Aufmerksamkeit streitet; unter dem Zeiger nimmt es die Schriftfarbe. */
.such-x {
    position: absolute; right: 6px; top: 50%; transform: translateY(-50%);
    background: none; border: 0; padding: 4px; line-height: 0;
    color: var(--muted); cursor: pointer;
}
.such-x:hover:not(:disabled) { background: none; color: var(--text); }
.such-x svg { display: block; }
/* Der Suchknopf des Browsers wäre ein zweites Kreuz daneben. */
.such-x + input, .search input, .topbar .suche input { appearance: none; -webkit-appearance: none; }
input[type="search"]::-webkit-search-cancel-button { display: none; }

/* ---------- Die Suche über alles (Kopfleiste) ----------
 * Ein Feld mit Lupe vor dem Zahnrad; die Treffer als Liste darunter,
 * gezeichnet wie die Branchenauswahl (`.combo-liste`), in Gruppen. Auf
 * dem Telefon nimmt das Feld die Breite zwischen Marke und Zahnrad. */
.topbar .suche { position: relative; display: flex; align-items: center; }
/* Lupe und Kreuz hängen im FELD, nicht in `.suche`: Auf dem Telefon gibt
   `.suche` seinen Bezugspunkt an die Kopfleiste ab, damit die
   Trefferliste über den Schirm spannt – die beiden wanderten sonst mit. */
.topbar .suche-feld { position: relative; display: flex; align-items: center; }
.topbar .suche-lupe {
    position: absolute; left: 10px; width: 16px; height: 16px; color: var(--muted); pointer-events: none;
}
.topbar .suche input {
    width: 220px; padding: 7px 30px 7px 32px; font-size: 14px; border-radius: 999px;
    transition: width .15s ease;
}
.topbar .suche input:focus { width: 320px; }
.topbar .suche-liste { left: auto; right: 0; min-width: 360px; max-width: min(520px, 92vw); max-height: 70vh; }
.suche-gruppe { padding: 4px 0; }
.suche-gruppe + .suche-gruppe { border-top: 1px solid var(--line); }
.suche-gruppe .label-like { padding: 4px 11px 2px; }
.suche-hinweis { padding: 8px 11px; }
.suche-zeile { white-space: normal; }
.suche-zeile > span:first-child { flex: 1 1 auto; min-width: 0; }
.suche-zeile .combo-hinweis { flex: 0 1 45%; text-align: right; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* ---------- Die Hilfe ----------
 * Zwei Spalten: links der Text (rollt), rechts das Verzeichnis (steht).
 * Auf dem Telefon eine Spalte, das Verzeichnis als Zeile darüber. */
/* 90 Prozent des Fensters, in beiden Richtungen – die Anleitung ist ein
   Text zum Lesen, kein Formular. `dvh` wie überall: misst, was auf dem
   Telefon wirklich da ist. */
.hilfe-box { display: flex; flex-direction: column; width: 90vw; height: 90vh; height: 90dvh; max-width: none; }
.hilfe-koerper { display: flex; gap: 20px; min-height: 0; flex: 1 1 auto; }
.hilfe-inhalt {
    flex: 1 1 auto; min-width: 0; overflow-y: auto; padding-right: 8px;
    font-size: 14.5px; line-height: 1.6;
}
.hilfe-inhalt h2 { font-size: 18px; margin: 22px 0 8px; padding-top: 6px; border-top: 1px solid var(--line); }
.hilfe-inhalt h2:first-child { margin-top: 0; padding-top: 0; border-top: 0; }
.hilfe-inhalt h3 { font-size: 15px; margin: 16px 0 6px; }
.hilfe-inhalt p { margin: 0 0 10px; }
.hilfe-inhalt ul { margin: 0 0 10px; padding-left: 20px; }
.hilfe-inhalt li { margin-bottom: 5px; }
.hilfe-inhalt code { font-size: 13px; background: var(--panel-2); padding: 1px 4px; border-radius: 4px; }
.hilfe-inhalt a { color: var(--accent); }
.hilfe-index {
    flex: 0 0 240px; overflow-y: auto; border-left: 1px solid var(--line); padding-left: 14px;
    display: flex; flex-direction: column; gap: 2px; font-size: 13px;
}
.hilfe-index a { color: var(--text); text-decoration: none; padding: 3px 8px; border-radius: 6px; }
.hilfe-index a.kapitel { font-weight: 600; margin-top: 6px; }
.hilfe-index a:not(.kapitel) { padding-left: 18px; color: var(--muted); }
.hilfe-index a:hover { background: var(--panel-2); }
.hilfe-index a.aktiv { background: var(--accent-fill); color: #fff; }
@media (max-width: 700px) {
    /* Auf dem Telefon der ganze Schirm: 90 Prozent ließen einen Rand, der
       nur Platz kostet. Der Schleier hat dort ein Polster von 20 Pixeln –
       die Box streckt sich über es hinweg. */
    .hilfe-box { width: 100vw; height: 100vh; height: 100dvh; border-radius: 0; margin: -20px; padding: 16px; }
    .hilfe-koerper { flex-direction: column-reverse; }
    .hilfe-index {
        flex: 0 0 auto; max-height: 96px; border-left: 0; border-bottom: 1px solid var(--line);
        padding: 0 0 8px; flex-direction: row; flex-wrap: wrap; gap: 4px;
    }
    .hilfe-index .label-like { display: none; }
    .hilfe-index a:not(.kapitel) { display: none; }
    .hilfe-index a.kapitel { margin-top: 0; }
}

