/* === Repartee Web Base Styles === */

/* Nerd Font for terminal (powerline glyphs, icons) */
@font-face {
    font-family: 'FiraCode Nerd Font Mono';
    src: url('/fonts/FiraCodeNerdFontMono-Regular.ttf') format('truetype');
    font-weight: normal;
    font-style: normal;
    font-display: swap;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
    /* Stable layout-viewport height. Using `100dvh` here caused the page
       to animate frame-by-frame as iOS Safari and Chrome Android
       expanded/collapsed their URL bars and virtual keyboard, which
       triggered our resize handlers on every frame and produced visible
       scroll drift. The lounge uses `100%` for the same reason — the
       chat scroll container fills whatever the layout viewport happens
       to be at startup and stays there. The virtual keyboard then
       either overlays (iOS Safari) or resizes the container (Android
       Chrome with `interactive-widget=resizes-content`, which we
       removed because it added more state changes than it solved). */
    height: 100%;
    background: var(--bg);
    color: var(--fg);
    font-family: 'FiraCode Nerd Font Mono', 'JetBrains Mono', 'Fira Code', 'SF Mono', 'Cascadia Code', monospace;
    /* User-adjustable via the Aa menu (inline --font-size on <html>,
       persisted in localStorage). The fallback here is the desktop default;
       the mobile media block below raises the no-override default to 14px. */
    font-size: var(--font-size, 13px);
    line-height: var(--line-height, 1.35);
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: manipulation;
}

