/* ==========================================================================
   Chat — Threema-inspired Design (Light + Dark)
   ========================================================================== */

:root {
    color-scheme: light dark;

    --radius-sm:   8px;
    --radius:      12px;
    --radius-lg:   18px;
    --radius-pill: 999px;

    --safe-top:    env(safe-area-inset-top);
    --safe-bottom: env(safe-area-inset-bottom);

    /* Brand — Logo-Petrol/Teal */
    --accent:        #1d8c84;
    --accent-rgb:    29, 140, 132;
    --accent-hover:  #15706a;
    --accent-soft:   #d4ebe8;
    --accent-dim:    #6dbab1;
    --danger:        #dc2626;
    --warning:       #f59e0b;
    --success:       #1d8c84;

    /* Light theme */
    --bg-app:        #f0f1f3;
    --bg-card:       #ffffff;
    --bg-elevated:   #ffffff;
    --bg-input:      #f3f4f6;
    --bg-hover:      #f7f8fa;
    --bg-pill:       #e5e7eb;

    --text-primary:   #111827;
    --text-secondary: #4b5563;
    --text-tertiary:  #9ca3af;

    --border:        #e5e7eb;
    --border-soft:   #eef0f3;

    --bubble-me-bg:     var(--accent);
    --bubble-me-text:   #ffffff;
    --bubble-them-bg:   #ffffff;
    --bubble-them-text: #111827;
    --bubble-shadow:    0 1px 1.5px rgba(15, 23, 42, 0.06);

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 14px -4px rgba(0, 0, 0, 0.10), 0 2px 4px rgba(0, 0, 0, 0.04);
    --shadow-lg: 0 20px 50px -12px rgba(0, 0, 0, 0.22);
}

@media (prefers-color-scheme: dark) {
    :root {
        --bg-app:        #0d0f12;
        --bg-card:       #1a1d22;
        --bg-elevated:   #232730;
        --bg-input:      #232730;
        --bg-hover:      #232730;
        --bg-pill:       #2d323c;

        --text-primary:   #f3f4f6;
        --text-secondary: #9ca3af;
        --text-tertiary:  #6b7280;

        --border:        #2a2e36;
        --border-soft:   #1f2329;

        --accent:        #3fb8af;
        --accent-rgb:    63, 184, 175;
        --accent-hover:  #6cd0c7;
        --accent-soft:   #0e3f3b;

        --bubble-me-bg:     #15706a;
        --bubble-them-bg:   #232730;
        --bubble-them-text: #f3f4f6;
        --bubble-shadow:    0 1px 2px rgba(0, 0, 0, 0.5);

        --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45);
        --shadow-md: 0 6px 18px -4px rgba(0, 0, 0, 0.55);
        --shadow-lg: 0 24px 60px -12px rgba(0, 0, 0, 0.7);
    }
}

/* ==========================================================================
   Reset
   ========================================================================== */

/* Wenn die Tastatur offen ist, gibt es keinen System-Nav-Bar mehr unten,
   den wir umgehen muessten — Composer soll direkt auf der Tastatur sitzen,
   kein leerer Streifen dazwischen. Klasse wird vom Capacitor-Keyboard-Plugin
   gesetzt (native.js) und zusaetzlich als Fallback per visualViewport-Diff
   in app.js. Direkt am Composer ueberschreiben, damit es auch dann greift,
   wenn die env()-Reaktion auf die CSS-Variable verzoegert ist. */
body.keyboard-open                    { --safe-bottom: 0px; }
body.keyboard-open .composer          { padding-bottom: 8px; }
body.keyboard-open .messages          { padding-bottom: 8px; }

*, *::before, *::after { box-sizing: border-box; }
html, body { margin: 0; height: var(--app-h, 100%); overflow: hidden; }
/* position:fixed nagelt den Body an die Visual-Viewport-Oberkante, damit die
   WebView den ganzen Layout-Container nicht mehr scrollen kann, wenn die
   Tastatur den Input nach oben "schieben" will. Hoehe kommt aus --app-h
   (JS-gesetzt auf visualViewport.height) → Composer sitzt damit immer
   direkt ueber der Tastatur. Der ggf. verbleibende Spalt zwischen Body
   und Tastatur-Top wird vom Activity-windowBackground (= --bg-app)
   abgedeckt (Patch in apply-android-patches.ps1). */
body { position: fixed; top: 0; left: 0; right: 0; }

/* In der nativen Webview (Capacitor) keine Scrollbalken zeigen. */
body.is-native, body.is-native * { scrollbar-width: none; -ms-overflow-style: none; }
body.is-native *::-webkit-scrollbar { width: 0; height: 0; display: none; }
body {
    background: var(--bg-app);
    color: var(--text-primary);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", "Helvetica Neue", system-ui, sans-serif;
    font-size: 15px;
    line-height: 1.45;
    -webkit-font-smoothing: antialiased;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}
input, button, textarea { font: inherit; color: inherit; }
input, textarea { user-select: text; }
button { cursor: pointer; border: 0; background: transparent; padding: 0; color: inherit; }
a { color: var(--accent); text-decoration: none; }
[hidden] { display: none !important; }

.icon { width: 22px; height: 22px; flex-shrink: 0; }

/* File-Inputs visuell verstecken, aber per JS .click() trotzdem auslösbar */
.visually-hidden {
    position: absolute !important;
    width: 1px !important;
    height: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0,0,0,0) !important;
    border: 0 !important;
    opacity: 0 !important;
    pointer-events: none !important;
}

#app { height: var(--app-h, 100%); position: relative; overflow: hidden; }

/* Auf Desktop / großen Bildschirmen den Chat auf 700 px begrenzen und
   horizontal zentrieren, damit die Bubbles nicht über die ganze Breite
   gehen. Auf Mobile (< 760 px) bleibt #app vollflächig. */
@media (min-width: 760px) {
    body { background: #0a0a0a; }
    #app {
        max-width: 700px;
        margin: 0 auto;
        box-shadow: 0 0 32px rgba(0, 0, 0, 0.5);
        border-left:  1px solid var(--border);
        border-right: 1px solid var(--border);
    }
}

/* ==========================================================================
   Screens
   ========================================================================== */

