/**
 * ChatNorris Styles v45
 * Mobile-first responsive design with proper Android/iOS keyboard support
 * v45: Mobile UI polish — modals, touch targets, settings/logout visibility, perf
 */

/* CSS Variables */
:root {
    --primary: #2563eb;
    --primary-dark: #1d4ed8;
    --primary-light: #3b82f6;
    --secondary: #64748b;
    --success: #22c55e;
    --warning: #f59e0b;
    --error: #ef4444;
    --bg: #0f172a;
    --bg-secondary: #1e293b;
    --bg-tertiary: #334155;
    --text: #f8fafc;
    --text-secondary: #94a3b8;
    /* Lightened from #64748b (which was 3.1:1 on --bg-secondary — below the
       WCAG AA 4.5:1 text minimum) to #9aa7b8. This clears AA on all three app
       surfaces: ~6.3:1 on --bg (#0f172a), ~5.2:1 on --bg-secondary (#1e293b),
       ~4.5:1 on --bg-tertiary/#334155 (message-other bubbles, offline notices).
       The old dark value is retained inline where it's decorative-only
       (scrollbar thumb, status backgrounds) so contrast only improved where
       muted text actually needs to be read. */
    --text-muted: #9aa7b8;
    --border: #475569;
    --message-own: #1e40af;
    --message-other: #334155;
    --radius: 12px;
    --radius-sm: 8px;
    --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
    --transition: 0.2s ease;
    /* Safe area fallbacks */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
    --safe-left: env(safe-area-inset-left, 0px);
    --safe-right: env(safe-area-inset-right, 0px);
}

/* Reset */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

/* Base - Cross-platform mobile support */
html {
    font-size: 16px;
    -webkit-text-size-adjust: 100%;
    -webkit-tap-highlight-color: transparent;
    height: 100%;
    /* NO overflow:hidden here - breaks Android keyboard resize with interactive-widget */
}

body {
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    -webkit-overflow-scrolling: touch;
    /* Prevent zooming on mobile */
    touch-action: pan-x pan-y;
    -ms-touch-action: pan-x pan-y;
}

/* iOS-specific: Use dvh when JS adds .ios-device class */
html.ios-device,
html.ios-device body {
    height: 100dvh;
    /* Prevent iOS Safari rubber-band over-scroll revealing bg */
    overflow: hidden;
}

a {
    color: var(--primary-light);
    text-decoration: none;
}

a:hover {
    text-decoration: underline;
}

/* Buttons */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.75rem 1.5rem;
    font-size: 1rem;
    font-weight: 500;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: background-color var(--transition), color var(--transition), transform var(--transition), opacity var(--transition);
    white-space: nowrap;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    user-select: none;
    -webkit-user-select: none;
}

.btn-primary {
    background: var(--primary);
    color: white;
}

.btn-primary:hover,
.btn-primary:active {
    background: var(--primary-dark);
}

.btn-primary:active {
    transform: scale(0.97);
}

.btn-secondary {
    background: var(--bg-tertiary);
    color: var(--text);
}

.btn-secondary:hover,
.btn-secondary:active {
    background: var(--border);
}

.btn-secondary:active {
    transform: scale(0.97);
}

.btn-danger {
    background: var(--error);
    color: white;
}

.btn-danger:hover {
    background: #dc2626;
}

.btn-icon {
    padding: 0.5rem;
    background: transparent;
    border-radius: 50%;
    min-width: 44px;
    min-height: 44px;
}

.btn-icon:hover,
.btn-icon:active {
    background: var(--bg-tertiary);
}

.btn-icon:active {
    transform: scale(0.92);
}

.btn:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Forms */
.form-group {
    margin-bottom: 1rem;
}

.form-label {
    display: block;
    margin-bottom: 0.5rem;
    font-weight: 500;
    color: var(--text-secondary);
}

.form-input {
    width: 100%;
    padding: 0.75rem 1rem;
    font-size: 16px; /* Prevents iOS zoom on focus */
    color: var(--text);
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    transition: border-color var(--transition);
    -webkit-appearance: none;
    appearance: none;
}

.form-input:focus {
    outline: none;
    border-color: var(--primary);
}

/* Keyboard focus gets a visible ring (pointer focus keeps just the border
   shift above). Without this, keyboard/switch-access users can't see which
   input is focused — the border-color change alone is too subtle and fails
   the WCAG focus-visible expectation. :focus-visible only triggers for
   keyboard/AT focus, so mouse/touch users don't see the ring. */
.form-input:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

.form-input::placeholder {
    color: var(--text-muted);
}

/* Password toggle */
.password-wrapper {
    position: relative;
}
.password-wrapper .form-input {
    padding-right: 2.75rem;
}
.toggle-password {
    position: absolute;
    right: 0.25rem;
    top: 50%;
    transform: translateY(-50%);
    background: none;
    border: none;
    cursor: pointer;
    color: var(--text-muted);
    padding: 0.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    min-height: 40px;
    -webkit-tap-highlight-color: transparent;
    border-radius: 50%;
    transition: color var(--transition), background var(--transition);
}
.toggle-password:hover {
    color: var(--text);
}
.toggle-password:active {
    background: rgba(148, 163, 184, 0.15);
}

/* Cards */
.card {
    background: var(--bg-secondary);
    border-radius: var(--radius);
    padding: 1.5rem;
    box-shadow: var(--shadow);
}

/* Auth Pages */
.auth-container {
    min-height: 100%;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 1.5rem;
    padding-top: calc(1.5rem + var(--safe-top));
    padding-bottom: calc(1.5rem + var(--safe-bottom));
    background: linear-gradient(135deg, var(--bg) 0%, var(--bg-secondary) 100%);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

/* Auth pages need body to allow scrolling (override chat-optimized overflow:hidden) */
body.auth-page {
    overflow: auto;
    overflow-x: hidden;
    height: auto;
    min-height: 100%;
    min-height: 100dvh;
}

.auth-card {
    width: 100%;
    max-width: 380px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 2rem 1.5rem;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

.auth-logo {
    text-align: center;
    margin-bottom: 2rem;
}

.auth-logo h1 {
    font-size: 2rem;
    font-weight: 700;
    background: linear-gradient(135deg, var(--text) 0%, var(--primary-light) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    margin-bottom: 0.5rem;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}

.auth-logo-icon {
    width: 2.25rem;
    height: 2.25rem;
    max-width: 2.25rem;
    max-height: 2.25rem;
    object-fit: cover;
    border-radius: 50%;
    -webkit-text-fill-color: initial;
    -webkit-background-clip: initial;
    background-clip: initial;
    background: none;
    flex-shrink: 0;
}

.auth-logo p {
    color: var(--text-muted);
    font-size: 0.9375rem;
}

.auth-form .form-group {
    margin-bottom: 1.25rem;
}

.auth-form .btn {
    width: 100%;
    margin-top: 0.5rem;
    padding: 0.875rem 1.5rem;
    font-weight: 600;
    white-space: normal;
    text-align: center;
}

.auth-footer {
    text-align: center;
    margin-top: 1.5rem;
    color: var(--text-muted);
    font-size: 0.9375rem;
}

.auth-footer a {
    font-weight: 500;
}

.auth-error {
    background: rgba(239, 68, 68, 0.1);
    border: 1px solid var(--error);
    color: var(--error);
    padding: 0.875rem 1rem;
    border-radius: var(--radius-sm);
    margin-bottom: 1.25rem;
    font-size: 0.9375rem;
}

/* ===================================
   Chat Layout - Height:100% for Android keyboard resize
   Uses interactive-widget=resizes-content in viewport meta
   =================================== */
.chat-container {
    display: flex;
    flex-direction: column;
    height: 100%;
    max-height: 100%;
    width: 100%;
    overflow: hidden;
    /* Account for safe areas on notched devices */
    padding-top: var(--safe-top);
    contain: layout style;
}

/* iOS-specific: Use dvh for proper keyboard handling */
html.ios-device .chat-container {
    height: 100dvh;
    max-height: 100dvh;
}

.chat-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0.75rem 1rem;
    background: rgba(30, 41, 59, 0.97);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    z-index: 100;
    will-change: transform;
}

.chat-header-info {
    flex: 1;
    min-width: 0;
}

.chat-header-info h1 {
    font-size: 1.125rem;
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.room-meta-line {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.chat-header-info .room-code {
    font-size: 0.75rem;
    color: var(--text-muted);
    font-family: monospace;
}

.room-expiry {
    font-size: 0.75rem;
    color: var(--warning);
    font-weight: 500;
    padding: 0.125rem 0.5rem;
    background: rgba(245, 158, 11, 0.15);
    border-radius: 4px;
}

.room-expiry.warning {
    color: var(--warning);
    background: rgba(245, 158, 11, 0.2);
}

.room-expiry.urgent {
    color: var(--error);
    background: rgba(239, 68, 68, 0.2);
    animation: pulse-urgent 1s infinite;
}

.room-expiry.expired {
    color: var(--error);
    background: rgba(239, 68, 68, 0.3);
}

@keyframes pulse-urgent {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.6; }
}

/* Chat header actions — quick buttons + kebab menu */
.chat-header-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
}

/* Toolbar icon buttons (participants, share, kebab) */
.toolbar-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    min-width: 38px;
    min-height: 38px;
    background: transparent;
    border: none;
    border-radius: 10px;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
    -webkit-tap-highlight-color: transparent;
    position: relative;
    flex-shrink: 0;
    box-sizing: border-box;
}

.toolbar-btn svg {
    width: 20px;
    height: 20px;
    min-width: 20px;
    min-height: 20px;
    flex-shrink: 0;
    pointer-events: none;
}

.toolbar-btn:hover {
    background: rgba(148, 163, 184, 0.15);
    color: var(--text);
}

.toolbar-btn:active {
    transform: scale(0.9);
    background: rgba(148, 163, 184, 0.2);
}

.toolbar-btn:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* Kebab (three-dot) button — hidden on desktop, visible on mobile */
.kebab-btn {
    display: none;
}

/* Kebab menu — desktop: inline flex row alongside quick buttons */
.kebab-menu {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* Kebab menu items — on desktop: icon-only toolbar buttons */
.kebab-item {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    min-width: 38px;
    min-height: 38px;
    background: transparent;
    border: none;
    border-radius: 10px;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease, transform 0.2s ease;
    -webkit-tap-highlight-color: transparent;
    flex-shrink: 0;
    box-sizing: border-box;
    font-size: 0.9375rem;
    font-weight: 500;
}

.kebab-item svg {
    width: 20px;
    height: 20px;
    min-width: 20px;
    min-height: 20px;
    flex-shrink: 0;
    pointer-events: none;
}

/* Hide text labels on desktop — icon only */
.kebab-item span {
    display: none;
}

.kebab-item:hover {
    background: rgba(148, 163, 184, 0.15);
    color: var(--text);
}

.kebab-item:active {
    transform: scale(0.92);
    background: rgba(148, 163, 184, 0.2);
}

/* Danger / Warning item variants */
.kebab-item-danger {
    color: #f87171;
}

.kebab-item-danger:hover {
    background: rgba(248, 113, 113, 0.15);
    color: #fca5a5;
}

.kebab-item-warning {
    color: #fbbf24;
}

.kebab-item-warning:hover {
    background: rgba(251, 191, 36, 0.15);
    color: #fcd34d;
}

/* Kebab divider — vertical on desktop */
.kebab-divider {
    width: 1px;
    height: 24px;
    background: linear-gradient(180deg, transparent 0%, var(--border) 20%, var(--border) 80%, transparent 100%);
    margin: 0 4px;
    opacity: 0.6;
}

/* Connection status — compact dot */
.connection-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    flex-shrink: 0;
    margin-left: 4px;
    transition: all 0.3s ease;
}

.connection-dot.connected {
    background: #34d399;
    box-shadow: 0 0 8px rgba(52, 211, 153, 0.6);
}

.connection-dot.disconnected {
    background: #f87171;
    box-shadow: 0 0 6px rgba(248, 113, 113, 0.5);
    animation: pulse-status 1.5s ease-in-out infinite;
}

.connection-dot.reconnecting {
    background: var(--warning);
    box-shadow: 0 0 4px var(--warning);
    animation: pulse-status 1s ease-in-out infinite;
}

@keyframes pulse-status {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.5; transform: scale(0.85); }
}

/* Main chat area - takes remaining space, can shrink with keyboard */
.chat-main {
    display: flex;
    flex: 1 1 auto;             /* Can grow AND shrink */
    min-height: 0;              /* Critical for flex children to shrink */
    overflow: hidden;
}

.chat-sidebar {
    display: none;
    width: 250px;
    background: var(--bg-secondary);
    border-right: 1px solid var(--border);
    flex-shrink: 0;
    flex-direction: column;
}