button,
input,
select,
textarea {
    font-family: inherit;
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

/* === Layout === */

.app {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
}

.layout-host {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.responsive-layout {
    display: flex;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.topic-bar {
    background: var(--bg-alt);
    padding: 2px 8px;
    /* Sized by its line box, not a fixed px height — the root font size is
       user-adjustable (Aa menu) and a hard 20px would clip larger fonts. */
    min-height: 20px;
    display: flex;
    align-items: center;
    overflow: hidden;
    white-space: nowrap;
    border-bottom: 1px solid var(--border);
}

.main-area {
    display: flex;
    flex: 1;
    overflow: hidden;
}

/* === Buffer List (left panel) === */

.buffer-list {
    width: 170px;
    background: var(--bg);
    border-right: 1px solid var(--border);
    overflow-y: auto;
    flex-shrink: 0;
    padding: 1px 0;
}

.buffer-list .buffer-item {
    width: 100%;
    padding: 0 6px;
    line-height: var(--line-height, 1.35);
    cursor: pointer;
    display: flex;
    align-items: center;
    gap: 4px;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: inherit;
    text-align: left;
}

.buffer-item .name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.buffer-item .unread-badge {
    flex-shrink: 0;
    font-size: 9px;
    line-height: 1.6;
    padding: 0 5px;
    border-radius: 8px;
    background: rgba(122, 162, 247, 0.18);
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}

/* Buffers of a disconnected network are dimmed at a glance. */
.buffer-item.offline .name { opacity: 0.45; }

.buffer-list .buffer-item:hover { background: rgba(255,255,255,0.03); }

.buffer-list .buffer-item.active {
    background: rgba(122, 162, 247, 0.1);
    border-left: 2px solid var(--accent);
}

.buffer-item .num { color: var(--fg-muted); }
.buffer-item .name { color: var(--fg-dim); }
.buffer-item.type-server { margin-top: 4px; border-top: 1px solid var(--border); padding-top: 2px; }
.buffer-item.type-server:first-child { margin-top: 0; border-top: none; padding-top: 0; }
.buffer-item.type-server .num { color: var(--accent); }
.buffer-item.type-server .name { color: var(--accent); font-weight: bold; }
.buffer-item.type-query .name { color: var(--cyan); }
.buffer-item.type-dcc .name { color: var(--yellow); }
.buffer-item.active .num { color: var(--yellow); }
.buffer-item.active .name { color: var(--bright); font-weight: bold; }
.buffer-item.activity-1 .name { color: var(--green); }
.buffer-item.activity-2 .name { color: var(--red); }
.buffer-item.activity-3 .name { color: var(--yellow); }
.buffer-item.activity-4 .name { color: var(--purple); }

/* === Chat View (center) === */

.chat-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.chat-messages {
    flex: 1;
    overflow-y: auto;
    overflow-x: hidden;
    padding: 2px 0;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    /* The pin in chat_view.rs is the only thing that decides where the
       viewport sits. Browser scroll-anchoring would otherwise fight us
       whenever an image preview decoded or a wrapped line re-measured. */
    overflow-anchor: none;
}

.chat-messages-outer {
    flex: 1;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
}

/* Wrapper for the `<For>` children inside .chat-messages. Kept as a
   single flex column so message rows behave predictably during
   programmatic scroll pins. */
.chat-messages-inner {
    display: flex;
    flex-direction: column;
}

.scroll-bottom-btn {
    position: absolute;
    bottom: 8px;
    right: 12px;
    width: 28px;
    height: 28px;
    border-radius: 50%;
    background: var(--bg-alt);
    border: 1px solid var(--border);
    color: var(--fg-muted);
    font-size: 14px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 5;
    opacity: 0.85;
    transition: opacity 0.15s;
    -webkit-tap-highlight-color: transparent;
}

.scroll-bottom-btn:focus-visible {
    opacity: 1;
}

.scroll-bottom-btn:hover { opacity: 1; }
.scroll-bottom-btn.hidden { display: none; }

/* Chat line — flex row, all items on same baseline.
   No `content-visibility` here: while it skips layout for off-screen
   lines, the deferred measurement makes scrollHeight grow whenever a
   line crosses into the viewport, which fights the scroll pin and was
   visible as up-then-down jitter on mobile. We can afford the full
   1000-row layout cost on every modern browser; thelounge does the
   same. If real-world perf ever justifies it, swap in a windowed
   renderer rather than re-introducing CSS virtualization. */
.chat-line {
    padding: 0 8px;
    display: flex;
    align-items: baseline;
    line-height: var(--line-height, 1.35);
    max-width: 100%;
    overflow: hidden;
}

.chat-line .ts {
    /* ch, not px: the column must scale with the user-adjustable font.
       9ch fits "HH:MM:SS" plus breathing room (≈70px at the 13px default). */
    width: 9ch;
    flex-shrink: 0;
    color: var(--fg-dim);
}
.chat-line .nick {
    flex-shrink: 0;
    text-align: right;
    white-space: nowrap;
}
.chat-line .nick .mode { color: var(--fg-muted); }
.chat-line .nick .name { color: var(--accent); font-weight: bold; cursor: pointer; }
.chat-line .nick .name:hover { text-decoration: underline; }
.chat-line .action-nick { cursor: pointer; }
.chat-line .action-nick:hover { text-decoration: underline; }
.chat-line .nick .sep { color: var(--accent); margin-left: 2px; }
.chat-line .text {
    padding-left: 4px;
    flex: 1;
    min-width: 0;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

/* Own message nick = green */
.chat-line.own .nick .name { color: var(--green); }
.chat-line.own .text { color: var(--bright); }

/* Mention/highlight background */
.chat-line.mention { background: var(--mention-bg); }
.chat-line.mention .text { color: var(--purple); }
.chat-line.highlight { background: var(--highlight-bg); }
.chat-line.highlight .text { color: var(--red); }

/* Mention log: pre-formatted line (mentions buffer) — no timestamp/nick column */
.chat-line.mention-log { background: var(--mention-bg); }
.chat-line.mention-log .mention-log-text { color: var(--purple); }

/* Date/backlog separator: centered, dimmed, no timestamp */
.chat-line.date-separator {
    justify-content: center;
    color: var(--fg-dim);
    padding: 4px 8px;
    opacity: 0.7;
}
.chat-line.date-separator .separator-text {
    text-align: center;
    letter-spacing: 0.5px;
}

/* Events: no nick column — text follows timestamp inline */

.chat-line .join-arrow { color: var(--green); }
.chat-line .part-arrow { color: var(--yellow); }
.chat-line .quit-arrow { color: var(--red); }
.chat-line .nick-arrow { color: var(--purple); }
.chat-line .kick-arrow { color: var(--red); }
.chat-line .kicked-arrow { color: var(--red); }
.chat-line .topic-arrow { color: var(--cyan); }
.chat-line .mode-arrow { color: var(--fg-muted); }
.chat-line .connect-arrow { color: var(--green); }
.chat-line .disconnect-arrow { color: var(--red); }
.chat-line .chghost-arrow { color: var(--purple); }
.chat-line .account-arrow { color: var(--fg-muted); }

/* Event-key-specific text coloring */
.chat-line.join-event { color: var(--green); }
.chat-line.part-event { color: var(--yellow); }
.chat-line.kick-event { color: var(--yellow); }
.chat-line.kicked-event { color: var(--red); font-weight: bold; }
.chat-line.nick-event { color: var(--purple); }
.chat-line.topic-event { color: var(--cyan); }
.chat-line.mode-event { color: var(--fg-muted); }

/* Action: * nick action text */
.chat-line.action { color: var(--yellow); }

/* Notice: -nick- text */
.chat-line.notice { color: var(--cyan); }
.chat-line .notice-body { color: var(--fg-muted); }
.chat-line .notice-nick { color: var(--cyan); }

/* === Nick List (right panel) === */

.nick-list {
    width: 150px;
    background: var(--bg);
    border-left: 1px solid var(--border);
    overflow-y: auto;
    flex-shrink: 0;
    padding: 1px 0;
}

.nick-list .mode-group {
    padding: 0 6px;
    color: var(--fg-muted);
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 1px;
    line-height: 1.6;
    margin-top: 3px;
}

.nick-list .mode-group:first-child { margin-top: 0; }

.nick-list .nick-entry {
    width: 100%;
    padding: 0 6px;
    line-height: var(--line-height, 1.35);
    cursor: pointer;
    border: 0;
    background: transparent;
    color: inherit;
    font-size: inherit;
    text-align: left;
}

.nick-entry .prefix-op { color: var(--green); }
.nick-entry .prefix-voice { color: var(--cyan); }
.nick-entry .prefix-normal { color: var(--fg-muted); }
.nick-entry.away { opacity: 0.4; }

/* === Bottom: Status + Input === */

.bottom-bar {
    background: var(--bg-alt);
    border-top: 1px solid var(--border);
    padding-bottom: env(safe-area-inset-bottom);
    /* Plain flex item — `flex: 0 0 auto` so the bar takes only its
       intrinsic height and the sibling `.chat-messages` (flex: 1)
       fills everything else. No `position: sticky`: sticky inside a
       flex column intermittently detached during the iOS Safari URL-
       bar collapse animation and on Android keyboard open. */
    flex: 0 0 auto;
}

.status-line {
    padding: 1px 8px;
    height: 17px;
    display: flex;
    align-items: center;
    white-space: nowrap;
    overflow: hidden;
    font-size: 12px;
}

.status-line .bracket { color: var(--fg-dim); }
.status-line .sep { color: var(--fg-dim); }
.status-line .nick { color: var(--accent); }
.status-line .muted { color: var(--fg-muted); }
.status-line .act-green { color: var(--green); }
.status-line .act-yellow { color: var(--yellow); }
.status-line .act-red { color: var(--red); }
.status-line .act-purple { color: var(--purple); }
.status-line .act-num { cursor: pointer; }
.status-line button.act-num {
    padding: 0;
    border: 0;
    background: transparent;
    font: inherit;
}
.status-line .act-num:hover { text-decoration: underline; }

.input-line {
    padding: 2px 8px;
    display: flex;
    align-items: center;
    gap: 6px;
    /* Anchor for the completion popup. */
    position: relative;
}

/* === Completion popup (@nick, /command, :emote) === */

.completion-popup {
    position: absolute;
    bottom: 100%;
    left: 8px;
    right: 8px;
    margin-bottom: 4px;
    max-height: 180px;
    overflow-y: auto;
    background: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.35);
    /* Above the chat area, but BELOW the mobile slide-out panels and their
       overlay (z-index 10/11) — an open panel must cover the popup. */
    z-index: 9;
    overscroll-behavior: contain;
}

.completion-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    cursor: pointer;
    color: var(--fg);
    -webkit-tap-highlight-color: transparent;
}

.completion-item.selected,
.completion-item:hover {
    background: rgba(122, 162, 247, 0.15);
}

.completion-emote {
    width: 18px;
    height: 18px;
    object-fit: contain;
}

@media (max-width: 767px) {
    /* Bigger touch targets on phones. */
    .completion-item { padding: 9px 12px; }
    .completion-popup { max-height: 210px; }
}

.input-line .prompt { color: var(--accent); }

.input-line textarea {
    flex: 1;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--fg);
    padding: 4px 8px;
    border-radius: 3px;
    outline: none;
    font-family: inherit;
    font-size: var(--font-size, 13px);
    line-height: var(--line-height, 1.35);
    resize: none;
    overflow: hidden;
    min-height: 0;
}

.input-line textarea:focus { border-color: var(--accent); }

.input-line .send-btn {
    background: var(--accent);
    color: var(--bg);
    border: none;
    padding: 4px;
    border-radius: 3px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    min-height: 28px;
    flex-shrink: 0;
    -webkit-tap-highlight-color: transparent;
}

/* === Login === */

.login-page {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
    gap: 16px;
}

.login-title {
    color: var(--accent);
    font-size: 24px;
}

.login-box {
    background: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 24px;
    min-width: 300px;
    text-align: center;
}

.login-box input {
    width: 100%;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--fg);
    padding: 8px 12px;
    border-radius: 4px;
    outline: none;
    font-family: inherit;
    font-size: 14px;
    margin-bottom: 12px;
}