.screen {
    position: absolute;
    inset: 0;
    display: none;
    flex-direction: column;
    padding-top: var(--safe-top);
    background: var(--bg-app);
}
.screen.active { display: flex; animation: fadeIn 200ms ease-out; }
.edge-swipe-zone {
    position: absolute;
    left: 0;
    top: 0;
    bottom: 0;
    width: 24px;
    z-index: 6;
    touch-action: none;
    background: transparent;
}
#screen-chat { touch-action: pan-y; }
#screen-chat.chat-back-swiping { transition: none !important; }
#screen-chat > .edge-swipe-zone { z-index: 20; }
@keyframes fadeIn {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   Topbar
   ========================================================================== */

.topbar {
    display: flex;
    align-items: center;
    gap: 4px;
    padding: 10px 8px 10px 14px;
    background: var(--accent);
    color: white;
    min-height: 56px;
    box-shadow: 0 1px 0 rgba(0,0,0,0.05);
}
.topbar .chat-title-wrap {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 1px;
}
.topbar h2 {
    margin: 0;
    font-size: 17px;
    font-weight: 600;
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    letter-spacing: -0.005em;
}
.topbar .chat-title-wrap h2 {
    flex: none;
}
.chat-client-info {
    font-size: 11px;
    font-weight: 400;
    opacity: 0.8;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.topbar .actions { display: flex; gap: 0; align-items: center; }

/* .server-switch-wrap ist jetzt das direkte Flex-Kind von .topbar (statt vorher
   dem <h2> direkt) — braucht daher selbst flex:1, sonst ruecken .actions
   (Version/Punkte/Menue) nicht mehr an den rechten Rand. */
.server-switch-wrap { flex: 1; min-width: 0; }
.server-switch-btn {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 1;
    min-width: 0;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: default;
}
body.is-native .server-switch-btn { cursor: pointer; }
.server-switch-title { display: flex; flex-direction: column; flex: 1; min-width: 0; justify-content: center; }
.server-switch-btn h2 { flex: none; }
.server-switch-subtitle {
    font-size: 11px;
    font-weight: 600;
    opacity: 0.85;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.server-switch-subtitle:empty { display: none; }
.server-switch-btn .icon-caret { width: 16px; height: 16px; flex: none; opacity: 0.85; }
#server-switch-menu { left: 0; right: auto; }
.server-switch-item { display: flex; align-items: center; gap: 2px; }
.server-switch-item .server-switch-select { flex: 1; min-width: 0; gap: 10px; }
.server-switch-item .account-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.server-switch-item.active .account-label { font-weight: 600; }
.server-switch-item .account-check { width: 18px; height: 18px; flex: none; color: var(--accent); }
.server-switch-item-version {
    font-size: 11px;
    font-weight: 600;
    opacity: 0.65;
    flex: none;
    font-variant-numeric: tabular-nums;
}
/* .icon-btn.server-switch-remove statt .server-switch-remove: erbt Basis-Look von
   .icon-btn (Zeile ~401 weiter unten), braucht hier aber gleiche Spezifitaet, um dessen
   Groesse zu ueberschreiben — sonst gewinnt .icon-btn per Reihenfolge im Stylesheet. */
.icon-btn.server-switch-remove {
    width: 34px;
    height: 34px;
    flex: none;
    margin-right: 4px;
    color: var(--text-secondary);
}
.icon-btn.server-switch-remove .icon { width: 18px; height: 18px; }
.icon-btn.server-switch-remove:active { background: var(--bg-hover); color: var(--danger); }

.topbar .icon-btn { color: white; }
.topbar .icon-btn:active { background: rgba(255,255,255,0.15); }

/* App-Version-Badge — kompakt, aber auf dem grünen Header klar lesbar */
.version-tag {
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    color: #ffffff;
    padding: 3px 6px;
    margin: 0 4px;
    border: 1px solid rgba(255, 255, 255, 0.55);
    border-radius: var(--radius-pill);
    background: rgba(0, 0, 0, 0.38);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.035em;
    white-space: nowrap;
    user-select: none;
}
.version-tag:empty { display: none; }

/* Verbindungs-Ampel: sitzt platzsparend als eigene Zeile ueber der Version-Pill.
   States kommen aus updateStatus()/setConnDot() in app.js. */
.status-cluster {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
}
.conn-dots {
    display: flex;
    align-items: center;
    gap: 3px;
}
.conn-dot {
    display: inline-block;
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    background: #888;
    box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.45),
                0 1px 2px rgba(0, 0, 0, 0.25);
    transition: background-color 200ms ease, box-shadow 200ms ease;
}
.conn-dot.is-off       { background: rgba(255,255,255,0.36); box-shadow: 0 0 0 1px rgba(255,255,255,0.38), 0 1px 2px rgba(0,0,0,0.2); }
.conn-dot.is-idle      { background: #94a3b8; box-shadow: 0 0 0 1px rgba(255,255,255,0.45), 0 0 5px rgba(148,163,184,0.4); }
.conn-dot.is-ok         { background: #16a34a; box-shadow: 0 0 0 1px rgba(255,255,255,0.5), 0 0 6px rgba(22,163,74,0.55); }
.conn-dot.is-connecting { background: #f59e0b; box-shadow: 0 0 0 1px rgba(255,255,255,0.5), 0 0 6px rgba(245,158,11,0.55); animation: conn-dot-pulse 1.2s ease-in-out infinite; }
.conn-dot.is-error      { background: #dc2626; box-shadow: 0 0 0 1px rgba(255,255,255,0.5), 0 0 6px rgba(220,38,38,0.55); }
@keyframes conn-dot-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.45; }
}
/* Dual-Mode: Native- und Web-Version untereinander, Web kleiner darunter. */
.version-tag.version-dual {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.05;
    padding: 4px 8px;
}
.version-tag.version-dual small {
    font-size: 9px;
    font-weight: 600;
    opacity: 0.78;
    letter-spacing: 0.02em;
    margin-top: 1px;
}

/* Version unterhalb der Anmeldung */
.version-line {
    width: max-content;
    margin: 18px auto 0;
    padding: 5px 10px;
    text-align: center;
    font-size: 14px;
    font-weight: 700;
    line-height: 1.2;
    color: var(--text-primary);
    background: var(--bg-pill);
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.04em;
    user-select: none;
}
.version-line:empty { display: none; }
.version-line.version-dual {
    display: flex;
    flex-direction: column;
    align-items: center;
    line-height: 1.1;
    padding: 6px 12px;
}
.version-line.version-dual small {
    font-size: 11px;
    font-weight: 600;
    opacity: 0.72;
    margin-top: 2px;
}

.icon-btn {
    width: 40px; height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    color: var(--text-primary);
    transition: background 100ms;
}
.icon-btn:active { background: var(--bg-hover); }
.icon-btn .icon { width: 22px; height: 22px; }

/* ==========================================================================
   Login
   ========================================================================== */

#screen-login {
    justify-content: center;
    align-items: center;
    padding: 24px;
    padding-bottom: var(--safe-bottom);
}
.login-card {
    width: 100%;
    max-width: 360px;
    background: var(--bg-card);
    border-radius: var(--radius-lg);
    padding: 36px 28px 28px;
    box-shadow: var(--shadow-md);
}
.login-logo {
    width: 72px; height: 72px;
    margin: 0 auto 18px;
    border-radius: 22px;
    display: flex; align-items: center; justify-content: center;
    background: var(--accent);
    box-shadow: 0 8px 24px -8px rgba(22, 163, 74, 0.55);
}
.login-logo svg { width: 36px; height: 36px; color: white; }
.login-card h1 {
    margin: 0 0 4px;
    text-align: center;
    font-size: 22px;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.login-card .subtitle {
    text-align: center;
    color: var(--text-secondary);
    font-size: 14px;
    margin: 0 0 22px;
}
.login-card form { display: flex; flex-direction: column; gap: 10px; }
.version-block-overlay {
    position: fixed;
    inset: 0;
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
    padding-top: calc(var(--safe-top) + 24px);
    padding-bottom: calc(var(--safe-bottom) + 24px);
    background: var(--bg-app);
}
.version-block-overlay[hidden] { display: none; }
.version-block-card {
    width: 100%;
    max-width: 360px;
    background: var(--bg-card);
    border-radius: var(--radius-lg);
    padding: 36px 28px 28px;
    box-shadow: var(--shadow-md);
    text-align: center;
}
.version-block-card h1 {
    margin: 0 0 8px;
    font-size: 20px;
    font-weight: 700;
    letter-spacing: -0.02em;
}
.version-block-card .subtitle {
    text-align: center;
    color: var(--text-secondary);
    font-size: 14px;
    line-height: 1.5;
    margin: 0 0 22px;
}
.version-block-card .btn { width: 100%; }
.version-block-current {
    margin: -10px 0 18px;
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.version-block-current:empty { display: none; }
.version-block-servers { margin: 0 0 18px; text-align: left; }
.version-block-servers-label {
    margin: 0 0 8px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
}
.version-block-server-list { display: flex; flex-direction: column; gap: 6px; }
.version-block-server-item {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 10px 12px;
    background: var(--bg-pill);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.version-block-server-item:active { background: var(--bg-hover); }
.version-block-server-item:disabled { opacity: 0.6; cursor: default; }
.version-block-server-item.active { border-color: var(--accent); }
.version-block-server-item .account-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.version-block-server-item .version-block-server-version {
    font-size: 11px;
    font-weight: 600;
    opacity: 0.7;
    flex: none;
    font-variant-numeric: tabular-nums;
}
.version-block-server-item .account-check { width: 16px; height: 16px; flex: none; color: var(--accent); }
.login-setup-hint {
    margin-top: 2px;
    margin-bottom: 0;
}
.login-app-download {
    margin-top: 14px;
    opacity: 1;
}
.login-app-download a {
    color: var(--accent);
    font-weight: 600;
    text-decoration: none;
}
.login-app-download a:hover,
.login-app-download a:active {
    text-decoration: underline;
}
.login-server-preview,
.login-server-info {
    margin-top: 10px;
    padding: 10px 12px;
    text-align: left;
    border-radius: var(--radius);
    background: var(--bg-input);
    border: 1px solid var(--border-soft);
    opacity: 1;
}
.login-server-preview strong {
    color: var(--text-primary);
}

.field {
    display: flex;
    align-items: center;
    background: var(--bg-input);
    border-radius: var(--radius);
    padding: 0 14px;
}
.field input,
.field textarea,
.field select {
    width: 100%;
    border: 0;
    background: transparent;
    padding: 13px 0;
    outline: none;
    font-size: 16px;
}
.field select {
    appearance: none;
    -webkit-appearance: none;
}
.field input::placeholder,
.field textarea::placeholder { color: var(--text-tertiary); }
.field-textarea {
    align-items: stretch;
    padding-top: 2px;
    padding-bottom: 2px;
}
.field textarea {
    resize: vertical;
    min-height: 72px;
    line-height: 1.35;
    font-family: inherit;
}

.btn {
    border-radius: var(--radius);
    padding: 13px 18px;
    font-size: 15px;
    font-weight: 600;
    transition: opacity 100ms, background 100ms, transform 80ms;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
}
.btn:active { transform: scale(0.98); }
.btn-primary {
    background: var(--accent);
    color: white;
}
.btn-primary:hover { background: var(--accent-hover); }
.btn-primary:disabled { opacity: 0.4; cursor: default; }
.btn-soft {
    background: var(--bg-pill);
    color: var(--text-primary);
}
.btn-danger { background: var(--danger); color: white; }

.error {
    color: var(--danger);
    background: rgba(220, 38, 38, 0.10);
    border-radius: var(--radius-sm);
    padding: 10px 14px;
    font-size: 13px;
    text-align: center;
    margin: 14px 0 0;
}

/* ==========================================================================
   Status-Bar
   ========================================================================== */

.status-bar {
    padding: 0;
    font-size: 11px;
    color: var(--text-tertiary);
    text-align: center;
    height: 0;
    overflow: hidden;
    transition: height 180ms;
    background: var(--bg-card);
}
.status-bar.connecting { padding: 4px 12px; height: 22px; color: var(--warning); }
.status-bar.error      { padding: 4px 12px; height: 22px; color: var(--danger); }

/* ==========================================================================
   Listen
   ========================================================================== */

.list {
    list-style: none;
    margin: 0;
    padding: 10px 10px calc(10px + var(--safe-bottom));
    overflow-y: auto;
    flex: 1;
    min-height: 0;
    background: var(--bg-app);
    display: flex;
    flex-direction: column;
    gap: 8px;
    scrollbar-width: none;
    -ms-overflow-style: none;
}
.list::-webkit-scrollbar { display: none; width: 0; height: 0; }

/* Extra Platz unten, damit sich der letzte Eintrag ueber den FAB
   hinausscrollen laesst -- sonst verdeckt der Button dauerhaft dessen
   Loeschen-Icon. */
#contacts-list {
    padding-bottom: calc(var(--safe-bottom) + 24px + 56px + 24px);
}

.list-item {
    --row-color: var(--accent);
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 12px 14px 12px 18px;
    cursor: pointer;
    position: relative;
    background: var(--bg-card);
    border-radius: 18px;
    box-shadow: var(--shadow-sm);
    transition: transform 100ms ease, box-shadow 120ms ease, background 120ms;
    overflow: hidden;
}
.list-item::before {
    content: '';
    position: absolute;
    left: 0; top: 12px; bottom: 12px;
    width: 4px;
    border-radius: 0 4px 4px 0;
    background: var(--row-color);
    opacity: 0.85;
}
.list-item:active {
    transform: scale(0.985);
    background: var(--bg-hover);
}

/* Lösch-Button rechts in jeder Kontakt-Zeile — dezent, klar als Aktion erkennbar */
.row-delete {
    width: 38px; height: 38px;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    opacity: 0.55;
    transition: opacity 120ms, background 120ms, color 120ms;
}
.row-delete:hover {
    opacity: 1;
    color: var(--danger, #ef4444);
    background: rgba(239, 68, 68, 0.10);
}
.row-delete:active { transform: scale(0.92); }
.row-delete .icon { width: 18px; height: 18px; }

/* Archivieren-Button rechts in jeder Kontakt-Zeile — ersetzt frueheres hartes Löschen */
.row-archive {
    width: 38px; height: 38px;
    flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    border-radius: 50%;
    background: transparent;
    color: var(--text-secondary);
    opacity: 0.55;
    transition: opacity 120ms, background 120ms, color 120ms;
}
.row-archive:hover {
    opacity: 1;
    color: var(--accent);
    background: rgba(var(--accent-rgb), 0.10);
}
.row-archive:active { transform: scale(0.92); }
.row-archive .icon { width: 18px; height: 18px; }

.avatar {
    width: 50px; height: 50px;
    border-radius: 16px;
    display: flex; align-items: center; justify-content: center;
    color: white;
    font-weight: 600;
    font-size: 19px;
    flex-shrink: 0;
    letter-spacing: -0.01em;
    position: relative;
    background-size: cover;
    background-position: center;
    overflow: hidden;
    box-shadow: 0 4px 10px -4px rgba(15, 23, 42, 0.22);
}
.avatar.sm { width: 36px; height: 36px; font-size: 14px; border-radius: 12px; }
.avatar.lg { width: 96px; height: 96px; font-size: 36px; border-radius: 28px; }
.avatar.xl { width: 132px; height: 132px; font-size: 50px; border-radius: 38px; }
.avatar.online::after {
    content: '';
    position: absolute;
    right: 1px;
    bottom: 1px;
    width: 13px;
    height: 13px;
    border-radius: 50%;
    background: var(--success);
    border: 2.5px solid var(--bg-card);
}

.item-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.item-row {
    display: flex;
    align-items: baseline;
    gap: 8px;
}
.item-title {
    font-weight: 500;
    font-size: 15.5px;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}
.item-title.unread { font-weight: 700; }
.item-time {
    font-size: 12px;
    color: var(--text-tertiary);
    flex-shrink: 0;
    font-variant-numeric: tabular-nums;
}
.item-time.unread { color: var(--accent); font-weight: 600; }
.item-preview {
    font-size: 14px;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}
.item-preview.unread { color: var(--text-primary); font-weight: 500; }
.item-preview .check {
    display: inline-flex;
    align-items: center;
    margin-right: 3px;
    color: var(--text-tertiary);
    vertical-align: -2px;
}
.item-preview .check .status-icon { width: 13px; height: 13px; }
.item-preview .check.read { color: var(--accent); }
.item-preview .check.error { color: #f87171; }
.unread-badge {
    background: var(--accent);
    color: white;
    font-size: 11px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: var(--radius-pill);
    min-width: 22px;
    text-align: center;
    flex-shrink: 0;
    line-height: 1.4;
    font-variant-numeric: tabular-nums;
}
.item-actions { display: flex; gap: 0; }
.item-actions .icon-btn { width: 36px; height: 36px; color: var(--text-secondary); }

.badge {
    display: inline-flex;
    align-items: center;
    padding: 2px 7px;
    border-radius: 4px;
    font-size: 10.5px;
    font-weight: 700;
    background: var(--accent-soft);
    color: var(--accent);
    margin-left: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.badge.neutral { background: var(--bg-pill); color: var(--text-secondary); }

.empty {
    padding: 60px 32px;
    text-align: center;
    color: var(--text-tertiary);
}
.empty .emoji { font-size: 38px; margin-bottom: 10px; }
.empty small { color: var(--text-tertiary); }

/* ==========================================================================
   Dropdown-Menü
   ========================================================================== */

.menu-wrap { position: relative; }
.menu-pop {
    position: absolute;
    top: 100%; right: 0;
    margin-top: 4px;
    background: var(--bg-elevated);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    min-width: 220px;
    padding: 6px;
    z-index: 50;
    color: var(--text-primary);
    animation: menuIn 140ms ease-out;
}
@media (prefers-color-scheme: light) {
    .menu-pop { border: 0.5px solid var(--border); }
}
@keyframes menuIn {
    from { opacity: 0; transform: translateY(-4px) scale(0.98); }
    to   { opacity: 1; transform: none; }
}
.menu-item {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 11px 12px;
    border-radius: 8px;
    text-align: left;
    color: var(--text-primary);
    font-size: 15px;
    transition: background 80ms;
}
.menu-item:active { background: var(--bg-hover); }
.menu-item .icon { width: 20px; height: 20px; color: var(--text-secondary); }
.menu-item.danger { color: var(--danger); }
.menu-item.danger .icon { color: var(--danger); }

/* ==========================================================================
   FAB
   ========================================================================== */

.fab {
    position: absolute;
    right: 20px;
    bottom: calc(var(--safe-bottom) + 24px);
    width: 56px; height: 56px;
    border-radius: 50%;
    background: var(--accent);
    color: white;
    display: flex; align-items: center; justify-content: center;
    box-shadow: 0 8px 22px -4px rgba(22, 163, 74, 0.55);
    transition: transform 80ms, box-shadow 120ms;
    z-index: 20;
}
.fab:active { transform: scale(0.94); }
.fab .icon { width: 24px; height: 24px; stroke-width: 2.5; }

/* ==========================================================================
   Dialog
   ========================================================================== */

dialog {
    background: var(--bg-card);
    color: var(--text-primary);
    border: 0;
    border-radius: var(--radius-lg);
    padding: 22px;
    max-width: 92vw;
    width: 360px;
    box-shadow: var(--shadow-lg);
}
/* WICHTIG: display/max-height NUR fuer [open] setzen. Ein unqualifiziertes
   "dialog { display: flex }" ueberschreibt (Autor- schlaegt UA-Stylesheet)
   die browsereigene Regel "dialog:not([open]) { display:none }" — dann
   werden ALLE Dialoge im DOM permanent sichtbar gerendert, egal ob offen
   oder zu (Bug v2.0.3: mehrere Dialoge uebereinander sichtbar). */
dialog[open] {
    /* An --app-h (visualViewport.height) statt an die volle Layout-Hoehe
       gebunden, sonst ragt der Dialog bei offener Tastatur ueber den
       sichtbaren Bereich hinaus (native dialog::modal max-height ist sonst
       gegen die ungeschrumpfte Seite berechnet). Kein natives Resize, gleiche
       Kompensation wie syncAppHeight() fuer den Rest der App. */
    max-height: calc(var(--app-h, 100vh) - 32px);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
/* Android laeuft mit windowSoftInputMode="adjustNothing" — die Layout-
   Viewport schrumpft NIE, nur visualViewport.height (--app-h) wird kleiner.
   Der native UA-Stylesheet zentriert dialog:modal aber per margin:auto
   IMMER innerhalb der vollen (ungeschrumpften) Fixed-Box. Ein kurzer,
   per max-height korrekt begrenzter Dialog landet dadurch trotzdem mittig
   in der vollen Seitenhoehe — und damit oft halb hinter der Tastatur, obwohl
   er selbst klein genug waere. Bei offener Tastatur daher oben andocken
   statt zentrieren, damit er komplett im sichtbaren (nicht von der Tastatur
   verdeckten) Bereich liegt. */
body.keyboard-open dialog[open] {
    /* --safe-top (env(safe-area-inset-top)) dazu, sonst liegt der Dialog-Kopf
       unter der Handy-Statusleiste (Uhrzeit/Akku) statt darunter. */
    top: calc(var(--safe-top) + 20px);
    left: 0;
    right: 0;
    bottom: auto;
    margin: 0 auto;
}
dialog::backdrop {
    background: rgba(0, 0, 0, 0.45);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
}
dialog h3 {
    margin: 0 0 14px;
    font-size: 17px;
    font-weight: 600;
}
dialog .dlg-body {
    display: flex;
    flex-direction: column;
    gap: 10px;
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}
dialog .actions {
    display: flex;
    gap: 8px;
    margin-top: 18px;
    justify-content: flex-end;
    flex-shrink: 0;
}
dialog .actions .btn { padding: 10px 18px; flex: 1; max-width: 140px; }
dialog .row { display: flex; align-items: center; gap: 12px; padding: 4px 0; }
dialog .row label { color: var(--text-primary); font-size: 15px; flex: 1; }

/* Admin-Diagnose-Dialog "Nachrichten-Info" (siehe openMessageInfo() in app.js) */
.msg-info { display: flex; flex-direction: column; gap: 2px; font-size: 14px; }
.msg-info-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border, rgba(255,255,255,0.08));
}
.msg-info-row:last-child { border-bottom: none; }
.msg-info-label { color: var(--text-tertiary); flex-shrink: 0; }
.msg-info-value { color: var(--text-primary); text-align: right; word-break: break-word; }
/* Original-Medium einer geloeschten Nachricht (Admin-Info) braucht die
   volle Zeilenbreite statt der schmalen rechten Haelfte. */
/* Statt :has() (Chrome < 105 kennt es nicht und macht dann die ganze Regel
   ungueltig) setzt msgInfoRow() in app.js die Klasse direkt, wenn value
   ein .msg-info-media enthaelt -- funktioniert dadurch auf jedem WebView. */
.msg-info-row.msg-info-row--media { flex-direction: column; align-items: flex-start; }
.msg-info-media { margin-top: 4px; max-width: 100%; }
.msg-info-media img,
.msg-info-media video { max-width: 100%; max-height: 260px; border-radius: 10px; display: block; }
.msg-info-media audio { width: 100%; }
.msg-info-media .collage-grid { max-width: 260px; }
.msg-info-section-title {
    margin: 14px 0 6px;
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-tertiary);
}
.msg-info-reads { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.msg-info-reads li {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    padding: 7px 0;
    border-bottom: 1px solid var(--border, rgba(255,255,255,0.08));
    font-size: 14px;
}
.msg-info-reads li:last-child { border-bottom: none; }
.msg-info-member { color: var(--text-primary); }
.msg-info-member-status {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    color: var(--text-tertiary);
    text-align: right;
}
.msg-info-member-status .status-icon { width: 14px; height: 14px; flex-shrink: 0; }
.msg-info-member-status.delivered { opacity: 0.85; }
.msg-info-member-status.read { color: #b5f8c1; }

.whats-new-dialog { width: 380px; }
.whats-new-dialog h3 { margin-bottom: 2px; }
.whats-new-subtitle {
    margin: 0 0 16px;
    font-size: 13px;
    color: var(--text-tertiary);
}
.whats-new-body {
    display: flex;
    flex-direction: column;
    gap: 12px;
    max-height: 58vh;
    overflow-y: auto;
    margin: 0 -4px;
    padding: 2px 4px;
}
/* Ein Kaertchen pro Versionsnummer -- wenn beim Update mehrere Versionen
   uebersprungen wurden, stehen mehrere dieser Kaertchen untereinander. */
.whats-new-version-group {
    background: var(--bg-hover);
    border-radius: var(--radius);
    padding: 14px 16px;
}
.whats-new-version {
    display: inline-block;
    margin: 0 0 10px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .03em;
    text-transform: uppercase;
    color: var(--accent);
    background: var(--accent-soft);
    padding: 3px 10px;
    border-radius: 999px;
}
.whats-new-change + .whats-new-change {
    margin-top: 14px;
    padding-top: 14px;
    border-top: 0.5px solid var(--border);
}
.whats-new-change h5 {
    display: flex;
    align-items: center;
    gap: 7px;
    margin: 0 0 6px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}
.whats-new-change h5::before {
    content: '';
    flex-shrink: 0;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
}
.whats-new-change p {
    margin: 0 0 8px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-secondary);
}
.whats-new-change p:last-child { margin-bottom: 0; }
.dialog-menu { gap: 8px; }
.dialog-menu .menu-item {
    background: var(--bg-input);
    border-radius: 10px;
}
.reaction-picker {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 10px;
}
.reaction-option {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 56px;
    border-radius: 14px;
    background: var(--bg-input);
    border: 1px solid transparent;
    font-size: 28px;
    transition: transform 120ms ease, border-color 120ms ease, background 120ms ease;
}
.reaction-option:hover,
.reaction-option:focus-visible {
    transform: translateY(-1px);
    /* Fallback fuer WebViews ohne color-mix() (Chrome < 111) -- exakt
       aequivalent zu color-mix(... 48%, transparent), wird von der
       color-mix()-Zeile darunter ueberschrieben wo unterstuetzt. */
    border-color: rgba(var(--accent-rgb), 0.48);
    border-color: color-mix(in srgb, var(--accent) 48%, transparent);
    outline: none;
}
.reaction-option.active {
    background: var(--bg-input);
    background: color-mix(in srgb, var(--accent) 16%, var(--bg-input));
    border-color: rgba(var(--accent-rgb), 0.55);
    border-color: color-mix(in srgb, var(--accent) 55%, transparent);
}
.forward-preview {
    margin: 0;
    padding: 10px 12px;
    border-left: 3px solid var(--accent);
    border-radius: 8px;
    background: var(--bg-input);
    color: var(--text-primary);
    text-align: left;
    opacity: 1;
}
/* Chat-Suchdialog (Suche/Links/Bilder-Tabs, siehe openChatSearch() in app.js) */
.chat-search-dialog { width: 440px; }
.chat-search-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: -6px -8px 10px 0;
    flex-shrink: 0;
}
.chat-search-header h3 { margin: 0; }
.chat-search-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 12px;
    flex-shrink: 0;
    background: var(--bg-input);
    border-radius: var(--radius-pill);
    padding: 3px;
}
.chat-search-tab {
    flex: 1;
    border: 0;
    background: transparent;
    color: var(--text-secondary);
    font-size: 13px;
    font-weight: 500;
    padding: 7px 4px;
    border-radius: var(--radius-pill);
    cursor: pointer;
}
.chat-search-tab.active { background: var(--accent); color: #fff; }
.chat-search-body { padding-top: 0; }
.chat-search-panel[hidden] { display: none; }
.chat-search-results, .chat-links-results { max-height: 46vh; }
.chat-search-snippet { color: var(--text-secondary); }
.chat-search-snippet mark {
    background: rgba(var(--accent-rgb), 0.35);
    background: color-mix(in srgb, var(--accent) 35%, transparent);
    color: var(--text-primary);
    border-radius: 3px;
    padding: 0 1px;
}
.chat-search-date {
    flex-shrink: 0;
    font-size: 11px;
    color: var(--text-tertiary);
    align-self: flex-start;
    padding-top: 2px;
}
.chat-link-url {
    display: block;
    color: var(--accent);
    word-break: break-all;
    font-size: 14px;
}
.chat-media-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 4px;
    max-height: 50vh;
    overflow-y: auto;
    padding-bottom: 4px;
}
.chat-media-item {
    display: block;
    position: relative;
    border: 0;
    padding: 0;
    cursor: pointer;
    aspect-ratio: 1;
    border-radius: 8px;
    background-size: cover;
    background-position: center;
    background-color: var(--bg-input);
}
.chat-media-item.is-video::after {
    content: '';
    position: absolute;
    inset: 0;
    margin: auto;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    background: rgba(0,0,0,.45) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path fill="white" d="M8 5v14l11-7z"/></svg>') center/16px no-repeat;
}

/* Nachrichten-Umfeld-Dialog (Klick auf Textsuche-Treffer): zeigt 5 Nachrichten
   davor/danach um die getroffene Nachricht, mit bidirektionalem Nachladen
   beim Scrollen. Bleibt bewusst ueber dem noch offenen chat-search-Dialog
   (kein closeChatSearch() beim Oeffnen) — Schliessen fuehrt daher zurueck
   zur Suchuebersicht. Volle Bildschirmbreite (kein Rand zum Backdrop links/
   rechts) -- sonst liegt ausserhalb des Dialogs noch ein Streifen des
   dahinterliegenden Chats frei, auf dem dessen eigener Zurueck-Wisch (ganz
   am linken Bildschirmrand) statt unserem eigenen ausloest, und Bubbles
   haben weniger Platz als im echten Chat. Die Hoehe bleibt bewusst
   kompakter als voll (max-height auf .message-context-body), damit der
   Schliessen-Button leicht erreichbar bleibt.
   Kein Dialog-Standard-Padding (das generische "dialog{padding:22px}"):
   Header und Liste bekommen stattdessen ihr eigenes Padding. Ein negativer
   Rand auf .message-context-list zum "Ausbrechen" aus dem Dialog-Padding
   waere hier ein Problem -- ein Kind mit negativem Rand VOR dem eigenen
   Scroll-Ursprung zaehlt im Scroll-Container als Overflow und macht ihn
   trotz identischer Sichtbreite horizontal scrollbar. */
.message-context-dialog { width: 100vw; max-width: 100vw; position: relative; touch-action: pan-y; padding: 0; }
.message-context-dialog .chat-search-header { padding: 18px 18px 8px; }
.message-context-body {
    padding: 0;
    max-height: min(64vh, 560px);
}
.message-context-list {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 10px 14px;
    background: var(--bg-app);
}
/* Bubbles sehen aus wie im normalen Chat (buildMessageBubbleEl()) — hier nur
   Ausrichtung + kleiner Abstand pro Zeile, keine zusaetzliche Meta-Zeile
   (Datum steht bereits im Suchtreffer-Eintrag bzw. am Tages-Separator). */
.context-message {
    display: flex;
    flex-direction: column;
    margin: 1px 0;
}
.context-message.me { align-items: flex-end; }
.context-message.them { align-items: flex-start; }
.context-action-bar {
    display: flex;
    gap: 6px;
    margin: 2px 4px 0;
}
/* Nicht-interaktiver Tages-Separator (Gegenstueck zu .day-sep im echten
   Chat, aber ohne Auf-/Zuklapp-Funktion — hier wird ja nur ein Ausschnitt
   angezeigt). */
.context-day-sep { cursor: default; }
/* Dauerhafte, dezente Markierung der Treffer-Nachricht — die kurze
   quote-highlight-Animation beim Oeffnen verblasst nach 1.2s, danach soll
   die Nachricht beim Scrollen im Umfeld trotzdem wiederzufinden sein. */
.bubble.context-target { box-shadow: 0 0 0 2px var(--accent), var(--bubble-shadow); }
.image-caption-dialog { width: 380px; }
.image-caption-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin: -6px -8px 14px 0;
    flex-shrink: 0;
}
.image-caption-header h3 { margin: 0; }
.image-caption-preview-wrap {
    border-radius: 16px;
    overflow: hidden;
    background: #000;
    flex-shrink: 1;
    min-height: 0;
    transition: max-height 160ms ease;
}
.image-caption-preview-grid {
    display: grid;
    gap: 6px;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    width: 100%;
    aspect-ratio: 1;
    max-height: min(42vh, 320px);
}
.image-caption-preview-grid.is-single {
    display: block;
    aspect-ratio: auto;
}
.image-caption-preview-grid.is-triple .image-caption-preview-item:first-child {
    grid-row: span 2;
}
.image-caption-preview-item {
    position: relative;
    overflow: hidden;
    min-width: 0;
    min-height: 0;
    border-radius: 12px;
    background: rgba(255, 255, 255, 0.06);
}
.image-caption-preview-item img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #000;
}
.image-caption-preview-grid.is-single .image-caption-preview-item img {
    max-height: min(42vh, 320px);
    object-fit: contain;
}
.image-caption-selection {
    margin: 8px 2px 0;
    font-size: 13px;
    color: var(--text-secondary);
    text-align: left;
}
/* Bei offener Tastatur etwas kleinere Vorschau, damit Bildunterschrift-Feld
   und Senden-Buttons ohne Scrollen sichtbar bleiben. Die Buttons selbst sind
   dank flex-shrink:0 (.actions, ausserhalb des scrollenden .dlg-body) auch
   ohne diese Verkleinerung immer erreichbar — das hier ist nur dafuer da,
   dass auch das Eingabefeld direkt sichtbar ist, ohne im Dialog scrollen
   zu muessen. */
body.keyboard-open .image-caption-preview-wrap { max-height: 150px; }
body.keyboard-open .image-caption-preview-grid,
body.keyboard-open .image-caption-preview-grid.is-single .image-caption-preview-item img { max-height: 150px; }
.image-caption-field { margin: 0; }
.image-caption-field textarea {
    resize: none;
    min-height: 44px;
    max-height: 110px;
}
.image-caption-actions { justify-content: space-between; }
.image-caption-actions .btn-soft { flex: 0 1 auto; max-width: none; }
.image-caption-actions .btn-primary { flex: 1 1 auto; max-width: none; }

/* Kompakte Result-Liste für Neuer-Chat-Dialog */
.member-pills {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    min-height: 24px;
    margin: 4px 0 8px;
}
.member-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 7px 11px;
    border-radius: 999px;
    background: var(--bg-pill);
    color: var(--text-primary);
    font-size: 13px;
    font-weight: 600;
}
.member-pill strong {
    font-size: 15px;
    line-height: 1;
    opacity: 0.7;
}
.group-member-row {
    display: flex;
    align-items: center;
    gap: 10px;
}
.group-member-row .name-block {
    flex: 1;
    min-width: 0;
}
.group-members .empty {
    padding: 18px 12px;
}
.list.compact {
    list-style: none;
    display: block;
    margin: 6px 0 0;
    padding: 0;
    gap: 0;
    max-height: 320px;
    overflow-y: auto;
    border-radius: 8px;
    background: var(--bg-card-sub, rgba(255,255,255,0.03));
}
.list.compact li {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    cursor: pointer;
    border-bottom: 1px solid var(--border);
}
.list.compact li:last-child { border-bottom: none; }
.list.compact li:hover { background: rgba(255,255,255,0.05); }
.list.compact .name-block { flex: 1; min-width: 0; }
.list.compact .name-block .display { font-weight: 500; color: var(--text-primary); }
.list.compact .name-block .username { font-size: 12px; color: var(--text-secondary); }
.list.compact .badge {
    font-size: 10px; padding: 2px 6px; border-radius: 999px;
    background: var(--accent); color: white;
}
#forward-results .select-check {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 1.5px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: transparent;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
#forward-results li.selected .select-check {
    background: var(--accent);
    border-color: var(--accent);
    color: white;
}
#forward-results li.selected { background: rgba(255,255,255,0.06); }
.forward-multi-hint { margin-bottom: 2px; }

.contact-share-name {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0;
    text-align: center;
}
.contact-field-icon {
    flex: 0 0 auto;
    width: 18px;
    height: 18px;
    color: var(--text-secondary);
}
#contact-share-fields .select-check {
    flex: 0 0 auto;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 1.5px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: center;
    color: transparent;
    transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
#contact-share-fields li.selected .select-check {
    background: var(--accent);
    border-color: var(--accent);
    color: white;
}
#contact-share-fields li.selected { background: rgba(255,255,255,0.06); }
.hint {
    font-size: 13px; color: var(--text-secondary); margin: 4px 0 0;
    text-align: center; opacity: 0.7;
}