/* Mobile sidebar as overlay */
@media (max-width: 767px) {
    .chat-sidebar {
        position: fixed;
        top: 0;
        right: 0;
        bottom: 0;
        width: 280px;
        max-width: 85vw;
        z-index: 200;
        transform: translateX(100%);
        transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
        box-shadow: -4px 0 20px rgba(0, 0, 0, 0.3);
        border-right: none;
        border-left: 1px solid var(--border);
        padding-top: var(--safe-top);
        padding-bottom: var(--safe-bottom);
    }

    .chat-sidebar.show {
        display: flex;
        transform: translateX(0);
    }
}

/* Desktop sidebar toggle */
@media (min-width: 768px) {
    .chat-sidebar.show {
        display: flex;
    }

    .chat-sidebar.hidden {
        display: none !important;
    }
}

/* Chat content - messages + input, shrinks with keyboard */
.chat-content {
    flex: 1 1 auto;             /* Can grow AND shrink */
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;              /* Critical for proper flex behavior */
    overflow: hidden;
}

/* Messages Area - scrollable, shrinks when keyboard opens */
.messages-container {
    flex: 1 1 auto;             /* Can grow AND shrink */
    overflow-y: auto;
    overflow-x: hidden;
    padding: 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
}

/* Message bubbles - Modern chat style */
.message {
    max-width: 80%;
    padding: 0.625rem 0.875rem;
    border-radius: 18px;
    word-wrap: break-word;
    animation: messageAppear 0.2s ease-out;
    position: relative;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

.message.own {
    align-self: flex-end;
    background: linear-gradient(135deg, var(--primary) 0%, var(--message-own) 100%);
    border-bottom-right-radius: 6px;
    margin-left: 15%;
}

.message.other {
    align-self: flex-start;
    background: var(--message-other);
    border-bottom-left-radius: 6px;
    margin-right: 15%;
}

.message.system {
    align-self: center;
    background: rgba(100, 116, 139, 0.1);
    color: var(--text-muted);
    font-size: 0.8125rem;
    padding: 0.5rem 1rem;
    border-radius: 20px;
    max-width: 90%;
    text-align: center;
}

.message.pending,
.message.sending {
    opacity: 0.7;
}

.message.retrying {
    opacity: 0.7;
    border-left: 3px solid var(--warning);
}

.message.failed {
    opacity: 0.9;
    border-left: 3px solid var(--error);
}

.message.sent {
    opacity: 1;
}

.message-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
    margin-top: 0.25rem;
}

.message-status {
    font-size: 0.625rem;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    margin-left: 4px;
}

.message-status .tick {
    width: 16px;
    height: 16px;
    color: var(--text-muted);
}

.message-status .tick.double {
    width: 20px;
}

/* Single tick - sent */
.message-status.ticks {
    color: var(--text-muted);
}

/* Offline-recipients inline notice (recipient not in room at send time).
   Sits under the message bubble with a small "tap to resend" button. */
.offline-recipients-notice {
    margin-top: 0.375rem;
    padding: 0.375rem 0.625rem;
    background: rgba(245, 158, 11, 0.08);
    border-left: 2px solid rgba(245, 158, 11, 0.5);
    border-radius: 4px;
    font-size: 0.75rem;
    color: var(--text-muted);
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
}
.offline-recipients-notice .offline-text {
    flex: 1;
    min-width: 0;
}
.offline-recipients-notice .offline-resend-btn {
    background: rgba(245, 158, 11, 0.18);
    color: var(--text);
    border: none;
    border-radius: 4px;
    padding: 0.25rem 0.625rem;
    font-size: 0.75rem;
    cursor: pointer;
    white-space: nowrap;
    transition: background 0.15s ease;
}
.offline-recipients-notice .offline-resend-btn:hover:not(:disabled) {
    background: rgba(245, 158, 11, 0.3);
}
.offline-recipients-notice .offline-resend-btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Double tick - delivered */
.message-status.ticks.delivered {
    color: var(--text-muted);
}

/* Double tick - read (blue) */
.message-status.ticks.read {
    color: #3b82f6;
}

.message-status.ticks.read .tick {
    color: #3b82f6;
}

/* Partial read - some but not all have read */
.message-status.ticks.partial-read {
    color: #60a5fa;
}

.message-status.ticks.partial-read .tick {
    color: #60a5fa;
}

/* Sending state - clock/pending */
.message-status.sending {
    opacity: 0.5;
}

.message-status.sending .tick {
    color: var(--text-muted);
    animation: pulse-sending 1s infinite;
}

@keyframes pulse-sending {
    0%, 100% { opacity: 0.5; }
    50% { opacity: 1; }
}

/* Failed state */
.message-status.failed {
    color: var(--error);
    font-weight: bold;
    font-size: 0.75rem;
}

.message.retrying .message-status {
    color: var(--warning);
}

.message.failed .message-status {
    color: var(--error);
}

.message .sender {
    display: block;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--primary-light);
    margin-bottom: 0.25rem;
}

.message p {
    margin: 0;
    white-space: pre-wrap;
    word-break: break-word;
}

/* Clickable links in messages */
.message-link {
    color: #4fc3f7;
    text-decoration: underline;
    word-break: break-all;
}

.message-link:hover {
    color: #81d4fa;
    text-decoration: underline;
}

.message.own .message-link {
    color: #e3f2fd;
}

.message.own .message-link:hover {
    color: #ffffff;
}

.message .time {
    display: block;
    font-size: 0.625rem;
    color: var(--text-muted);
    text-align: right;
    margin-top: 0.25rem;
}

@keyframes messageAppear {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

/* ===================================
   Message Input - Modern Chat Input Design
   With dvh + interactive-widget, stays above keyboard on iOS/Android
   =================================== */
.message-input-container {
    display: flex;
    align-items: flex-end;
    gap: 0.75rem;
    padding: 0.75rem 1rem;
    /* Add safe area padding for devices with home indicators */
    padding-bottom: calc(0.75rem + env(safe-area-inset-bottom, 0px));
    background: var(--bg-secondary);
    border-top: 1px solid var(--border);
    flex-shrink: 0;
    z-index: 50;
    /* Ensure input stays above iOS keyboard */
    -webkit-transform: translateZ(0);
    transform: translateZ(0);
}

/* Attach file button */
.input-action-btn {
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    color: var(--text-muted);
    background: transparent;
    border-radius: 50%;
    flex-shrink: 0;
    transition: all 0.2s ease;
}

/* Ensure taps/clicks target the button, not its SVG child */
.input-action-btn svg {
    pointer-events: none;
}

.input-action-btn:hover,
.input-action-btn:active {
    color: var(--text);
    background: var(--bg-tertiary);
}

.input-action-btn:active {
    transform: scale(0.92);
}

.input-action-btn.active {
    color: var(--primary);
    background: rgba(99, 102, 241, 0.15);
}

/* Attachment wrapper for menu positioning */
.attachment-wrapper {
    position: relative;
}

/* Attachment Menu — uses position:fixed to escape overflow:hidden on .chat-content */
.attachment-menu {
    position: fixed;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 8px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 180px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.2);
    opacity: 0;
    visibility: hidden;
    transform: translateY(10px) scale(0.95);
    transform-origin: bottom left;
    transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0.2s cubic-bezier(0.4, 0, 0.2, 1),
                transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 1000;
}

.attachment-menu.show {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
}

.attachment-option {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
    background: transparent;
    border: none;
    border-radius: 12px;
    color: var(--text);
    font-size: 0.9375rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s ease;
    -webkit-tap-highlight-color: transparent;
    text-align: left;
    width: 100%;
}

.attachment-option svg {
    width: 24px;
    height: 24px;
    flex-shrink: 0;
    color: var(--text-secondary);
    transition: color 0.15s ease;
}

.attachment-option:hover {
    background: var(--bg-tertiary);
}

.attachment-option:hover svg {
    color: var(--primary);
}

.attachment-option:active {
    transform: scale(0.98);
    background: var(--bg);
}

.attachment-option span {
    flex: 1;
}

/* Attachment menu arrow/pointer */
.attachment-menu::before {
    content: '';
    position: absolute;
    bottom: -6px;
    left: 18px;
    width: 12px;
    height: 12px;
    background: var(--bg-secondary);
    border-right: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    transform: rotate(45deg);
}

/* Text input wrapper */
.message-input-wrapper {
    flex: 1;
    display: flex;
    align-items: flex-end;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 24px;
    padding: 0.625rem 1rem;
    min-width: 0;
    min-height: 48px;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.message-input-wrapper:focus-within {
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.15);
}

#message-input {
    flex: 1;
    background: transparent;
    border: none;
    color: var(--text);
    font-size: 16px; /* Prevents iOS zoom on focus */
    resize: none;
    max-height: 120px;
    min-height: 24px;
    line-height: 1.5;
    -webkit-appearance: none;
    appearance: none;
    min-width: 0;
    width: 100%;
    font-family: inherit;
}

#message-input:focus {
    outline: none;
}

#message-input::placeholder {
    color: var(--text-muted);
}

/* Send button */
.send-btn {
    min-width: 48px;
    min-height: 48px;
    border-radius: 50%;
    padding: 0;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--primary);
    transition: all 0.2s ease;
    box-shadow: 0 2px 8px rgba(37, 99, 235, 0.3);
}

.send-btn:hover {
    background: var(--primary-dark);
    box-shadow: 0 4px 12px rgba(37, 99, 235, 0.4);
    transform: translateY(-1px);
}

.send-btn:active {
    transform: scale(0.92) translateY(0);
    box-shadow: 0 1px 4px rgba(37, 99, 235, 0.3);
}

.send-btn svg {
    margin-left: 2px; /* Visual centering for send icon */
}

/* ===================================
   Voice Recording UI
   =================================== */
.voice-recording-overlay {
    display: none;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: linear-gradient(to top, var(--bg-secondary) 0%, rgba(30, 41, 59, 0.98) 100%);
    padding: 1.5rem 1rem;
    padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
    z-index: 100;
    border-top: 1px solid var(--border);
    animation: slideUp 0.2s ease;
}

.voice-recording-overlay.show {
    display: block;
}