.login-box button {
    width: 100%;
    background: var(--accent);
    color: var(--bg);
    border: none;
    padding: 8px 16px;
    border-radius: 4px;
    cursor: pointer;
    font-family: inherit;
    font-size: 14px;
}

.login-box .error { color: var(--red); font-size: 12px; margin-top: 8px; }

/* === Mentions Badge === */

.mention-badge {
    color: var(--purple);
    font-size: 10px;
    background: rgba(187, 154, 247, 0.2);
    padding: 0 5px;
    border-radius: 8px;
    cursor: pointer;
    border: 0;
    font-family: inherit;
}

/* === Mobile === */

/* Desktop: hide mobile elements */
@media (min-width: 768px) {
    .mobile-topbar,
    .slide-overlay,
    .slide-panel-left,
    .slide-panel-right { display: none !important; }
}

/* Mobile: hide desktop, show mobile */
@media (max-width: 767px) {
    .responsive-layout {
        display: flex;
        flex-direction: column;
        height: 100%;
        overflow: hidden;
        /* Keep vertical scrolling and pinch zoom native while reserving
           horizontal swipes for the side-panel gesture handler. */
        touch-action: pan-y pinch-zoom;
        overscroll-behavior: none;
    }

    .desktop-topic,
    .desktop-tools { display: none !important; }

    .buffer-list, .nick-list {
        display: none; /* hidden by default, shown inside slide-out panels */
    }

    /* Chat area — vertical scroll only, no horizontal */
    .chat-area {
        overflow: hidden;
        min-width: 0;
    }
    .chat-messages {
        touch-action: pan-y pinch-zoom;
    }

    /* Inline chat layout — no nick column */
    .chat-line {
        display: block;
        padding: 0 6px;
        overflow: hidden;
        overflow-wrap: anywhere;
    }
    .chat-line .ts {
        display: inline;
        width: auto;
        margin-right: 4px;
    }
    .chat-line .nick {
        display: inline;
        width: auto;
        text-align: left;
    }
    .chat-line .text {
        display: inline;
        padding-left: 0;
        overflow-wrap: anywhere;
    }

    /* Mobile top bar — safe-area padding keeps it clear of the notch /
       status bar (viewport-fit=cover extends the page under them). */
    .mobile-topbar {
        display: flex;
        background: var(--bg-alt);
        padding: 4px 8px;
        padding-top: calc(4px + env(safe-area-inset-top));
        align-items: center;
        border-bottom: 1px solid var(--border);
        min-height: 44px;
        flex-shrink: 0;
        touch-action: pan-y pinch-zoom;
    }
    .mobile-topbar .hamburger,
    .mobile-topbar .nicklist-btn {
        color: var(--fg-muted);
        cursor: pointer;
        font-size: 16px;
        min-width: 40px;
        min-height: 40px;
        padding: 6px;
        border: 0;
        background: transparent;
        font-family: inherit;
        -webkit-tap-highlight-color: transparent;
    }
    .mobile-topbar-center {
        flex: 1;
        text-align: center;
        overflow: hidden;
        white-space: nowrap;
        text-overflow: ellipsis;
        padding: 0 8px;
    }
    .mobile-topbar .mobile-chan {
        color: var(--accent);
        font-weight: bold;
        font-size: 13px;
    }
    .mobile-topbar .mobile-topic {
        color: var(--fg-muted);
        font-size: 11px;
    }
    .mobile-topbar-right {
        display: flex;
        gap: 6px;
        align-items: center;
        flex-shrink: 0;
    }

    /* Slide-out overlay — always in DOM, toggled via .visible */
    .slide-overlay {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        z-index: 10;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.2s ease;
    }
    .slide-overlay.visible {
        opacity: 1;
        pointer-events: auto;
    }

    .slide-panel-left {
        position: fixed;
        left: 0; top: 0; bottom: 0;
        width: 220px;
        background: var(--bg-alt);
        border-right: 1px solid var(--border);
        z-index: 11;
        overflow-y: auto;
        transform: translateX(-100%);
        transition: transform 0.2s ease;
        display: flex;
        flex-direction: column;
        touch-action: pan-y pinch-zoom;
        will-change: transform;
        /* Clear the notch / home indicator (viewport-fit=cover). */
        padding-top: env(safe-area-inset-top);
        padding-bottom: env(safe-area-inset-bottom);
        padding-left: env(safe-area-inset-left);
    }
    .slide-panel-left.open { transform: translateX(0); }

    .slide-panel-right {
        position: fixed;
        right: 0; top: 0; bottom: 0;
        width: 180px;
        background: var(--bg-alt);
        border-left: 1px solid var(--border);
        z-index: 11;
        overflow-y: auto;
        transform: translateX(100%);
        transition: transform 0.2s ease;
        display: flex;
        flex-direction: column;
        touch-action: pan-y pinch-zoom;
        will-change: transform;
        /* Clear the notch / home indicator (viewport-fit=cover). */
        padding-top: env(safe-area-inset-top);
        padding-bottom: env(safe-area-inset-bottom);
        padding-right: env(safe-area-inset-right);
    }
    .slide-panel-right.open { transform: translateX(0); }

    .slide-panel-header {
        padding: 8px 10px;
        border-bottom: 1px solid var(--border);
        display: flex;
        align-items: center;
        justify-content: space-between;
        flex-shrink: 0;
    }

    .slide-panel-title {
        color: var(--accent);
        font-weight: bold;
    }

    .slide-panel-count {
        color: var(--fg-muted);
        font-size: 10px;
        margin-left: 6px;
    }

    /* Override desktop buffer-list/nick-list styles inside panels */
    .slide-panel-left .buffer-list,
    .slide-panel-right .nick-list {
        display: block;
        width: auto;
        border: none;
    }

    /* Compact status bar on mobile */
    .status-line { font-size: 11px; }

    .scroll-bottom-btn {
        width: 44px;
        height: 44px;
    }

    .mention-badge {
        min-height: 32px;
        padding-inline: 9px;
    }

    /* Larger no-override default on phones (tester: 13px is too small).
       An explicit --font-size from the Aa menu still wins. */
    html, body { font-size: var(--font-size, 14px); }

    /* Touch-friendly input — never below 16px, which is the threshold that
       stops iOS Safari from auto-zooming the page on focus. */
    .input-line textarea {
        font-size: max(16px, var(--font-size, 14px));
        padding: 6px 8px;
    }
}