.switch {
    position: relative;
    width: 44px; height: 26px;
    background: var(--bg-pill);
    border-radius: 999px;
    transition: background 160ms;
    flex-shrink: 0;
    cursor: pointer;
}
.switch::after {
    content: '';
    position: absolute;
    left: 2px; top: 2px;
    width: 22px; height: 22px;
    border-radius: 50%;
    background: white;
    transition: left 160ms;
    box-shadow: 0 2px 4px rgba(0,0,0,0.18);
}
.switch.on { background: var(--accent); }
.switch.on::after { left: 20px; }
.switch.disabled { opacity: 0.5; pointer-events: none; cursor: default; }

.switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 8px 0;
    cursor: pointer;
    user-select: none;
}
.switch-row > span:first-child {
    flex: 1;
    color: var(--text-primary);
    font-size: 14px;
}

/* ==========================================================================
   Chat
   ========================================================================== */

/* Eine gemeinsame, feste Zeile fuer Verbindungsstatus, Gruppen-Info und
   "... tippt"-Hinweis -- verschwindet nie (kein hidden/height:0-Toggle wie
   frueher bei zwei getrennten Bars), damit das Ein-/Ausblenden keinen
   Reflow mehr ausloest (Nachrichten/Composer wurden sonst kurz verschoben).
   Prioritaet beim Anzeigen: Verbindungsfehler > "tippt" > Gruppen-Info. */