@keyframes slideUp {
    from {
        transform: translateY(100%);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

.voice-recording-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
    max-width: 300px;
    margin: 0 auto;
}

.voice-recording-indicator {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px;
    height: 64px;
    color: var(--error);
}

.voice-recording-pulse {
    position: absolute;
    width: 100%;
    height: 100%;
    background: var(--error);
    border-radius: 50%;
    opacity: 0.3;
    animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
    0%, 100% {
        transform: scale(1);
        opacity: 0.3;
    }
    50% {
        transform: scale(1.3);
        opacity: 0.1;
    }
}

.voice-recording-time {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.voice-recording-actions {
    display: flex;
    gap: 1.5rem;
    margin-top: 0.5rem;
}

.voice-action-btn {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.voice-action-btn:first-child {
    background: var(--bg-tertiary);
    color: var(--text-muted);
}

.voice-action-btn:first-child:hover {
    background: var(--error);
    color: white;
}

.voice-action-btn.btn-primary {
    background: var(--success);
    box-shadow: 0 2px 8px rgba(34, 197, 94, 0.3);
}

.voice-action-btn.btn-primary:hover {
    background: #16a34a;
}

/* Voice message in chat */
.voice-message {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem 0.75rem;
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius);
    min-width: 200px;
    max-width: 280px;
}

.voice-message-play {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--primary);
    color: white;
    border: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    transition: all 0.2s ease;
}

.voice-message-play:hover {
    background: var(--primary-dark);
    transform: scale(1.05);
}

.voice-message-play.playing {
    background: var(--error);
}

.voice-message-info {
    flex: 1;
    min-width: 0;
}

.voice-message-waveform {
    height: 24px;
    display: flex;
    align-items: center;
    gap: 2px;
    margin-bottom: 4px;
}

.voice-message-waveform span {
    width: 3px;
    background: var(--primary-light);
    border-radius: 2px;
    opacity: 0.5;
}

.voice-message-waveform.playing span {
    animation: waveform 0.5s ease-in-out infinite alternate;
}

.voice-message-waveform span:nth-child(1) { height: 8px; animation-delay: 0s; }
.voice-message-waveform span:nth-child(2) { height: 16px; animation-delay: 0.1s; }
.voice-message-waveform span:nth-child(3) { height: 12px; animation-delay: 0.2s; }
.voice-message-waveform span:nth-child(4) { height: 20px; animation-delay: 0.3s; }
.voice-message-waveform span:nth-child(5) { height: 14px; animation-delay: 0.4s; }
.voice-message-waveform span:nth-child(6) { height: 18px; animation-delay: 0.5s; }
.voice-message-waveform span:nth-child(7) { height: 10px; animation-delay: 0.6s; }
.voice-message-waveform span:nth-child(8) { height: 22px; animation-delay: 0.7s; }
.voice-message-waveform span:nth-child(9) { height: 16px; animation-delay: 0.8s; }
.voice-message-waveform span:nth-child(10) { height: 12px; animation-delay: 0.9s; }

@keyframes waveform {
    from { opacity: 0.3; }
    to { opacity: 1; }
}

.voice-message-duration {
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* File Messages */
.file-message {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.5rem;
    background: rgba(255, 255, 255, 0.05);
    border-radius: var(--radius);
    min-width: 200px;
}

.file-icon {
    font-size: 1.75rem;
    line-height: 1;
    flex-shrink: 0;
}

.file-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.file-name {
    font-size: 0.875rem;
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-size {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.save-file-btn {
    min-width: 60px;
    min-height: 36px;
    padding: 0.5rem 1rem;
    font-size: 0.8125rem;
    font-weight: 500;
    background: rgba(255, 255, 255, 0.15);
    border: none;
    border-radius: var(--radius-sm);
    color: inherit;
    cursor: pointer;
    transition: background 0.2s, transform 0.1s;
    -webkit-tap-highlight-color: transparent;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.save-file-btn:hover {
    background: rgba(255, 255, 255, 0.25);
}

.save-file-btn:active {
    transform: scale(0.95);
}

/* Mobile: Ensure touch-friendly size */
@media (max-width: 767px) {
    .save-file-btn {
        min-width: 64px;
        min-height: 40px;
        padding: 0.5rem 1rem;
        font-size: 0.875rem;
    }
}

/* Touch devices: Larger touch targets */
@media (hover: none) and (pointer: coarse) {
    .save-file-btn {
        min-height: 44px;
        padding: 0.625rem 1.25rem;
    }
}

/* Image Messages */
.image-message {
    position: relative;
    max-width: 300px;
    border-radius: var(--radius);
    overflow: hidden;
}

.chat-image {
    display: block;
    width: 100%;
    max-height: 300px;
    object-fit: cover;
    cursor: pointer;
    border-radius: var(--radius);
    transition: transform 0.2s ease;
}

.chat-image:hover {
    transform: scale(1.02);
}

.chat-image:active {
    transform: scale(0.98);
}

.image-caption,
.video-caption,
.audio-caption {
    margin-top: 0.25rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

/* Video Messages */
.video-message {
    position: relative;
    max-width: 320px;
    border-radius: var(--radius);
    overflow: hidden;
}

.chat-video {
    display: block;
    width: 100%;
    max-height: 240px;
    background: #000;
    border-radius: var(--radius);
}

/* Audio Messages */
.audio-message {
    min-width: 250px;
    max-width: 320px;
}

.chat-audio {
    width: 100%;
    height: 40px;
    border-radius: var(--radius-sm);
}

.audio-info {
    font-size: 0.75rem;
    color: var(--text-muted);
    margin-top: 0.25rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.media-actions {
    display: flex;
    justify-content: flex-end;
    margin-top: 0.5rem;
    gap: 0.5rem;
}

/* Sidebar Backdrop (Mobile) */
.sidebar-backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 199;
    opacity: 0;
    transition: opacity 0.3s ease;
}

.sidebar-backdrop.show {
    display: block;
    opacity: 1;
}

/* Participants */
.participants-header {
    padding: 1rem;
    border-bottom: 1px solid var(--border);
}

.participants-header h2 {
    font-size: 0.875rem;
    font-weight: 600;
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

.participants-list {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem;
}

.participant {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    padding: 0.75rem;
    border-radius: var(--radius-sm);
}

.participant:hover {
    background: var(--bg-tertiary);
}

.participant .status-dot {
    width: 8px;
    height: 8px;
    background: var(--text-muted);
    border-radius: 50%;
    transition: background-color 0.3s ease;
}

.participant.online .status-dot {
    background: var(--success);
}

.participant.offline .status-dot {
    background: var(--text-muted);
}

.participant .name {
    flex: 1;
    min-width: 0;
    font-weight: 500;
    /* Truncate long spaceless usernames with an ellipsis instead of wrapping
       and misaligning the row (matches .room-name / chat-header behavior). */
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.participant .you {
    font-size: 0.75rem;
    color: var(--text-muted);
}

.participant.self {
    background: rgba(37, 99, 235, 0.1);
}

/* Participant info wrapper */
.participant .participant-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

/* Poke button */
.participant .poke-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    transition: all 0.2s ease;
    flex-shrink: 0;
    opacity: 0.6;
}

.participant .poke-btn:hover {
    background: var(--primary);
    color: white;
    opacity: 1;
    transform: scale(1.05);
}

.participant .poke-btn:active {
    transform: scale(0.95);
}

.participant .poke-btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
    transform: none;
}

/* Poking animation */
.participant .poke-btn.poking {
    animation: poke-pulse 0.5s ease-in-out infinite;
}

@keyframes poke-pulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.1); }
}

/* Poked state - brief success feedback */
.participant .poke-btn.poked {
    background: var(--success);
    color: white;
    opacity: 1;
}

.participant .poke-btn.poked svg {
    animation: poke-ring 0.5s ease-out;
}

@keyframes poke-ring {
    0% { transform: rotate(0deg); }
    25% { transform: rotate(-15deg); }
    50% { transform: rotate(15deg); }
    75% { transform: rotate(-10deg); }
    100% { transform: rotate(0deg); }
}

/* Show poke button more prominently for offline users */
.participant.offline .poke-btn {
    opacity: 0.8;
    color: var(--warning);
}

.participant.offline .poke-btn:hover {
    background: var(--warning);
    color: white;
    opacity: 1;
}

/* Room Selection */
.rooms-container {
    /* Room-list scroll architecture — mirrors the WORKING in-room chat view
       (.chat-container + .messages-container), which scrolls fine on Android.
       Key idea: the OUTER container is a FIXED-height, NON-scrolling flex
       column (overflow:hidden). The header stays pinned; the LIST child
       (.rooms-list) is the actual scroll region.

       The previous attempt put overflow-y:auto on THIS container with the
       list as a flex:1 child. That failed on Android Chrome because a flex
       child defaults to min-height:auto and refuses to shrink below its
       content — so the list expanded past the container and the container's
       own scroll never engaged reliably. Delegating the scroll to the child
       (with min-height:0 on that child) is the pattern that actually works. */
    height: 100vh;          /* fallback for browsers without dvh */
    height: 100dvh;         /* preferred: excludes dynamic browser UI */
    max-height: 100vh;
    max-height: 100dvh;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 1rem;
    padding-top: calc(1rem + var(--safe-top));
    /* No safe-bottom padding on the CONTAINER — because it has overflow:hidden,
       any bottom padding here would clip the scrollable list ABOVE the nav bar.
       The bottom clearance for the Android nav bar lives on .rooms-list instead
       (its scrollable content padding), so the last room card can scroll fully
       into view above the system bar. */
    padding-bottom: 0;
    padding-left: calc(1rem + var(--safe-left));
    padding-right: calc(1rem + var(--safe-right));
    overflow: hidden;       /* outer never scrolls; the list child does */
}

/* iOS rooms page: moved to iOS-Specific Fixes section at bottom */

.rooms-header {
    display: flex;
    flex-direction: column;
    gap: 1rem;
    margin-bottom: 1.5rem;
}

.rooms-header-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
    min-width: 0;
}

.rooms-header h1 {
    font-size: 1.75rem;
    font-weight: 700;
    background: linear-gradient(135deg, var(--text) 0%, var(--primary-light) 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.rooms-header-icons {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex-shrink: 0;
}

.rooms-header-icons .btn-icon {
    color: var(--text-secondary);
    border-radius: 10px;
}

/* Neutral like its siblings — the shield glyph carries the meaning,
   not the link color the <a> would otherwise inherit */
#admin-portal-link {
    color: var(--text-secondary);
}

#invite-btn {
    color: var(--success);
}

#logout-btn {
    color: var(--error);
}

.rooms-actions {
    display: flex;
    gap: 0.5rem;
    flex-wrap: wrap;
}

/* Primary action buttons in header */
.rooms-actions .btn-primary,
.rooms-actions .btn-secondary {
    flex: 1;
    min-width: 0;
    padding: 0.875rem 1rem;
    font-weight: 600;
    white-space: normal;
    text-align: center;
}

.rooms-list {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    /* flex: 1 1 auto + min-height:0 is the combination that makes a flex
       child actually shrink and become its own scroll container. Without
       min-height:0 the child stays at content height and overflows the
       parent instead of scrolling — that was the Android room-list bug. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-y: contain;
    /* Bottom clearance so the LAST room card can scroll fully into view above
       the Android system nav bar (home / back / recent-apps).
       max() guarantees a real gap even when env(safe-area-inset-bottom)
       reports 0px — which happens on Android devices using 3-button
       navigation, or where Chrome doesn't populate the inset. 1rem base +
       whatever the safe-area inset is, but never less than 4.5rem total
       (~72px) which comfortably clears both gesture-pill and 3-button bars. */
    padding-bottom: max(4.5rem, calc(1rem + var(--safe-bottom)));
}

.room-card {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1rem 1.25rem;
    background: var(--bg-secondary);
    border: 1px solid transparent;
    border-radius: var(--radius);
    cursor: pointer;
    transition: all var(--transition);
}

.room-card:hover {
    transform: translateY(-2px);
    border-color: var(--border);
    box-shadow: var(--shadow);
}

.room-card:active {
    transform: translateY(0);
}

/* Room card avatar/icon */
.room-avatar {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: linear-gradient(135deg, var(--primary) 0%, var(--primary-dark) 100%);
    display: flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    color: white;
    font-weight: 600;
    font-size: 1.125rem;
}

.room-info {
    flex: 1;
    min-width: 0;
}

.room-name {
    font-weight: 600;
    font-size: 1rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    margin-bottom: 0.25rem;
}

.room-meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    font-size: 0.75rem;
    color: var(--text-muted);
}

.room-meta-item {
    display: flex;
    align-items: center;
    gap: 0.25rem;
}

.room-meta-item svg {
    width: 14px;
    height: 14px;
    opacity: 0.7;
}

.room-card-badge {
    padding: 0.25rem 0.5rem;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-radius: 4px;
    background: rgba(245, 158, 11, 0.15);
    color: var(--warning);
}

.room-card-badge.password {
    background: rgba(139, 92, 246, 0.15);
    color: #a78bfa;
}

.dm-badge {
    padding: 0.125rem 0.5rem;
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-radius: 4px;
    background: rgba(37, 99, 235, 0.15);
    color: var(--primary);
}

.room-arrow {
    color: var(--text-muted);
    transition: transform var(--transition);
}

.room-card:hover .room-arrow {
    transform: translateX(4px);
    color: var(--primary-light);
}

.empty-state {
    text-align: center;
    padding: 4rem 1.5rem;
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
}

.empty-state h2 {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: var(--text);
}

.empty-state p {
    color: var(--text-muted);
    max-width: 280px;
}

/* Modals */
.modal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.7);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    padding-top: calc(1rem + var(--safe-top));
    padding-bottom: calc(1rem + var(--safe-bottom));
    z-index: 1000;
    opacity: 0;
    visibility: hidden;
    transition: all var(--transition);
}

.modal-overlay.show {
    opacity: 1;
    visibility: visible;
}

.modal {
    width: 100%;
    max-width: 400px;
    max-height: calc(100vh - 2rem - var(--safe-top) - var(--safe-bottom));
    max-height: calc(100dvh - 2rem - var(--safe-top) - var(--safe-bottom));
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 1.5rem;
    transform: translateY(20px) scale(0.95);
    transition: transform var(--transition);
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.4);
}

.modal-overlay.show .modal {
    transform: translateY(0) scale(1);
}

.modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 1.5rem;
}

.modal-header h2 {
    font-size: 1.25rem;
    font-weight: 600;
}

.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.5rem;
    cursor: pointer;
    padding: 0.25rem;
    border-radius: 50%;
    /* 44px tap target (was 36px). The × glyph stays centered via flex. */
    width: 44px;
    height: 44px;
    min-width: 44px;
    min-height: 44px;
    display: flex;
    -webkit-tap-highlight-color: transparent;
    align-items: center;
    justify-content: center;
    transition: all var(--transition);
}

.modal-close:hover {
    background: var(--bg-tertiary);
    color: var(--text);
}

.modal-footer {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    margin-top: 1.5rem;
}

.modal-footer .btn {
    flex: 1;
    min-width: 0;
    min-height: 44px;
    white-space: normal;
    text-align: center;
}