/* === Theme switcher === */

/* Shared row for the theme swatches + Aa button in the bottom bar / panel. */
.bar-tools {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    background: var(--bg-alt);
}

.theme-picker {
    display: flex;
    gap: 4px;
    padding: 2px 8px;
    justify-content: center;
    background: var(--bg-alt);
}

/* === Appearance (Aa) menu === */

.appearance-btn {
    font-family: inherit;
    font-size: 11px;
    padding: 0 6px;
    cursor: pointer;
    background: transparent;
    border: 1px solid var(--fg-muted);
    border-radius: 4px;
    color: var(--fg-muted);
    line-height: 1.5;
    -webkit-tap-highlight-color: transparent;
}
.appearance-btn:hover { color: var(--fg); border-color: var(--accent); }

.appearance-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 40;
}

.appearance-modal {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 41;
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    width: min(320px, 92vw);
    background: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
}

.appearance-row {
    display: flex;
    align-items: center;
    gap: 10px;
}

.appearance-label {
    flex: 1;
    color: var(--fg);
    font-size: 13px;
}

.appearance-step {
    width: 32px;
    height: 32px;
    border: 1px solid var(--border);
    border-radius: 6px;
    background: var(--bg);
    color: var(--fg);
    font-size: 16px;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
}
.appearance-step:hover { border-color: var(--accent); }