#chat-status {
    display: flex;
    align-items: center;
    flex-shrink: 0;
    gap: 6px;
    height: 18px;
    margin: 0;
    padding: 0 16px;
    overflow: hidden;
    background: var(--bg-card);
    border-top: 0.5px solid var(--border);
    color: var(--text-tertiary);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.01em;
    text-align: left;
    border-radius: 0;
    white-space: nowrap;
    text-overflow: ellipsis;
}
#chat-status-text {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
#chat-status.connecting { color: var(--warning); }
/* Ueberschreibt die generische .error-Klasse (Formular-Fehlerbanner,
   siehe .error weiter oben), die sonst margin/padding/Hintergrund
   reinmischen wuerde. */
#chat-status.error {
    color: var(--danger);
    background: var(--bg-card);
}
#chat-status.is-typing  { color: var(--accent); }
.typing-dots {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}
.typing-dots i {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: currentColor;
    opacity: 0.28;
    animation: typing-pulse 1.1s ease-in-out infinite;
}
.typing-dots i:nth-child(2) { animation-delay: 0.16s; }
.typing-dots i:nth-child(3) { animation-delay: 0.32s; }
@keyframes typing-pulse {
    0%, 100% { opacity: 0.24; transform: translateY(0); }
    40% { opacity: 0.9; transform: translateY(-1px); }
}

.messages {
    --peer-color: var(--accent);
    flex: 1;
    overflow-y: auto;
    padding: 16px 14px calc(8px + var(--safe-bottom));
    display: flex;
    flex-direction: column;
    gap: 3px;
    background: var(--bg-app);
}

/* Sichtbar nach jumpToChatMessage() (Sprung aus der Chat-Suche in die
   Verlaufsmitte) — bringt den User per Klick zurueck zu den aktuellsten
   Nachrichten (laedt den Chat einfach neu). */
.chat-jump-latest {
    position: absolute;
    left: 50%;
    bottom: 84px;
    transform: translateX(-50%);
    z-index: 5;
    border: 0;
    padding: 8px 16px;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    font-size: 13px;
    font-weight: 500;
    box-shadow: var(--shadow-lg);
    cursor: pointer;
}

.day-group {
    display: flex;
    flex-direction: column;
}
.day-messages {
    display: flex;
    flex-direction: column;
    gap: 3px;
}
.day-group:not(.expanded) .day-messages { display: none; }

.day-sep {
    align-self: center;
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-card);
    color: var(--text-secondary);
    padding: 6px 12px 6px 16px;
    border-radius: var(--radius-lg);
    margin: 16px 0 8px;
    box-shadow: var(--shadow-sm);
    border: 0;
    font-family: inherit;
    cursor: pointer;
    text-align: center;
    max-width: 88%;
}
.day-sep-lines {
    display: flex;
    flex-direction: column;
    gap: 2px;
    align-items: center;
    min-width: 0;
}
.day-sep-date {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
}
.day-sep-stats {
    font-size: 10.5px;
    font-weight: 500;
    color: var(--text-secondary);
    opacity: 0.8;
}
.day-sep .icon {
    width: 13px;
    height: 13px;
    opacity: 0.75;
    flex-shrink: 0;
    transition: transform 0.15s ease;
    transform: rotate(-90deg);
}
.day-group.expanded .day-sep .icon { transform: rotate(0deg); }
.day-group.loading .day-sep { opacity: 0.6; pointer-events: none; }
.day-group.loading .day-sep .icon { animation: day-sep-spin 0.7s linear infinite; }
@keyframes day-sep-spin {
    from { transform: rotate(0deg); }
    to   { transform: rotate(360deg); }
}