/* Notifications */
#notifications {
    position: fixed;
    top: calc(1rem + var(--safe-top));
    left: 1rem;
    right: 1rem;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    pointer-events: none;
}

.notification {
    padding: 0.875rem 1.25rem;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
    animation: slideDown 0.3s ease;
    max-width: 400px;
    width: 100%;
    pointer-events: auto;
    border: 1px solid var(--border);
    font-weight: 500;
}

.notification.success {
    border-color: var(--success);
    background: linear-gradient(135deg, rgba(34, 197, 94, 0.15) 0%, var(--bg-secondary) 100%);
}

.notification.error {
    border-color: var(--error);
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.15) 0%, var(--bg-secondary) 100%);
}

.notification.warning {
    border-color: var(--warning);
    background: linear-gradient(135deg, rgba(245, 158, 11, 0.15) 0%, var(--bg-secondary) 100%);
}

.notification.info {
    border-color: var(--primary);
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.15) 0%, var(--bg-secondary) 100%);
}

.notification.fade-out {
    animation: fadeOut 0.3s ease forwards;
}

@keyframes slideDown {
    from {
        transform: translateY(-20px);
        opacity: 0;
    }
    to {
        transform: translateY(0);
        opacity: 1;
    }
}

@keyframes fadeOut {
    to {
        transform: translateY(-20px);
        opacity: 0;
    }
}

/* Notification Permission Banner */
.notification-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.75rem 1rem;
    background: linear-gradient(135deg, rgba(37, 99, 235, 0.2) 0%, rgba(59, 130, 246, 0.1) 100%);
    border-bottom: 1px solid var(--primary);
    animation: slideDown 0.3s ease;
    flex-wrap: wrap;
}

.notification-banner-content {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex: 1;
    min-width: 0;
}

.notification-banner-icon {
    font-size: 1.25rem;
    flex-shrink: 0;
}

.notification-banner-text {
    font-size: 0.875rem;
    color: var(--text);
}

.notification-banner-actions {
    display: flex;
    gap: 0.5rem;
    flex-shrink: 0;
}

.btn-small {
    padding: 0.375rem 0.75rem;
    font-size: 0.75rem;
}

@media (max-width: 480px) {
    .notification-banner {
        flex-direction: column;
        align-items: stretch;
        gap: 0.75rem;
    }

    .notification-banner-actions {
        justify-content: flex-end;
    }
}

/* Connection Status - see .connection-dot in header */

/* Loading Spinner */
.spinner {
    width: 24px;
    height: 24px;
    border: 2px solid var(--border);
    border-top-color: var(--primary);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
    margin: 0 auto;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

/* Utilities */
.hidden {
    display: none !important;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}

/* PWA Install Button */
#install-btn {
    display: none;
    position: fixed;
    bottom: calc(1rem + var(--safe-bottom));
    right: 1rem;
    z-index: 100;
}

/* PWA Install Banner */
.install-banner {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    background: linear-gradient(135deg, rgba(37,99,235,0.12), rgba(37,99,235,0.06));
    border: 1px solid rgba(37,99,235,0.25);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    margin-top: 1rem;
    max-width: 380px;
    width: 100%;
    box-sizing: border-box;
    animation: installSlideUp 0.4s ease-out;
}

@keyframes installSlideUp {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
}

.install-banner-icon {
    flex-shrink: 0;
    color: var(--primary);
    display: flex;
    align-items: center;
}

.install-banner-text {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}

.install-banner-text strong {
    font-size: 0.8125rem;
    color: var(--text);
    line-height: 1.2;
}

.install-banner-text span {
    font-size: 0.6875rem;
    color: var(--text-muted);
    line-height: 1.2;
}

.install-banner .btn-sm {
    flex-shrink: 0;
    padding: 0.375rem 0.875rem;
    font-size: 0.75rem;
    min-height: 32px;
}

.install-banner-close {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 1.25rem;
    cursor: pointer;
    padding: 0.25rem;
    line-height: 1;
    opacity: 0.6;
    transition: opacity var(--transition);
}

.install-banner-close:hover {
    opacity: 1;
}

/* Scrollbar Styling */
::-webkit-scrollbar {
    width: 6px;
}

::-webkit-scrollbar-track {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
    background: var(--text-muted);
}

/* Focus Visible for Accessibility */
:focus-visible {
    outline: 2px solid var(--primary);
    outline-offset: 2px;
}

/* ===================================
   Media Viewer (Fullscreen Lightbox)
   =================================== */
.media-viewer {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 1000;
}

.media-viewer.show {
    display: flex;
    align-items: center;
    justify-content: center;
}

.media-viewer-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.95);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
}

.media-viewer-close {
    position: absolute;
    top: calc(1rem + var(--safe-top));
    right: calc(1rem + var(--safe-right));
    z-index: 1001;
    background: rgba(255, 255, 255, 0.1);
    border: none;
    border-radius: 50%;
    padding: 0.75rem;
    cursor: pointer;
    color: white;
    transition: background 0.2s;
    min-width: 48px;
    min-height: 48px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.media-viewer-close:hover {
    background: rgba(255, 255, 255, 0.2);
}

.media-viewer-content {
    position: relative;
    z-index: 1001;
    /* Sized, not shrink-to-fit. The zoom code measures how far the image
       overflows this box to decide how far it may be panned; a box that hugs
       the image would always compute zero overflow and panning would be dead. */
    width: 95vw;
    height: 95vh;
    height: 95dvh;  /* dvh excludes Android's dynamic browser UI so media isn't clipped */
    display: flex;
    align-items: center;
    justify-content: center;
    /* Zoomed-in pixels stay inside the frame instead of spilling over the
       backdrop and the close button. */
    overflow: hidden;
}

/*
 * Full-screen photo. Rendered directly in the page rather than inside the
 * sandboxed iframe used for video — an <img> cannot execute script whatever the
 * blob holds (SVG scripting is disabled in image context, and isPreviewable()
 * excludes SVG regardless), so the sandbox bought nothing here while making the
 * image tiny, soft and impossible to zoom.
 */
.media-viewer-image {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    /* We implement pinch/pan ourselves; without this the WebView would also
       scroll-and-zoom the page underneath and fight every gesture. */
    touch-action: none;
    transform-origin: center center;
    will-change: transform;
    user-select: none;
    -webkit-user-select: none;
    -webkit-user-drag: none;
    cursor: zoom-in;
    /* No transition: a transform tween makes pinch feel laggy and rubbery,
       because the image is always chasing the fingers rather than tracking them. */
}

.media-viewer-image.zoomed {
    cursor: grab;
}

.media-viewer-image.zoomed:active {
    cursor: grabbing;
}

.media-viewer-image {
    max-width: 95vw;
    max-height: 90vh;
    max-height: 90dvh;
    object-fit: contain;
    border-radius: var(--radius);
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}

.media-viewer-video {
    max-width: 95vw;
    max-height: 90vh;
    max-height: 90dvh;
    border-radius: var(--radius);
    background: #000;
}

/* ===================================
   Desktop Styles (768px+)
   =================================== */
@media (min-width: 768px) {
    .chat-sidebar {
        display: flex;
    }

    .chat-sidebar.hidden {
        display: none;
    }

    .message {
        max-width: 60%;
    }

    .rooms-container {
        max-width: 600px;
        margin: 0 auto;
        padding: 2rem 1.5rem;
    }

    .rooms-header {
        flex-direction: row;
        align-items: center;
        justify-content: space-between;
        flex-wrap: wrap;
        row-gap: 0.75rem;
    }

    .rooms-header-top {
        flex: 0 1 auto;
        min-width: 0;
    }

    .rooms-actions {
        flex: none;
        width: auto;
    }

    .rooms-actions .btn-primary,
    .rooms-actions .btn-secondary {
        flex: none;
        min-width: 120px;
    }

    .room-card {
        padding: 1.25rem 1.5rem;
    }

    .room-avatar {
        width: 52px;
        height: 52px;
        font-size: 1.25rem;
    }

    .auth-card {
        padding: 2rem;
    }
}

@media (min-width: 1024px) {
    .chat-sidebar {
        width: 300px;
    }

    .message {
        max-width: 50%;
    }

    .rooms-container {
        max-width: 700px;
    }
}

/* ===================================
   Mobile Styles (767px and below)
   =================================== */
@media (max-width: 767px) {
    /* Prevent text selection on interactive elements */
    .btn, .emoji, .room-card, .participant {
        -webkit-user-select: none;
        user-select: none;
    }

    /* Mobile: show kebab button, hide inline menu */
    .kebab-btn {
        display: flex;
    }

    /* Kebab dropdown — fixed overlay positioned via JS */
    .kebab-menu {
        display: none;
        position: fixed;
        flex-direction: column;
        background: var(--bg-secondary);
        border: 1px solid var(--border);
        border-radius: 14px;
        padding: 6px;
        min-width: 220px;
        max-width: calc(100vw - 16px);
        /* Cap height + scroll so a tall menu can't clip its last item off-screen
           on Android (previously only iOS had this bound). The JS positioner
           becomes a hint rather than the sole guard. */
        max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 60px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.35), 0 2px 8px rgba(0, 0, 0, 0.2);
        z-index: 1000;
        gap: 2px;
    }

    .kebab-menu.show {
        display: flex;
    }

    /* Kebab items in dropdown — full row with icon + text */
    .kebab-item {
        width: 100%;
        min-width: unset;
        min-height: 44px;
        height: auto;
        padding: 10px 16px;
        gap: 12px;
        border-radius: 10px;
        justify-content: flex-start;
        color: var(--text);
    }

    .kebab-item span {
        display: inline;
    }

    .kebab-item:active {
        background: rgba(148, 163, 184, 0.15);
    }

    .kebab-item-danger {
        color: #f87171;
    }

    .kebab-item-warning {
        color: #fbbf24;
    }

    /* Kebab divider — horizontal in dropdown */
    .kebab-divider {
        width: 100%;
        height: 1px;
        margin: 4px 0;
        background: var(--border);
        opacity: 0.5;
    }

    /* Compact header on mobile */
    .chat-header {
        padding: 0.5rem 0.5rem;
        gap: 0.5rem;
    }

    .chat-header-info {
        flex: 1;
        min-width: 0;
        overflow: hidden;
    }

    .chat-header-info h1 {
        font-size: 1rem;
    }

    .toolbar-btn {
        /* 44px min tap target (was 36px) — WCAG 2.5.5 / comfortable phone tap.
           The 20px SVG stays centered via the base rule's flex centering. */
        width: 44px;
        height: 44px;
        min-width: 44px;
        min-height: 44px;
    }

    /* Room list mobile optimizations */
    .rooms-header {
        gap: 0.75rem;
        margin-bottom: 1rem;
    }

    .rooms-header h1 {
        font-size: 1.5rem;
    }

    .rooms-header-icons .btn-icon {
        min-width: 40px;
        min-height: 40px;
        width: 40px;
        height: 40px;
        padding: 0.375rem;
    }

    .rooms-header-icons .btn-icon svg {
        width: 20px;
        height: 20px;
    }

    .rooms-header-icons {
        gap: 2px;
    }

    .rooms-actions .btn-primary,
    .rooms-actions .btn-secondary {
        padding: 0.75rem 1rem;
        font-size: 0.9375rem;
    }

    /* Optimize room cards for touch */
    .room-card {
        min-height: 68px;
        padding: 0.875rem 1rem;
        gap: 0.75rem;
    }

    .room-avatar {
        width: 44px;
        height: 44px;
        font-size: 1rem;
    }

    .room-name {
        font-size: 0.9375rem;
    }

    .room-meta {
        font-size: 0.6875rem;
        gap: 0.5rem;
    }

    /* Full-width modals — mobile-optimized */
    .modal {
        max-width: none;
        margin: 0.5rem;
        padding: 1.25rem;
        border-radius: var(--radius-sm);
    }

    .modal-header {
        margin-bottom: 1rem;
    }

    .modal-header h2 {
        font-size: 1.125rem;
    }

    .modal-footer {
        margin-top: 1rem;
        gap: 0.5rem;
    }

    /* Compact input area */
    .message-input-container {
        padding: 0.5rem 0.75rem;
        padding-bottom: calc(0.5rem + var(--safe-bottom));
        gap: 0.5rem;
    }

    .message-input-wrapper {
        padding: 0.5rem 0.875rem;
        min-height: 44px;
        border-radius: 22px;
    }

    /* .input-action-btn keeps its base 44px on mobile (previously shrunk to
       40px here). The send-btn is already 44px in this block, so matching the
       attach/voice buttons to 44px keeps the composer row visually consistent
       and hits the tap-target floor. Space isn't the constraint — send-btn
       already coexists at 44px in the same row. */
    .send-btn {
        min-width: 44px;
        min-height: 44px;
    }

    /* Attachment menu mobile */
    .attachment-menu {
        min-width: 200px;
        padding: 6px;
    }

    .attachment-option {
        padding: 14px 16px;
        gap: 14px;
        font-size: 1rem;
        border-radius: 10px;
    }

    .attachment-option svg {
        width: 26px;
        height: 26px;
    }

    /* Smaller messages */
    .message {
        max-width: 85%;
        padding: 0.5rem 0.75rem;
        margin-left: 10%;
        margin-right: 10%;
    }

    .message.own {
        margin-left: 10%;
        margin-right: 0;
    }

    .message.other {
        margin-left: 0;
        margin-right: 10%;
    }

    /* Media messages */
    .image-message {
        max-width: 240px;
    }

    .video-message {
        max-width: 280px;
    }

    .chat-image {
        max-height: 200px;
    }

    .chat-video {
        max-height: 180px;
    }

    .audio-message {
        min-width: 200px;
        max-width: 260px;
    }

    .file-message {
        min-width: 180px;
    }

    .media-viewer-close {
        top: calc(0.5rem + var(--safe-top));
        right: 0.5rem;
    }
}