.appearance-value {
    min-width: 52px;
    text-align: center;
    color: var(--accent);
    font-size: 13px;
    font-variant-numeric: tabular-nums;
}

.appearance-actions {
    display: flex;
    justify-content: space-between;
    gap: 8px;
    margin-top: 2px;
}

.appearance-reset,
.appearance-close {
    padding: 6px 12px;
    border-radius: 6px;
    border: none;
    cursor: pointer;
    font-size: 12px;
    font-family: inherit;
}
.appearance-reset { background: var(--border); color: var(--fg); }
.appearance-close { background: var(--accent); color: var(--bg); font-weight: 600; }

.theme-swatch {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    cursor: pointer;
    border: 1px solid transparent;
    padding: 0;
}

.theme-swatch.active { border-color: var(--accent); }
.theme-swatch:hover { border-color: var(--fg-muted); }

@media (max-width: 767px) {
    .theme-swatch {
        width: 28px;
        height: 28px;
    }
}

/* === Shell terminal view (beamterm WebGL2 canvas) === */

.shell-terminal {
    flex: 1 1 0;
    display: block;
    width: 100%;
    min-height: 0;
    background: #000;
    outline: none;
}

.shell-terminal:focus {
    box-shadow: inset 0 0 0 1px var(--accent);
}