/* Sentinel-Button "Ältere Nachrichten laden" ganz oben im Chat. Wird vom
   IntersectionObserver beobachtet — sichtbar = Trigger für nächste Seite. */
.load-older {
    align-self: center;
    margin: 6px 0 4px;
    padding: 6px 14px;
    border-radius: var(--radius-pill);
    background: var(--bg-pill);
    color: var(--text-secondary);
    font-size: 12px;
    cursor: pointer;
}
.load-older:active { opacity: 0.7; }

/* "Neue Nachrichten"-Trenner über der ersten ungelesenen Bubble. */
.unread-sep {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 14px 4px 6px;
    color: var(--accent);
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.unread-sep::before,
.unread-sep::after {
    content: '';
    flex: 1;
    height: 1px;
    background: var(--accent);
    opacity: 0.45;
}

.bubble {
    max-width: 78%;
    padding: 10px 14px 8px;
    border-radius: 20px;
    word-wrap: break-word;
    overflow-wrap: anywhere;
    /* Eingabe-Newlines (Shift+Enter / Composer-Newline) sichtbar machen, aber
       weiter umbrechen. */
    white-space: pre-wrap;
    line-height: 1.45;
    user-select: text;
    font-size: 15px;
    position: relative;
    box-shadow: var(--bubble-shadow);
    touch-action: pan-y;
    transition: transform 160ms ease, box-shadow 160ms ease;
}
.bubble.swiping { transition: none; z-index: 2; }
.bubble.swiping::after {
    position: absolute;
    top: 50%;
    width: 30px;
    height: 30px;
    margin-top: -15px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    content: '↩';
    color: var(--accent);
    background: var(--bg-card);
    box-shadow: var(--shadow-sm);
    font-size: 18px;
    font-weight: 700;
}
.bubble.swipe-right::after { right: calc(100% + 10px); }
.bubble.swipe-left::after  { left: calc(100% + 10px); transform: scaleX(-1); }
.bubble.quote-highlight { animation: quote-highlight 1.2s ease; }
@keyframes quote-highlight {
    0%, 100% { box-shadow: var(--bubble-shadow); }
    25%, 70% {
        box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.35);
        box-shadow: 0 0 0 4px color-mix(in srgb, var(--accent) 35%, transparent);
    }
}
.bubble.me {
    align-self: flex-end;
    background: var(--bubble-me-bg);
    color: var(--bubble-me-text);
    border-bottom-right-radius: 6px;
}
.bubble.them {
    align-self: flex-start;
    /* Fallback ohne Peer-Tinting fuer WebViews ohne color-mix() (Chrome <
       111) -- schlichtes --bubble-them-bg statt der Personen-Faerbung,
       von der color-mix()-Zeile darunter ueberschrieben wo unterstuetzt. */
    background: var(--bubble-them-bg);
    background: color-mix(in srgb, var(--peer-color, var(--accent)) 10%, var(--bubble-them-bg));
    color: var(--bubble-them-text);
    border-bottom-left-radius: 6px;
}
@media (prefers-color-scheme: dark) {
    .bubble.them {
        background: var(--bubble-them-bg);
        background: color-mix(in srgb, var(--peer-color, var(--accent)) 22%, var(--bubble-them-bg));
    }
}
.bubble + .bubble.me   { margin-top: 2px; border-top-right-radius: 6px; }
.bubble + .bubble.them { margin-top: 2px; border-top-left-radius: 6px; }
.bubble.me + .bubble.them, .bubble.them + .bubble.me { margin-top: 10px; }

/* Reine-Emoji-Bubbles (1-3 Emojis): ohne Hintergrund, mit doppelt grosser
   Schrift. Wie in WhatsApp/iMessage. Meta-Zeit rutscht unter das Emoji,
   damit sie nicht mitten ins Riesen-Emoji hineinragt. */
.bubble.emoji-only {
    background: transparent;
    box-shadow: none;
    padding: 2px 4px;
    border-radius: 0;
    font-size: 30px;
    line-height: 1.1;
}
/* .me/.them explizit wiederholen: .bubble.group-colored (Absender-Einfaerbung,
   auch in 1:1-Chats aktiv) hat dieselbe Selektor-Spezifitaet wie .emoji-only
   und steht spaeter im Stylesheet — ohne diese staerker spezifischen
   Overrides wuerde group-colored den transparenten Hintergrund bei
   empfangenen Reine-Emoji-Nachrichten wieder zudecken (bei eigenen
   Nachrichten faellt das nicht auf, weil .me dort schon vorher gewinnt). */
.bubble.emoji-only.me,
.bubble.emoji-only.them { background: transparent; color: var(--text-primary); }
.bubble.emoji-only .bubble-text { font-size: 30px; }
.bubble.emoji-only .meta {
    display: block;
    margin: 4px 0 0;
    font-size: 10.5px;
    color: var(--text-tertiary);
}
.bubble.emoji-only.me .meta,
.bubble.emoji-only.them .meta { color: var(--text-tertiary); }
.bubble.emoji-only.me .check.read { color: var(--accent); }

