        :root {
            --bg:       #0d0f12;
            --surface:  #141720;
            --surface2: #1b1f2c;
            --border:   #252a3a;
            --accent:   #5b8af0;   /* dove slate-blue */
            --accent2:  #3ecf8e;   /* iridescent neck-green */
            --accent3:  #8e1f53;   /* iridescent neck-wine - used for "you" identifiers */
            --accent3-deep: #300924; /* deepest wine shadow */
            --muted:    #4a5270;
            --text:     #d4daf5;
            --text-dim: #7b85a8;
            --danger:   #e05c6a;
            --warn:     #f0a854;
            --mono:     'IBM Plex Mono', monospace;
            --sans:     'IBM Plex Sans', sans-serif;
        }
        * { box-sizing: border-box; margin: 0; padding: 0; }
        html { height: 100%; overflow: hidden; overscroll-behavior: none; }
        /* Pin the document so iOS can't rubber-band / pan the whole app under the
           Dynamic Island or home indicator (that pan is what scrolled the header
           and call bar off-screen, and what let the page drift sideways). Only the
           inner scroll regions — .messages-area and the sidebar lists — scroll.
           100dvh = the *visible* viewport, so the shell never overflows the screen. */
        body {
            background: var(--bg); color: var(--text); font-family: var(--sans);
            overflow: hidden; overscroll-behavior: none;
            position: fixed; top: 0; left: 0; right: 0;
            height: 100vh; height: 100dvh;
        }

        .screen { display: none; width: 100%; height: 100vh; height: 100dvh; }
        .screen.active { display: flex; }

        /* ── AUTH ── */
        #authScreen {
            flex-direction: column; align-items: center; justify-content: center;
            background:
                radial-gradient(ellipse 60% 50% at 30% 40%, rgba(91,138,240,.08) 0%, transparent 70%),
                radial-gradient(ellipse 50% 60% at 70% 70%, rgba(62,207,142,.05) 0%, transparent 70%),
                var(--bg);
        }
        .auth-logo { font-family: var(--mono); font-size: 2rem; font-weight: 600; letter-spacing: .15em; color: var(--accent); margin-bottom: 6px; }
        /* Custom dove mark used in place of the 🕊 emoji so the brand is consistent
           with the app icon (and is our own art, not a vendor's emoji glyph).
           Sized in em so it scales with whatever logo context it sits in. */
        .logo-img { height: 1.05em; width: auto; vertical-align: -0.16em; margin-right: .12em; }
        .empty-icon img { width: 54px; height: 54px; display: block; }
        .auth-tagline { font-size: .78rem; color: var(--muted); letter-spacing: .12em; text-transform: uppercase; margin-bottom: 40px; }
        .auth-mission { font-size: .78rem; color: var(--muted); letter-spacing: .12em; text-transform: uppercase; margin-bottom: 10px; }
        .auth-box { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 36px 32px; width: 340px; box-shadow: 0 24px 60px rgba(0,0,0,.5); }
        .tab-row { display: flex; border-bottom: 1px solid var(--border); margin-bottom: 28px; }
        .tab-btn { background: none; border: none; color: var(--text-dim); font-family: var(--mono); font-size: .78rem; letter-spacing: .08em; padding: 8px 16px 12px; cursor: pointer; position: relative; transition: color .2s; }
        .tab-btn.active { color: var(--accent); }
        .tab-btn.active::after { content: ''; position: absolute; bottom: -1px; left: 0; right: 0; height: 2px; background: var(--accent); border-radius: 2px 2px 0 0; }
        .auth-panel { display: none; }
        .auth-panel.active { display: block; }
        .field { margin-bottom: 14px; }
        .field label { display: block; font-size: .72rem; letter-spacing: .1em; text-transform: uppercase; color: var(--text-dim); margin-bottom: 6px; font-family: var(--mono); }
        .field input { width: 100%; padding: 10px 12px; background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--sans); font-size: .9rem; transition: border-color .2s; outline: none; }
        .field input:focus { border-color: var(--accent); }
        .submit-btn { width: 100%; padding: 11px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-family: var(--mono); font-weight: 600; font-size: .85rem; letter-spacing: .06em; cursor: pointer; margin-top: 6px; transition: opacity .2s; }
        .submit-btn:hover { opacity: .88; }
        .submit-btn:disabled { opacity: .4; cursor: not-allowed; }
        .turnstile-wrap { display: flex; justify-content: center; margin: 14px 0; }
        .auth-status { text-align: center; font-size: .8rem; margin-top: 14px; min-height: 20px; color: var(--text-dim); font-family: var(--mono); }
        .auth-status.error { color: var(--danger); }
        .auth-status.ok { color: var(--accent2); }

        /* ── WINDOWS CLIENT DOWNLOAD on auth screen ── */
        .download-client-wrap { margin-top: 4px; }
        .download-client-label {
            display: flex; align-items: center; gap: 8px; justify-content: center;
            font-family: var(--sans); font-size: .78rem; letter-spacing: .12em;
            text-transform: uppercase; color: var(--muted); margin: 8px;
        }
        .download-win-icon { width: 13px; height: 13px; fill: currentColor; flex-shrink: 0; }
        .download-client-options { display: flex; gap: 8px; justify-content: center; }
        .download-option-btn {
            flex: 1; max-width: 140px; padding: 8px 12px; text-align: center;
            background: var(--surface); border: 1px solid var(--border); border-radius: 7px;
            color: var(--text-dim); font-family: var(--mono); font-size: .75rem; letter-spacing: .05em;
            text-decoration: none; transition: border-color .2s, color .2s;
        }
        .download-option-btn:hover { border-color: var(--accent); color: var(--accent); }

        /* ── PRIVACY/MISSION LINK on auth screen - small, unobtrusive ── */
        .privacy-link-btn { background: none; border: none; color: var(--muted); font-family: var(--sans); font-size: .78rem; letter-spacing: .12em; text-transform: uppercase; cursor: pointer; padding-top: 6px; text-align: center; }
        .privacy-link-btn:hover { color: var(--accent); }

        /* ── PRIVACY SCREEN ── */
        #privacyScreen {
            flex-direction: column;
            overflow-y: auto;
            padding: calc(14px + env(safe-area-inset-top)) 18px calc(50px + env(safe-area-inset-bottom));
            background:
                radial-gradient(ellipse 60% 50% at 30% 10%, rgba(91,138,240,.06) 0%, transparent 70%),
                radial-gradient(ellipse 50% 40% at 70% 80%, rgba(62,207,142,.04) 0%, transparent 70%),
                var(--bg);
        }
        .privacy-container { max-width: 720px; margin: 0 auto; width: 100%; color: var(--text); }
        .privacy-back { background: none; border: 1px solid var(--border); color: var(--text-dim); font-family: var(--mono); font-size: .8rem; cursor: pointer; padding: 7px 14px; border-radius: 6px; margin-bottom: 28px; transition: background .15s, color .15s, border-color .15s; }
        .privacy-back:hover { background: var(--surface2); color: var(--accent); border-color: var(--accent); }
        .privacy-eyebrow { font-family: var(--mono); font-size: .68rem; color: var(--muted); letter-spacing: .14em; text-transform: uppercase; margin-bottom: 6px; }
        .privacy-title { font-family: var(--mono); font-size: 1.7rem; color: var(--accent); letter-spacing: .04em; margin-bottom: 8px; font-weight: 600; }
        .privacy-subtitle { font-size: .9rem; color: var(--text-dim); margin-bottom: 36px; line-height: 1.5; }
        .privacy-section { margin-bottom: 36px; }
        .privacy-section h2 { font-family: var(--mono); font-size: .9rem; color: var(--accent2); letter-spacing: .12em; text-transform: uppercase; margin-bottom: 14px; padding-bottom: 6px; border-bottom: 1px solid var(--border); font-weight: 600; }
        .privacy-section p { font-size: .92rem; line-height: 1.7; color: var(--text); margin-bottom: 14px; }
        /* Mission lead - left-bordered for visual emphasis */
        .privacy-mission p { font-size: .98rem; line-height: 1.75; color: var(--text); border-left: 3px solid var(--accent3); padding: 4px 0 4px 18px; margin-left: 2px; }
        .privacy-section ul { margin: 6px 0 14px 22px; }
        .privacy-section ul li { font-size: .9rem; line-height: 1.7; margin-bottom: 6px; color: var(--text); }
        .privacy-section ul li strong { color: var(--accent); font-weight: 600; }
        .privacy-section code { font-family: var(--mono); font-size: .82rem; background: var(--surface2); padding: 2px 7px; border-radius: 4px; color: var(--accent2); border: 1px solid var(--border); }
        .privacy-table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: .85rem; }
        .privacy-table th, .privacy-table td { padding: 10px 12px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; line-height: 1.5; }
        .privacy-table th { color: var(--text-dim); font-family: var(--mono); font-size: .68rem; letter-spacing: .08em; text-transform: uppercase; }
        .privacy-table td:first-child { font-weight: 500; color: var(--accent); font-family: var(--mono); font-size: .8rem; }
        .privacy-yesno { display: flex; flex-direction: column; gap: 16px; margin-top: 10px; }
        .privacy-yesno-block { padding: 14px 16px; border-radius: 8px; }
        .privacy-yesno-block.yes { background: rgba(62,207,142,.06); border: 1px solid rgba(62,207,142,.18); }
        .privacy-yesno-block.no  { background: rgba(224,92,106,.06); border: 1px solid rgba(224,92,106,.18); }
        .privacy-yesno-block h3 { font-family: var(--mono); font-size: .82rem; letter-spacing: .06em; margin-bottom: 8px; font-weight: 600; }
        .privacy-yesno-block.yes h3 { color: var(--accent2); }
        .privacy-yesno-block.no  h3 { color: var(--danger); }
        .privacy-yesno-block ul { margin: 0 0 0 20px; }
        .privacy-yesno-block ul li { margin-bottom: 4px; font-size: .87rem; }

        /* Donation callout on the privacy page - wine accent matches brand identity */
        .privacy-donate-section { background: rgba(142,31,83,.05); border: 1px solid rgba(142,31,83,.2); border-radius: 10px; padding: 22px 24px; }
        .privacy-donate-section h2 { border-bottom-color: var(--accent3); color: var(--accent3); }
        .donate-btn {
            display: inline-block; margin-top: 6px;
            padding: 12px 26px; font-family: var(--mono); font-size: .88rem; font-weight: 600;
            letter-spacing: .06em; color: #fdeef5; text-decoration: none;
            background: linear-gradient(135deg, var(--accent3) 0%, var(--accent3-deep) 100%);
            border: 1px solid #b32f6a; border-radius: 8px;
            transition: transform .12s, box-shadow .12s;
        }
        .donate-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 22px rgba(142,31,83,.4); color: #fff; }

        /* Privacy link in sidebar footer - accessible without logging out */
        .sidebar-privacy-link { background: none; border: none; color: var(--muted); cursor: pointer; font-size: .65rem; font-family: var(--mono); padding: 6px 0; letter-spacing: .08em; text-transform: uppercase; transition: color .15s; }
        .sidebar-privacy-link:hover { color: var(--accent); }

        /* Sidebar donation icon */
        .sidebar-donate-link { background: none; border: none; color: var(--muted); cursor: pointer; font-size: .8rem; padding: 6px 0; text-decoration: none; transition: color .15s, transform .15s; line-height: 1; }
        .sidebar-donate-link:hover { color: var(--accent3); transform: scale(1.15); }

        /* Acknowledgement checkbox - must be checked to enable the destructive reset button */
        .reset-checkbox { display: flex; gap: 8px; align-items: flex-start; font-size: .8rem; color: var(--text-dim); cursor: pointer; padding: 10px 0; line-height: 1.5; }
        .reset-checkbox input[type=checkbox] { accent-color: var(--danger); margin-top: 2px; flex-shrink: 0; }

        /* ── UNLOCK PANEL (returning user - password re-entry to decrypt keys) ── */
        .unlock-greeting { font-family: var(--mono); font-size: 1rem; font-weight: 600; color: var(--accent); margin-bottom: 14px; }
        .unlock-reason { font-size: .78rem; color: var(--text-dim); line-height: 1.65; padding: 12px 14px; background: rgba(91,138,240,.06); border: 1px solid rgba(91,138,240,.15); border-radius: 6px; }
        .unlock-reason strong { color: var(--text); font-weight: 500; }
        .unlock-icon { font-size: 1.1rem; display: block; margin-bottom: 7px; }
        .unlock-switch { background: none; border: none; color: var(--muted); font-size: .72rem; font-family: var(--mono); cursor: pointer; margin-top: 12px; display: block; width: 100%; text-align: center; transition: color .2s; padding: 0; }
        .unlock-switch:hover { color: var(--text-dim); }

        /* ── VERIFICATION BANNER ── */
        .verify-banner { display: none; background: rgba(240,168,84,.08); border-bottom: 1px solid rgba(240,168,84,.2); padding: 10px 16px; font-size: .78rem; color: var(--warn); font-family: var(--mono); align-items: center; gap: 10px; }
        .verify-banner.show { display: flex; }
        .resend-btn { background: none; border: 1px solid var(--warn); color: var(--warn); border-radius: 4px; padding: 3px 10px; font-family: var(--mono); font-size: .72rem; cursor: pointer; transition: opacity .2s; white-space: nowrap; }
        .resend-btn:hover { opacity: .7; }

        /* ── CHAT ── */
        #chatScreen { flex-direction: row; }

        .sidebar { width: var(--sidebar-w, 230px); min-width: 0; flex-shrink: 0; overflow: hidden; background: var(--surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; }

        /* ── SIDEBAR RESIZE HANDLE ── */
        .sidebar-resize-handle { width: 10px; flex-shrink: 0; cursor: col-resize; position: relative; z-index: 20; transition: background .15s; }
        .sidebar-resize-handle::after { content: ''; position: absolute; inset: 0; background: var(--accent); opacity: 0; transition: opacity .15s; }
        .sidebar-resize-handle:hover::after, .sidebar-resize-handle.dragging::after { opacity: .35; }
        /* Topmost element of the contacts view — clear the Dynamic Island. */
        .sidebar-header { padding: calc(14px + env(safe-area-inset-top)) calc(14px + env(safe-area-inset-right)) 12px calc(14px + env(safe-area-inset-left)); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 8px; }
        .sidebar-logo { font-family: var(--mono); font-size: .95rem; font-weight: 600; color: var(--accent); letter-spacing: .1em; }
        .ws-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--muted); margin-left: auto; transition: background .3s; }
        .ws-dot.online { background: var(--accent2); box-shadow: 0 0 6px var(--accent2); }

        .add-bar { padding: 10px 10px 0; display: flex; gap: 6px; }
        .add-bar input { flex: 1; background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--mono); font-size: .75rem; padding: 7px 10px; outline: none; transition: border-color .2s; }
        .add-bar input:focus { border-color: var(--accent); }
        .add-bar input::placeholder { color: var(--muted); }
        .add-bar button { background: var(--accent); border: none; border-radius: 6px; color: #fff; font-family: var(--mono); font-size: .75rem; padding: 7px 10px; cursor: pointer; white-space: nowrap; transition: opacity .2s; }
        .add-bar button:hover { opacity: .85; }

        /* Sidebar search - same visual style as the add-bar input so they read as siblings */
        .search-bar { padding: 8px 10px 0; }
        .search-bar input { width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--mono); font-size: .75rem; padding: 7px 10px; outline: none; transition: border-color .2s; }
        .search-bar input:focus { border-color: var(--accent); }
        .search-bar input::placeholder { color: var(--muted); }

        .section-label { padding: 14px 14px 5px; font-size: .63rem; letter-spacing: .14em; text-transform: uppercase; color: var(--muted); font-family: var(--mono); display: flex; align-items: center; gap: 6px; }
        /* Collapsible section headers (Contacts / Groups) */
        .section-toggle { cursor: pointer; user-select: none; transition: color .15s; outline: none; }
        .section-toggle:hover { color: var(--text-dim); }
        .section-caret { font-size: .55rem; display: inline-block; transition: transform .15s; }
        .section-toggle.collapsed .section-caret { transform: rotate(-90deg); }
        .section-badge { background: var(--danger); color: #fff; font-size: .6rem; border-radius: 10px; padding: 1px 6px; }

        /* The wrapper owns the flex space + scrolling; the two lists size to
           their content inside it. This keeps the footer pinned to the bottom in
           every collapse state, and makes the Groups header sit directly under the
           last contact instead of being shoved to the bottom. */
        .sidebar-lists { flex: 1; min-height: 0; overflow-y: auto; }
        .sidebar-lists::-webkit-scrollbar { width: 3px; }
        .sidebar-lists::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
        .user-list { padding: 2px 6px 6px; }

        .contact-item { display: flex; align-items: center; gap: 9px; padding: 7px 8px; border-radius: 6px; cursor: pointer; transition: background .15s; touch-action: manipulation; }
        .contact-item:hover { background: var(--surface2); }
        .contact-item.active { background: rgba(91,138,240,.15); }
        .contact-item.active .ci-name { color: var(--accent); }
        .ci-avatar { width: 28px; height: 28px; border-radius: 50%; background: var(--surface2); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: .72rem; color: var(--text-dim); flex-shrink: 0; text-transform: uppercase; }
        .ci-avatar.online { border-color: var(--accent2); }
        .ci-name { font-size: .84rem; color: var(--text); flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .ci-status { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
        .ci-status.online { background: var(--accent2); }
        .ci-status.connecting { background: var(--warn); animation: blink 1s infinite; }
        .ci-status.offline { background: var(--muted); }
        .ci-unread { background: var(--accent); color: #fff; font-family: var(--mono); font-size: .6rem; border-radius: 10px; padding: 1px 6px; }

        .invite-item { padding: 8px 8px; border-radius: 6px; margin-bottom: 2px; background: rgba(240,168,84,.06); border: 1px solid rgba(240,168,84,.15); }
        .invite-from { font-family: var(--mono); font-size: .75rem; color: var(--warn); margin-bottom: 6px; }
        .invite-actions { display: flex; gap: 5px; }
        .inv-btn { flex: 1; padding: 4px 0; border: none; border-radius: 4px; font-family: var(--mono); font-size: .7rem; cursor: pointer; transition: opacity .2s; }
        .inv-btn:hover { opacity: .8; }
        .inv-btn.accept { background: var(--accent2); color: #000; }
        .inv-btn.decline { background: var(--surface2); color: var(--text-dim); border: 1px solid var(--border); }

        .pending-item { display: flex; align-items: center; gap: 9px; padding: 6px 8px; border-radius: 6px; opacity: .6; }
        .pending-label { font-size: .75rem; color: var(--text-dim); flex: 1; }
        .pending-tag { font-family: var(--mono); font-size: .6rem; color: var(--warn); }
        /* Cancel a sent invite. Always visible (no hover on touch); the row's .6
           opacity keeps it subtle until tapped. */
        .pending-cancel { background: none; border: none; color: var(--muted); font-size: .8rem; line-height: 1; padding: 4px 6px; margin-left: 2px; cursor: pointer; border-radius: 4px; transition: color .15s, background .15s; }
        .pending-cancel:hover { color: var(--danger); background: rgba(224,92,106,.12); }

        .sidebar-footer { padding: 10px calc(12px + env(safe-area-inset-right)) calc(10px + env(safe-area-inset-bottom)) calc(12px + env(safe-area-inset-left)); border-top: 1px solid var(--border); display: flex; align-items: center; gap: 9px; }
        /* Your own avatar - wine accent distinguishes "you" from other contacts everywhere */
        .my-avatar { width: 28px; height: 28px; border-radius: 50%; background: rgba(142,31,83,.22); border: 1px solid var(--accent3); display: flex; align-items: center; justify-content: center; font-family: var(--mono); font-size: .72rem; color: #ff9cc8; text-transform: uppercase; flex-shrink: 0; }
        .my-name { font-size: .84rem; color: var(--text); font-weight: 500; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .logout-btn { background: none; border: none; color: var(--muted); cursor: pointer; font-size: .9rem; padding: 4px; transition: color .2s; }
        .logout-btn:hover { color: var(--danger); }

        .chat-main { flex: 1; display: flex; flex-direction: column; min-width: 0; }
        .empty-state { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; color: var(--muted); gap: 10px; }
        .empty-icon { font-size: 2.5rem; opacity: .25; }
        .empty-text { font-family: var(--mono); font-size: .78rem; letter-spacing: .1em; }
        .empty-sub { font-size: .75rem; color: var(--muted); opacity: .7; }
        /* Cold-start onboarding hub (shown in the empty state for a user with no conversations yet). */
        .empty-onboard, .empty-select { display: flex; flex-direction: column; align-items: center; gap: 10px; max-width: 320px; text-align: center; padding: 0 16px; }
        .empty-onboard .empty-sub { opacity: .85; line-height: 1.6; }
        .empty-actions { display: flex; flex-direction: column; gap: 10px; width: 100%; margin-top: 10px; }
        .empty-invite-btn { background: var(--accent); color: #fff; border: none; border-radius: 8px; padding: 12px 18px; font-family: var(--mono); font-weight: 600; font-size: .88rem; letter-spacing: .03em; cursor: pointer; transition: opacity .2s; touch-action: manipulation; }
        .empty-invite-btn:hover { opacity: .9; }
        .empty-add-btn { background: none; color: var(--accent); border: 1px solid var(--border); border-radius: 8px; padding: 10px 18px; font-family: var(--mono); font-size: .78rem; cursor: pointer; transition: border-color .2s, color .2s; touch-action: manipulation; }
        .empty-add-btn:hover { border-color: var(--accent); }
        .empty-hint { font-size: .72rem; color: var(--muted); margin-top: 16px; line-height: 1.5; }
        /* Invite-link context banner on the auth screen. */
        .auth-invite-banner { max-width: 340px; width: 100%; margin-bottom: 16px; padding: 12px 16px; border: 1px solid rgba(91,138,240,.3); background: rgba(91,138,240,.08); border-radius: 8px; font-size: .82rem; line-height: 1.5; color: var(--text); text-align: center; }
        .auth-invite-banner strong { color: var(--accent); }

        /* ── CHAT HEADER ── */
        /* Top bar of the chat view: pad content below the Dynamic Island and grow
           the bar by the same amount so its 52px content height is preserved.
           env(...) is 0 on desktop/Android-no-notch, so this is a no-op there. */
        .chat-header { padding: env(safe-area-inset-top) calc(16px + env(safe-area-inset-right)) 0 calc(16px + env(safe-area-inset-left)); height: calc(52px + env(safe-area-inset-top)); border-bottom: 1px solid var(--border); display: flex; align-items: center; gap: 12px; flex-shrink: 0; }
        .chat-header-name { font-family: var(--mono); font-size: .92rem; font-weight: 600; }

        .rtc-pill { margin-left: auto; display: flex; align-items: center; gap: 5px; font-family: var(--mono); font-size: .68rem; color: var(--muted); background: var(--surface2); border: 1px solid var(--border); border-radius: 20px; padding: 3px 10px; }
        .rtc-dot { width: 6px; height: 6px; border-radius: 50%; background: var(--muted); }
        .rtc-dot.connected { background: var(--accent2); box-shadow: 0 0 5px var(--accent2); }
        .rtc-dot.connecting { background: var(--warn); animation: blink 1s infinite; }

        /* ── CALL BUTTON ── */
        .call-btn {
            display: none;
            background: none;
            border: 1px solid var(--border);
            border-radius: 6px;
            color: var(--accent2);
            font-size: 1rem;
            width: 32px; height: 32px;
            align-items: center; justify-content: center;
            cursor: pointer;
            transition: background .15s, border-color .15s;
            flex-shrink: 0;
        }
        .call-btn:hover { background: rgba(62,207,142,.1); border-color: var(--accent2); }
        .call-btn.visible { display: flex; }
        .call-btn.in-call { color: var(--danger); border-color: var(--danger); animation: pulse-red 1.5s infinite; }
        @keyframes pulse-red { 0%,100%{box-shadow:0 0 0 0 rgba(224,92,106,.4)} 50%{box-shadow:0 0 0 6px rgba(224,92,106,0)} }

        @keyframes blink { 0%,100%{opacity:1} 50%{opacity:.3} }

        .key-banner { padding: 7px 20px; border-bottom: 1px solid rgba(62,207,142,.15); display: flex; align-items: center; gap: 7px; font-family: var(--mono); font-size: .7rem; color: var(--accent2); background: rgba(62,207,142,.05); flex-shrink: 0; }
        .key-banner.warn { border-bottom-color: rgba(240,168,84,.2); color: var(--warn); background: rgba(240,168,84,.05); }

        /* ── ACTIVE CALL BAR ── */
        .call-bar {
            display: none;
            padding: 0 16px;
            height: 48px;
            background: rgba(62,207,142,.08);
            border-bottom: 1px solid rgba(62,207,142,.2);
            align-items: center;
            gap: 12px;
            flex-shrink: 0;
            font-family: var(--mono);
            font-size: .78rem;
            color: var(--accent2);
        }
        .call-bar.active { display: flex; }
        .call-bar-timer { font-variant-numeric: tabular-nums; letter-spacing: .05em; }
        .call-bar-actions { margin-left: auto; display: flex; gap: 8px; }
        .call-action-btn {
            background: var(--surface2);
            border: 1px solid var(--border);
            border-radius: 6px;
            color: var(--text);
            font-family: var(--mono);
            font-size: .72rem;
            padding: 5px 12px;
            cursor: pointer;
            transition: background .15s;
            display: flex; align-items: center; gap: 5px;
        }
        .call-action-btn:hover { background: var(--surface); }
        .call-action-btn.muted { color: var(--warn); border-color: var(--warn); }
        .call-action-btn.hangup { color: var(--danger); border-color: var(--danger); }
        .call-action-btn.hangup:hover { background: rgba(224,92,106,.1); }
        .call-action-btn.screen-active { color: var(--accent2); border-color: var(--accent2); }
        .call-action-btn.cam-active { color: var(--accent); border-color: var(--accent); }

        /* ── Unified call/voice bar ── */
        .call-bar-id { white-space: nowrap; flex-shrink: 0; }
        .call-action-btn.icon { padding: 5px 9px; font-size: .92rem; line-height: 1; }
        .call-action-btn.join { color: #06120c; background: var(--accent2); border-color: var(--accent2); font-weight: 600; }
        .call-action-btn.join:hover { filter: brightness(1.08); background: var(--accent2); }
        /* Reveal only the controls relevant to each mode (peer call / in room / discovery) */
        .call-bar:not(.mode-room):not(.mode-discover) .voice-room-roster { display: none; }
        .call-bar.mode-discover .icon,
        .call-bar.mode-discover #callSettings,
        .call-bar.mode-discover #hangupBtn,
        .call-bar.mode-discover #callTimer { display: none; }
        .call-bar:not(.mode-discover) #voiceJoinBtn { display: none; }
        /* Settings cog dropdown - PTT (+ key bind) and noise suppression */
        .call-settings { position: relative; display: flex; }
        .call-settings-menu { display: none; position: absolute; right: 0; top: calc(100% + 6px); width: 230px; background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 5px; z-index: 60; box-shadow: 0 8px 24px rgba(0,0,0,.45); }
        .call-settings.open .call-settings-menu { display: block; }
        .cs-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 7px 8px; font-size: .74rem; color: var(--text); }
        .cs-row.cs-sub { padding-top: 0; padding-left: 18px; color: var(--text-dim); font-size: .7rem; }
        .cs-toggle, .cs-bind { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text-dim); font-family: var(--mono); font-size: .7rem; padding: 4px 10px; cursor: pointer; min-width: 56px; text-align: center; }
        .cs-toggle.on { color: var(--accent2); border-color: var(--accent2); }
        .cs-bind { color: var(--accent); border-color: rgba(91,138,240,.4); }
        .cs-bind.binding { color: var(--warn); border-color: var(--warn); }
        .cs-row.cs-col { flex-direction: column; align-items: stretch; gap: 4px; }
        .cs-select { width: 100%; max-width: 100%; background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--mono); font-size: .7rem; padding: 4px 6px; cursor: pointer; }
        .cs-divider { height: 1px; background: var(--border); margin: 3px 4px 5px; }

        /* ── Voice-room roster chips (rendered inside the call bar) ── */
        .voice-room-roster { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; flex: 1; min-width: 0; }
        .vr-chip {
            display: inline-flex; align-items: center; gap: 5px;
            background: var(--surface2); border: 1px solid var(--border); border-radius: 999px;
            padding: 2px 9px 2px 2px; font-size: .72rem; color: var(--text);
            max-width: 150px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
        }
        .vr-chip.me { border-color: rgba(62,207,142,.4); color: var(--accent2); }
        .vr-av {
            width: 18px; height: 18px; border-radius: 50%; flex-shrink: 0;
            background: var(--bg); border: 1px solid var(--border);
            display: inline-flex; align-items: center; justify-content: center;
            font-size: .58rem; text-transform: uppercase; overflow: hidden;
        }
        .vr-av img { width: 100%; height: 100%; object-fit: cover; }
        .vr-empty { color: var(--muted); font-style: italic; }
        /* Speaking indicator - green ring on the avatar of whoever's talking (incl. you) */
        .vr-chip { animation: vr-pop .16s ease; }
        .vr-chip .vr-av { transition: box-shadow .12s ease; }
        .vr-chip.speaking { border-color: rgba(62,207,142,.55); }
        .vr-chip.speaking .vr-av { box-shadow: 0 0 0 2px var(--accent2), 0 0 7px 1px rgba(62,207,142,.55); }
        @keyframes vr-pop { from { opacity: 0; } to { opacity: 1; } }
        /* Sidebar live-voice count badge on a group row */
        .ci-voice {
            flex-shrink: 0; font-size: .6rem; color: var(--accent2); font-family: var(--mono);
            background: rgba(62,207,142,.12); border: 1px solid rgba(62,207,142,.25);
            border-radius: 999px; padding: 1px 6px; display: inline-flex; align-items: center; gap: 2px;
        }

        /* Video container - shows screen share / webcam feed during an active call */
        .video-container { display: none; flex-shrink: 0; height: 55vh; max-height: 500px; min-height: 180px; background: #000; position: relative; border-bottom: 1px solid var(--border); }
        .video-container.active { display: flex; align-items: center; justify-content: center; }
        .remote-video { width: 100%; height: 100%; object-fit: contain; background: #000; display: block; }
        .local-video { position: absolute; bottom: 12px; right: 12px; width: 160px; height: 120px; object-fit: cover; border-radius: 8px; border: 2px solid rgba(255,255,255,.15); background: #000; z-index: 1; display: none; }
        .local-video.solo { position: static; width: 100%; height: 100%; object-fit: contain; border: none; border-radius: 0; }
        /* Tap a tile to view that feed full-screen (overlay, not the native Fullscreen API - works in both webviews) */
        .remote-video, .local-video { cursor: pointer; }
        .video-fs { display: none; position: fixed; inset: 0; z-index: 1500; background: #000; align-items: center; justify-content: center; }
        .video-fs.active { display: flex; }
        .fs-video { width: 100%; height: 100%; object-fit: contain; background: #000; }
        .fs-close { position: absolute; top: calc(10px + env(safe-area-inset-top)); right: calc(12px + env(safe-area-inset-right)); width: 40px; height: 40px; border-radius: 50%; background: rgba(0,0,0,.55); border: 1px solid rgba(255,255,255,.3); color: #fff; font-size: 1rem; cursor: pointer; display: flex; align-items: center; justify-content: center; }
        .video-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 3px; width: 100%; height: 100%; padding: 3px; }
        .video-grid video { width: 100%; height: 100%; object-fit: contain; background: #111; border-radius: 4px; }

        /* ── INCOMING CALL OVERLAY ── */
        .call-overlay {
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(13,15,18,.85);
            backdrop-filter: blur(4px);
            z-index: 1000;
            align-items: center;
            justify-content: center;
        }
        .call-overlay.active { display: flex; }
        .call-modal {
            background: var(--surface);
            border: 1px solid var(--border);
            border-radius: 16px;
            padding: 40px 48px;
            text-align: center;
            box-shadow: 0 32px 80px rgba(0,0,0,.6);
            display: flex;
            flex-direction: column;
            align-items: center;
            gap: 16px;
            min-width: 300px;
        }
        .call-avatar-lg {
            width: 72px; height: 72px;
            border-radius: 50%;
            background: rgba(91,138,240,.15);
            border: 2px solid var(--accent);
            display: flex; align-items: center; justify-content: center;
            font-family: var(--mono);
            font-size: 1.8rem;
            color: var(--accent);
            text-transform: uppercase;
            animation: ring-pulse 1.5s infinite;
        }
        @keyframes ring-pulse {
            0%,100% { box-shadow: 0 0 0 0 rgba(91,138,240,.4); }
            50%      { box-shadow: 0 0 0 16px rgba(91,138,240,0); }
        }
        .call-modal-name { font-family: var(--mono); font-size: 1.1rem; font-weight: 600; color: var(--text); }
        .call-modal-sub { font-size: .8rem; color: var(--text-dim); font-family: var(--mono); }
        .call-modal-actions { display: flex; gap: 16px; margin-top: 8px; }
        .call-accept-btn {
            background: var(--accent2);
            border: none;
            border-radius: 50%;
            width: 56px; height: 56px;
            font-size: 1.4rem;
            cursor: pointer;
            display: flex; align-items: center; justify-content: center;
            transition: opacity .2s;
            box-shadow: 0 0 20px rgba(62,207,142,.3);
        }
        .call-accept-btn:hover { opacity: .85; }
        .call-decline-btn {
            background: var(--danger);
            border: none;
            border-radius: 50%;
            width: 56px; height: 56px;
            font-size: 1.4rem;
            cursor: pointer;
            display: flex; align-items: center; justify-content: center;
            transition: opacity .2s;
            box-shadow: 0 0 20px rgba(224,92,106,.3);
        }
        .call-decline-btn:hover { opacity: .85; }

        /* ── OUTGOING CALL OVERLAY ── */
        .calling-overlay {
            display: none;
            position: fixed;
            inset: 0;
            background: rgba(13,15,18,.85);
            backdrop-filter: blur(4px);
            z-index: 1000;
            align-items: center;
            justify-content: center;
        }
        .calling-overlay.active { display: flex; }

        .messages-area { flex: 1; overflow-y: auto; padding: 16px 20px; display: flex; flex-direction: column; gap: 2px; }
        .messages-area::-webkit-scrollbar { width: 4px; }
        .messages-area::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
        .history-loading { text-align: center; font-family: var(--mono); font-size: .7rem; color: var(--muted); padding: 8px 0 4px; }

        .msg-group { display: flex; flex-direction: column; gap: 2px; margin-bottom: 6px; }
        .msg-group-header { display: flex; align-items: baseline; gap: 10px; margin-bottom: 2px; }
        .msg-author { font-weight: 500; font-size: .86rem; color: var(--accent); }
        .msg-author.self { color: var(--accent2); }
        .msg-time { font-family: var(--mono); font-size: .63rem; color: var(--muted); }
        /* pre-wrap preserves shift+enter line breaks; word-break wraps long URLs.
           touch-action:manipulation prevents iOS double-tap zoom so the reaction picker can use double-tap.
           -webkit-touch-callout:none stops iOS's native long-press menu (Copy/Save Image/Share) from
           hijacking the long-press - that's our own context menu's gesture now. */
        .msg-bubble { background: var(--surface2); border: 1px solid var(--border); border-radius: 0 8px 8px 8px; padding: 8px 12px; font-size: .87rem; line-height: 1.5; max-width: 72%; word-break: break-word; align-self: flex-start; white-space: pre-wrap; touch-action: manipulation; -webkit-touch-callout: none; }
        /* touch-action isn't inherited, so the child <img> still allowed double-tap-to-zoom, which collided
           with the double-tap-to-react gesture and froze the WebView compositor. Disable it here too, and
           suppress the iOS image long-press callout so our context menu wins. */
        .msg-bubble img { touch-action: manipulation; -webkit-touch-callout: none; }
        /* On touch devices, suppress text selection on messages so a long-press opens our context menu
           cleanly instead of the iOS selection magnifier. Desktop keeps normal selection (and uses
           right-click for the same menu); Copy in the menu covers the lost manual selection on mobile. */
        @media (hover: none) and (pointer: coarse) {
            .msg-bubble, .msg-bubble * { -webkit-user-select: none; user-select: none; }
        }
        /* "You" bubble - wine-colored solid fill */
        .msg-bubble.self {
            background: #300924;
            border-color: rgba(255,255,255,.05);
            color: #fdeef5;
            border-radius: 8px 0 8px 8px;  /* sharp corner at TOP-RIGHT (TL, TR=0, BR, BL) */
            align-self: flex-end;
        }
        /* Centered time chip shown at a day boundary or after a gap in the conversation */
        .time-chip { align-self: center; font-family: var(--mono); font-size: .65rem; color: var(--muted); padding: 14px 0 6px; letter-spacing: .06em; }
        .msg-bubble.system { background: none; border: none; color: var(--muted); font-family: var(--mono); font-size: .7rem; letter-spacing: .04em; align-self: center; padding: 3px 0; white-space: normal; }
        .msg-bubble.error-msg { color: var(--danger); font-family: var(--mono); font-size: .75rem; }
        .msg-bubble a { color: var(--accent); text-decoration: underline; word-break: break-all; }
        .msg-bubble a:hover { color: var(--accent2); }
        /* Links inside self bubbles - pink tone for contrast against the wine fill */
        .msg-bubble.self a { color: var(--accent); text-decoration: underline; word-break: break-all; }
        .msg-bubble.self a:hover { color: var(--accent2); }

        /* Lift the message box above the home indicator so it's fully tappable
           without the user having to over-scroll the page up to reach it. */
        .input-bar { padding: 10px calc(16px + env(safe-area-inset-right)) calc(14px + env(safe-area-inset-bottom)) calc(16px + env(safe-area-inset-left)); display: flex; gap: 8px; align-items: flex-end; flex-shrink: 0; }
        .input-bar textarea { flex: 1; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; color: var(--text); font-family: var(--sans); font-size: .88rem; padding: 9px 13px; resize: none; outline: none; max-height: 120px; min-height: 38px; line-height: 1.4; transition: border-color .2s; }
        .input-bar textarea:focus { border-color: var(--accent); }
        .input-bar textarea::placeholder { color: var(--muted); }
        /* Hide the persistent scrollbar inside the message field (content still scrolls past max-height). */
        .input-bar textarea { scrollbar-width: none; }
        .input-bar textarea::-webkit-scrollbar { width: 0; height: 0; display: none; }
        .send-btn { background: var(--accent); border: none; border-radius: 8px; width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: white; font-size: 1rem; transition: opacity .2s; flex-shrink: 0; }
        .send-btn:hover { opacity: .85; }
        .send-btn:disabled { opacity: .3; cursor: not-allowed; }
        .attach-btn { background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; cursor: pointer; color: var(--text-dim); font-size: 1.1rem; transition: background .15s, color .15s; flex-shrink: 0; }
        .attach-btn:hover { background: var(--surface); color: var(--accent); }

        /* ── COMING-SOON MODAL ── */
        .cs-list { list-style: none; margin: 12px 0 0; padding: 0; }
        .cs-list li { padding: 9px 0; border-bottom: 1px solid var(--border); display: flex; align-items: flex-start; gap: 10px; font-size: .82rem; color: var(--text); }
        .cs-list li:last-child { border-bottom: none; }
        .cs-list .cs-icon { font-size: 1.1rem; line-height: 1; flex-shrink: 0; }
        .cs-list .cs-label { font-weight: 500; }
        .cs-list .cs-desc { color: var(--text-dim); font-size: .75rem; margin-top: 2px; line-height: 1.45; }
        .cs-intro { font-size: .8rem; color: var(--text-dim); line-height: 1.55; margin-bottom: 4px; }

        /* z-index sits above every overlay (the fullscreen image viewer is 2000) so confirmations
           like "Saved to Photos" are visible even when fired from on top of a modal - otherwise the
           toast renders behind the dark backdrop and the user never sees it. A toast is transient
           feedback, so it should always be the topmost layer. */
        .toast { position: fixed; bottom: 22px; right: 22px; background: var(--surface2); border: 1px solid var(--border); border-radius: 8px; padding: 11px 15px; font-size: .8rem; color: var(--text); box-shadow: 0 8px 32px rgba(0,0,0,.4); transform: translateY(70px); opacity: 0; transition: all .25s ease; z-index: 3000; font-family: var(--mono); max-width: 280px; }

        /* ── IMAGE MESSAGES ── */
        /* File attachment card - compact, clickable block with icon + name + size */
        .msg-bubble.is-file { padding: 10px 14px; max-width: 320px; cursor: pointer; display: flex; align-items: center; gap: 10px; transition: background .15s; }
        .msg-bubble.is-file:hover { background: var(--surface); }
        .msg-bubble.is-file.self:hover { background: #3d1232; }
        .file-icon { font-size: 1.6rem; flex-shrink: 0; line-height: 1; }
        .file-info { flex: 1; min-width: 0; }
        .file-name { font-size: .82rem; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .file-meta { font-size: .68rem; color: var(--text-dim); font-family: var(--mono); margin-top: 2px; }
        .msg-bubble.self .file-meta { color: rgba(253,238,245,.5); }

        .msg-bubble.is-image { padding: 4px; max-width: 280px; }
        .msg-bubble.is-image img { max-width: 100%; height: auto; display: block; border-radius: 6px; cursor: zoom-in; min-height: 50px; background: var(--surface); }
        .msg-bubble.is-image.loading::after { content: 'Decrypting…'; display: block; font-family: var(--mono); font-size: .68rem; color: var(--text-dim); text-align: center; padding: 4px 0 2px; }

        /* Full-screen image viewer (click any image to expand) */
        .image-modal { position: fixed; inset: 0; background: rgba(0,0,0,.92); z-index: 2000; display: none; align-items: center; justify-content: center; padding: 20px; cursor: zoom-out; overflow: hidden; }
        .image-modal.active { display: flex; }
        /* touch-action:none hands every touch gesture on the image to our JS zoom/pan handler
           (app.js) instead of the browser; transform-origin keeps pinch + double-tap zooming
           around the image centre. The transform itself is set inline by the handler. */
        .image-modal img { max-width: 100%; max-height: 100%; border-radius: 4px; box-shadow: 0 8px 40px rgba(0,0,0,.6); touch-action: none; transform-origin: center center; will-change: transform; }
        /* Top-right action cluster in the image viewer - Share + Save side by side. */
        .img-actions { position: absolute; top: calc(12px + env(safe-area-inset-top)); right: calc(12px + env(safe-area-inset-right)); display: flex; gap: 8px; z-index: 1; }
        .img-action-btn { background: rgba(0,0,0,.6); border: 1px solid rgba(255,255,255,.3); color: #fff; font-family: var(--mono); font-size: .78rem; padding: 8px 14px; border-radius: 8px; cursor: pointer; touch-action: manipulation; }
        /* Close affordance - the image no longer closes on tap (it zooms), so this and the
           backdrop are the explicit exits. Mirrors the Save button on the opposite corner. */
        .img-close-btn { position: absolute; top: calc(12px + env(safe-area-inset-top)); left: calc(12px + env(safe-area-inset-left)); background: rgba(0,0,0,.6); border: 1px solid rgba(255,255,255,.3); color: #fff; font-family: var(--mono); font-size: 1rem; line-height: 1; width: 36px; height: 36px; border-radius: 8px; cursor: pointer; z-index: 1; touch-action: manipulation; }

        /* ── EMOJI REACTIONS ── */
        .reactions-row { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 3px; align-self: flex-start; max-width: 72%; }
        .reactions-row.self { align-self: flex-end; }
        .reaction-chip { display: inline-flex; align-items: center; gap: 3px; background: var(--surface2); border: 1px solid var(--border); border-radius: 10px; padding: 1px 7px; font-size: .72rem; cursor: pointer; user-select: none; transition: background .12s, border-color .12s; }
        .reaction-chip:hover { background: var(--surface); }
        .reaction-chip.mine { background: rgba(91,138,240,.15); border-color: var(--accent); }
        .reaction-chip .count { color: var(--text-dim); font-family: var(--mono); font-size: .68rem; }
        /* Floating reaction picker - compact quick row with expandable full emoji grid.
           touch-action:manipulation on the picker + every button opts these controls out of
           double-tap-to-zoom. The viewport leaves pinch/double-tap zoom enabled on purpose (the
           full-screen image viewer wants pinch), so without this the Android WebView eats rapid
           taps on the "···"/Delete buttons as zoom gestures - they appear to do nothing, and a
           stray zoom on the fixed-body layout can wedge tap hit-testing entirely ("can't click,
           only scroll"). iOS WKWebView doesn't, which is why this only bit Android. */
        .reaction-picker { position: fixed; z-index: 1100; background: var(--surface); border: 1px solid var(--border); border-radius: 14px; box-shadow: 0 8px 24px rgba(0,0,0,.5); overflow: hidden; min-width: 220px; touch-action: manipulation; }
        .reaction-picker button { touch-action: manipulation; }
        .rp-quick { display: flex; align-items: center; padding: 5px 7px; gap: 1px; }
        .rp-quick button { background: none; border: none; cursor: pointer; font-size: 1.25rem; border-radius: 8px; padding: 5px 6px; line-height: 1; transition: background .12s, transform .12s; flex-shrink: 0; }
        .rp-quick button:hover { background: var(--surface2); transform: scale(1.12); }
        .rp-sep { width: 1px; background: var(--border); align-self: stretch; margin: 3px 4px; flex-shrink: 0; }
        .picker-more { font-size: .78rem; color: var(--text-dim); letter-spacing: .05em; padding: 5px 9px; }
        .rp-quick .picker-more:hover { background: var(--surface2); color: var(--accent); transform: none; }
        .picker-more.open { background: rgba(91,138,240,.1); color: var(--accent); }
        .rp-expanded { border-top: 1px solid var(--border); padding: 7px; }
        .rp-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 1px; max-height: 208px; overflow-y: auto; margin-bottom: 4px; }
        .rp-grid::-webkit-scrollbar { width: 3px; }
        .rp-grid::-webkit-scrollbar-thumb { background: var(--border); border-radius: 2px; }
        .rp-grid button { background: none; border: none; cursor: pointer; font-size: 1.1rem; border-radius: 5px; padding: 3px; line-height: 1; transition: background .1s; width: 100%; aspect-ratio: 1; display: flex; align-items: center; justify-content: center; }
        .rp-grid button:hover { background: var(--surface2); }
        .picker-delete { background: none; border: none; cursor: pointer; color: var(--danger); font-family: var(--mono); font-size: .75rem; width: 100%; padding: 6px 4px; border-top: 1px solid var(--border); transition: background .15s; text-align: center; display: block; border-radius: 0; }
        .picker-delete:hover { background: rgba(224,92,106,.1); }
        /* Context-menu action rows below the emoji row - Reply / Copy / Share / Save / Delete,
           rendered as a vertical iOS-style list. Each is shown/hidden per message type in JS. */
        .rp-actions { display: flex; flex-direction: column; border-top: 1px solid var(--border); }
        .rp-action { background: none; border: none; cursor: pointer; color: var(--text); font-family: var(--sans); font-size: .82rem; text-align: left; padding: 9px 14px; display: flex; align-items: center; gap: 8px; transition: background .12s; }
        .rp-action:hover { background: var(--surface2); }
        .rp-action.danger { color: var(--danger); }
        .rp-action.danger:hover { background: rgba(224,92,106,.1); }

        /* ── PAGINATION ── */
        .load-older { align-self: center; padding: 8px 14px; margin: 8px 0; font-family: var(--mono); font-size: .7rem; color: var(--text-dim); background: var(--surface2); border: 1px solid var(--border); border-radius: 14px; cursor: pointer; transition: background .15s, color .15s; }
        .load-older:hover { background: var(--surface); color: var(--accent); }
        .load-older.exhausted { cursor: default; opacity: .55; }
        .load-older.exhausted:hover { background: var(--surface2); color: var(--text-dim); }

        /* ── BACK BUTTON - mobile only, returns from chat pane to sidebar ── */
        .back-btn { background: none; border: none; color: var(--text); font-size: 1.4rem; padding: 0 6px 0 0; cursor: pointer; display: none; align-items: center; justify-content: center; flex-shrink: 0; line-height: 1; }
        .back-btn:hover { color: var(--accent); }

        /* ── MOBILE LAYOUT - narrow viewports show one pane at a time ── */
        @media (max-width: 720px) {
            /* Auth screen: switch from centered to top-aligned so taller content can scroll */
            #authScreen { justify-content: flex-start; overflow-y: auto; padding: calc(14px + env(safe-area-inset-top)) 16px calc(32px + env(safe-area-inset-bottom)); }

            /* Stop iOS auto-zooming when a field is focused. WKWebView zooms the
               page whenever the focused input's font-size is < 16px; pinning all
               text-entry fields to 16px on phones prevents it without disabling
               pinch-zoom elsewhere (e.g. the full-screen image viewer). The
               !important sidesteps the more specific selectors like `.field input`. */
            input[type="text"], input[type="email"], input[type="password"],
            input[type="search"], input[type="tel"], input[type="url"],
            input:not([type]), textarea, select { font-size: 16px !important; }

            /* The 16px no-zoom floor makes fields taller than their old ~12-14px
               text did. Trim vertical padding on phones so the sidebar inputs keep
               their compact height, and re-match the message textarea to the 38px
               attach/send buttons (8px pad + 1.25 line-height = 38px single-line,
               then it grows normally as you type). */
            .add-bar input, .add-bar button, .search-bar input { padding: 5px 10px; }
            .input-bar textarea { padding: 8px 13px; line-height: 1.25; }
            .auth-box { width: 100%; max-width: 340px; }

            /* Both panes are full-width; .show-chat on the parent toggles which is visible */
            /* Hard-override: CSS var from desktop resize must not affect mobile layout */
            .sidebar { width: 100% !important; min-width: 0; }
            .chat-main { width: 100%; min-width: 0; }
            .sidebar-resize-handle { display: none; }
            /* Default state: sidebar visible, chat hidden */
            #chatScreen .chat-main { display: none; }
            /* show-chat state: chat takes over, sidebar hidden */
            #chatScreen.show-chat .sidebar { display: none; }
            #chatScreen.show-chat .chat-main { display: flex; }
            /* Back button only relevant on mobile */
            .back-btn { display: flex; }
            /* ── TOP-BAR VERTICAL POSITION (phones) ──────────────────────────
               Both top bars must clear the Dynamic Island. Apple's
               env(safe-area-inset-top) (~59px on a 17 Pro) is conservative — the
               island's real bottom edge is ~48–51px — so we pull the bars UP from
               that line by --topbar-trim. Raise --topbar-trim to lift them more
               (eventually the clock/island will start to overlap); lower it to
               drop them. The max(…, 14px) floor does double duty: it stops them vanishing on iOS,
               and on Android — where env(safe-area-inset-top) is ~0, so the bar otherwise sat a
               cramped 4px from the top edge — it gives a comfortable ~14px gap that balances the
               padding below the bar. THIS ONE NUMBER is the dial. */
            #chatScreen { --topbar-trim: 10px; }
            /* The chat header's top row is busy (back arrow, avatar, name, call/info/search icons) and
               sits right where a Dynamic Island / hole-punch camera lives, so it felt cramped on BOTH
               platforms. Unlike the sidebar — which keeps the --topbar-trim space-reclaim the user liked
               — the chat header uses the FULL env(safe-area-inset-top) (no trim), so its content clears
               the island/punch with real breathing room on iOS too. The 20px floor covers no-notch
               devices (Android, older iPhones) where the inset is ~0. Re-introduce a small trim here, or
               adjust the floor, if it ever reads as too tall. */
            .chat-header {
                height: auto; min-height: 52px;
                padding: max(env(safe-area-inset-top), 20px) calc(10px + env(safe-area-inset-right)) 5px calc(10px + env(safe-area-inset-left));
                gap: 8px;
            }
            .sidebar-header {
                padding: max(calc(env(safe-area-inset-top) - var(--topbar-trim)), 14px) calc(12px + env(safe-area-inset-right)) 10px calc(12px + env(safe-area-inset-left));
            }
            /* Call bar: auto height so buttons wrap instead of overflowing off-screen */
            .call-bar { height: auto; min-height: 44px; padding: 7px 12px; flex-wrap: wrap; row-gap: 6px; }
            .call-bar > span:first-child { display: none; }
            .call-bar-timer { margin-left: auto; }
            .call-bar-actions { margin-left: 0; width: 100%; flex-wrap: wrap; gap: 5px; }
            .call-action-btn { font-size: .66rem; padding: 6px 8px; flex: 1 1 auto; justify-content: center; }
            /* End button spans full width so it is always easy to find and tap */
            .call-action-btn.hangup { flex: 1 1 100%; padding: 8px; }
        }
        .toast.show { transform: translateY(0); opacity: 1; }

        /* ── DELETE CONVERSATION BUTTON - danger color at reduced opacity ── */
        .retain-btn { background: none; border: 1px solid rgba(224,92,106,.35); border-radius: 6px; color: rgba(224,92,106,.65); font-size: .9rem; width: 32px; height: 32px; display: none; align-items: center; justify-content: center; cursor: pointer; transition: background .15s, color .15s, border-color .15s; flex-shrink: 0; }
        .retain-btn:hover { background: rgba(224,92,106,.12); border-color: var(--danger); color: var(--danger); }
        .retain-btn.visible { display: flex; }

        /* Remove-contact button - appears on hover */
        .contact-item { position: relative; }
        .ci-remove { display: none; position: absolute; right: 4px; top: 50%; transform: translateY(-50%); background: none; border: none; color: var(--muted); font-size: .7rem; line-height: 1; padding: 3px 5px; cursor: pointer; border-radius: 4px; transition: color .15s, background .15s; z-index: 1; }
        .contact-item:hover .ci-remove { display: block; }
        .ci-remove:hover { color: var(--danger); background: rgba(224,92,106,.12); }

        /* ── GROUPS SIDEBAR ── */
        .section-row { display: flex; align-items: center; padding-right: 10px; }
        .section-row .section-label { flex: 1; }
        .add-group-btn { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 1rem; padding: 0 4px 0 0; margin-top: 9px; transition: color .2s; }
        .add-group-btn:hover { color: var(--accent); }

        /* ── NEW GROUP MODAL ── */
        .modal-overlay { position: fixed; inset: 0; background: rgba(13,15,18,.85); backdrop-filter: blur(4px); z-index: 1000; display: flex; align-items: center; justify-content: center; }
        .modal-box { background: var(--surface); border: 1px solid var(--border); border-radius: 10px; padding: 28px; width: 320px; box-shadow: 0 24px 60px rgba(0,0,0,.5); }
        .modal-title { font-family: var(--mono); font-size: .9rem; font-weight: 600; color: var(--accent); margin-bottom: 18px; letter-spacing: .08em; }
        .member-check { display: flex; align-items: center; gap: 8px; padding: 5px 4px; border-radius: 4px; cursor: pointer; font-size: .83rem; color: var(--text); }
        .member-check:hover { background: var(--surface2); }
        .member-check input[type=checkbox] { accent-color: var(--accent); width: 14px; height: 14px; }
        .modal-actions { display: flex; gap: 8px; margin-top: 12px; }
        .modal-cancel { background: var(--surface2); color: var(--text-dim); border: 1px solid var(--border); }

        /* ── SHARE / INVITE MODAL ── */
        /* QR stays on a white card — scanners want high contrast, so we don't
           invert it for the dark theme. */
        .qr-card { background: #fff; border-radius: 10px; padding: 14px; display: inline-block; line-height: 0; margin-bottom: 14px; }
        .qr-card svg { width: 200px; height: 200px; display: block; }
        .share-link { font-family: var(--mono); font-size: .72rem; color: var(--accent); background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px; margin-bottom: 14px; word-break: break-all; user-select: all; }
        /* Username in the footer is tappable to open the share modal. */
        .my-name { cursor: pointer; }
        .my-name:hover { color: var(--accent); }

        /* ── PROFILE AVATARS - uploaded image overrides the letter fallback ── */
        .ci-avatar img, .my-avatar img, #peerAvatar img, .modal-box .ci-avatar img { width: 100%; height: 100%; object-fit: cover; border-radius: 50%; display: block; }
        .my-avatar { cursor: pointer; transition: transform .15s; overflow: hidden; }
        .my-avatar:hover { transform: scale(1.05); }
        .ci-avatar { overflow: hidden; }
        #peerAvatar { overflow: hidden; }

        /* ── GROUP SETTINGS / AVATAR CROP modal helpers ── */
        .info-btn { background: none; border: 1px solid var(--border); border-radius: 6px; color: var(--text-dim); font-size: .85rem; width: 32px; height: 32px; display: none; align-items: center; justify-content: center; cursor: pointer; transition: background .15s; flex-shrink: 0; }
        .info-btn:hover { background: var(--surface2); border-color: var(--accent); color: var(--accent); }
        .info-btn.visible { display: flex; }

        /* Member list inside the group settings modal */
        .gs-member { display: flex; align-items: center; gap: 10px; padding: 8px 6px; border-bottom: 1px solid var(--border); }
        .gs-member:last-child { border-bottom: none; }
        .gs-member .ci-avatar { width: 30px; height: 30px; font-size: .75rem; }
        .gs-member-name { flex: 1; font-size: .85rem; color: var(--text); }
        .gs-admin-badge { font-family: var(--mono); font-size: .6rem; color: var(--accent2); border: 1px solid var(--accent2); padding: 1px 6px; border-radius: 10px; letter-spacing: .04em; }
        .gs-kick-btn { background: none; border: 1px solid var(--danger); color: var(--danger); border-radius: 4px; font-family: var(--mono); font-size: .65rem; padding: 3px 8px; cursor: pointer; letter-spacing: .04em; transition: background .15s; }
        .gs-kick-btn:hover { background: rgba(224,92,106,.12); }
        .gs-leave-btn { background: var(--danger); color: #fff; border: none; border-radius: 6px; padding: 9px; width: 100%; font-family: var(--mono); font-weight: 600; font-size: .78rem; letter-spacing: .06em; cursor: pointer; margin-top: 14px; transition: opacity .2s; }
        .gs-leave-btn:hover { opacity: .85; }
        /* Admin "add a contact" row in group settings - input + Add button. */
        .gs-add-row { display: flex; gap: 8px; margin-top: 12px; }
        .gs-add-row input { flex: 1; min-width: 0; padding: 8px 10px; background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--sans); font-size: .85rem; outline: none; transition: border-color .2s; }
        .gs-add-row input:focus { border-color: var(--accent); }
        .gs-add-row button { flex-shrink: 0; padding: 8px 16px; background: var(--accent); color: #fff; border: none; border-radius: 6px; font-family: var(--mono); font-size: .78rem; font-weight: 600; cursor: pointer; transition: opacity .2s; }
        .gs-add-row button:hover { opacity: .9; }

        /* ── AVATAR CROP UI ── */
        .crop-window {
            width: 240px; height: 240px; border-radius: 50%; overflow: hidden;
            background: var(--surface2); border: 2px solid var(--accent); margin: 14px auto;
            position: relative; cursor: grab; user-select: none; touch-action: none;
        }
        .crop-window.dragging { cursor: grabbing; }
        .crop-window img { position: absolute; top: 0; left: 0; transform-origin: top left; pointer-events: none; }
        .crop-window.empty::before {
            content: 'Choose an image to crop';
            position: absolute; inset: 0; display: flex; align-items: center; justify-content: center;
            color: var(--muted); font-family: var(--mono); font-size: .75rem; text-align: center; padding: 0 18px;
        }
        .crop-controls { display: flex; align-items: center; gap: 10px; margin: 10px 4px 6px; }
        .crop-controls input[type=range] { flex: 1; accent-color: var(--accent); }
        .crop-controls label { font-family: var(--mono); font-size: .7rem; color: var(--text-dim); }
        .crop-file-btn { background: var(--surface2); border: 1px solid var(--border); color: var(--text); border-radius: 6px; padding: 8px; cursor: pointer; font-family: var(--mono); font-size: .75rem; text-align: center; transition: background .15s; }
        .crop-file-btn:hover { background: var(--surface); border-color: var(--accent); }

        /* ── REPLY / QUOTE ──
           When replying, a preview of the quoted message sits above the input.
           Inside a message bubble, the quoted text appears as an indented block above the new text. */
        .reply-preview { display: flex; align-items: flex-start; gap: 10px; padding: 8px 16px; background: var(--surface2); border-top: 1px solid var(--border); flex-shrink: 0; }
        .reply-preview-bar { width: 3px; align-self: stretch; background: var(--accent); border-radius: 2px; flex-shrink: 0; }
        .reply-preview-content { flex: 1; min-width: 0; }
        .reply-preview-author { font-family: var(--mono); font-size: .68rem; color: var(--accent); letter-spacing: .04em; }
        .reply-preview-text { font-size: .8rem; color: var(--text-dim); margin-top: 2px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
        .reply-preview-close { background: none; border: none; color: var(--muted); cursor: pointer; font-size: 1rem; padding: 4px 6px; line-height: 1; transition: color .15s; }
        .reply-preview-close:hover { color: var(--danger); }

        /* Inline quoted block inside a bubble.
           Clickable - scrolls to and highlights the original message. */
        .quoted-msg { display: block; border-left: 3px solid var(--accent); padding: 4px 10px; margin: -2px -2px 6px; background: rgba(91,138,240,.06); border-radius: 4px; cursor: pointer; font-size: .78rem; line-height: 1.35; transition: background .12s; }
        .quoted-msg:hover { background: rgba(91,138,240,.12); }
        .msg-bubble.self .quoted-msg { border-left-color: rgba(253,238,245,.45); background: rgba(255,255,255,.06); }
        .msg-bubble.self .quoted-msg:hover { background: rgba(255,255,255,.12); }
        .quoted-msg-author { font-family: var(--mono); font-size: .65rem; color: var(--accent); letter-spacing: .04em; margin-bottom: 2px; }
        .msg-bubble.self .quoted-msg-author { color: rgba(253,238,245,.7); }
        .quoted-msg-text { color: var(--text-dim); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; max-height: 2.7em; }
        .msg-bubble.self .quoted-msg-text { color: rgba(253,238,245,.75); }
        /* When the user clicks a quoted block, the target message briefly flashes so it's easy to find. */
        .msg-bubble.quote-flash { animation: quote-flash 1.4s ease-out; }
        @keyframes quote-flash { 0%, 30% { background: rgba(91,138,240,.35); } 100% { } }

        .picker-reply { font-size: 1.05rem; }
        .rp-quick .picker-reply:hover { background: rgba(91,138,240,.12); color: var(--accent); }

        /* ── TYPING INDICATOR ──
           Shown below the messages area when the other party is typing in the active conversation.
           Three dots bounce in sequence; the text reads "X is typing" for 1:1, or names for groups. */
        .typing-indicator { display: flex; align-items: center; gap: 8px; padding: 4px 18px 6px; font-family: var(--mono); font-size: .68rem; color: var(--text-dim); flex-shrink: 0; min-height: 18px; }
        .typing-dots { display: inline-flex; gap: 3px; }
        .typing-dots span { width: 5px; height: 5px; border-radius: 50%; background: var(--text-dim); animation: typing-dot 1.2s infinite; }
        .typing-dots span:nth-child(2) { animation-delay: .2s; }
        .typing-dots span:nth-child(3) { animation-delay: .4s; }
        @keyframes typing-dot { 0%, 60%, 100% { opacity: .3; transform: translateY(0); } 30% { opacity: 1; transform: translateY(-3px); } }

        /* ── MESSAGE SEARCH ── */
        .msg-search-btn { background: none; border: 1px solid var(--border); border-radius: 6px; color: var(--text-dim); font-size: .85rem; width: 32px; height: 32px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: background .15s, color .15s, border-color .15s; flex-shrink: 0; }
        .msg-search-btn:hover { background: var(--surface2); color: var(--accent); border-color: var(--accent); }
        .msg-search-btn.active { color: var(--accent); border-color: var(--accent); background: rgba(91,138,240,.1); }

        .msg-search-bar { display: flex; align-items: center; gap: 8px; padding: 6px 16px; background: var(--surface2); border-bottom: 1px solid var(--border); flex-shrink: 0; }
        .msg-search-bar input { flex: 1; background: var(--surface); border: 1px solid var(--border); border-radius: 6px; color: var(--text); font-family: var(--mono); font-size: .8rem; padding: 6px 10px; outline: none; transition: border-color .2s; }
        .msg-search-bar input:focus { border-color: var(--accent); }
        .msg-search-bar input::placeholder { color: var(--muted); }
        .msg-search-count { font-family: var(--mono); font-size: .68rem; color: var(--text-dim); white-space: nowrap; min-width: 60px; text-align: right; }
        .msg-search-close { background: none; border: none; color: var(--muted); cursor: pointer; font-size: .9rem; padding: 4px 6px; transition: color .15s; line-height: 1; }
        .msg-search-close:hover { color: var(--danger); }

        .msg-bubble.search-dim { opacity: 0.18; }
        mark.search-hit { background: #f0c030; color: #000; border-radius: 2px; padding: 0 1px; }

        /* ── ACTIVE CALL SIDEBAR INDICATOR ── */
        .contact-item.in-call { border-left: 3px solid var(--accent2); padding-left: 5px; background: rgba(62,207,142,.07); }