/* === Clickable links === */

.msg-link {
    color: var(--link, #87cefa);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    cursor: pointer;
    word-break: break-all;
}

.msg-link:hover {
    text-decoration-thickness: 2px;
}

/* === Inline built-in emotes (:name:) === */
.emote {
    height: 1.4em;
    width: auto;
    vertical-align: middle;
    margin: 0 1px;
    /* Preserve animated GIF crispness for small pixel-art emotes. */
    image-rendering: auto;
}

/* Visually-hidden ":name:" kept in the DOM so copy/paste and screen readers
   still surface the shortcode for an emote rendered as an <img>. */
.emote-code {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* === Link image previews === */

.msg-previews {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 4px 0 2px 56px; /* indent under the message text column */
}

.msg-preview-card {
    position: relative;
    /* Reserve-upfront: the card occupies its full fixed box from the
       first render, so the async image load never reflows the chat —
       the log must not float while a freshly-switched buffer's
       previews stream in. The image itself starts transparent and
       fades in on load (`.loaded` on the <img>); a failed load
       collapses the card via the inline onerror handler, which
       compensates scrollTop so the reader doesn't feel it (the rare
       path — /api/preview is proxied + cached server-side). */
    display: inline-block;
}

.msg-preview-thumb {
    display: block;
    /* Fixed box reserves layout space BEFORE the image loads, so async
       loads don't reflow the chat (which is anchored to bottom — every
       reflow visibly jumps the scroll position). `object-fit: contain`
       letterboxes images smaller than the box. */
    width: 320px;
    height: 200px;
    border: 1px solid var(--border, rgba(128, 128, 128, 0.25));
    border-radius: 4px;
    background: var(--bg-alt, #111);
    object-fit: contain;
    /* Pixels fade in on decode; the box never moves. */
    opacity: 0;
    transition: opacity 0.2s ease;
}
.msg-preview-thumb.loaded { opacity: 1; }

.msg-preview-dismiss {
    position: absolute;
    top: 2px;
    right: 2px;
    width: 18px;
    height: 18px;
    border: none;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.55);
    color: #fff;
    font-size: 14px;
    line-height: 16px;
    text-align: center;
    cursor: pointer;
    padding: 0;
    opacity: 0;
    transition: opacity 0.15s ease;
}

.msg-preview-card:hover .msg-preview-dismiss {
    opacity: 1;
}

@media (max-width: 720px) {
    .msg-previews { margin-left: 0; }
    .msg-preview-thumb {
        /* Full-width on mobile; `aspect-ratio` reserves vertical space
           proportionally so the layout doesn't jump when the image loads. */
        width: 100%;
        height: auto;
        aspect-ratio: 16 / 10;
    }
    .msg-preview-dismiss {
        width: 32px;
        height: 32px;
        line-height: 30px;
        opacity: 1;
    }
}

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

/* ===== Add-server wizard modal ===== */
.wizard-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.5);
    z-index: 40;
}
.wizard-modal {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(460px, 92vw);
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    background: var(--bg-alt);
    border: 1px solid var(--border);
    border-radius: 10px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
    z-index: 41;
}
.wizard-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border);
}
.wizard-head h3 { margin: 0; font-size: 15px; color: var(--fg); }
.wizard-x {
    cursor: pointer;
    color: var(--fg-muted);
    font-size: 16px;
    border: 0;
    padding: 4px;
    background: transparent;
}
.wizard-x:hover { color: var(--fg); }
.wizard-tabs { display: flex; gap: 4px; padding: 10px 16px 0; }
.wizard-tab {
    padding: 6px 14px;
    border: none;
    background: transparent;
    color: var(--fg-muted);
    cursor: pointer;
    border-radius: 7px 7px 0 0;
    font-size: 13px;
}
.wizard-tab.active { background: var(--bg); color: var(--fg); }
.wizard-body {
    padding: 14px 16px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    overflow-y: auto;
}
.wizard-row { display: flex; flex-direction: column; gap: 4px; }
.wizard-label {
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--fg-muted);
}
.wizard-row input,
.wizard-row select {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 7px 9px;
    color: var(--fg);
    font-size: 13px;
}
.wizard-row input:focus,
.wizard-row select:focus { outline: none; border-color: var(--accent); }
.wizard-check {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--fg);
}
.wizard-error { color: #e06c75; font-size: 12px; margin: 0 16px; }
.wizard-foot {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
    padding: 12px 16px;
    border-top: 1px solid var(--border);
}
.wizard-btn {
    padding: 7px 16px;
    border-radius: 7px;
    border: none;
    cursor: pointer;
    font-size: 13px;
}
.wizard-btn.p { background: var(--accent); color: var(--bg); font-weight: 600; }
.wizard-btn.s { background: var(--border); color: var(--fg); }
.add-network-btn {
    width: calc(100% - 8px);
    margin: 4px;
    border: 1px dashed var(--border);
    background: transparent;
    color: var(--fg-muted);
    border-radius: 6px;
    padding: 5px;
    cursor: pointer;
    font-size: 12px;
}
.add-network-btn:hover { color: var(--accent); border-color: var(--accent); }
.error-toast {
    position: fixed;
    top: 16px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: min(560px, 92vw);
    padding: 10px 14px;
    background: var(--bg-alt);
    border: 1px solid var(--red);
    border-radius: 8px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
    z-index: 60;
}
.error-toast-msg { color: var(--red); font-size: 13px; }
.error-toast-x { cursor: pointer; color: var(--fg-muted); font-size: 14px; }
.error-toast-x { border: 0; padding: 2px; background: transparent; }
.error-toast-x:hover { color: var(--fg); }

/* === Emote / emoji pickers === */
.emote-picker-modal,
.emoji-picker-modal {
    position: fixed;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 41;
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    background: var(--bg-alt);
    border: 1px solid var(--fg-muted);
    border-radius: 8px;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}
.emote-picker-modal { width: min(560px, 92vw); max-height: 70vh; }
.emoji-picker-modal { width: min(420px, 92vw); max-height: 70vh; }

.emote-picker-filter {
    font-family: inherit;
    font-size: 13px;
    padding: 6px 8px;
    background: var(--bg);
    color: var(--fg);
    border: 1px solid var(--fg-muted);
    border-radius: 4px;
}
.emote-picker-filter:focus { outline: none; border-color: var(--accent); }

.emote-picker-grid {
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
    gap: 6px;
}
.emote-picker-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
    padding: 6px;
    cursor: pointer;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    color: var(--fg);
}
.emote-picker-cell:hover { border-color: var(--accent); background: var(--bg); }
.emote-picker-cell img { width: 32px; height: 32px; object-fit: contain; }
.emote-picker-name {
    font-size: 11px;
    color: var(--fg-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 68px;
    white-space: nowrap;
}

.emoji-picker-tabs { display: flex; gap: 4px; flex-wrap: wrap; }
.emoji-tab {
    cursor: pointer;
    background: var(--bg);
    border: 1px solid var(--fg-muted);
    border-radius: 4px;
    color: var(--fg-muted);
    padding: 2px 8px;
    font-size: 12px;
}
.emoji-tab:hover { color: var(--fg); border-color: var(--accent); }
.emoji-picker-grid {
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(34px, 1fr));
    gap: 4px;
}
.emoji-cell {
    cursor: pointer;
    background: transparent;
    border: none;
    font-size: 22px;
    line-height: 1;
    padding: 4px;
    border-radius: 4px;
}
.emoji-cell:hover { background: var(--bg); }