.bubble .meta {
    display: inline-block;
    font-size: 10.5px;
    margin-left: 6px;
    vertical-align: baseline;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    color: var(--text-tertiary);
}
.bubble.me .meta { color: rgba(255,255,255,0.80); }
.bubble .edited-tag { font-style: italic; opacity: 0.85; }
.bubble .check { display: inline-flex; align-items: center; margin-left: 3px; font-weight: 600; }
.bubble .check .status-icon { width: 13px; height: 13px; vertical-align: -1px; }
.bubble .check.delivered { opacity: 0.85; }
.bubble .check.read { color: #b5f8c1; }
.bubble.them .check.read { color: var(--accent); }
.bubble .check.error { color: #f87171; cursor: pointer; }

/* Admin-Debug: zeigt an, ob eine Nachricht lokal (IndexedDB) gecached ist.
   Deckender Farb-Hintergrund statt nur eingefaerbtem Text — sonst auf hellen,
   dunklen oder akzentfarbenen Bubbles (Light/Dark-Theme, eigene vs. fremde
   Bubble, Gruppenfarben) je nach Kontext kaum lesbar. Deckende Farbe macht
   den Kontrast unabhaengig vom darunterliegenden Bubble-Theme. */
.bubble .cache-debug {
    display: inline-block;
    margin-left: 4px;
    padding: 1px 4px;
    border-radius: 4px;
    font-size: 8.5px;
    font-weight: 700;
    line-height: 1.3;
    letter-spacing: 0.02em;
    vertical-align: baseline;
}
.bubble .cache-debug.hit { background: #2e9e52; color: #fff; }
.bubble .cache-debug.miss { background: #d64545; color: #fff; }

.message-quote {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-width: 150px;
    margin: 0 0 6px;
    padding: 7px 9px;
    border: 0;
    border-left: 3px solid var(--accent);
    border-radius: 7px;
    background: rgba(0,0,0,0.07);
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.bubble.me .message-quote {
    border-left-color: rgba(255,255,255,0.9);
    background: rgba(255,255,255,0.16);
}
.message-quote.has-thumb {
    flex-direction: row;
    align-items: center;
    gap: 8px;
}
.message-quote-thumb {
    width: 36px;
    height: 36px;
    flex-shrink: 0;
    border-radius: 6px;
    object-fit: cover;
}
.message-quote-body {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}
.message-quote strong {
    color: var(--accent);
    font-size: 12px;
    line-height: 1.25;
}
.bubble.me .message-quote strong { color: #d7ffe0; }
.message-quote span {
    overflow: hidden;
    color: inherit;
    font-size: 12.5px;
    line-height: 1.35;
    opacity: 0.78;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.group-sender {
    display: inline-block;
    max-width: 100%;
    margin: 0 10px 6px 0;
    padding: 4px 10px;
    border-radius: 14px 14px 14px 6px;
    background: #ffffff;
    box-shadow: inset 0 0 0 1px var(--bubble-custom-sender-shadow, rgba(15, 23, 42, 0.08));
    color: var(--bubble-custom-sender-text, var(--sender-color, var(--accent)));
    font-size: 12px;
    font-weight: 700;
    line-height: 1.25;
    white-space: normal;
    word-break: break-word;
}
.bubble.me .group-sender {
    color: var(--bubble-custom-sender-text, rgba(255,255,255,0.92));
}
/* Bild- und Datei-Bubbles */
.bubble.media {
    padding: 4px 4px 6px;
    background: var(--bubble-them-bg);
    background: color-mix(in srgb, var(--peer-color, var(--accent)) 10%, var(--bubble-them-bg));
}
.bubble.media.me {
    background: var(--bubble-me-bg);
}
@media (prefers-color-scheme: dark) {
    .bubble.media {
        background: var(--bubble-them-bg);
        background: color-mix(in srgb, var(--peer-color, var(--accent)) 22%, var(--bubble-them-bg));
    }
}
.bubble.group-colored {
    background: var(--bubble-custom-bg);
    color: var(--bubble-custom-text);
}
.bubble.group-colored .meta,
.bubble.group-colored .check {
    color: var(--bubble-custom-meta);
}
.bubble.group-colored .check.read {
    color: var(--bubble-custom-check-read);
}
.bubble.group-colored .check.error {
    color: #f87171;
}
.bubble.group-colored .message-quote {
    background: var(--bubble-custom-quote-bg);
    border-left-color: var(--bubble-custom-quote-border);
}
.bubble.group-colored .message-quote strong {
    color: var(--bubble-custom-quote-strong);
}
.bubble.group-colored .file-icon {
    background: var(--bubble-custom-file-icon-bg);
}
.bubble.group-colored .contact-icon {
    background: var(--bubble-custom-file-icon-bg);
}
.bubble.group-colored .reaction-chip {
    background: var(--bubble-custom-reaction-bg);
    border-color: var(--bubble-custom-reaction-border);
    color: var(--bubble-custom-reaction-text);
}
.bubble.group-colored .reaction-chip.mine {
    background: var(--bubble-custom-reaction-mine-bg);
    border-color: var(--bubble-custom-reaction-mine-border);
    color: var(--bubble-custom-reaction-mine-text);
}
.bubble.media img.attachment,
.bubble.media video.attachment {
    display: block;
    max-width: 100%;
    max-height: 360px;
    border-radius: 14px;
    background: #000;
}
.bubble.media img.attachment { cursor: zoom-in; }
.bubble.media video.attachment { width: 100%; }
.bubble.media .attachment-collage {
    display: block;
    width: min(280px, 72vw);
    border: 0;
    padding: 0;
    border-radius: 14px;
    background: transparent;
    overflow: hidden;
    cursor: pointer;
}
.bubble.media .attachment-collage:focus-visible {
    outline: 2px solid var(--accent);
    outline: 2px solid color-mix(in srgb, var(--accent) 75%, white);
    outline-offset: 2px;
}
.collage-grid {
    display: grid;
    width: 100%;
    aspect-ratio: 1;
    gap: 4px;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-rows: minmax(0, 1fr);
}
.collage-grid.is-single {
    aspect-ratio: auto;
    grid-template-columns: 1fr;
}
.collage-grid.is-triple .collage-tile:first-child {
    grid-row: span 2;
}
.collage-tile {
    position: relative;
    overflow: hidden;
    min-width: 0;
    min-height: 0;
    background: rgba(0, 0, 0, 0.08);
}
.collage-tile img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    background: #000;
}
.collage-more {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.46);
    color: #fff;
    font-size: 28px;
    font-weight: 700;
    letter-spacing: 0.02em;
}
.bubble.media .meta {
    margin: 4px 8px 0;
    padding-top: 2px;
    display: block;
    text-align: right;
}
.bubble.media .media-caption {
    margin: 8px 10px 0;
    line-height: 1.35;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.bubble.media .message-quote { width: auto; margin: 2px 2px 5px; }

/* Geometrie (Groesse/Position/Overflow/Pin-Koordinaten) wird bewusst INLINE
   in appendMessage() gesetzt, nicht hier — sonst kann eine Stylesheet-Regel
   mit hoeherer/gleicher Spezifitaet (z.B. .bubble.media img.attachment) die
   Pin-Position bei manchen Geraeten/WebViews unbemerkt verschieben. Hier nur
   rein dekorative Eigenschaften, die keinen Einfluss auf Layout/Position haben. */
.location-attach {
    color: inherit;
    background: var(--bg-input);
    box-shadow: inset 0 0 0 1px rgba(0,0,0,0.06);
}
.location-attach .location-map {
    cursor: pointer;
    transition: filter 0.15s ease;
}
.location-attach:active .location-map { filter: brightness(0.92); }
.location-attach .location-pin {
    filter: drop-shadow(0 2px 3px rgba(0,0,0,0.45));
}
.location-attach .location-caption {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 18px 12px 9px;
    background: linear-gradient(to top, rgba(0,0,0,0.6), rgba(0,0,0,0));
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    pointer-events: none;
}
.location-attach .location-caption .icon { width: 15px; height: 15px; flex-shrink: 0; }
/* Kartendienst nicht erreichbar — der error-Handler in appendMessage() schaltet
   display/Layout direkt inline um (aus demselben Grund wie oben), hier nur
   noch die Optik des Platzhalters. */
.location-attach.map-failed .location-caption {
    background: none;
    color: var(--text-secondary);
    justify-content: center;
    padding: 8px 12px 0;
}

.file-attach {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    min-width: 220px;
    color: inherit;
}
.file-icon {
    width: 38px; height: 38px;
    border-radius: 10px;
    background: rgba(0,0,0,0.08);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.bubble.me .file-icon { background: rgba(255,255,255,0.20); }
.file-icon .icon { color: inherit; width: 22px; height: 22px; }
.file-info { min-width: 0; }
.file-name {
    font-size: 14px;
    font-weight: 500;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.file-size {
    font-size: 12px;
    opacity: 0.7;
}

.contact-card {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding: 10px 12px;
    min-width: 220px;
    color: inherit;
}
.contact-card-head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-bottom: 6px;
}
.contact-icon {
    width: 38px; height: 38px;
    border-radius: 50%;
    background: rgba(0,0,0,0.08);
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
}
.bubble.me .contact-icon { background: rgba(255,255,255,0.20); }
.contact-icon .icon { color: inherit; width: 22px; height: 22px; }
.contact-name {
    font-size: 14px;
    font-weight: 600;
    min-width: 0;
    overflow-wrap: break-word;
}
.contact-details {
    display: flex;
    flex-direction: column;
    border-top: 1px solid rgba(0,0,0,0.08);
}
.bubble.me .contact-details { border-top-color: rgba(255,255,255,0.20); }
.contact-detail {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 2px;
    color: inherit;
    text-decoration: none;
}
.contact-detail-icon { width: 16px; height: 16px; flex-shrink: 0; opacity: 0.8; }
.contact-detail-value {
    font-size: 13px;
    min-width: 0;
    overflow-wrap: break-word;
}
.contact-detail-label {
    font-size: 11px;
    opacity: 0.65;
    margin-left: auto;
    padding-left: 8px;
    flex-shrink: 0;
}

.bubble.call_log {
    align-self: center;
    background: var(--bg-pill);
    color: var(--text-secondary);
    font-size: 13px;
    border-radius: 10px;
    padding: 5px 14px;
    box-shadow: none;
}

.bubble.deleted .deleted-text {
    font-style: italic;
    opacity: 0.75;
}
.bubble.deleted.me .deleted-text { color: rgba(255,255,255,0.85); }

/* ==========================================================================
   Composer
   ========================================================================== */

.composer {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 8px 8px calc(8px + var(--safe-bottom));
    background: var(--bg-card);
    border-top: 0.5px solid var(--border);
    align-items: center;
    position: relative;
}
.composer-reply {
    flex: 0 0 100%;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 8px 7px 11px;
    border-left: 3px solid var(--accent);
    border-radius: 8px;
    background: var(--bg-input);
}
.composer-reply[hidden] { display: none; }
.composer-reply-thumb {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    border-radius: 6px;
    object-fit: cover;
}
.composer-reply-thumb[hidden] { display: none; }
.composer-reply-copy {
    min-width: 0;
    flex: 1;
    display: flex;
    flex-direction: column;
}
.composer-reply strong { color: var(--accent); font-size: 12px; }
.composer-reply span {
    overflow: hidden;
    color: var(--text-secondary);
    font-size: 13px;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.composer-reply .icon-btn { width: 30px; height: 30px; flex-shrink: 0; }
.composer-reply .icon { width: 17px; height: 17px; }
.composer-edit { border-left-color: var(--warning); }
.composer-edit strong { color: var(--warning); }
.composer .input-wrap {
    position: relative;
    flex: 1;
    background: var(--bg-input);
    border-radius: 0;
    padding: 4px 8px 4px 14px;
    display: flex;
    align-items: center;
    min-height: 44px;
}
.composer .input-wrap input,
.composer .input-wrap textarea {
    width: 100%;
    border: 0;
    background: transparent;
    outline: none;
    font-size: 16px;
    padding: 8px 4px;
    appearance: none;
    -webkit-appearance: none;
}
/* Mehrzeilige Eingabe: Enter = Newline, Senden nur per Button. Autosize
   passiert in JS (siehe autosizeMsgInput); max-height begrenzt die Höhe und
   schaltet Scroll an, damit der Composer nicht beliebig wächst. */
.composer .input-wrap textarea {
    resize: none;
    line-height: 1.35;
    max-height: 140px;
    overflow-y: auto;
    font-family: inherit;
}
.composer .icon-btn { color: var(--text-secondary); }
.composer .send {
    width: 42px; height: 42px;
    border-radius: 50%;
    background: var(--accent);
    color: white;
    display: flex; align-items: center; justify-content: center;
    flex-shrink: 0;
    transition: transform 80ms, opacity 120ms, background 120ms;
}
.composer .send:active { transform: scale(0.92); }
.composer .send:disabled { background: var(--bg-pill); color: var(--text-tertiary); cursor: default; transform: none; }
.composer .send .icon { width: 20px; height: 20px; }

/* Mic-Knopf neben Senden — wird im Aufnahme-Modus durch .record-bar verdeckt */
#btn-record { color: var(--text-secondary); }
#btn-record:active { background: var(--bg-hover); }
.composer.is-recording > .input-wrap,
.composer.is-recording > #btn-attach,
.composer.is-recording > #btn-record,
.composer.is-recording > .send,
.composer.is-preview   > .input-wrap,
.composer.is-preview   > #btn-attach,
.composer.is-preview   > #btn-record,
.composer.is-preview   > .send { display: none; }

/* Aufnahme- und Preview-Leiste: ersetzen visuell die Composer-Eingabe */
.record-bar,
.preview-bar {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 6px;
    background: var(--bg-input);
    border-radius: var(--radius-pill);
    min-height: 44px;
}
.record-bar[hidden],
.preview-bar[hidden] { display: none; }
.record-dot {
    width: 10px; height: 10px;
    margin: 0 4px 0 6px;
    border-radius: 50%;
    background: var(--danger);
    animation: recPulse 1.2s ease-in-out infinite;
    flex-shrink: 0;
}
.composer.is-paused .record-dot {
    animation: none;
    opacity: 0.45;
}
@keyframes recPulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50%      { opacity: 0.35; transform: scale(0.85); }
}
.record-time {
    flex: 1;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.02em;
    padding-left: 2px;
}
.record-btn {
    width: 38px; height: 38px;
    border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    transition: transform 80ms, background 120ms, color 120ms;
    flex-shrink: 0;
}
.record-btn:active { transform: scale(0.92); }
.record-btn.cancel  { background: var(--bg-pill); color: var(--text-secondary); }
.record-btn.neutral { background: var(--bg-pill); color: var(--text-primary); }
.record-btn.stop    { background: var(--danger);  color: white; }
.record-btn.confirm { background: var(--accent);  color: white; }
.record-btn .icon { width: 18px; height: 18px; }

/* Preview-Audio: HTML5-Controls verstecken — wir steuern selbst über
   #preview-play. Das <audio> bleibt im DOM, damit src/play()/pause() arbeiten. */
#preview-audio {
    width: 1px; height: 1px;
    visibility: hidden;
    position: absolute;
}

/* Voice-Bubble: Play-Knopf + Audio-Element (HTML5-Controls) */
.bubble.voice {
    padding: 8px 12px;
    min-width: 240px;
    max-width: 320px;
}
.bubble.voice audio {
    display: block;
    width: 100%;
    height: 36px;
}
.bubble.voice audio::-webkit-media-controls-panel {
    background: transparent;
}
.bubble.voice .meta { display: block; text-align: right; margin: 2px 0 0; }

/* ==========================================================================
   Twemoji-Bilder — ersetzen System-Emoji-Glyphen ueberall im UI.
   Hoehe/Breite an Textgroesse koppeln, damit das Bild zusammen mit dem
   umgebenden Text skaliert (Picker 22 px, Bubble 15 px, Jumbo-Bubble 30 px).
   ========================================================================== */

img.emoji {
    height: 1em;
    width: 1em;
    margin: 0 .05em;
    vertical-align: -0.15em;
    display: inline-block;
    user-select: none;
    -webkit-user-drag: none;
}

/* Im Picker sitzt das Bild als einziger Inhalt im Button — zentrieren statt
   oben-links kleben lassen. Etwas groesser als der Font, damit die Kachel
   besser ausgefuellt wirkt. */
.emoji-tabs button img.emoji,
.emoji-grid button img.emoji {
    height: 1.2em;
    width: 1.2em;
    margin: 0;
    vertical-align: middle;
}
.emoji-grid button {
    display: grid;
    place-items: center;
}
.emoji-tabs button {
    display: grid;
    place-items: center;
}

/* Im Jumbo-Mode (max 3 Emojis solo) braucht das Bild keinen Baseline-Versatz —
   und sieht groesser besser aus, wenn es voll an der Textgroesse haengt. */
.bubble.emoji-only img.emoji {
    height: 1em;
    width: 1em;
    margin: 0 .05em;
    vertical-align: middle;
}

/* In Reaktions-Chips und Reaktions-Picker zentriert. */
.reaction-chip img.emoji,
.reaction-picker img.emoji {
    vertical-align: middle;
    margin: 0 1px;
}

/* ==========================================================================
   Emoji-Picker
   ========================================================================== */

.emoji-picker {
    /* Eigene volle Breite als letzte Composer-Zeile (DOM-Position: letztes
       Kind von .composer, siehe index.html) — die Nachrichtenleiste bleibt
       darueber stehen, der Picker klappt sich flex-wrap:wrap darunter auf. */
    flex: 0 0 100%;
    min-width: 0;
    background: var(--bg-card);
    border: 0.5px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: 4px;
    /* Faellt auf 320px zurueck, bis die echte Tastaturhoehe des Geraets
       gemessen wurde (siehe --keyboard-h in app.js/syncAppHeight). */
    height: var(--keyboard-h, 320px);
    display: flex;
    flex-direction: column;
    z-index: 30;
    animation: pickerIn 150ms ease-out;
}
@keyframes pickerIn {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}
.emoji-picker-modes {
    display: flex;
    gap: 4px;
    padding-bottom: 4px;
    border-bottom: 0.5px solid var(--border);
    margin-bottom: 4px;
    flex-shrink: 0;
}
.emoji-mode-btn {
    padding: 4px 10px;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    transition: background 80ms;
}
.emoji-mode-btn .icon { width: 18px; height: 18px; display: block; }
.emoji-mode-btn.active { background: var(--accent-soft); color: var(--accent); }
.emoji-mode-btn:active { background: var(--bg-hover); }

.emoji-tabs {
    display: flex;
    gap: 1px;
    padding-bottom: 4px;
    overflow-x: auto;
    border-bottom: 0.5px solid var(--border);
}
.emoji-tabs button {
    flex-shrink: 0;
    padding: 3px 5px;
    border-radius: 6px;
    font-size: 17px;
    line-height: 1;
    transition: background 80ms;
}
.emoji-tabs button.active { background: var(--accent-soft); }
.emoji-tabs button:active { background: var(--bg-hover); }
.emoji-grid {
    flex: 1;
    overflow-y: auto;
    padding-top: 2px;
    display: grid;
    /* Adaptiv: passt sich der Picker-Breite an, Zellen wachsen aber nicht
       unbegrenzt mit (max 38px) — sonst wirkt der Abstand zwischen den
       Emojis auf dem jetzt vollbreiten Picker zu grosszuegig. */
    grid-template-columns: repeat(auto-fill, minmax(34px, 38px));
    gap: 0;
    justify-content: space-between;
}
.emoji-grid button {
    aspect-ratio: 1;
    font-size: 22px;
    line-height: 1;
    border-radius: 6px;
    padding: 0;
    transition: background 60ms;
}
.emoji-grid button:active { background: var(--bg-hover); }

.gif-panel {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.gif-search {
    flex-shrink: 0;
    margin-bottom: 4px;
    padding: 6px 10px;
    border-radius: 999px;
    border: 0.5px solid var(--border);
    background: var(--bg-hover);
    color: var(--text-primary);
    font-size: 14px;
}
/* Echte GIPHY-Vorschaubilder kommen in stark unterschiedlichen Seiten-
   verhaeltnissen (Hochkant, Breitbild, quadratisch) und oft nur ~100px breit.
   Ein starres Grid mit fixem aspect-ratio + object-fit:cover zwingt jedes
   Bild in dieselbe Box -- je nach Browser/Zeilenhoehen-Rundung kollidiert
   das mit dem naechsten Grid-Row und Kacheln schieben sich sichtbar
   uebereinander. Ein Spalten-Layout (Masonry via column-count) behaelt die
   natuerliche Bildhoehe, es gibt nichts zum Ueberlappen. */
.gif-grid {
    flex: 1;
    overflow-y: auto;
    column-count: 2;
    column-gap: 4px;
}
.gif-grid button {
    display: block;
    position: relative;
    width: 100%;
    margin: 0 0 4px;
    border-radius: 8px;
    overflow: hidden;
    padding: 0;
    background: var(--bg-hover);
    break-inside: avoid;
    -webkit-column-break-inside: avoid;
}
.gif-grid button img {
    display: block;
    width: 100%;
    height: auto;
}
.gif-grid button:active { opacity: 0.75; }
.gif-grid button.is-sending::after {
    content: '';
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.35);
}
.gif-status {
    text-align: center;
    color: var(--text-tertiary);
    font-size: 13px;
    padding: 12px 0;
}

.emoji-inline-suggestions {
    position: absolute;
    left: 12px;
    top: 6px;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px;
    border-radius: 999px;
    border: 0.5px solid var(--border);
    background: var(--bg-card);
    box-shadow: var(--shadow-lg);
    z-index: 35;
    pointer-events: auto;
}
.emoji-inline-suggestions[hidden] { display: none; }
.emoji-inline-suggestions button {
    width: 34px;
    height: 34px;
    border-radius: 50%;
    padding: 0;
    font-size: 21px;
    line-height: 1;
    transition: transform 80ms, background 80ms;
}
.emoji-inline-suggestions button:active {
    background: var(--bg-hover);
    transform: scale(0.94);
}
.composer-caret-mirror {
    position: absolute;
    top: -9999px;
    left: 0;
    visibility: hidden;
    pointer-events: none;
    white-space: pre-wrap;
    word-break: break-word;
    overflow: hidden;
}
/* ==========================================================================
   Attach-Menü
   ========================================================================== */

.camera-capture {
    position: fixed;
    inset: 0;
    z-index: 120;
    background: rgba(0, 0, 0, 0.92);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 18px;
}
.camera-capture__stage {
    position: relative;
    /* Feste 3:4-Aspect-Ratio ragt im Querformat (breiter, aber sehr niedriger
       Viewport) sonst ueber die sichtbare Hoehe hinaus und schiebt Ausloeser/
       Buttons (position:absolute, am Stage-Boden) aus dem Bild. Breite daher
       zusaetzlich an die verfuegbare Hoehe koppeln (--app-h statt 100vh, siehe
       syncAppHeight()), damit die Stage in jeder Orientierung komplett samt
       Controls sichtbar bleibt. Die tatsaechliche Foto-Aufnahme nutzt ohnehin
       die volle Sensor-Aufloesung (captureDirectCamera), nicht diesen Frame. */
    width: min(100%, 560px, calc((var(--app-h, 100vh) - 36px) * 3 / 4));
    aspect-ratio: 3 / 4;
    border-radius: 24px;
    overflow: hidden;
    background: #000;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}
@media (orientation: landscape) {
    /* Querformat: Kamerabild ist ebenfalls quer, daher Seitenverhaeltnis
       umkehren statt weiter 3:4 hoch zu erzwingen (sonst wirkt der
       Ausschnitt schmal). Breite jetzt an die Hoehe gekoppelt via 4:3 quer. */
    .camera-capture__stage {
        width: min(94%, 860px, calc((var(--app-h, 100vh) - 36px) * 4 / 3));
        aspect-ratio: 4 / 3;
    }
}
.camera-capture__video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.camera-capture__top {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    padding: 16px 18px;
    color: #fff;
    font-size: 16px;
    font-weight: 700;
    background: linear-gradient(to bottom, rgba(0, 0, 0, 0.62), rgba(0, 0, 0, 0));
}
.camera-capture__controls {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: 12px;
    padding: 18px;
    background: linear-gradient(to top, rgba(0, 0, 0, 0.72), rgba(0, 0, 0, 0));
}
.camera-capture__btn {
    min-width: 112px;
    min-height: 48px;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.16);
    color: #fff;
    border: 1px solid rgba(255, 255, 255, 0.22);
    font-weight: 700;
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}
.camera-capture__btn:disabled {
    opacity: 0.55;
}
.camera-capture__btn.ghost {
    justify-self: start;
}
.camera-capture__btn.shutter {
    min-width: 76px;
    width: 76px;
    height: 76px;
    padding: 0;
    border: 6px solid rgba(255, 255, 255, 0.95);
    background: rgba(255, 255, 255, 0.22);
    box-shadow: 0 0 0 5px rgba(0, 0, 0, 0.16);
}
.camera-capture__btn.switch {
    min-width: 48px;
    width: 48px;
    height: 48px;
    padding: 0;
    justify-self: end;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.camera-capture__btn.switch .icon {
    width: 22px;
    height: 22px;
}
.camera-capture__hint {
    position: absolute;
    left: 18px;
    right: 18px;
    bottom: 108px;
    text-align: center;
    color: rgba(255, 255, 255, 0.95);
    font-size: 13px;
    font-weight: 600;
    text-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
}
.attach-menu {
    position: absolute;
    left: 8px;
    bottom: calc(100% + 6px);
    background: var(--bg-elevated);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: 6px;
    z-index: 30;
    min-width: 180px;
    animation: menuIn 140ms ease-out;
}

/* ==========================================================================
   Profil-Screen
   ========================================================================== */

.profile-content {
    flex: 1;
    overflow-y: auto;
    padding: 24px 18px calc(24px + var(--safe-bottom));
    background: var(--bg-app);
}
.profile-avatar-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 24px 0 28px;
}
.profile-avatar {
    position: relative;
    cursor: pointer;
}
.group-avatar-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin-bottom: 14px;
}
.group-avatar-wrap.compact {
    margin-bottom: 18px;
}
.group-avatar-picker {
    border: 0;
    background: transparent;
    padding: 0;
    cursor: pointer;
}
.group-avatar-picker:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 4px;
    border-radius: 40px;
}
.group-avatar-wrap.readonly .group-avatar-picker {
    cursor: default;
}
.group-avatar-wrap.readonly .edit-badge {
    display: none;
}
.profile-avatar .edit-badge {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 36px; height: 36px;
    border-radius: 50%;
    background: var(--accent);
    color: white;
    display: flex; align-items: center; justify-content: center;
    border: 3px solid var(--bg-app);
}
.profile-avatar .edit-badge .icon { width: 18px; height: 18px; }
.profile-section {
    background: var(--bg-card);
    border-radius: var(--radius);
    padding: 14px;
    margin-bottom: 14px;
}
.profile-section h4 {
    margin: 0 0 10px;
    font-size: 11px;
    font-weight: 700;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.color-swatch-grid {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 10px;
}
.color-swatch {
    width: 100%;
    aspect-ratio: 1;
    border-radius: 50%;
    border: 0;
    padding: 0;
    cursor: pointer;
    position: relative;
    box-shadow: inset 0 0 0 2px rgba(0,0,0,0.08);
}
.color-swatch.selected::after {
    content: '';
    position: absolute;
    inset: -3px;
    border-radius: 50%;
    border: 2px solid var(--text-primary);
}
.color-swatch:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}
.admin-scroll {
    flex: 1;
    overflow-y: auto;
    padding: 12px 12px calc(88px + var(--safe-bottom));
}
.admin-server-card {
    margin-bottom: 12px;
}
.admin-users-list {
    padding: 0;
    overflow: visible;
    background: transparent;
}
.admin-inline-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    margin-top: 12px;
}
.admin-inline-actions .btn {
    flex: 1 1 220px;
}
.admin-backup-card {
    margin-bottom: 12px;
}
.admin-usage-card {
    margin-bottom: 12px;
}
.admin-usage-controls {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: center;
    margin-top: 10px;
}
.admin-usage-controls select {
    flex: 1 1 180px;
    min-width: 0;
    padding: 8px 10px;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border);
    background: var(--bg-input);
    color: var(--text-primary);
    font-size: 13px;
}
.admin-usage-period {
    display: flex;
    background: var(--bg-pill);
    border-radius: var(--radius-pill);
    padding: 3px;
    gap: 2px;
}
.admin-usage-period button {
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-size: 12px;
    font-weight: 600;
    padding: 6px 12px;
    border-radius: var(--radius-pill);
    cursor: pointer;
}
.admin-usage-period button.active {
    background: var(--accent);
    color: #fff;
}
.admin-usage-chart {
    margin-top: 16px;
    overflow-x: auto;
}
.admin-usage-chart svg {
    display: block;
}
.admin-usage-legend {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin-top: 8px;
    font-size: 12px;
    color: var(--text-secondary);
}
.admin-usage-legend span {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.admin-usage-legend i {
    width: 10px;
    height: 10px;
    border-radius: 3px;
    display: inline-block;
}
.admin-usage-table-wrap {
    margin-top: 14px;
    overflow-x: auto;
}
.admin-usage-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12.5px;
}
.admin-usage-table th,
.admin-usage-table td {
    text-align: left;
    padding: 7px 10px;
    border-bottom: 1px solid var(--border-soft);
    white-space: nowrap;
}
.admin-usage-table th {
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.03em;
}
.admin-usage-table th.num {
    text-align: right;
}
.admin-usage-table td.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
}
.backup-docker-dialog {
    max-width: 560px;
    width: 92vw;
}
.backup-docker-textarea {
    width: 100%;
    min-height: 160px;
    resize: vertical;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 12.5px;
    line-height: 1.5;
    padding: 10px;
    border-radius: 8px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-primary);
    white-space: pre;
    overflow: auto;
}
.profile-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 6px 0;
}
.profile-row label {
    font-size: 13px;
    color: var(--text-secondary);
    flex-shrink: 0;
    min-width: 110px;
}