/* Extra-small screens (below 400px) */
@media (max-width: 400px) {
    .chat-header {
        padding: 0.375rem 0.375rem;
        gap: 0.25rem;
    }

    .chat-header-info h1 {
        font-size: 0.875rem;
    }

    .chat-header-info .room-meta-line {
        font-size: 0.65rem;
    }

    .toolbar-btn {
        /* Keep the 44px tap floor even on the smallest phones (was 34px).
           Space is preserved by tightening chat-header gap/padding, not by
           shrinking the buttons themselves. */
        width: 44px;
        height: 44px;
        min-width: 44px;
        min-height: 44px;
    }

    #back-btn {
        min-width: 44px;
        min-height: 44px;
        width: 44px;
        height: 44px;
        padding: 0.25rem;
    }

    #back-btn svg {
        width: 20px;
        height: 20px;
    }

    /* Rooms header: tighten padding but hold the 40px tap size */
    .rooms-header-icons .btn-icon {
        min-width: 40px;
        min-height: 40px;
        width: 40px;
        height: 40px;
        padding: 0.25rem;
    }

    .rooms-header-icons .btn-icon svg {
        width: 18px;
        height: 18px;
    }

    .rooms-header h1 {
        font-size: 1.25rem;
    }

    .rooms-actions .btn-primary,
    .rooms-actions .btn-secondary {
        padding: 0.625rem 0.75rem;
        font-size: 0.875rem;
    }
}

/* Landscape mobile - compact but still tappable */
@media (max-height: 500px) and (orientation: landscape) {
    .chat-header {
        padding: 0.25rem 0.5rem;
    }

    .toolbar-btn {
        width: 32px;
        height: 32px;
        min-width: 32px;
        min-height: 32px;
    }

    .message-input-container {
        padding: 0.25rem 0.5rem;
        padding-bottom: calc(0.25rem + var(--safe-bottom));
    }

    .messages-container {
        padding: 0.5rem;
        gap: 0.5rem;
    }

    .emoji-picker-container {
        max-height: 100px;
    }
}

/* ===================================
   Touch Device Optimizations
   =================================== */
@media (hover: none) and (pointer: coarse) {
    /* Remove hover effects on touch devices */
    .btn:hover {
        background: inherit;
    }

    .btn-primary:hover {
        background: var(--primary);
    }

    .btn-secondary:hover {
        background: var(--bg-tertiary);
    }

    .room-card:hover {
        transform: none;
    }

    .chat-image:hover {
        transform: none;
    }

    /* Toolbar button touch optimizations */
    .toolbar-btn:hover {
        background: transparent;
        color: var(--text-secondary);
    }

    .toolbar-btn:hover svg {
        transform: none;
    }

    .toolbar-btn:active {
        background: rgba(148, 163, 184, 0.2);
        transform: scale(0.92);
    }

    .kebab-item:hover {
        background: transparent;
    }

    .kebab-item:active {
        background: rgba(148, 163, 184, 0.15);
    }

    .kebab-item-danger:hover {
        background: transparent;
        color: #f87171;
    }

    .kebab-item-danger:active {
        background: rgba(248, 113, 113, 0.2);
    }

    .kebab-item-warning:hover {
        background: transparent;
        color: #fbbf24;
    }

    .kebab-item-warning:active {
        background: rgba(251, 191, 36, 0.2);
    }

    /* Ensure textarea is properly styled */
    #message-input {
        font-size: 16px !important; /* Prevents zoom */
        -webkit-appearance: none;
        appearance: none;
    }

    /* Attachment menu touch optimizations */
    .attachment-option:hover {
        background: transparent;
    }

    .attachment-option:hover svg {
        color: var(--text-secondary);
    }

    .attachment-option:active {
        background: var(--bg-tertiary);
        transform: scale(0.98);
    }

    .attachment-option:active svg {
        color: var(--primary);
    }

    /* Settings accordion touch optimizations */
    .settings-section-header:hover {
        background: transparent;
    }

    .settings-section-header:active {
        background: rgba(148, 163, 184, 0.12);
    }

    .settings-section:hover {
        border-color: var(--border);
    }
}

/* ===================================
   Key Fingerprint & Verification
   =================================== */

/* Fingerprint display in participant list */
.participant .key-fingerprint {
    display: block;
    font-size: 0.625rem;
    font-family: monospace;
    color: var(--text-muted);
    letter-spacing: 0.05em;
    cursor: pointer;
    padding: 0.125rem 0.25rem;
    border-radius: 4px;
    transition: all 0.2s ease;
    margin-left: auto;
}

.participant .key-fingerprint:hover {
    background: var(--bg-tertiary);
    color: var(--text-secondary);
}

/* Key Verification Modal */
.key-verification-modal {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
    opacity: 0;
    visibility: hidden;
    transition: all 0.3s ease;
}

.key-verification-modal.show {
    opacity: 1;
    visibility: visible;
}

.key-verification-backdrop {
    position: absolute;
    inset: 0;
    background: rgba(0, 0, 0, 0.8);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
}

.key-verification-content {
    position: relative;
    z-index: 1;
    background: var(--bg-secondary);
    border-radius: var(--radius);
    padding: 1.5rem;
    max-width: 400px;
    width: 100%;
    transform: translateY(20px);
    transition: transform 0.3s ease;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.5);
}

.key-verification-modal.show .key-verification-content {
    transform: translateY(0);
}

.key-verification-content h3 {
    font-size: 1.25rem;
    font-weight: 600;
    margin-bottom: 0.5rem;
    color: var(--text);
}

.key-instruction {
    font-size: 0.875rem;
    color: var(--text-secondary);
    margin-bottom: 1.25rem;
    line-height: 1.5;
}

.key-fingerprint-full {
    font-family: monospace;
    font-size: 0.9rem;
    letter-spacing: 0.1em;
    text-align: center;
    padding: 1rem;
    background: var(--bg);
    border-radius: var(--radius-sm);
    color: var(--success);
    border: 1px solid var(--border);
    word-break: break-all;
    line-height: 1.8;
}

.key-actions {
    display: flex;
    gap: 0.75rem;
    margin-top: 1.25rem;
}

.key-actions button {
    flex: 1;
    padding: 0.75rem 1rem;
    font-size: 0.875rem;
    font-weight: 500;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: all 0.2s ease;
}

.btn-copy-fingerprint {
    background: var(--primary);
    color: white;
}

.btn-copy-fingerprint:hover {
    background: var(--primary-dark);
}

.btn-close-verification {
    background: var(--bg-tertiary);
    color: var(--text);
}

.btn-close-verification:hover {
    background: var(--border);
}

/* Decryption Failed Message Styling */
.message.decryption-failed {
    opacity: 0.7;
    border-left: 3px solid var(--warning);
}

.message.decryption-failed p {
    color: var(--text-muted);
    font-style: italic;
}

/* Mobile adjustments for key fingerprint */
@media (max-width: 767px) {
    .participant .key-fingerprint {
        font-size: 0.5rem;
        padding: 0.1rem 0.2rem;
    }

    .key-fingerprint-full {
        font-size: 0.75rem;
        padding: 0.75rem;
    }

    .key-verification-content {
        padding: 1rem;
    }

    .key-actions {
        flex-direction: column;
    }
}

/* ===================================
   Refresh Button Animation
   =================================== */
#refresh-btn.spinning svg {
    animation: spin-refresh 1s linear infinite;
}

@keyframes spin-refresh {
    from {
        transform: rotate(0deg);
    }
    to {
        transform: rotate(360deg);
    }
}

/* Connection Status Indicator - see .connection-dot in header */

/* Queued message status (offline queue) */
.message.queued {
    opacity: 0.6;
    border-left: 3px solid var(--secondary);
}

.message.queued .message-status {
    color: var(--secondary);
}

.message.queued::before {
    content: '';
    position: absolute;
    top: 50%;
    left: -20px;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
    background: var(--secondary);
    border-radius: 50%;
    animation: pulse-queue 2s ease-in-out infinite;
}

@keyframes pulse-queue {
    0%, 100% { opacity: 0.3; }
    50% { opacity: 0.8; }
}

/* ===================================
   Screenshot Protection Styles
   =================================== */

/* System message for screenshot alerts in chat */
.message.screenshot-notice {
    background: linear-gradient(135deg, rgba(239, 68, 68, 0.2), rgba(239, 68, 68, 0.1));
    border: 1px solid var(--error);
    text-align: center;
    padding: 0.75rem;
    margin: 0.5rem 0;
}

.message.screenshot-notice p {
    color: var(--error);
    font-weight: 500;
}

/* ---------------------------
   Privacy Shield
   --------------------------- */

/* Blur the messages area when the window loses focus.
   Forces any external screenshot tool (Snipping Tool, OBS, etc.) to
   refocus the window first — giving keyboard listeners a chance to fire. */
#messages.privacy-blur > *:not(.privacy-watermark) {
    filter: blur(12px);
    transition: filter 0.12s ease;
    -webkit-user-select: none;
    user-select: none;
    pointer-events: none;
}

#messages {
    position: relative;
}

/* Repeating username+room watermark grid overlaid on messages.
   Low-opacity, non-interactive — doesn't prevent screenshots,
   makes leaked ones traceable to the viewer. */
.privacy-watermark {
    position: absolute;
    inset: 0;
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    align-content: start;
    justify-items: center;
    pointer-events: none;
    -webkit-user-select: none;
    user-select: none;
    z-index: 1;
    overflow: hidden;
}

.privacy-watermark span {
    display: block;
    padding: 2.25rem 0.5rem;
    font-size: 0.75rem;
    color: var(--text);
    opacity: 0.055;
    transform: rotate(-28deg);
    white-space: nowrap;
    font-weight: 600;
    letter-spacing: 0.05em;
}

/* Warning button style for leave chat */
.btn-warning {
    background: var(--warning);
    color: #000;
}

.btn-warning:hover,
.btn-warning:active {
    background: #d97706;
}

/* ===========================
   Voice Call Styles
   =========================== */

/* Call button in participant list (matches poke-btn) */
.participant .call-participant-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    border: none;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--success);
    cursor: pointer;
    transition: all 0.2s ease;
    flex-shrink: 0;
    opacity: 0.6;
}

/* Touch devices: enlarge the participant-row poke/call buttons to a 44px tap
   floor (they're 32px by default, which is fine for a mouse but a mis-tap
   magnet on phones). Scoped to coarse pointers so desktop sidebar density is
   preserved. The 16px SVGs stay centered via the existing flex centering. */
@media (hover: none) and (pointer: coarse) {
    .participant .poke-btn,
    .participant .call-participant-btn {
        width: 44px;
        height: 44px;
        min-width: 44px;
        min-height: 44px;
        opacity: 0.8;
    }
}

.participant .call-participant-btn:hover {
    background: var(--success);
    color: white;
    opacity: 1;
    transform: scale(1.05);
}

.participant .call-participant-btn:active {
    transform: scale(0.95);
}

/* Call overlay (outgoing / active) */
.call-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(15, 23, 42, 0.95);
    /* Above the 1000 modal/menu band so an incoming/active call overlay is
       never rendered under a modal or dropdown (was 200, below modals).
       Still below #notifications (2000) and the screenshot alert (9999). */
    z-index: 1500;
    align-items: center;
    justify-content: center;
    animation: fadeIn 0.2s ease;
}

.call-overlay.active {
    display: flex;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}

.call-content {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.5rem;
    text-align: center;
    max-width: 340px;
    width: 100%;
    box-sizing: border-box;
    padding: 2rem;
}