/* Input-line picker buttons */
.input-emote-btn {
    font-family: inherit;
    font-size: 13px;
    padding: 0 8px;
    margin-right: 4px;
    cursor: pointer;
    background: transparent;
    border: 1px solid var(--fg-muted);
    border-radius: 4px;
    color: var(--fg-muted);
}
.input-emote-btn:hover { color: var(--fg); border-color: var(--accent); }

/* Phones provide a system emoji keyboard, so hide the extra picker button. */
@media (max-width: 767px) {
    .input-emote-btn.emoji { display: none; }
}

/* ── Scrollbars ──────────────────────────────────────────────────────────
   Safari/macOS draws thin, auto-hiding overlay scrollbars natively, so the UI
   looked clean there; every other browser fell back to wide, opaque OS
   scrollbars that eat layout width and clash with the theme. Style them to be
   thin, theme-coloured, and reveal only while the pointer is over the scrolling
   area — matching Safari across Chrome, Edge and Firefox. The thumb uses the
   per-theme --fg-muted / --fg-dim tokens, so it adapts to every theme. */

/* Firefox — inherits to every scrollable descendant. It cannot hide the thumb
   on hover, so it shows a permanently-thin themed bar (still far subtler than
   the default).

   Gated behind `@supports not selector(::-webkit-scrollbar)` so ONLY Firefox
   applies it: Chrome/Edge 121+ now support `scrollbar-color`, and when it is set
   they ignore the `::-webkit-scrollbar-*` pseudo-elements entirely — which would
   kill the reveal-on-hover thumb below and leave a permanently-visible bar. The
   feature query keeps WebKit browsers on the pseudo-element path. */
@supports not selector(::-webkit-scrollbar) {
    html {
        scrollbar-width: thin;
        scrollbar-color: var(--fg-muted) transparent;
    }
}

/* WebKit (Chrome, Edge, Safari) — thin track, no arrow buttons, rounded thumb. */
*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}
*::-webkit-scrollbar-track,
*::-webkit-scrollbar-corner {
    background: transparent;
}
*::-webkit-scrollbar-thumb {
    /* Transparent (invisible) by default. The 2px transparent border plus
       background-clip:padding-box insets it into a slim rounded pill when shown. */
    background-color: transparent;
    border: 2px solid transparent;
    border-radius: 8px;
    background-clip: padding-box;
}
/* Reveal while the pointer is over the scrolling area; brighten while dragging. */
*:hover::-webkit-scrollbar-thumb {
    background-color: var(--fg-muted);
}
*::-webkit-scrollbar-thumb:hover,
*::-webkit-scrollbar-thumb:active {
    background-color: var(--fg-dim);
}