/* ==========================================================================
   Call-Screen
   ========================================================================== */

.call-screen { background: #000; padding: 0; }
.call-screen #remote-video {
    width: 100%; height: 100%; object-fit: cover;
    background: #000;
}
.call-screen #local-video {
    position: absolute;
    top: calc(var(--safe-top) + 16px);
    right: 16px;
    width: 100px;
    height: 140px;
    object-fit: cover;
    border-radius: 12px;
    border: 1.5px solid rgba(255,255,255,0.30);
    background: #111;
    box-shadow: 0 10px 30px rgba(0,0,0,0.5);
}
#call-info {
    position: absolute;
    top: calc(var(--safe-top) + 28px);
    left: 0; right: 0;
    text-align: center;
    color: white;
    text-shadow: 0 1px 3px rgba(0,0,0,0.6);
    pointer-events: none;
}
#call-peer-name { font-size: 24px; font-weight: 600; letter-spacing: -0.02em; }
#call-status { font-size: 14px; opacity: 0.85; margin-top: 4px; }
/* Diagnose-Anzeige fuer Call-Verbindungsaufbau. Zeigt ICE-Server, Kandidaten-
   Typen, State-Wechsel, Selected-Pair. Wird via Call-Debug-Events aus
   js/call.js gefuettert. Standardmaessig unsichtbar; nur eingeblendet wenn
   body.call-debug-on gesetzt ist — das schaltet ein Toggle im Admin-Profil. */