.call-avatar {
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 80px;
    height: 80px;
    color: var(--primary-light);
}

.call-pulse {
    position: absolute;
    width: 100%;
    height: 100%;
    background: var(--primary);
    border-radius: 50%;
    opacity: 0.2;
    animation: callPulse 2s ease-in-out infinite;
}

/* The peer's decrypted avatar, filling the circle over the generic glyph.
   The pulse animation scales past 100%, so it still rings around the photo. */
.call-avatar-img {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
}

@keyframes callPulse {
    0%, 100% {
        transform: scale(1);
        opacity: 0.2;
    }
    50% {
        transform: scale(1.4);
        opacity: 0.05;
    }
}

.incoming-call-overlay .call-avatar {
    color: var(--success);
}

.incoming-pulse {
    position: relative;
}

.incoming-pulse::before {
    content: '';
    position: absolute;
    width: 100%;
    height: 100%;
    background: var(--success);
    border-radius: 50%;
    opacity: 0.2;
    animation: callPulse 1.5s ease-in-out infinite;
}

.call-info {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    min-width: 0;   /* let the flex child shrink so long names wrap inside */
}

.call-name {
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--text);
    /* Long spaceless usernames must wrap inside the overlay rather than
       pushing it wider than the screen. overflow-wrap:anywhere breaks a
       single long token; word-break:break-word is deprecated so avoid it. */
    max-width: 100%;
    overflow-wrap: anywhere;
}

.call-status {
    font-size: 0.9rem;
    color: var(--text-secondary);
}

.call-duration {
    font-size: 1.8rem;
    font-weight: 600;
    color: var(--text);
    font-variant-numeric: tabular-nums;
}

.call-actions {
    display: flex;
    gap: 1.5rem;
    margin-top: 1rem;
}

.call-action-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    border: none;
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s ease;
    color: white;
}

.call-action-btn:active {
    transform: scale(0.95);
}

.call-end {
    background: var(--error);
}

.call-end:hover {
    background: #dc2626;
}

.call-decline {
    background: var(--error);
}

.call-decline:hover {
    background: #dc2626;
}

.call-accept {
    background: var(--success);
}

.call-accept:hover {
    background: #16a34a;
}

.call-mute {
    background: var(--bg-tertiary);
}

.call-mute:hover {
    background: var(--secondary);
}

.call-mute.muted {
    background: var(--warning);
    color: #000;
}

.call-mute.muted .mute-off-icon {
    display: none;
}

.call-mute.muted .mute-on-icon {
    display: block !important;
}

.call-mute:not(.muted) .mute-on-icon {
    display: none !important;
}

/* Audio output (speaker/headset/BT) picker */
.call-audio {
    background: var(--bg-tertiary);
}

.call-audio:hover {
    background: var(--secondary);
}

/* Loudspeaker active (native app audio route = speaker) */
.call-audio.speaker-on {
    background: var(--primary, #3b82f6);
    color: #fff;
}

.call-audio-menu {
    margin-top: 0.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    background: var(--bg-secondary, #1e293b);
    border: 1px solid var(--border, rgba(255,255,255,0.12));
    border-radius: 12px;
    padding: 0.4rem;
    max-width: 320px;
    width: 90%;
    margin-left: auto;
    margin-right: auto;
    box-shadow: 0 8px 24px rgba(0,0,0,0.35);
}

.call-audio-menu-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.6rem 0.8rem;
    border: none;
    border-radius: 8px;
    background: transparent;
    color: var(--text-primary, #f1f5f9);
    font-size: 0.9rem;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.call-audio-menu-item:hover {
    background: var(--bg-tertiary, rgba(255,255,255,0.06));
}

.call-audio-menu-item.active {
    background: var(--primary, #3b82f6);
    color: #fff;
}

/* In-call indicator bar */
.call-indicator {
    /* Fixed BOTTOM banner (lobby): a minimized call stays an obvious, tappable
       handle without covering the top bar / navigation. z-index sits just below
       the call overlay (1500): while the full call is up the overlay covers it;
       when minimized the overlay is hidden and this shows above page content.
       The in-room page instead uses the --flow variant below (in-flow above the
       composer), because a fixed bottom bar would cover the message input. */
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    padding-bottom: calc(0.55rem + var(--safe-bottom));
    background: var(--success);
    color: white;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    /* 900, was 1400. At 1400 this fixed bottom bar painted OVER the modal
       overlay (z-index 1000), covering ~32px of the bottom of an open Settings
       modal during a minimized call — including whatever section the user had
       just expanded. 900 keeps it above all normal page content (headers 100,
       composer 50, sidebar 200) and only below the 1000 modal band, so an open
       modal now covers the call HANDLE — correct, since it is a handle rather
       than an alert and returns the moment the modal closes.
       Deliberately NOT solved by raising .modal-overlay: #incoming-call-overlay
       shares z-index 1500, and lifting modals above it would put an incoming
       call behind any open modal with its blurred backdrop eating the
       answer/decline taps. */
    z-index: 900;
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.3);
}

/* In-room variant: a normal row of the chat flex column, directly above the
   message composer. Never overlaps the input, rides up with the keyboard, and
   being in-flow sidesteps the .chat-container `contain: layout style` trap
   that breaks position:fixed children (why the old bar had to be body-level). */
.call-indicator--flow {
    position: static;
    padding-bottom: 0.55rem; /* composer below already handles the safe area */
    flex-shrink: 0;
    box-shadow: none;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
}

.call-indicator-dot {
    width: 8px;
    height: 8px;
    background: white;
    border-radius: 50%;
    animation: callDotPulse 1s ease-in-out infinite;
}

@keyframes callDotPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.call-indicator-btn {
    margin-left: auto;
    padding: 0.15rem 0.5rem;
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: var(--radius-sm);
    background: transparent;
    color: white;
    font-size: 0.75rem;
    cursor: pointer;
    transition: background 0.2s;
}

.call-indicator-btn:hover {
    background: rgba(255, 255, 255, 0.2);
}

/* ===================================
   In-call navigation sandbox — a same-origin iframe over the page so a live
   call survives "navigation" (the underlying page, which owns the WebRTC
   connection, never unloads). The green top bar is the way back to the call.
   z-index 1300: above page content and the in-flow indicator, below the full
   call overlay (1500) and the lobby's fixed indicator (1400).
   =================================== */
.call-nav-frame {
    position: fixed;
    inset: 0;
    z-index: 1300;
    display: flex;
    flex-direction: column;
    background: var(--bg-primary);
}

.call-nav-frame-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.55rem 1rem;
    padding-top: calc(0.55rem + var(--safe-top));
    background: var(--success);
    color: white;
    font-size: 0.85rem;
    font-weight: 600;
    cursor: pointer;
    flex-shrink: 0;
    box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.call-nav-frame-close {
    margin-left: auto;
    padding: 0.15rem 0.55rem;
    border: 1px solid rgba(255, 255, 255, 0.5);
    border-radius: var(--radius-sm);
    background: transparent;
    color: white;
    font-size: 0.85rem;
    cursor: pointer;
}

.call-nav-frame-page {
    flex: 1 1 auto;
    width: 100%;
    border: 0;
    background: var(--bg-primary);
}

/* ===================================
   Performance — GPU hints for low-end devices
   =================================== */
.modal-overlay,
.chat-sidebar,
.voice-recording-overlay,
.media-viewer {
    will-change: opacity;
}

.modal-overlay.show .modal {
    will-change: transform;
}

/* Reduce backdrop-filter cost on low-end devices */
@media (max-width: 767px) {
    .modal-overlay {
        backdrop-filter: blur(2px);
        -webkit-backdrop-filter: blur(2px);
    }
}

/* Respect reduced motion preference */
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }

    .modal-overlay .modal {
        transform: none;
    }

    .modal-overlay.show .modal {
        transform: none;
    }
}

/* ===================================
   Settings Accordion
   =================================== */
.settings-modal {
    padding: 1.5rem;
}

.settings-accordion {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.settings-section {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    transition: border-color 0.2s ease;
}

.settings-section:hover {
    border-color: var(--text-muted);
}

.settings-section.open {
    border-color: var(--primary);
}

.settings-section-header {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    width: 100%;
    padding: 0.875rem 1rem;
    background: transparent;
    border: none;
    color: var(--text);
    cursor: pointer;
    font-size: 0.9375rem;
    font-weight: 500;
    text-align: left;
    -webkit-tap-highlight-color: transparent;
    touch-action: manipulation;
    transition: background-color 0.15s ease;
    min-height: 52px;
}

.settings-section-header:hover {
    background: rgba(148, 163, 184, 0.08);
}

.settings-section-header:active {
    background: rgba(148, 163, 184, 0.12);
}

.settings-section-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    background: var(--bg-tertiary);
    border-radius: 8px;
    color: var(--text-secondary);
    transition: color 0.2s ease, background 0.2s ease;
}

.settings-section.open .settings-section-icon {
    background: rgba(37, 99, 235, 0.15);
    color: var(--primary-light);
}

.settings-section-title {
    flex: 1;
    min-width: 0;
    /* Was nowrap + ellipsis, which silently TRUNCATED the longer Greek titles
       («Κλείδωμα Εφαρμογής», «Ενεργές Συνεδρίες») on narrow phones — the status
       chip beside it is flex-shrink:0 and never gives width back. A section
       whose own name is cut off reads as broken, so wrap to a second line
       instead; the header is min-height, not fixed height, so it just grows. */
    overflow-wrap: break-word;
    word-break: break-word;
}

.settings-section-value {
    font-size: 0.8125rem;
    color: var(--text-muted);
    /* Never let the chip force the title to truncate: it may shrink, and it
       keeps its own text on one line. */
    flex-shrink: 1;
    min-width: 0;
    white-space: nowrap;
    text-align: right;
}

.settings-chevron {
    flex-shrink: 0;
    color: var(--text-muted);
    transition: transform 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

.settings-section.open .settings-chevron {
    transform: rotate(180deg);
}

/* Collapsible body */
.settings-section-body {
    max-height: 0;
    overflow: hidden;
    /* visibility, not just max-height: `max-height: 0; overflow: hidden` hides a
       section visually but leaves every descendant in the TAB ORDER. The modal's
       focus trap queries the whole modal, so Tab used to walk through the avatar
       password box, both language buttons, the checkboxes, the online-status
       select and all three password fields while they were invisible — and on
       Android the soft keyboard would pop open for a field inside a closed
       section. `visibility: hidden` removes them from focus and the a11y tree.
       The 0s delay defers it until the collapse animation has finished, so the
       content doesn't vanish instantly on the way closed. */
    visibility: hidden;
    transition: max-height 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                padding 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                visibility 0s linear 0.3s;
    padding: 0 0.875rem;
}

.settings-section.open .settings-section-body {
    /* 1200px is purely the ANIMATION target — max-height cannot transition
       to/from `auto`, so the expand needs a concrete number to travel to.
       It is NOT a layout limit: toggleSettingsSection() sets max-height:none
       via .settings-section-expanded once the transition finishes, so a section
       that ever outgrows 1200px is never silently clipped.
       Deliberately NOT solved with overflow-y:auto — the .open class applies
       from the first frame while max-height is still animating up from 0, so
       content exceeds the box for ~300ms and desktop would flash a scrollbar on
       every single expand. */
    max-height: 1200px;
    visibility: visible;
    transition-delay: 0s, 0s, 0s;
    padding: 0 0.875rem 0.875rem;
}

/* Applied for one frame while the accordion collapses the OTHER sections, so
   toggleSettingsSection() can force a synchronous reflow and measure final
   positions instead of positions that are still 300ms from settling. */
.settings-section.no-anim .settings-section-body {
    transition: none !important;
}

/* Set by JS once the expand transition has COMPLETED, removing the animation
   cap entirely so tall content can never be clipped. Applied after the fact
   precisely so it costs nothing during the animation. */
.settings-section.settings-section-expanded .settings-section-body {
    max-height: none;
}

/* Session rows can outnumber any fixed cap — scroll them inside their own box
   so the section never grows past the accordion's animation cap above. */
#sessions-list {
    max-height: 320px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* overscroll-behavior: contain was REMOVED. This inner scroller covers most
       of the Sessions section, so a touch drag almost always starts inside it;
       `contain` blocks scroll chaining, so on reaching the end of the list the
       drag stopped dead and the modal felt frozen. .modal already sets
       overscroll-behavior: contain, which is what actually stops the page
       behind the modal from scrolling — this one only broke the gesture. */
}

/* One button size inside settings. There were four (36px inline blobs on the
   App Lock and Revoke buttons, 44px on the language pair and the footer), and
   the 36px ones were App Lock's primary action and Sessions' destructive
   action — the two that most needed a real tap target. */
.settings-row-btn {
    font-size: 0.75rem;
    padding: 0.5rem 0.75rem;
    min-height: 44px;
    flex-shrink: 0;
}

/* .btn is white-space: nowrap globally, and .settings-section has
   overflow: hidden, so a long Greek label on a full-width button inside a
   section («Αποσύνδεση Όλων των Άλλων Συσκευών») was clipped with no ellipsis.
   The footer has this escape hatch already; sections did not. */
.settings-section-body .btn {
    white-space: normal;
    text-align: center;
}

/* Replaces the inline style="width: 100%" repeated on four buttons at three
   different font sizes. Narrower side padding so long Greek labels have room
   before they need to wrap. */
.btn-block {
    width: 100%;
    padding-left: 0.75rem;
    padding-right: 0.75rem;
}

.settings-version-row {
    margin-top: 1rem;
    text-align: center;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* Shared option row inside sections */
.settings-option-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.75rem;
    background: var(--bg-tertiary);
    border-radius: var(--radius-sm);
}

/* Replaces style="margin-top: 0.5rem" repeated on every row after the first.
   Adjacent-sibling so the first row in a section never gets a stray top gap,
   and rows hidden with display:none still don't contribute one. */
.settings-option-row + .settings-option-row {
    margin-top: 0.5rem;
}

/* The explanatory paragraph at the top of a section (was an inline
   margin-bottom on each one). */
.settings-section-intro {
    margin-bottom: 0.75rem;
}

/* The language pair: two equal buttons that must be able to SHRINK below their
   content width (flex items refuse by default), so a long localised label can
   never push the row past the modal edge. Was seven inline properties each. */
.settings-lang-row {
    display: flex;
    gap: 0.5rem;
    padding-top: 0.375rem;
}

.settings-lang-row .btn {
    flex: 1 1 0;
    min-width: 0;
    min-height: 44px;
    padding-left: 0.5rem;
    padding-right: 0.5rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.settings-option-info {
    min-width: 0;
    flex: 1;
}

.settings-option-label {
    font-size: 0.875rem;
    color: var(--text);
    margin-bottom: 0.25rem;
    /* Long unbroken tokens (user-agent strings, IPs, long Greek labels) must
       wrap inside the row instead of pushing it wider than the modal. */
    overflow-wrap: break-word;
    word-break: break-word;
}

.settings-option-desc {
    font-size: 0.75rem;
    color: var(--text-muted);
    line-height: 1.4;
    overflow-wrap: break-word;
    word-break: break-word;
}

/* Toggle switch */
.settings-toggle {
    position: relative;
    display: inline-block;
    width: 48px;
    height: 26px;
    flex-shrink: 0;
}

.settings-toggle input {
    /* THE control, not a hidden shadow of one.
       Was `opacity:0; width:0; height:0` with the actual tap handled by an
       onclick on the wrapper <span>. That meant: the focus ring drew around a
       0x0 box, keyboard users had no visible target, and — worst — the on/off
       APPEARANCE was painted by inline-style JS duplicated in four places, so
       any path that opened Settings without going through the #settings-btn
       handler showed both switches stuck OFF regardless of the real value.
       Making the input cover the switch means the thing you see is the thing
       you tap, and :checked below drives the visuals from actual state. */
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
    z-index: 1;
}

.settings-toggle-track {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: var(--border);
    border-radius: 13px;
    transition: background 0.3s;
}

.settings-toggle-dot {
    position: absolute;
    height: 20px;
    width: 20px;
    left: 3px;
    bottom: 3px;
    background: #fff;
    border-radius: 50%;
    transition: transform 0.3s;
    pointer-events: none;
}

/* State-driven appearance. General sibling (~), not adjacent (+): the dot is
   the SECOND element after the input, so `+` would never match it. */
.settings-toggle input:checked ~ .settings-toggle-track {
    background: var(--primary);
}

.settings-toggle input:checked ~ .settings-toggle-dot {
    transform: translateX(22px);
}

.settings-toggle input:disabled ~ .settings-toggle-track {
    opacity: 0.5;
}

/* A real, visible focus indicator on the thing the user actually sees. */
.settings-toggle input:focus-visible ~ .settings-toggle-track {
    outline: 2px solid var(--primary-light);
    outline-offset: 2px;
}

/* Password form inside accordion needs tighter spacing */
.settings-section-body .form-group {
    margin-bottom: 0.875rem;
}

.settings-section-body .form-group:last-of-type {
    margin-bottom: 0.75rem;
}

/* --- Settings mobile optimizations --- */
@media (max-width: 767px) {
    /* .modal.settings-modal, not .settings-modal: the plain class ties on
       specificity (0-1-0) with the generic `.modal` rules, so which one wins is
       decided purely by source order — and in the <=360px block below the
       generic rule comes LAST and silently beat this one. Qualifying both keeps
       the intent regardless of where the rules sit.
       The margin was also removed: it sits OUTSIDE the max-height box, so the
       modal's outer size exceeded the overlay's content box and it overhung
       ~6px into the safe-area padding at each end. The overlay's own 1rem
       padding is the gutter. */
    .modal.settings-modal {
        padding: 1rem;
    }

    .settings-modal .modal-header {
        margin-bottom: 0.75rem;
    }

    .settings-modal .modal-footer {
        margin-top: 0.75rem;
    }

    .settings-accordion {
        gap: 0.375rem;
    }

    .settings-section-header {
        padding: 0.75rem 0.75rem;
        gap: 0.625rem;
        min-height: 48px;
        font-size: 0.875rem;
    }

    .settings-section-icon {
        width: 30px;
        height: 30px;
    }

    .settings-section-icon svg {
        width: 16px;
        height: 16px;
    }

    .settings-section-body {
        padding: 0 0.75rem;
    }

    .settings-section.open .settings-section-body {
        padding: 0 0.75rem 0.75rem;
    }

    .settings-option-row {
        gap: 0.5rem;
        padding: 0.625rem;
        /* Let an action button (Forget Device, Revoke) drop to its own line
           when the label beside it genuinely doesn't fit, instead of the two
           fighting over width and one of them poking out of the card. */
        flex-wrap: wrap;
    }

    .settings-option-row > .btn {
        /* flex-basis 100% is what makes the flex-wrap above REAL. It used to be
           `flex-shrink: 0; margin-left: auto`, and the wrap could never fire:
           .settings-option-info is `flex: 1 1 0%` with min-width:0, so its
           hypothetical size is 0px and the line only ever measured
           0 + gap + button — which always fits. The button therefore never
           dropped; the text column silently squeezed instead. In Greek that is
           brutal: «Απενεργοποίηση» is a rigid ~115px nowrap block, leaving the
           label ~160px and wrapping «Το Κλείδωμα Εφαρμογής είναι ενεργό σε αυτή
           τη συσκευή» to three lines. 100% basis always exceeds the line, so
           the button deterministically takes its own row at every width and in
           every language. Toggle/select rows are unaffected — this only targets
           rows whose action is a .btn. */
        flex: 0 0 100%;
        margin-left: 0;
    }

    .settings-option-label {
        font-size: 0.8125rem;
    }

    .settings-option-desc {
        font-size: 0.6875rem;
    }

    /* Ensure form inputs don't overflow */
    .settings-section-body .form-input {
        max-width: 100%;
    }

    .settings-section-body .form-group {
        margin-bottom: 0.75rem;
    }
}

/* Extra-small settings for very small phones */
@media (max-width: 360px) {
    /* This block used to LOSE to the generic `.modal { padding: 1rem }` in the
       "Extra-small modal improvements" section further down the file, so the
       narrowest phones — the ones that need the width most, and where Greek is
       tightest — silently rendered 16px of padding instead of the intended 12px. */
    .modal.settings-modal {
        padding: 0.75rem;
    }

    .settings-section-header {
        padding: 0.625rem 0.625rem;
        gap: 0.5rem;
        font-size: 0.8125rem;
    }

    .settings-section-icon {
        width: 28px;
        height: 28px;
    }

    .settings-section-body {
        padding: 0 0.625rem;
    }

    .settings-section.open .settings-section-body {
        padding: 0 0.625rem 0.625rem;
    }

    .settings-option-row {
        flex-direction: column;
        align-items: stretch;
        gap: 0.5rem;
    }

    .settings-option-row > .btn {
        /* Rows are stacked here — a full-width button reads better than one
           hugging the right edge (margin-left:auto is the ≥361px behaviour). */
        margin-left: 0;
        width: 100%;
    }

    .settings-toggle {
        align-self: flex-start;
    }
}

/* ===================================
   Settings / Logout icon visibility in rooms header
   =================================== */
#settings-btn svg,
#logout-btn svg {
    filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.3));
}

#settings-btn:active svg,
#logout-btn:active svg {
    transform: scale(0.9);
}

/* ===================================
   Extra-small modal improvements (< 360px phones)
   =================================== */
@media (max-width: 360px) {
    .modal {
        padding: 1rem;
        margin: 0.375rem;
    }

    .modal-header h2 {
        font-size: 1rem;
    }

    .modal-footer .btn {
        padding: 0.625rem 0.75rem;
        font-size: 0.875rem;
    }

    .auth-card {
        padding: 1.5rem 1.25rem;
    }

    .auth-logo h1 {
        font-size: 1.625rem;
    }
    .auth-logo-icon {
        width: 1.875rem;
        height: 1.875rem;
    }
}

/* ===================================
   iOS-Specific Fixes (iPhone notch / Dynamic Island / home indicator)
   Applied via .ios-device class added by JS on iOS/iPadOS devices
   =================================== */

/* --- Lobby / Rooms page --- */
/* iOS now uses the SAME scroll architecture as the base rule: the container
   is a fixed-height non-scrolling flex column and .rooms-list is the scroll
   region. We keep the iOS-only safe-area padding on the container (for header
   clearance under the Dynamic Island) but scroll happens in the child. */
html.ios-device .rooms-container {
    height: 100dvh;
    min-height: 100dvh;
    max-height: 100dvh;
    box-sizing: border-box;
    overflow: hidden;
    /* Use max() to guarantee minimum clearance on Dynamic Island devices (iPhone 14 Pro+)
       even if env() returns 0 in some PWA edge cases */
    padding-top: max(3.5rem, calc(1.25rem + env(safe-area-inset-top, 0px)));
    /* Bottom clearance is handled by .rooms-list's padding-bottom (which uses
       max() including var(--safe-bottom)). Keeping bottom padding on this
       overflow:hidden container would clip the scroll region above the iPhone
       home indicator — the same clipping bug we just fixed for Android. */
    padding-bottom: 0;
}

/* Rooms header needs extra breathing room on iOS - icons were too high and untappable */
html.ios-device .rooms-header {
    /* Slight extra gap so buttons aren't flush against the safe area edge */
    margin-bottom: 1rem;
}

html.ios-device .rooms-header-top {
    /* Ensure the row doesn't wrap and icons stay reachable on Dynamic Island devices */
    min-height: 44px;
    /* Extra top padding so icons clear the Dynamic Island's wider exclusion zone */
    padding-top: max(0px, calc(env(safe-area-inset-top, 0px) * 0.15));
}

/* --- Chat page --- */
html.ios-device .chat-container {
    /* padding-top already uses var(--safe-top) which works.
       Ensure the container fills exactly the visual viewport */
    box-sizing: border-box;
    overflow: hidden;
}

/* Chat header: give extra top padding on iOS for Dynamic Island clearance */
html.ios-device .chat-header {
    /* The chat-container has padding-top for safe-top, but in standalone PWA mode
       with black-translucent the header can sit under the Dynamic Island.
       Use a meaningful fraction so it clears on iPhone 15+ */
    padding-top: max(0.5rem, calc(0.25rem + env(safe-area-inset-top, 0px) * 0.35));
}

/* Kebab menu on mobile iOS: account for safe areas so it doesn't go under dynamic island */
@media (max-width: 767px) {
    html.ios-device .kebab-menu {
        /* Ensure menu doesn't render behind the status bar / dynamic island */
        max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 60px);
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* --- Input area --- */
/* iOS home indicator: extra padding for message input */
html.ios-device .message-input-container {
    padding-bottom: calc(0.625rem + env(safe-area-inset-bottom, 0px));
}

/* --- Modals --- */
/* On iOS the modal max-height with vh can be wrong; dvh is more accurate */
html.ios-device .modal {
    max-height: calc(100dvh - 2rem - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
}

html.ios-device .modal-overlay {
    /* Ensure overlay covers full iOS viewport including under status bar */
    padding-top: calc(1rem + env(safe-area-inset-top, 0px));
    padding-bottom: calc(1rem + env(safe-area-inset-bottom, 0px));
}

/* --- Mobile sidebar on iOS --- */
@media (max-width: 767px) {
    html.ios-device .chat-sidebar {
        padding-top: env(safe-area-inset-top, 0px);
        padding-bottom: env(safe-area-inset-bottom, 0px);
        height: 100dvh;
    }
}

/* --- Auth pages on iOS --- */
html.ios-device .auth-container {
    min-height: 100dvh;
    padding-top: calc(1.5rem + env(safe-area-inset-top, 0px));
    padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}

html.ios-device body.auth-page {
    min-height: 100dvh;
}

/* --- Notifications on iOS --- */
html.ios-device #notifications {
    top: calc(1rem + env(safe-area-inset-top, 0px));
}

/* --- Media viewer on iOS --- */
html.ios-device .media-viewer-image {
    max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 2rem);
}