.call-debug-wrap { display: none; }
body.call-debug-on .call-debug-wrap {
    display: block;
    position: relative;
    margin: 10px 0 0;
}
.call-debug {
    margin: 0;
    padding: 6px 8px;
    max-height: 40vh;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    font-family: ui-monospace, Menlo, Consolas, monospace;
    font-size: 11px;
    line-height: 1.35;
    color: #b9f6c9;
    background: rgba(0, 0, 0, 0.55);
    border-radius: 6px;
    white-space: pre-wrap;
    text-align: left;
    user-select: text;
    overscroll-behavior: contain;
}
.call-debug:empty { display: none; }
.call-debug:empty + .call-debug-copy { display: none; }
.call-debug:empty ~ .call-debug-copy { display: none; }
.call-debug-copy {
    position: absolute;
    top: 4px;
    right: 4px;
    z-index: 1;
    padding: 3px 8px;
    font-size: 11px;
    line-height: 1.2;
    color: #fff;
    background: rgba(22, 163, 74, 0.85);
    border: 0;
    border-radius: 4px;
    cursor: pointer;
}
.call-debug-copy--secondary {
    right: 56px;
    background: rgba(59, 130, 246, 0.85);
}
.call-debug-copy--secondary:active { background: rgba(59, 130, 246, 1); }
.call-debug-copy:active { background: rgba(22, 163, 74, 1); }
.call-debug-copy.copied { background: rgba(59, 130, 246, 0.9); }
#call-controls {
    position: absolute;
    bottom: calc(var(--safe-bottom) + 40px);
    left: 0; right: 0;
    display: flex;
    justify-content: center;
    gap: 18px;
}
.call-btn {
    position: relative;
    width: 64px; height: 64px;
    border-radius: 50%;
    background: rgba(255,255,255,0.18);
    color: white;
    display: flex; align-items: center; justify-content: center;
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    transition: transform 80ms, background 120ms;
}
.call-btn:active { transform: scale(0.92); }
.call-btn:disabled { opacity: 0.45; pointer-events: none; }
.call-btn.muted { background: rgba(255,255,255,0.55); color: #1d1d1f; }
.call-btn.muted::after {
    content: '';
    position: absolute;
    width: 38px;
    height: 3px;
    border-radius: 999px;
    background: currentColor;
    transform: rotate(-45deg);
    box-shadow: 0 0 0 1px rgba(255,255,255,0.14);
    pointer-events: none;
}
.call-btn.active { background: rgba(255,255,255,0.55); color: #1d1d1f; }
.call-btn.danger { background: var(--danger); }
.call-btn .icon { width: 26px; height: 26px; }

/* ==========================================================================
   Incoming-Call-Dialog
   ========================================================================== */

.incoming-call {
    text-align: center;
    padding: 32px 24px 24px;
    width: 320px;
}
.incoming-call .avatar { margin: 0 auto 18px; }
.incoming-call h3 { font-size: 22px; margin: 0 0 4px; font-weight: 600; }
.incoming-call .subtitle { color: var(--text-secondary); margin: 0 0 24px; font-size: 14px; }
.incoming-call .actions { justify-content: center; gap: 12px; }
.incoming-call .actions .btn { flex: 1; max-width: none; padding: 14px; }

/* ==========================================================================
   Image-Lightbox
   ========================================================================== */

.lightbox {
    position: fixed; inset: 0;
    background: rgba(0,0,0,0.92);
    display: flex; align-items: center; justify-content: center;
    z-index: 1000;
    overscroll-behavior: contain;
    touch-action: none;
}
.lightbox > .edge-swipe-zone { z-index: 1002; }
.lightbox-stage {
    width: 100%; height: 100%;
    display: flex; align-items: center; justify-content: center;
    overflow: hidden;
    padding: 16px;
}
.lightbox img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: 4px;
    cursor: zoom-in;
    transform-origin: center;
    will-change: transform;
    -webkit-user-drag: none;
    user-select: none;
}
.lightbox .close,
.lightbox .nav {
    position: absolute;
    width: 44px; height: 44px;
    border-radius: 50%;
    background: rgba(255,255,255,0.15);
    color: white;
    display: flex; align-items: center; justify-content: center;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    z-index: 1003;
}
.lightbox .close {
    top: calc(var(--safe-top) + 14px);
    right: 16px;
}
.lightbox .nav {
    top: 50%;
    transform: translateY(-50%);
}
.lightbox .nav.prev { left: 16px; }
.lightbox .nav.next { right: 16px; }
.lightbox .nav[hidden] { display: none; }
.lightbox-counter {
    position: absolute;
    left: 50%;
    bottom: calc(var(--safe-bottom) + 18px);
    transform: translateX(-50%);
    padding: 7px 12px;
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.42);
    color: #fff;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.02em;
    z-index: 1003;
}
/* Teilen/Weiterleiten/Antworten unten im Bild-Vollbild — nur sichtbar, wenn
   openLightbox() eine zugehoerige Nachricht mitbekommen hat (siehe
   items[].message in openLightbox()), z. B. aus der Bildsuche. */
.lightbox-actions {
    position: absolute;
    left: 50%;
    bottom: calc(var(--safe-bottom) + 18px);
    transform: translateX(-50%);
    display: flex;
    gap: 10px;
    z-index: 1003;
}
.lightbox-actions[hidden] { display: none; }
.lightbox-action-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 8px 16px;
    border: 0;
    border-radius: 14px;
    background: rgba(255,255,255,0.15);
    color: #fff;
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    font-size: 11px;
    cursor: pointer;
}
.lightbox-action-btn[hidden] { display: none; }
.lightbox-action-btn .icon { width: 20px; height: 20px; }
.lightbox-action-btn:hover,
.lightbox-action-btn:focus-visible { background: rgba(255,255,255,0.25); outline: none; }

/* ==========================================================================
   Progress-Overlay (Video-Kompression / Upload)
   ========================================================================== */

.overlay-progress {
    position: fixed; inset: 0;
    background: rgba(0, 0, 0, 0.55);
    backdrop-filter: blur(6px);
    -webkit-backdrop-filter: blur(6px);
    display: flex; align-items: center; justify-content: center;
    z-index: 1100;
    padding: 24px;
}
.overlay-card {
    background: var(--bg-card);
    color: var(--text-primary);
    border-radius: var(--radius-lg);
    padding: 26px 22px;
    width: 100%; max-width: 320px;
    text-align: center;
    box-shadow: var(--shadow-lg);
}
.overlay-card h3 {
    margin: 14px 0 12px;
    font-size: 16px;
    font-weight: 600;
}
.overlay-card progress {
    width: 100%; height: 6px;
    border: 0;
    border-radius: 4px;
    overflow: hidden;
    background: var(--bg-pill);
    accent-color: var(--accent);
}
.overlay-card progress::-webkit-progress-bar  { background: var(--bg-pill); border-radius: 4px; }
.overlay-card progress::-webkit-progress-value { background: var(--accent); border-radius: 4px; transition: width 200ms; }
.overlay-card progress::-moz-progress-bar      { background: var(--accent); border-radius: 4px; }
.overlay-card .subtitle {
    color: var(--text-secondary);
    font-size: 13px;
    margin-top: 10px;
}

.spinner {
    width: 38px; height: 38px;
    margin: 0 auto;
    border-radius: 50%;
    border: 3px solid var(--bg-pill);
    border-top-color: var(--accent);
    animation: spin 800ms linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* ==========================================================================
   Versions-Tag
   ========================================================================== */

.version {
    position: fixed;
    bottom: 4px;
    left: 6px;
    font-size: 10px;
    color: var(--text-tertiary);
    opacity: 0.5;
    pointer-events: none;
    z-index: 5;
    font-variant-numeric: tabular-nums;
}
.version.version-dual {
    line-height: 1.1;
    display: flex;
    flex-direction: column;
}
.version.version-dual small {
    font-size: 8px;
    opacity: 0.85;
}

/* Sichtbare Schnellaktionen neben jeder Bubble. Long-Press bleibt frei, damit
   Text weiter mit der nativen Geste markiert werden kann. */
.bubble-action-bar {
    position: absolute;
    bottom: 4px;
    display: flex;
    align-items: center;
    gap: 4px;
    z-index: 2;
}
.bubble.me .bubble-action-bar { right: calc(100% + 6px); }
.bubble.them .bubble-action-bar { left: calc(100% + 6px); flex-direction: row-reverse; }
.bubble-action-btn {
    width: 24px;
    height: 24px;
    padding: 0;
    border: 0;
    background: var(--bg-card);
    color: var(--text-secondary);
    opacity: 0.78;
    border-radius: 999px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: var(--shadow-sm);
    transition: opacity 120ms, background 120ms, transform 120ms;
}
.bubble-action-btn .icon { width: 14px; height: 14px; }
.bubble-action-btn:hover,
.bubble-action-btn:focus-visible {
    opacity: 1;
    transform: scale(1.05);
    outline: none;
}
@media (max-width: 420px) {
    .bubble-action-bar { gap: 3px; }
    .bubble.me .bubble-action-bar { right: calc(100% + 4px); }
    .bubble.them .bubble-action-bar { left: calc(100% + 4px); flex-direction: row-reverse; }
    .bubble-action-btn {
        width: 22px;
        height: 22px;
    }
    .bubble-action-btn .icon {
        width: 13px;
        height: 13px;
    }
}
/* Links in Nachrichten */
.msg-link {
    color: inherit;
    text-decoration: underline;
    text-underline-offset: 2px;
    word-break: break-all;
}
.bubble.me .msg-link { color: #d7ffe0; }
.bubble.them .msg-link { color: var(--accent); }
.bubble.group-colored .msg-link { color: var(--bubble-custom-text); }
.message-reactions {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 7px;
}
.reaction-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 9px;
    border-radius: 999px;
    border: 1px solid rgba(var(--accent-rgb), 0.18);
    border: 1px solid color-mix(in srgb, var(--accent) 18%, transparent);
    background: var(--bg-card);
    background: color-mix(in srgb, var(--bg-card) 92%, var(--accent) 8%);
    color: var(--text-primary);
    font-size: 12px;
    line-height: 1;
}
.reaction-chip.mine {
    background: var(--bg-card);
    background: color-mix(in srgb, var(--accent) 18%, var(--bg-card));
    border-color: rgba(var(--accent-rgb), 0.55);
    border-color: color-mix(in srgb, var(--accent) 55%, transparent);
    color: var(--accent);
}
.reaction-chip .emoji {
    font-size: 15px;
    line-height: 1;
}
.reaction-chip .count {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}
.bubble.me .reaction-chip {
    background: rgba(255,255,255,0.18);
    border-color: rgba(255,255,255,0.22);
    color: #fff;
}
.bubble.me .reaction-chip.mine {
    background: rgba(255,255,255,0.28);
    border-color: rgba(255,255,255,0.45);
}

/* Toast — kurze Statusmeldung (z. B. nach Kopieren) */
.app-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%) translateY(20px);
    background: rgba(0,0,0,0.86);
    color: #fff;
    padding: 10px 18px;
    border-radius: 22px;
    font-size: 14px;
    z-index: 9999;
    opacity: 0;
    pointer-events: none;
    transition: opacity 180ms, transform 180ms;
}
.app-toast.show {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
}