html.ios-device .media-viewer-video {
    max-height: calc(100dvh - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px) - 2rem);
}

/* --- Voice recording overlay on iOS --- */
html.ios-device .voice-recording-overlay {
    padding-bottom: calc(2rem + env(safe-area-inset-bottom, 0px));
}

/* --- Fixed bottom elements on iOS (install button, etc.) --- */
html.ios-device #install-btn {
    bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}

/* --- iOS settings modal: tighter to stay within safe areas --- */
html.ios-device .settings-modal {
    max-height: calc(100dvh - 1.5rem - env(safe-area-inset-top, 0px) - env(safe-area-inset-bottom, 0px));
}

/* --- iPhone SE / small iOS screens --- */
@media (max-width: 375px) {
    html.ios-device .rooms-header-icons .btn-icon {
        min-width: 40px;
        min-height: 40px;
        width: 40px;
        height: 40px;
        padding: 0.25rem;
    }

    html.ios-device .rooms-header-icons .btn-icon svg {
        width: 18px;
        height: 18px;
    }

    html.ios-device .rooms-header h1 {
        font-size: 1.25rem;
    }
}

/* --- iOS PWA standalone mode: extra safety for Dynamic Island devices --- */
@media (display-mode: standalone) {
    html.ios-device .rooms-container {
        /* In standalone PWA with black-translucent, ensure header icons
           are never hidden under the Dynamic Island / status bar area */
        padding-top: max(3.75rem, calc(1.5rem + env(safe-area-inset-top, 0px)));
    }

    html.ios-device .chat-container {
        padding-top: max(2.5rem, env(safe-area-inset-top, 0px));
    }
}

/* =============================================================================
   Welcome modal (post-update community message).
   Inherits .modal-overlay + .modal layout, adds friendly framing on top.
   Kept tasteful: no flashing, no over-the-top accents — just a warm dialog.
   ============================================================================= */
.modal.welcome-modal {
    max-width: 460px;
    text-align: center;
    padding: 2rem 1.75rem 1.75rem;
}

.welcome-modal .welcome-icon {
    font-size: 3rem;
    line-height: 1;
    margin-bottom: 0.75rem;
    /* gentle float animation; respects prefers-reduced-motion below */
    animation: welcomeFloat 3.5s ease-in-out infinite;
}

.welcome-modal .welcome-title {
    font-size: 1.5rem;
    font-weight: 700;
    margin: 0 0 1rem 0;
    color: var(--text);
    /* subtle gradient on supported browsers; falls back to plain color */
    background: linear-gradient(135deg, var(--primary-light, #60a5fa), #a78bfa);
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
}

.welcome-modal .welcome-body {
    color: var(--text-secondary);
    font-size: 0.95rem;
    line-height: 1.6;
    margin-bottom: 1.5rem;
}

.welcome-modal .welcome-body p {
    margin: 0 0 0.875rem 0;
}

.welcome-modal .welcome-body p:last-child {
    margin-bottom: 0;
}

.welcome-modal .welcome-quip {
    color: var(--text-muted);
    font-style: italic;
    font-size: 0.875rem;
}

.welcome-modal .welcome-thanks {
    color: var(--text);
    font-weight: 500;
}

.welcome-modal .welcome-actions {
    display: flex;
    justify-content: center;
}

.welcome-modal .welcome-actions .btn {
    min-width: 140px;
}

@keyframes welcomeFloat {
    0%, 100% { transform: translateY(0); }
    50%      { transform: translateY(-6px); }
}

@media (prefers-reduced-motion: reduce) {
    .welcome-modal .welcome-icon {
        animation: none;
    }
}


/* ============================================================
   Avatars (zero-knowledge profile pictures)
   One shared .avatar slot so message bubbles, participant rows,
   and the settings preview can never drift apart.
   ============================================================ */
.avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-size: 0.75rem;
    font-weight: 600;
    flex-shrink: 0;
    overflow: hidden;
    user-select: none;
}
.avatar img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}
/* The initial stays in the DOM under the image: if the image fails to load
   (onerror strips .has-image) the letter is already there to show through. */
.avatar.has-image .avatar-initial {
    visibility: hidden;
}

.message-sender-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: 0.25rem;
}
.message-avatar {
    width: 22px;
    height: 22px;
    font-size: 0.65rem;
}
/* .sender keeps its own margin-bottom for rooms with no avatars; inside the
   row wrapper the row owns the spacing. */
.message-sender-row .sender {
    margin-bottom: 0;
}

.participant-avatar {
    width: 32px;
    height: 32px;
    font-size: 0.8rem;
    margin-right: 0.5rem;
}

/* Settings editor */
.avatar-large {
    width: 72px;
    height: 72px;
    font-size: 1.75rem;
}
.avatar-editor {
    display: flex;
    align-items: center;
    gap: 1rem;
}
.avatar-editor-actions {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    flex: 1;
    min-width: 0;
}

/* ============================================================
   Login: session-duration picker (replaces the dead 30-day box)
   ============================================================ */
.session-duration {
    display: flex;
    gap: 0.5rem;
}
.session-duration input {
    flex: 1;
    min-width: 0;
}
.session-duration select {
    flex: 1.4;
    min-width: 0;
}

/* ============================================================
   Friends
   ============================================================ */
.friends-btn-wrap {
    position: relative;
}
.friends-badge {
    position: absolute;
    top: 2px;
    right: 2px;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--error);
    color: #fff;
    font-size: 0.65rem;
    font-weight: 700;
    line-height: 16px;
    text-align: center;
    pointer-events: none;
}

.friends-modal {
    display: flex;
    flex-direction: column;
    max-height: 85vh;
}

.add-friend-form {
    display: flex;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}
.add-friend-form input {
    flex: 1;
    min-width: 0;
}

.friends-tabs {
    display: flex;
    gap: 0.25rem;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0.5rem;
}
.friends-tab {
    flex: 1;
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 0.85rem;
    font-weight: 600;
    padding: 0.6rem 0.25rem;
    min-height: 44px;
    cursor: pointer;
    border-bottom: 2px solid transparent;
    transition: color var(--transition), border-color var(--transition);
}
.friends-tab.active {
    color: var(--primary-light);
    border-bottom-color: var(--primary-light);
}

.friends-panels {
    flex: 1;
    overflow-y: auto;
    min-height: 200px;
    -webkit-overflow-scrolling: touch;
}
.friends-list .empty-state {
    padding: 2rem 1rem;
    text-align: center;
    color: var(--text-muted);
}

.friends-group-label {
    font-size: 0.7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: var(--text-muted);
    margin: 0.75rem 0 0.25rem;
}

.friend-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.25rem;
    border-radius: var(--radius-sm);
}
.friend-row + .friend-row {
    border-top: 1px solid rgba(71, 85, 105, 0.35);
}
.friend-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-weight: 600;
    flex-shrink: 0;
    user-select: none;
}
.friend-row .status-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--secondary);
    flex-shrink: 0;
}
.friend-row.online .status-dot {
    background: var(--success);
}
.friend-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
}
.friend-name {
    font-weight: 600;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.friend-status {
    font-size: 0.7rem;
    color: var(--text-muted);
}
.friend-row.online .friend-status {
    color: var(--success);
}
.friend-actions {
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
}
.friend-actions .btn-icon {
    width: 44px;
    height: 44px;
    min-width: 44px;
}
@media (min-width: 768px) {
    /* Denser rows where a mouse is the pointer; the 44px floor is a touch rule. */
    .friend-actions .btn-icon {
        width: 36px;
        height: 36px;
        min-width: 36px;
    }
}

/* ============================================================
   Call: minimize (keep chatting during a call) + zoom lightbox
   ============================================================ */
/* Minimized: the full overlay collapses entirely; the slim top indicator
   (shown separately by call.js) becomes the handle back. The call itself is a
   separate <audio>/WebRTC element, so hiding the overlay never touches it. */
.call-overlay.minimized {
    display: none;
}
.call-minimize-btn {
    position: absolute;
    top: calc(1rem + var(--safe-top));
    left: 1rem;
    width: 40px;
    height: 40px;
    /* Hidden by default; shown only once the call is CONNECTED (see below).
       Keying it off .active alone showed a dead button during the outgoing
       ring, where minimizeCall() no-ops because the call isn't active yet. */
    display: none;
    align-items: center;
    justify-content: center;
    border: none;
    border-radius: 50%;
    background: rgba(255, 255, 255, 0.12);
    color: #fff;
    cursor: pointer;
    z-index: 2;
    transition: background var(--transition);
}
.call-minimize-btn:hover {
    background: rgba(255, 255, 255, 0.22);
}
/* Only offer minimize once connected. call.js adds .in-call in showActiveCallUI. */
.call-overlay.in-call .call-minimize-btn {
    display: flex;
}

.avatar-zoom-overlay {
    display: none;
    position: fixed;
    inset: 0;
    z-index: 2100;               /* above the call overlay (1500) and modals */
    background: rgba(15, 23, 42, 0.94);
    align-items: center;
    justify-content: center;
    flex-direction: column;
    gap: 1rem;
    padding: 2rem;
    cursor: zoom-out;
    animation: fadeIn 0.15s ease;
}
.avatar-zoom-overlay.show {
    display: flex;
}
.avatar-zoom-img {
    max-width: min(80vw, 420px);
    max-height: 70vh;
    width: auto;
    height: auto;
    border-radius: 16px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
    object-fit: contain;
}
.avatar-zoom-name {
    color: #fff;
    font-size: 1.1rem;
    font-weight: 600;
}
.avatar.has-image,
.friend-avatar.has-image,
.participant-avatar.has-image {
    cursor: zoom-in;
}

/* ============================================================
   Friends — compact rows (override the taller first pass)
   ============================================================ */
.friend-row {
    display: flex;
    align-items: center;
    gap: 0.625rem;
    padding: 0.4rem 0.25rem;
    border-radius: var(--radius-sm);
    min-height: 52px;
}

.friend-avatar {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    font-weight: 600;
    font-size: 1rem;
    flex-shrink: 0;
    overflow: hidden;
    user-select: none;
}
.friend-avatar img {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
}
.friend-avatar.has-image .friend-avatar-initial {
    visibility: hidden;
}

/* Name column takes all remaining width and truncates instead of wrapping,
   which is what was hiding names behind the buttons before. */
.friend-info {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.1rem;
}
.friend-name {
    font-weight: 600;
    font-size: 0.95rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.friend-status {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.72rem;
    color: var(--text-muted);
}
.friend-row.online .friend-status {
    color: var(--success);
}
.friend-status .status-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--secondary);
    flex-shrink: 0;
}
.friend-row.online .friend-status .status-dot {
    background: var(--success);
}

/* Actions never grow; the name column yields to them. Two icon buttons + a
   kebab, tight enough that a long name still shows on a 320px screen. */
.friend-actions {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    flex: 0 0 auto;
}
.friend-actions .btn-icon {
    width: 40px;
    height: 40px;
    min-width: 40px;
    padding: 0;
}
.friend-actions .btn-small {
    padding: 0.3rem 0.6rem;
    min-height: 36px;
    font-size: 0.8rem;
    white-space: nowrap;
}

/* Kebab overflow menu */
.friend-kebab {
    position: relative;
}
.friend-kebab-menu {
    display: none;
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 2px;
    min-width: 150px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    z-index: 20;
    overflow: hidden;
}
.friend-kebab-menu.open {
    display: block;
}
.friend-kebab-item {
    display: block;
    width: 100%;
    text-align: left;
    padding: 0.7rem 0.9rem;
    background: none;
    border: none;
    color: var(--text);
    font-size: 0.85rem;
    cursor: pointer;
}
.friend-kebab-item:hover {
    background: var(--bg-tertiary);
}
.friend-kebab-item.danger {
    color: #f87171;
}

@media (min-width: 768px) {
    .friend-actions .btn-icon {
        width: 34px;
        height: 34px;
        min-width: 34px;
    }
}
