/* ── CSS Variables: Dark theme (default) ─────────────────────────── */

:root, [data-theme="dark"] {
    /* Every legacy token below aliases a foundation token from
       foundation.css. This is a one-way migration step: components
       keep their old names; the palette moves under them. */
    --bg-main:           var(--bg-0);
    --bg-sidebar:        var(--bg-1);
    --bg-input:          var(--bg-2);
    --bg-message-hover:  var(--bg-2);
    --bg-server-rail:    var(--bg-0);
    --bg-elevated:       var(--bg-1);

    --text-primary:      var(--ink-1);
    --text-secondary:    var(--ink-2);
    --text-muted:        var(--ink-3);
    --text-placeholder:  var(--ink-4);

    --accent:            var(--moss-2);
    --accent-hover:      var(--moss-3);
    --accent-glow:       color-mix(in oklab, var(--moss-2) 18%, transparent);
    --accent-subtle:     color-mix(in oklab, var(--moss-2) 8%,  transparent);

    --accent-green:      var(--ok);
    --accent-green-hover:color-mix(in oklab, var(--ok) 80%, black);
    --accent-green-glow: color-mix(in oklab, var(--ok) 18%, transparent);

    --danger:            var(--err);
    --danger-hover:      color-mix(in oklab, var(--err) 80%, black);
    --danger-glow:       color-mix(in oklab, var(--err) 18%, transparent);

    --online:            var(--moss-2);
    --unread:            var(--amber);

    --border:            var(--line);
    --border-subtle:     var(--line-soft);

    --scrollbar-thumb:   var(--bg-3);
    --scrollbar-track:   transparent;

    --shadow-sm:         0 1px 2px rgba(0, 0, 0, 0.2);
    --shadow-md:         0 4px 12px rgba(0, 0, 0, 0.3);
    --shadow-lg:         0 8px 32px rgba(0, 0, 0, 0.4);
    --shadow-inset:      inset 0 1px 3px rgba(0, 0, 0, 0.2);

    /* --focus-ring is owned by foundation.css; redeclaring it here as
       `var(--focus-ring, ...)` introduces a same-selector self-reference
       cycle that resolves to the guaranteed-invalid value, blanking the
       focus ring on every element that consumes it. Foundation already
       defines the token, so style.css inherits it without a redeclare. */

    --overlay-bg:        rgba(0, 0, 0, 0.6);
    --backdrop-blur:     blur(4px);

    --transition-fast:   var(--motion-fast);
    --transition-normal: var(--motion);
    --transition-smooth: var(--motion-slow) var(--motion-ease);
}

/* Legacy alias — IBM Plex Mono is no longer loaded; route to JetBrains Mono
   until components migrate to --font-mono directly. */
code, pre, .peer-id-text, .invite-code-display textarea, .welcome-invite-input {
    font-family: var(--font-mono) !important;
}

/* ── CSS Variables: Light theme ──────────────────────────────────── */

[data-theme="light"] {
    --bg-main: #ffffff;
    --bg-sidebar: #f2f3f5;
    --bg-input: #ebedef;
    --bg-message-hover: #f6f6f7;
    --bg-server-rail: #e3e5e8;
    --bg-elevated: #ffffff;
    --text-primary: #2e3338;
    --text-secondary: #4f5660;
    --text-muted: #747f8d;
    --text-placeholder: #a3a6aa;
    --accent: #5865f2;
    --accent-hover: #4752c4;
    --accent-glow: rgba(88, 101, 242, 0.12);
    --accent-subtle: rgba(88, 101, 242, 0.06);
    --accent-green: #3ba55c;
    --accent-green-hover: #2d8049;
    --accent-green-glow: rgba(59, 165, 92, 0.12);
    --danger: #ed4245;
    --danger-hover: #c73538;
    --danger-glow: rgba(237, 66, 69, 0.12);
    --online: #3ba55c;
    --unread: #f0b232;
    --border: #e3e5e8;
    --border-subtle: #ebedef;
    --scrollbar-thumb: #c7ccd1;
    --scrollbar-track: transparent;
    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.06);
    --shadow-md: 0 4px 12px rgba(0, 0, 0, 0.08);
    --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.12);
    --shadow-inset: inset 0 1px 3px rgba(0, 0, 0, 0.06);
    --focus-ring: 0 0 0 2px var(--accent-glow), 0 0 0 1px var(--accent);
    --overlay-bg: rgba(0, 0, 0, 0.35);
    --backdrop-blur: blur(4px);
    --transition-fast: 0.12s ease;
    --transition-normal: 0.18s ease;
    --transition-smooth: 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}

/* ── Reset & Base ────────────────────────────────────────────────── */

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

html, body {
    width: 100%;
    height: 100%;
    height: 100dvh; /* dynamic viewport height -- respects mobile browser chrome */
    overflow: hidden;
    font-family: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 14px;
    line-height: 1.5;
    color: var(--text-primary);
    background: var(--bg-main);
    -webkit-text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

code, pre, .peer-id-text, .invite-code-display textarea, .welcome-invite-input {
    font-family: 'IBM Plex Mono', 'SF Mono', 'Fira Code', monospace;
}

/* ── Icons ──────────────────────────────────────────────────────── */

.icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    flex-shrink: 0;
}

.icon svg {
    display: block;
    width: 1em;
    height: 1em;
}

/* Size variants */
.icon-sm svg { width: 14px; height: 14px; }
.icon-md svg { width: 18px; height: 18px; }
.icon-lg svg { width: 22px; height: 22px; }

/* ── Focus Visible (accessibility) ───────────────────────────────── */

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

button:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    box-shadow: var(--focus-ring);
}

/* ── App Layout ──────────────────────────────────────────────────── */

.app {
    display: flex;
    width: 100%;
    height: 100%;
    height: 100dvh;
    overflow: hidden;
    position: relative;
}

/* ── Server Rail (Discord-style icon strip) ──────────────────────── */

.server-rail {
    width: 72px;
    min-width: 72px;
    background: var(--bg-server-rail);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 12px 0;
    gap: 8px;
    overflow-y: auto;
}

.server-icon {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    background: var(--bg-input);
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    font-size: 18px;
    font-weight: 600;
    color: var(--text-muted);
    transition: border-radius var(--transition-normal), background var(--transition-normal), color var(--transition-normal), box-shadow var(--transition-normal);
    flex-shrink: 0;
    position: relative;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
}

.server-icon:hover {
    border-radius: 16px;
    background: var(--accent);
    color: white;
    box-shadow: var(--shadow-md);
}

.server-icon.active {
    border-radius: 16px;
    background: var(--accent);
    color: white;
}

/* Active indicator pip on the left side of server icon */
.server-icon.active::before {
    content: '';
    position: absolute;
    left: -12px;
    width: 4px;
    height: 40px;
    background: var(--text-primary);
    border-radius: 0 4px 4px 0;
    transition: height var(--transition-normal);
}

.server-icon:hover:not(.active)::before {
    content: '';
    position: absolute;
    left: -12px;
    width: 4px;
    height: 20px;
    background: var(--text-primary);
    border-radius: 0 4px 4px 0;
    transition: height var(--transition-normal);
}

.server-icon.add-server {
    background: transparent;
    border: 2px dashed var(--text-muted);
    font-size: 24px;
    color: var(--text-muted);
    transition: border-color var(--transition-normal), color var(--transition-normal), background var(--transition-normal);
}

.server-icon.add-server:hover {
    border-color: var(--online);
    color: var(--online);
    background: transparent;
}

.server-icon.add-server:hover::before {
    display: none;
}

.server-rail-divider {
    width: 32px;
    height: 2px;
    background: var(--border);
    border-radius: 1px;
    flex-shrink: 0;
}

/* ── Sidebar ─────────────────────────────────────────────────────── */

.sidebar {
    width: 240px;
    min-width: 240px;
    background: var(--bg-sidebar);
    display: flex;
    flex-direction: column;
    border-right: 1px solid var(--border);
}

.sidebar-header {
    display: flex;
    align-items: center;
    padding: 16px;
    font-size: 16px;
    font-weight: 600;
    border-bottom: 1px solid var(--border);
    letter-spacing: -0.01em;
    min-height: 52px;
    overflow: hidden;
}

/* Truncate long server names in sidebar header */
.sidebar-header span,
.sidebar-header .server-name-text {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    flex: 1;
}

/* ── Channel List ────────────────────────────────────────────────── */

.channel-list {
    flex: 1;
    overflow-y: auto;
    padding: 8px;
}

.channel-list-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 12px 8px;
}

.channel-list-title {
    font-size: 11px;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    font-weight: 600;
}

.channel-add-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 18px;
    cursor: pointer;
    padding: 4px 6px;
    line-height: 1;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.channel-add-btn:hover {
    color: var(--text-primary);
    background: var(--bg-message-hover);
}

.channel-create-input {
    padding: 2px 12px 6px;
}

.channel-type-toggle {
    display: flex;
    gap: 4px;
    margin-bottom: 4px;
}

.type-btn {
    flex: 1;
    padding: 6px 8px;
    font-size: 12px;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-muted);
    cursor: pointer;
    transition: all var(--transition-fast);
    min-height: 32px;
    font-family: inherit;
    font-weight: 500;
    -webkit-tap-highlight-color: transparent;
}

.type-btn.active {
    background: var(--accent);
    border-color: var(--accent);
    color: white;
}

.type-btn:hover:not(.active) {
    border-color: var(--text-muted);
    background: var(--bg-message-hover);
}

.channel-create-input input {
    width: 100%;
    padding: 8px 10px;
    background: var(--bg-input);
    border: 1px solid var(--accent);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    outline: none;
    transition: box-shadow var(--transition-normal);
}

.channel-create-input input:focus {
    box-shadow: var(--focus-ring);
}

/* ── Channel Items ───────────────────────────────────────────────── */

.channel-item {
    padding: 7px 12px;
    border-radius: 6px;
    cursor: pointer;
    color: var(--text-muted);
    display: flex;
    justify-content: space-between;
    align-items: center;
    transition: background var(--transition-fast), color var(--transition-fast), transform var(--transition-fast);
    position: relative;
    margin-left: 4px;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}

.channel-item:hover {
    background: var(--bg-message-hover);
    color: var(--text-secondary);
}

.channel-item:active {
    transform: scale(0.99);
}

.channel-item.active {
    color: var(--text-primary);
    background: var(--bg-input);
}

/* Active channel left indicator bar (Discord-style) */
.channel-item.active::before {
    content: '';
    position: absolute;
    left: -4px;
    top: 50%;
    transform: translateY(-50%);
    width: 3px;
    height: 60%;
    background: var(--accent);
    border-radius: 0 2px 2px 0;
    transition: height var(--transition-normal);
}

.channel-item-right {
    display: flex;
    align-items: center;
    gap: 4px;
}

/* Legacy `.channel-item .unread-badge` amber rule deleted in phase 1f —
 * the `UnreadBadge` atom now owns all badge styling in foundation.css. */

/* Delete button -- hidden by default, visible on hover */
.channel-item .delete-btn {
    display: none;
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 12px;
    cursor: pointer;
    padding: 2px 6px;
    line-height: 1;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
}

.channel-item:hover .delete-btn {
    display: inline-block;
}

.channel-item .delete-btn:hover {
    color: var(--danger);
    background: var(--danger-glow);
}

/* ── User Area & Connection Status ───────────────────────────────── */

.user-area {
    padding: 12px;
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    gap: 8px;
}

.user-area .status-dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: var(--online);
    flex-shrink: 0;
}

.connection-status {
    padding: 10px 14px;
    display: flex;
    align-items: center;
    gap: 10px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-muted);
    background: var(--bg-sidebar);
}

.connection-status .status-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    border: 2px solid var(--bg-sidebar);
    box-shadow: 0 0 0 1px var(--border);
    transition: background var(--transition-normal), box-shadow var(--transition-normal);
}

.connection-status .status-dot.connected {
    background: var(--online);
    box-shadow: 0 0 0 1px var(--online);
}

.connection-status .status-dot.connecting {
    background: var(--warning, #f0b232);
    box-shadow: 0 0 0 1px var(--warning, #f0b232);
    animation: pulse 1.5s ease-in-out infinite;
}

.connection-status .status-dot.disconnected {
    background: var(--danger);
    box-shadow: 0 0 0 1px var(--danger);
}

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

/* ── Main Content ────────────────────────────────────────────────── */

.main-content {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

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

/* ── Loading State ───────────────────────────────────────────────── */

.loading {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100dvh;
    color: var(--text-muted);
    font-size: 16px;
}

/* ── Channel Header ──────────────────────────────────────────────── */

.channel-header {
    padding: 12px 16px;
    font-size: 16px;
    font-weight: 600;
    border-bottom: 1px solid var(--border);
    display: flex;
    justify-content: space-between;
    align-items: center;
    flex-shrink: 0;
    letter-spacing: -0.01em;
    min-height: 48px;
    gap: 8px;
}

.channel-header .peer-count {
    font-size: 12px;
    color: var(--text-muted);
    font-weight: 400;
    white-space: nowrap;
}

/* ── Messages ────────────────────────────────────────────────────── */

.message-list {
    flex: 1;
    overflow-y: auto;
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 0;
}

.message {
    padding: 4px 8px;
    position: relative;
    border-left: 2px solid transparent;
    border-radius: 6px;
    /* `transform` here drives the 200ms snap-back for the swipe
     * gestures (spec §Swipe gestures). `.is-dragging` disables the
     * transition so the translate tracks the finger 1:1. Reduced
     * motion collapses the snap-back to an instant state change. */
    transition:
        background var(--transition-fast),
        border-color var(--transition-fast),
        transform 200ms ease-out;
    cursor: pointer;
    touch-action: pan-y;
}

.message.is-dragging {
    transition: none;
}

@media (prefers-reduced-motion: reduce) {
    .message {
        transition:
            background var(--transition-fast),
            border-color var(--transition-fast);
    }
}

.message:hover {
    background: var(--bg-message-hover);
    border-left-color: var(--accent);
}

.message.mentioned {
    background: rgba(88, 101, 242, 0.08);
    border-left-color: var(--accent);
}

.message.mentioned:hover {
    background: rgba(88, 101, 242, 0.12);
}

.message.long-press-active {
    background: var(--bg-message-hover);
    border-left-color: var(--accent);
    transition: background 0.15s ease;
}

.message .meta {
    display: flex;
    align-items: baseline;
    gap: 8px;
}

.message .author { font-weight: 600; font-size: 14px; }
/* Phase 2a Task 15 — spec §Accessibility / ARIA labels.
   `.author-btn` is the semantic `<button>` wrapper for the display-name —
   the profile-card entry point (see `profile-card.md`). Strip the UA
   default button chrome so the visual reads identical to the previous
   `<span>` while keeping `<button>` semantics for screen readers and
   keyboard users. */
.message .author-btn {
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    cursor: pointer;
    text-align: inherit;
    line-height: inherit;
}
.message .author-btn:focus-visible {
    outline: 2px solid var(--accent, var(--willow, currentColor));
    outline-offset: 2px;
    border-radius: 2px;
}
.message .timestamp { font-size: 11px; color: var(--text-muted); }
.message .edited { font-size: 10px; color: var(--text-placeholder); font-style: italic; }

/* Phase 2a Task 16 — spec §Edge cases:
   - 500-char single-word bodies must wrap without breaking layout →
     `word-break: break-word` + `overflow-wrap: anywhere` + `min-width: 0`
     (the last one lets flex children actually shrink below their
     content size so the break rules apply).
   - Right-to-left paragraphs must pick their own base direction →
     `unicode-bidi: plaintext` + `direction: auto`.
*/
.message .body {
    margin-top: 2px;
    line-height: 1.5;
    word-break: break-word;
    overflow-wrap: anywhere;
    min-width: 0;
    unicode-bidi: plaintext;
    direction: auto;
}
.message .body.deleted { color: var(--text-muted); font-style: italic; }
/* Phase 2a Task 14 — spec §Copy / Deleted placeholder + empty-body
   fallback. Both variants render the same quiet italic stub in
   `--ink-3`; keeping them as distinct classes so test selectors and
   future copy divergence stay clean. */
.message .body--deleted { color: var(--ink-3); font-style: italic; }
.message .body--empty   { color: var(--ink-3); font-style: italic; }

/* ── Reply Preview (Discord-style connected quote) ───────────────── */

.message .reply-preview {
    font-size: 12px;
    color: var(--text-muted);
    padding: 4px 12px 4px 16px;
    margin-bottom: 4px;
    margin-left: 2px;
    border-left: 2px solid var(--border);
    border-radius: 0 4px 4px 0;
    background: var(--accent-subtle);
    position: relative;
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 100%;
}

/* Connected curve indicator for reply */
.message .reply-preview::before {
    content: '';
    position: absolute;
    left: -2px;
    top: 0;
    bottom: 0;
    width: 2px;
    background: var(--accent);
    opacity: 0;
    transition: opacity var(--transition-fast);
}

.message .reply-clickable {
    cursor: pointer;
    transition: color var(--transition-fast), border-left-color var(--transition-fast);
}

.message .reply-clickable:hover {
    color: var(--accent);
    border-left-color: var(--accent);
}

.message .reply-clickable:hover::before {
    opacity: 1;
}

/* ── Message Grouping ────────────────────────────────────────────── */

.message.grouped {
    margin-top: 2px;
}

/* First message in a group gets extra top rounding */
.message:not(.grouped) {
    margin-top: 4px;
    border-radius: 6px 6px 4px 4px;
}

.message:not(.grouped) + .message.grouped {
    border-radius: 4px;
}

/* ── Reactions ───────────────────────────────────────────────────── */

.message .reactions {
    display: flex;
    gap: 6px;
    margin-top: 6px;
    flex-wrap: wrap;
    align-items: center;
}

.message .reaction {
    background: var(--bg-input);
    padding: 3px 10px;
    border-radius: 12px;
    font-size: 13px;
    color: var(--text-secondary);
    border: 1px solid var(--border);
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast), transform var(--transition-fast);
    line-height: 1.4;
    font-family: inherit;
    -webkit-tap-highlight-color: transparent;
    white-space: nowrap;
}

.message .reaction:hover {
    background: var(--accent-subtle, rgba(88,101,242,0.15));
    border-color: var(--accent);
    transform: scale(1.05);
}

.message .reaction:active {
    transform: scale(0.95);
}

/* ── Message Action Bar (dropdown) ────────────────────────────────── */

.message-actions {
    /* Phase 2a Task 12: the action bar is now a *positioning anchor* for
       the hover toolbar + dropdown. The toolbar itself controls its own
       visibility via `.message:hover .message-hover-toolbar` below, so
       `.message-actions` stays mounted at all times (it's inert until the
       toolbar inside flips opacity). This keeps the dropdown's absolute
       positioning stable and avoids layout thrash on hover. */
    position: absolute;
    top: -14px;
    right: 8px;
    z-index: 2;
}

/* ── Phase 2a Task 12 · Desktop hover toolbar ─────────────────────────
   Spec: docs/specs/2026-04-19-ui-design/message-row.md §Hover toolbar.
   Inline-flex row of 26 × 26 IconBtns + thin divider; fades in over
   `--motion-fast` on `.message:hover` / `.message:focus-within`;
   reduced-motion collapses the transition to none (opacity-only state
   change). Hidden on mobile viewports (<=720 px) where the long-press
   action sheet is the entry point. */
.message-hover-toolbar {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    padding: 3px;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: var(--shadow-2);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--motion-fast, 120ms) ease;
}

.message:hover .message-hover-toolbar,
.message:focus-within .message-hover-toolbar {
    opacity: 1;
    pointer-events: auto;
}

.toolbar-btn {
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-radius: 6px;
    padding: 0;
    cursor: pointer;
    color: var(--ink-2);
    font-family: inherit;
    font-size: 13px;
    line-height: 1;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--motion-fast, 120ms) ease,
                color var(--motion-fast, 120ms) ease;
}

.toolbar-btn:hover {
    background: var(--bg-2);
    color: var(--ink-1);
}

.toolbar-btn .icon {
    width: 14px;
    height: 14px;
    font-size: 14px;
}

.toolbar-btn--quick-react {
    font-size: 14px;
}

.toolbar-divider {
    width: 1px;
    align-self: stretch;
    background: var(--line);
    margin: 2px 2px;
}

@media (prefers-reduced-motion: reduce) {
    .message-hover-toolbar {
        transition: none;
    }
    .toolbar-btn {
        transition: none;
    }
}

@media (max-width: 720px) {
    .message-hover-toolbar {
        display: none;
    }
}

/* Legacy trigger (kept for visual regressions + clarity); the hover
   toolbar wraps it now, so these rules only apply when that `.action-
   trigger` appears inside `.message-hover-toolbar` via `.toolbar-btn`. */
.action-trigger {
    background: transparent;
    color: var(--ink-2);
    -webkit-tap-highlight-color: transparent;
}

.action-trigger:hover {
    background: var(--bg-2);
    color: var(--ink-1);
}

.message-dropdown {
    position: absolute;
    top: 100%;
    right: 0;
    background: var(--bg-sidebar);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 4px;
    min-width: 160px;
    z-index: 10;
    box-shadow: var(--shadow-lg);
    animation: dropdownFadeIn 0.12s ease-out;
}

@keyframes dropdownFadeIn {
    from { opacity: 0; transform: translateY(-4px) scale(0.98); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.dropdown-item {
    display: block;
    width: 100%;
    padding: 8px 12px;
    background: transparent;
    border: none;
    color: var(--text-primary);
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    border-radius: 4px;
    font-family: inherit;
    transition: background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.dropdown-item:hover {
    background: var(--bg-input);
}

.dropdown-danger {
    color: var(--danger);
}

.dropdown-danger:hover {
    background: var(--danger-glow);
}

.dropdown-emoji-row {
    display: flex;
    gap: 2px;
    padding: 4px;
    flex-wrap: wrap;
}

.dropdown-emoji-row button {
    background: transparent;
    border: none;
    font-size: 18px;
    padding: 6px;
    cursor: pointer;
    border-radius: 6px;
    transition: background var(--transition-fast), transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.dropdown-emoji-row button:hover {
    background: var(--bg-input);
    transform: scale(1.15);
}

/* ── Mobile Action Sheet (bottom drawer, Discord-style) ──────────── */

.mobile-action-sheet-overlay {
    display: none;
}

.mobile-action-sheet {
    display: none;
}

@media (max-width: 900px) {
    .mobile-action-sheet-overlay {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        z-index: 99;
        opacity: 0;
        pointer-events: none;
        transition: opacity 0.3s ease;
    }

    .mobile-action-sheet-overlay.open {
        opacity: 1;
        pointer-events: auto;
    }

    .mobile-action-sheet {
        display: flex;
        flex-direction: column;
        position: fixed;
        bottom: 0;
        left: 0;
        right: 0;
        z-index: 100;
        background: var(--bg-sidebar);
        border-top: 1px solid var(--border);
        border-radius: 16px 16px 0 0;
        padding: 8px 0;
        padding-bottom: max(8px, env(safe-area-inset-bottom));
        transform: translateY(100%);
        visibility: hidden;
        transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1), visibility 0s 0.3s;
        box-shadow: 0 -4px 20px rgba(0, 0, 0, 0.3);
    }

    .mobile-action-sheet::before {
        content: '';
        width: 36px;
        height: 4px;
        background: var(--text-muted);
        border-radius: 2px;
        margin: 4px auto 8px;
        opacity: 0.4;
    }

    .mobile-action-sheet.open {
        transform: translateY(0);
        visibility: visible;
        transition: transform 0.3s cubic-bezier(0.32, 0.72, 0, 1), visibility 0s 0s;
    }


    .mobile-action-sheet .sheet-item {
        display: block;
        width: 100%;
        padding: 14px 20px;
        background: transparent;
        border: none;
        color: var(--text-primary);
        font-size: 16px;
        text-align: left;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
    }

    .mobile-action-sheet .sheet-item:active {
        background: var(--bg-input);
    }

    /* Phase 2a Task 13 / spec §Long-press action sheet:
       `delete` renders in the foundation `--err` ink. `--danger` is
       the legacy alias that already resolves to `var(--err)` at
       `:root`, so both class names point at the same token.
       `.sheet-item--delete` is the spec-named variant; `.sheet-danger`
       stays for back-compat. */
    .mobile-action-sheet .sheet-danger,
    .mobile-action-sheet .sheet-item--delete {
        color: var(--err);
    }

    /* Trailing `cancel` — separator above, muted ink. Per spec the
       cancel sits at the bottom of the sheet with a clear break from
       the action column above. */
    .mobile-action-sheet .sheet-cancel {
        border-top: 1px solid var(--border);
        margin-top: 4px;
        padding-top: 14px;
        color: var(--text-muted);
    }

    .mobile-action-sheet .sheet-emoji-row {
        display: flex;
        justify-content: center;
        gap: 4px;
        padding: 8px 16px;
        flex-wrap: wrap;
    }

    .mobile-action-sheet .sheet-emoji-row button {
        font-size: 24px;
        padding: 8px;
        background: transparent;
        border: none;
        border-radius: 8px;
        cursor: pointer;
        min-width: 44px;
        min-height: 44px;
    }

    .mobile-action-sheet .sheet-emoji-row button:active {
        background: var(--bg-input);
    }

}

/* On desktop, hide the action sheet entirely */
@media (min-width: 901px) {
    .mobile-action-sheet,
    .mobile-action-sheet-overlay {
        display: none !important;
    }
}

/* ── Edit Bar (above input, similar to reply bar) ────────────────── */

.edit-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 14px;
    margin-bottom: 6px;
    background: var(--bg-input);
    border-left: 3px solid var(--unread);
    border-radius: 6px;
    font-size: 13px;
    color: var(--text-secondary);
    animation: slideDown 0.15s ease-out;
}

.edit-bar-text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.edit-bar-cancel {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 14px;
    padding: 4px 8px;
    margin-left: 8px;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.edit-bar-cancel:hover {
    color: var(--danger);
    background: var(--danger-glow);
}

/* ── Reply Bar (above input) ─────────────────────────────────────── */

.reply-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 14px;
    margin-bottom: 6px;
    background: var(--bg-input);
    border-left: 3px solid var(--accent);
    border-radius: 6px;
    font-size: 13px;
    color: var(--text-secondary);
    animation: slideDown 0.15s ease-out;
}

.reply-bar-text {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.reply-bar-cancel {
    background: transparent;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 14px;
    padding: 4px 8px;
    margin-left: 8px;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.reply-bar-cancel:hover {
    color: var(--danger);
    background: var(--danger-glow);
}

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

/* ── Input Area ──────────────────────────────────────────────────── */

.input-area {
    padding: 12px 16px;
    border-top: 1px solid var(--border);
    flex-shrink: 0;
    background: var(--bg-main);
}

.input-area input, .input-area textarea {
    width: 100%;
    padding: 10px 14px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-primary);
    font-size: 14px;
    font-family: inherit;
    outline: none;
    resize: none;
    box-shadow: var(--shadow-inset);
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
}

.input-area input:focus, .input-area textarea:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring), var(--shadow-inset);
}

.input-area input::placeholder, .input-area textarea::placeholder {
    color: var(--text-placeholder);
}

/* ── Input Row (attach button + input) ───────────────────────────── */

.input-row {
    display: flex;
    align-items: flex-end;
    gap: 0;
}

.input-row .input-area {
    flex: 1;
    min-width: 0;
}

.file-share-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 20px;
    padding: 12px 8px 12px 16px;
    cursor: pointer;
    line-height: 1;
    flex-shrink: 0;
    transition: color var(--transition-fast), transform var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
    border-radius: 8px;
}

.file-share-btn:hover {
    color: var(--text-primary);
    transform: scale(1.1);
}

/* ── File Card (inline file attachment) ──────────────────────────── */

.file-card {
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 12px;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: 400px;
    margin-top: 4px;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.file-card:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.file-card .file-icon {
    font-size: 24px;
    flex-shrink: 0;
}

.file-card .file-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.file-card .file-name {
    color: var(--accent);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.file-card .file-size {
    color: var(--text-muted);
    font-size: 12px;
}

.file-card .download-btn {
    flex-shrink: 0;
    font-size: 16px;
    padding: 6px 10px;
}

/* ── Upload Dialog ───────────────────────────────────────────────── */
/* Spec: docs/specs/2026-04-19-ui-design/files-inline.md §Upload dialog.
   Modal sheet on --bg-1, --line border, radius 12 px, --shadow-2.
   Scrim absorbs click-away dismissal. */

.upload-dialog__scrim {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.45);
    z-index: 900;
}

.upload-dialog {
    position: fixed;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    z-index: 901;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow-2);
    padding: 16px;
    min-width: 360px;
    max-width: 520px;
    width: calc(100vw - 32px);
    max-height: calc(100vh - 64px);
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.upload-dialog__picker {
    display: flex;
    align-items: center;
    gap: 12px;
}

.upload-dialog__browse {
    background: transparent;
    color: var(--ink-0);
    border: 1px solid var(--moss-1);
    border-radius: 8px;
    padding: 8px 14px;
    cursor: pointer;
    font-size: 14px;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--transition-fast);
}

.upload-dialog__browse:hover {
    background: rgba(66, 92, 61, 0.18);
}

.upload-dialog__hint {
    color: var(--ink-2);
    font-size: 13px;
}

.upload-dialog__list {
    list-style: none;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    max-height: 50vh;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.upload-dialog__list:empty {
    display: none;
}

.upload-dialog__row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: rgba(255, 255, 255, 0.02);
}

.upload-dialog__icon {
    color: var(--ink-2);
    font-size: 18px;
    flex-shrink: 0;
}

.upload-dialog__filename {
    flex: 1;
    min-width: 0;
    color: var(--ink-1);
    font-size: 14px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.upload-dialog__size {
    color: var(--ink-2);
    font-size: 12px;
    flex-shrink: 0;
}

.upload-dialog__status {
    color: var(--ink-2);
    font-size: 12px;
    flex-shrink: 0;
    min-width: 70px;
    text-align: right;
}

.upload-dialog__cancel {
    background: transparent;
    border: none;
    color: var(--ink-2);
    cursor: pointer;
    padding: 4px 6px;
    border-radius: 6px;
    flex-shrink: 0;
    transition: color var(--transition-fast), background var(--transition-fast);
}

.upload-dialog__cancel:hover {
    color: var(--ink-0);
    background: rgba(255, 255, 255, 0.06);
}

.upload-dialog__footer {
    display: flex;
    align-items: center;
    gap: 12px;
    padding-top: 8px;
    border-top: 1px solid var(--line);
}

.upload-dialog__spacer {
    flex: 1;
}

.upload-dialog__cancel-all,
.upload-dialog__confirm {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--ink-1);
    border-radius: 8px;
    padding: 8px 14px;
    cursor: pointer;
    font-size: 14px;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--transition-fast), border-color var(--transition-fast),
        color var(--transition-fast);
}

.upload-dialog__cancel-all:hover {
    color: var(--ink-0);
    background: rgba(255, 255, 255, 0.04);
}

.upload-dialog__confirm {
    border-color: var(--moss-1);
    color: var(--ink-0);
}

.upload-dialog__confirm:hover:not([disabled]) {
    background: rgba(66, 92, 61, 0.18);
}

.upload-dialog__confirm[disabled] {
    opacity: 0.5;
    cursor: not-allowed;
}

/* ── Drag Overlay ────────────────────────────────────────────────── */
/* Spec: docs/specs/2026-04-19-ui-design/files-inline.md
   §Drag-and-drop. Full-viewport tint + centered dashed --moss-2
   panel with a 32 px upload icon and `drop to attach` label. Spec
   §Motion: drag overlay crossfades in even under reduced motion. */

.drag-overlay {
    position: fixed;
    inset: 0;
    z-index: 950;
    background: color-mix(in oklab, var(--moss-2) 18%, transparent);
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    animation: willow-drag-overlay-fade 120ms ease-out;
}

@keyframes willow-drag-overlay-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

.drag-overlay__panel {
    border: 2px dashed var(--moss-2);
    border-radius: 14px;
    padding: 32px 56px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    color: var(--ink-0);
    background: rgba(0, 0, 0, 0.25);
}

.drag-overlay__icon {
    font-size: 32px;
    color: var(--ink-0);
}

.drag-overlay__label {
    font-size: 16px;
    color: var(--ink-0);
}

@media (prefers-reduced-motion: reduce) {
    .drag-overlay {
        animation: willow-drag-overlay-fade 1ms linear;
    }
}

/* ── Member List (right sidebar) ─────────────────────────────────── */

/* On desktop, the wrapper is transparent -- member-list renders normally */
.member-list-wrapper {
    display: contents;
}

.members-overlay {
    display: none;
}

.mobile-members-toggle {
    display: none;
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 13px;
    cursor: pointer;
    padding: 6px 10px;
    border-radius: 6px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
    min-height: 36px;
    align-items: center;
    justify-content: center;
}

.mobile-members-toggle:hover {
    color: var(--text-primary);
    background: var(--bg-input);
}

.channel-header-right {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}

.member-list {
    width: 220px;
    min-width: 220px;
    background: var(--bg-sidebar);
    border-left: 1px solid var(--border);
    padding: 16px 12px;
    overflow-y: auto;
}

.member-list h3 {
    font-size: 11px;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 8px;
    margin-top: 16px;
    letter-spacing: 0.06em;
    font-weight: 600;
}

.member-list h3:first-child {
    margin-top: 0;
}

.member-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    border-radius: 6px;
    font-size: 13px;
    flex-wrap: wrap;
    transition: background var(--transition-fast);
    cursor: default;
}

.member-item:hover { background: var(--bg-message-hover); }

.member-item .status-dot {
    width: 10px; height: 10px;
    border-radius: 50%;
    background: var(--online);
    flex-shrink: 0;
    border: 2px solid var(--bg-sidebar);
    box-shadow: 0 0 0 1px var(--border-subtle);
}

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

.member-item .member-name {
    flex-shrink: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}

.member-peer-id {
    font-size: 10px;
    color: var(--text-placeholder);
    font-weight: normal;
    font-family: 'IBM Plex Mono', monospace;
}

/* ── Member Badges (Owner, Trusted) ──────────────────────────────── */

.member-item .badge {
    font-size: 10px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 10px;
    flex-shrink: 0;
    letter-spacing: 0.02em;
    text-transform: uppercase;
}

.member-item .owner-badge {
    background: var(--accent);
    color: white;
    box-shadow: 0 1px 3px rgba(88, 101, 242, 0.3);
}

.member-item .trusted-badge {
    background: var(--online);
    color: white;
    box-shadow: 0 1px 3px rgba(59, 165, 92, 0.3);
}

/* ── Infrastructure / Worker Nodes ────────────────────────────────── */

.infra-header {
    display: flex;
    align-items: center;
    gap: 5px;
}

.infra-header .icon {
    font-size: 12px;
    opacity: 0.6;
}

.worker-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    border-radius: 8px;
    margin-bottom: 2px;
    transition: background var(--transition-fast);
    cursor: default;
    border: 1px solid transparent;
}

.worker-item:hover {
    background: var(--bg-message-hover);
    border-color: var(--border-subtle);
}

.worker-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border-radius: 8px;
    background: var(--accent-subtle);
    color: var(--accent);
    font-size: 15px;
    flex-shrink: 0;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.worker-item:hover .worker-icon {
    background: var(--accent-glow);
}

.worker-item.offline .worker-icon {
    background: var(--bg-input);
    color: var(--text-muted);
}

.worker-info {
    display: flex;
    flex-direction: column;
    min-width: 0;
    flex: 1;
}

.worker-name {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.worker-peer-id {
    font-size: 10px;
    color: var(--text-placeholder);
    font-family: 'IBM Plex Mono', monospace;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.worker-status {
    flex-shrink: 0;
}

.worker-badge {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 10px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 10px;
    letter-spacing: 0.03em;
    text-transform: uppercase;
}

.worker-badge .icon {
    font-size: 10px;
}

.worker-badge.online {
    background: rgba(59, 165, 92, 0.12);
    color: var(--online);
}

.worker-badge.offline {
    background: var(--bg-input);
    color: var(--text-muted);
}

/* ── Member Actions -- visible on hover ──────────────────────────── */

.member-actions {
    display: none;
    gap: 4px;
    width: 100%;
    padding-left: 18px;
    margin-top: 4px;
}

.member-item:hover .member-actions {
    display: flex;
}

.member-actions .btn {
    font-size: 11px;
    padding: 3px 8px;
}

/* ── Settings Panel ──────────────────────────────────────────────── */

.settings-panel {
    flex: 1;
    padding: 32px;
    overflow-y: auto;
    max-width: 700px;
}

.settings-panel h2 {
    font-size: 24px;
    font-weight: 600;
    margin-bottom: 24px;
    letter-spacing: -0.02em;
}

.settings-panel h3 {
    font-size: 15px;
    font-weight: 600;
    margin-bottom: 10px;
    color: var(--text-primary);
}

.settings-panel label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.settings-panel input {
    width: 100%;
    padding: 10px 14px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 14px;
    font-family: inherit;
    margin-bottom: 16px;
    outline: none;
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
}

.settings-panel input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

/* ── Settings Section Cards ──────────────────────────────────────── */

.settings-section {
    margin-bottom: 24px;
    padding: 20px;
    border: 1px solid var(--border-subtle);
    border-radius: 10px;
    background: var(--bg-sidebar);
    transition: border-color var(--transition-normal);
}

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

.settings-section:last-child {
    margin-bottom: 0;
}

.settings-status {
    background: var(--accent-subtle);
    color: var(--accent);
    padding: 10px 14px;
    border-radius: 6px;
    margin-bottom: 20px;
    font-size: 13px;
    font-weight: 500;
    border-left: 3px solid var(--accent);
    animation: slideDown 0.15s ease-out;
}

/* ── Peer ID Display ─────────────────────────────────────────────── */

.peer-id-display {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
}

.peer-id-text {
    flex: 1;
    background: var(--bg-input);
    padding: 10px 12px;
    border-radius: 6px;
    font-size: 11px;
    color: var(--text-secondary);
    word-break: break-all;
    min-width: 0;
    border: 1px solid var(--border-subtle);
    user-select: all;
    cursor: text;
    transition: border-color var(--transition-normal);
}

.peer-id-text:hover {
    border-color: var(--border);
}

/* ── Invite Section ──────────────────────────────────────────────── */

.invite-section,
.join-section {
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--border);
}

.invite-code-display {
    margin-top: 8px;
}

.invite-code-display textarea {
    width: 100%;
    height: 60px;
    padding: 10px 14px;
    background: var(--bg-server-rail);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 11px;
    outline: none;
    resize: none;
    margin-bottom: 4px;
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
    user-select: all;
}

.invite-code-display textarea:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

/* ── Buttons ─────────────────────────────────────────────────────── */

.btn {
    padding: 8px 16px;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    font-size: 14px;
    font-weight: 500;
    font-family: inherit;
    transition: background var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast), transform 0.1s ease;
    position: relative;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
}

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

.btn-primary {
    background: var(--accent);
    color: white;
    box-shadow: 0 1px 3px rgba(88, 101, 242, 0.3);
}

.btn-primary:hover {
    background: var(--accent-hover);
    box-shadow: 0 2px 8px rgba(88, 101, 242, 0.4);
}

.btn-danger {
    background: var(--danger);
    color: white;
    box-shadow: 0 1px 3px rgba(237, 66, 69, 0.3);
}

.btn-danger:hover {
    background: var(--danger-hover);
    box-shadow: 0 2px 8px rgba(237, 66, 69, 0.4);
}

.btn-sm {
    padding: 4px 10px;
    font-size: 12px;
    border-radius: 4px;
}

.empty-state {
    color: var(--text-muted);
    padding: 16px;
    text-align: center;
}

/* ── Role Manager ────────────────────────────────────────────────── */

.role-manager {
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--border);
}

.role-manager-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 0 8px;
}

.role-manager-title {
    font-size: 11px;
    text-transform: uppercase;
    color: var(--text-muted);
    letter-spacing: 0.06em;
    font-weight: 600;
}

.role-add-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 18px;
    cursor: pointer;
    padding: 4px 6px;
    line-height: 1;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.role-add-btn:hover {
    color: var(--text-primary);
    background: var(--bg-message-hover);
}

.role-create-input {
    padding: 2px 0 6px;
}

.role-create-input input {
    width: 100%;
    padding: 8px 10px;
    background: var(--bg-input);
    border: 1px solid var(--accent);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    outline: none;
    transition: box-shadow var(--transition-normal);
}

.role-create-input input:focus {
    box-shadow: var(--focus-ring);
}

.role-item {
    padding: 12px 0;
    border-bottom: 1px solid var(--border-subtle);
}

.role-item:last-child {
    border-bottom: none;
}

.role-item-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.role-name {
    font-weight: 600;
    font-size: 14px;
    color: var(--text-primary);
}

.role-delete-btn {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 14px;
    cursor: pointer;
    padding: 4px 8px;
    line-height: 1;
    border-radius: 4px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.role-delete-btn:hover {
    color: var(--danger);
    background: var(--danger-glow);
}

.permission-toggles {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 14px;
    margin-bottom: 10px;
}

.permission-toggle {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 2px 0;
}

.permission-toggle input[type="checkbox"] {
    accent-color: var(--accent);
    width: 15px;
    height: 15px;
    cursor: pointer;
    margin: 0;
}

.permission-toggle input[type="checkbox"]:disabled {
    cursor: default;
    opacity: 0.5;
}

.role-assign {
    display: flex;
    align-items: center;
    gap: 6px;
    margin-top: 6px;
}

.role-assign-input {
    flex: 1;
    padding: 6px 10px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 12px;
    font-family: inherit;
    outline: none;
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
}

.role-assign-input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

.role-section {
    margin-top: 24px;
    padding-top: 24px;
    border-top: 1px solid var(--border);
}

/* ── Jump-to-Latest Pill ─────────────────────────────────────────── */
/*
 * Spec: docs/specs/2026-04-19-ui-design/message-row.md
 *       §Scroll anchoring (jump-to-latest pill).
 *
 * The pill floats at the bottom-right of the message list when the
 * user is more than 120 px from the bottom. Contents: chevron-down
 * glyph + "jump to latest" label + optional " · {N} new" count.
 * Click smooth-scrolls to bottom and clears the count.
 */

.message-list-container {
    flex: 1;
    position: relative;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.jump-to-latest {
    position: absolute;
    bottom: 16px;
    right: 16px;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 9999px;
    box-shadow: var(--shadow-2);
    color: var(--ink-1);
    font-family: inherit;
    font-size: 12px;
    cursor: pointer;
    z-index: 2;
    -webkit-tap-highlight-color: transparent;
    animation: fadeInUp 0.2s ease-out;
}

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

.jump-to-latest:hover {
    background: var(--bg-2);
}

.jump-to-latest svg {
    width: 14px;
    height: 14px;
    color: var(--ink-2);
}

.jump-to-latest__count {
    color: var(--moss-3);
    font-weight: 500;
}

.jump-to-latest:focus-visible {
    outline: 2px solid var(--focus-ring);
    outline-offset: 2px;
}

@media (max-width: 720px) {
    .jump-to-latest {
        bottom: 80px;
        right: 12px;
    }
}

@media (prefers-reduced-motion: reduce) {
    .jump-to-latest {
        animation: none;
    }
}

/* ── Loading Spinner ─────────────────────────────────────────────── */

.loading-spinner {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 40px 16px;
    color: var(--text-muted);
    font-size: 14px;
}

.spinner {
    width: 32px;
    height: 32px;
    border: 3px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

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

/* ── Scrollbar Theming ───────────────────────────────────────────── */

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: var(--scrollbar-track); }
::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border-radius: 3px;
    transition: background 0.2s;
}
::-webkit-scrollbar-thumb:hover { background: var(--text-muted); }

/* Firefox scrollbar */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) var(--scrollbar-track);
}

/* ── Theme Toggle Button ─────────────────────────────────────────── */

.theme-toggle {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 18px;
    cursor: pointer;
    padding: 6px 8px;
    line-height: 1;
    flex-shrink: 0;
    border-radius: 6px;
    transition: color var(--transition-fast), background var(--transition-fast), transform var(--transition-normal);
    -webkit-tap-highlight-color: transparent;
    min-width: 36px;
    min-height: 36px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.theme-toggle:hover {
    color: var(--text-primary);
    background: var(--bg-input);
    transform: rotate(15deg);
}

/* ── Mute Toggle (settings) ──────────────────────────────────────── */

.settings-checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 12px;
    cursor: pointer;
}

.settings-checkbox input[type="checkbox"] {
    width: auto;
    margin-bottom: 0;
    accent-color: var(--accent);
}

/* ── Mobile Nav Toggle Button ────────────────────────────────────── */

.mobile-nav-toggle {
    display: none;
    background: transparent;
    border: none;
    color: var(--text-primary);
    font-size: 22px;
    padding: 6px 10px;
    cursor: pointer;
    line-height: 1;
    border-radius: 6px;
    transition: background var(--transition-fast), color var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.mobile-nav-toggle:hover {
    background: var(--bg-input);
}

/* ── Overlay for Closing Sidebar on Mobile ───────────────────────── */

.sidebar-overlay {
    display: none;
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    z-index: 9;
    -webkit-backdrop-filter: var(--backdrop-blur);
    backdrop-filter: var(--backdrop-blur);
}

/* ── Message links & embeds ─────────────────────────────────────── */

.message-link {
    color: var(--accent);
    text-decoration: none;
    word-break: break-all;
    transition: color var(--transition-fast);
}

.message-link:hover {
    text-decoration: underline;
    color: var(--accent-hover);
}

.message-embeds {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 8px;
    max-width: 400px;
}

.embed-link {
    display: block;
    border-radius: 8px;
    overflow: hidden;
    border: 1px solid var(--border);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.embed-link:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.embed-image {
    display: block;
    max-width: 100%;
    max-height: 300px;
    object-fit: contain;
    background: var(--bg-input);
    border-radius: 8px;
}

/* ── Typing Indicator ────────────────────────────────────────────── */

.typing-indicator {
    padding: 4px 16px;
    font-size: 12px;
    color: var(--text-muted);
    font-style: italic;
    height: 24px;
    min-height: 24px;
    max-height: 24px;
    display: flex;
    align-items: center;
    gap: 4px;
    flex-shrink: 0;
    overflow: hidden;
}

/* Animated typing dots -- applied via CSS when text is present */
.typing-indicator:not(:empty)::after {
    content: '';
    display: inline-flex;
    width: 20px;
    height: 6px;
    background: radial-gradient(circle, var(--text-muted) 1.5px, transparent 1.5px);
    background-size: 7px 6px;
    background-position: 0 0;
    animation: typingDots 1.4s steps(3) infinite;
    flex-shrink: 0;
}

@keyframes typingDots {
    0% { opacity: 0.3; }
    33% { opacity: 0.6; }
    66% { opacity: 1; }
    100% { opacity: 0.3; }
}

/* ── Server Gear Button ──────────────────────────────────────────── */

.server-gear-btn {
    margin-left: auto;
    background: transparent;
    color: var(--text-muted);
    font-size: 16px;
    padding: 6px 8px;
    border: none;
    border-radius: 6px;
    cursor: pointer;
    transition: color var(--transition-fast), background var(--transition-fast), transform var(--transition-normal);
    -webkit-tap-highlight-color: transparent;
    min-width: 32px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.server-gear-btn:hover {
    color: var(--text-primary);
    background: var(--bg-input);
    transform: rotate(60deg);
}

/* ── Server Settings Link Button ─────────────────────────────────── */

.server-settings-link {
    width: 100%;
    background: var(--bg-input);
    border: 1px solid var(--border);
    color: var(--text-primary);
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.server-settings-link:hover {
    background: var(--accent);
    border-color: var(--accent);
    color: white;
}

/* ── Settings Server Label ───────────────────────────────────────── */

.settings-server-label {
    margin-bottom: 16px;
    font-size: 13px;
}

.settings-server-prefix {
    color: var(--text-muted);
}

.settings-server-name {
    color: var(--text-primary);
    font-weight: 600;
}

.settings-hint {
    color: var(--text-muted);
    font-size: 12px;
    margin: -4px 0 8px;
}

.server-settings-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 20px;
}

.server-settings-header h2 {
    margin: 0;
}


/* ── Extra small screens (< 380px) ──────────────────────────────── */

@media (max-width: 380px) {
    .welcome-card {
        padding: 20px 16px;
    }

    .welcome-card h1 {
        font-size: 22px;
    }

    .welcome-card h1.willow-wordmark {
        font-size: 34px;
    }

    .willow-mark-lg {
        font-size: 38px;
    }

    .welcome-option {
        padding: 16px;
    }

    .channel-header {
        font-size: 14px;
    }

    .settings-panel {
        padding: 12px;
    }
}

/* ── Welcome / Onboarding Screen ─────────────────────────────────── */

.welcome-screen {
    display: flex;
    align-items: safe center;
    justify-content: center;
    min-height: 100vh;
    min-height: 100dvh;
    padding: 48px 20px;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    /* Animated subtle radial gradient background */
    background:
        radial-gradient(ellipse at 20% 50%, var(--accent-glow) 0%, transparent 50%),
        radial-gradient(ellipse at 80% 50%, rgba(59, 165, 92, 0.06) 0%, transparent 50%),
        var(--bg-main);
    animation: welcomeGlow 8s ease-in-out infinite alternate;
}

@keyframes welcomeGlow {
    0% {
        background:
            radial-gradient(ellipse at 20% 50%, var(--accent-glow) 0%, transparent 50%),
            radial-gradient(ellipse at 80% 50%, rgba(59, 165, 92, 0.06) 0%, transparent 50%),
            var(--bg-main);
    }
    50% {
        background:
            radial-gradient(ellipse at 30% 40%, var(--accent-glow) 0%, transparent 55%),
            radial-gradient(ellipse at 70% 60%, rgba(59, 165, 92, 0.08) 0%, transparent 55%),
            var(--bg-main);
    }
    100% {
        background:
            radial-gradient(ellipse at 25% 55%, var(--accent-glow) 0%, transparent 50%),
            radial-gradient(ellipse at 75% 45%, rgba(59, 165, 92, 0.06) 0%, transparent 50%),
            var(--bg-main);
    }
}

.welcome-card {
    background: var(--bg-sidebar);
    border-radius: 16px;
    padding: 48px;
    max-width: 720px;
    width: 100%;
    box-shadow: var(--shadow-lg);
    border: 1px solid var(--border);
    position: relative;
    /* Subtle glow border effect */
    background-image: linear-gradient(var(--bg-sidebar), var(--bg-sidebar)),
        linear-gradient(135deg, var(--accent-glow), transparent 40%, transparent 60%, rgba(59, 165, 92, 0.1));
    background-origin: border-box;
    background-clip: padding-box, border-box;
    animation: cardFadeIn 0.4s ease-out;
}

@keyframes cardFadeIn {
    from { opacity: 0; transform: translateY(12px) scale(0.98); }
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.welcome-card h1 {
    font-size: 32px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 8px;
    text-align: center;
    letter-spacing: -0.03em;
}

.welcome-card .tagline {
    color: var(--text-muted);
    text-align: center;
    margin-bottom: 36px;
    font-size: 15px;
    letter-spacing: -0.01em;
}

.welcome-options {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 24px;
}

.welcome-option {
    background: var(--bg-main);
    border-radius: 12px;
    padding: 24px;
    border: 1px solid var(--border);
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal), transform var(--transition-normal);
}

.welcome-option:hover {
    border-color: var(--border);
    box-shadow: var(--shadow-md);
    transform: translateY(-2px);
}

/* Create option -- accent blue tint on hover */
.welcome-option:first-child:hover {
    border-color: rgba(88, 101, 242, 0.3);
}

/* Join option -- green tint on hover */
.welcome-option:last-child:hover {
    border-color: rgba(59, 165, 92, 0.3);
}

.welcome-option h2 {
    font-size: 18px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 20px;
    letter-spacing: -0.01em;
}

/* Create option heading -- accent color */
.welcome-option:first-child h2 {
    color: var(--accent);
}

/* Join option heading -- green color */
.welcome-option:last-child h2 {
    color: var(--accent-green);
}

.welcome-option label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.welcome-option input {
    width: 100%;
    padding: 10px 14px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 14px;
    margin-bottom: 12px;
    outline: none;
    font-family: inherit;
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
}

.welcome-option input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

.welcome-option input::placeholder {
    color: var(--text-placeholder);
}

.welcome-invite-input {
    width: 100%;
    height: 80px;
    padding: 10px 14px;
    background: var(--bg-server-rail);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 12px;
    outline: none;
    resize: none;
    margin-bottom: 12px;
    transition: border-color var(--transition-normal), box-shadow var(--transition-normal);
    user-select: all;
}

.welcome-invite-input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

.welcome-invite-input::placeholder {
    color: var(--text-placeholder);
}

.welcome-btn {
    width: 100%;
}

/* Join option -- green button instead of blue */
.welcome-option:last-child .btn-primary {
    background: var(--accent-green);
    box-shadow: 0 1px 3px rgba(59, 165, 92, 0.3);
}

.welcome-option:last-child .btn-primary:hover {
    background: var(--accent-green-hover);
    box-shadow: 0 2px 8px rgba(59, 165, 92, 0.4);
}

.welcome-status {
    background: var(--accent-subtle);
    color: var(--accent);
    padding: 10px 14px;
    border-radius: 6px;
    margin-bottom: 12px;
    font-size: 13px;
    font-weight: 500;
    border-left: 3px solid var(--accent);
    animation: slideDown 0.15s ease-out;
}

.welcome-status-error {
    color: var(--danger);
    border-left-color: var(--danger);
    background: var(--danger-glow);
    animation: errorShake 0.3s ease-out;
}

@keyframes errorShake {
    0%, 100% { transform: translateX(0); }
    25% { transform: translateX(-4px); }
    75% { transform: translateX(4px); }
}

.welcome-hint {
    color: var(--text-muted);
    font-size: 12px;
    margin: -4px 0 8px;
    line-height: 1.5;
}

.welcome-peer-id {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 10px 14px;
    margin-bottom: 16px;
    transition: border-color var(--transition-normal);
    cursor: text;
}

.welcome-peer-id:hover {
    border-color: var(--accent);
}

.join-profile-step {
    margin-top: 8px;
    animation: slideDown 0.2s ease-out;
}

.join-profile-buttons {
    display: flex;
    gap: 8px;
    align-items: center;
    margin-top: 12px;
}

.join-profile-buttons .welcome-btn {
    flex: 1;
}

.welcome-peer-id .peer-id-text {
    flex: 1;
    font-size: 11px;
    color: var(--text-secondary);
    word-break: break-all;
    user-select: all;
}

/* ── Welcome hero (brand mark + wordmark + tagline) ──────────────── */

.welcome-hero {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    margin-bottom: 28px;
    animation: willow-pop-in var(--motion-slow) var(--motion-ease);
}

.welcome-hero .tagline {
    margin: 0;
}

.welcome-hero .welcome-greeting {
    margin-top: 14px;
}

.willow-mark-lg {
    color: var(--willow);
    font-size: 56px;
    line-height: 1;
    display: inline-flex;
    filter: drop-shadow(0 4px 16px color-mix(in oklab, var(--willow) 40%, transparent));
}

.willow-wordmark {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 400;
    font-size: 54px;
    line-height: 1.05;
    letter-spacing: -0.02em;
    color: var(--ink-0);
    margin: 4px 0 0;
    text-align: center;
}

/* Override legacy h1 rule inside welcome-card for wordmark only. */
.welcome-card h1.willow-wordmark {
    font-size: 54px;
    font-weight: 400;
    margin-bottom: 0;
    letter-spacing: -0.02em;
}

.welcome-greeting {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 16px;
    color: var(--moss-3);
    margin: 2px 0 0;
    text-align: center;
    animation: willow-pop-in var(--motion) var(--motion-ease);
}

/* ── Welcome step 1 (display name first) ─────────────────────────── */

.welcome-step {
    animation: willow-pop-in var(--motion-slow) var(--motion-ease);
}

.welcome-step--name {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0;
    padding: 8px 0;
    max-width: 380px;
    margin: 0 auto;
}

.willow-mark--small {
    font-size: 52px;
    margin-bottom: 18px;
}

.welcome-name-heading {
    font-family: var(--font-display);
    font-style: italic;
    font-weight: 400;
    font-size: 36px;
    line-height: 1.1;
    letter-spacing: -0.015em;
    color: var(--ink-0);
    margin: 0 0 28px;
    text-align: center;
}

/* Override legacy welcome-card h1 rule. */
.welcome-card h1.welcome-name-heading {
    font-size: 36px;
    font-weight: 400;
    margin: 0 0 28px;
}

.welcome-name-input {
    width: 100%;
    padding: 15px 20px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--ink-0);
    font-family: var(--font-ui);
    font-size: 16px;
    text-align: center;
    outline: none;
    margin-bottom: 14px;
    transition:
        border-color var(--transition-normal),
        box-shadow var(--transition-normal);
}

.welcome-name-input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

.welcome-name-input::placeholder {
    color: var(--text-placeholder);
    font-style: italic;
}

.welcome-continue-btn {
    width: 100%;
    padding: 13px 20px;
    font-size: 15px;
    letter-spacing: 0.02em;
}

/* ── Welcome shared display-name row (above tabs) ─────────────────── */

.welcome-name-row {
    margin-bottom: 16px;
}

.welcome-name-row label {
    display: block;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    margin-bottom: 6px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.welcome-name-row input {
    width: 100%;
    padding: 10px 14px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius-s);
    color: var(--text-primary);
    font-size: 14px;
    outline: none;
    font-family: inherit;
    transition:
        border-color var(--transition-normal),
        box-shadow var(--transition-normal);
}

.welcome-name-row input:focus {
    border-color: var(--accent);
    box-shadow: var(--focus-ring);
}

.welcome-name-row input::placeholder {
    color: var(--text-placeholder);
}

/* Secondary copy inside the join flow (peer-id instructions). */
.welcome-hint--flow {
    margin: 12px 0 12px;
    line-height: 1.5;
}

/* Numbered step list for the join flow. */
.welcome-join-steps {
    list-style: none;
    counter-reset: joinstep;
    padding: 0;
    margin: 12px 0 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.welcome-join-steps li {
    counter-increment: joinstep;
    position: relative;
    padding: 4px 0 4px 36px;
    font-size: 13px;
    color: var(--ink-2);
    line-height: 1.5;
}

.welcome-join-steps li::before {
    content: counter(joinstep);
    position: absolute;
    left: 0;
    top: 2px;
    width: 24px;
    height: 24px;
    border-radius: 999px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--moss-3);
    font-family: var(--font-mono);
    font-size: 11px;
    font-weight: 500;
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Share step — inline controls to the right of the text. */
.welcome-join-steps__share {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

.welcome-join-steps__text {
    flex: 1;
    min-width: 0;
}

.welcome-join-steps__controls {
    display: inline-flex;
    align-items: center;
    gap: 4px;
}

.welcome-join-copied {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-right: 2px;
    padding: 2px 6px;
    border-radius: var(--radius-s);
    background: var(--moss-0);
    color: var(--moss-3);
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.01em;
    animation: welcome-join-copied-in 160ms var(--motion, ease-out);
}

.welcome-join-copied .icon {
    width: 12px;
    height: 12px;
    color: var(--moss-3);
}

@keyframes welcome-join-copied-in {
    from { opacity: 0; transform: translateX(4px); }
    to { opacity: 1; transform: translateX(0); }
}

.welcome-join-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border-radius: var(--radius-s);
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink-2);
    font-size: 14px;
    cursor: pointer;
    transition:
        background var(--motion-fast) var(--motion-ease),
        color var(--motion-fast) var(--motion-ease),
        border-color var(--motion-fast) var(--motion-ease);
}

.welcome-join-icon-btn:hover {
    background: var(--bg-3);
    color: var(--ink-0);
    border-color: var(--moss-2);
}

.welcome-join-icon-btn.active {
    background: var(--moss-0);
    color: var(--moss-3);
    border-color: var(--moss-2);
}

/* Revealed full peer id under the share step. */
.welcome-join-steps__full-id {
    display: block;
    flex-basis: 100%;
    margin-top: 6px;
    padding: 8px 10px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    font-family: var(--font-mono);
    font-size: 11px;
    color: var(--ink-1);
    word-break: break-all;
    user-select: all;
    animation: willow-pop-in var(--motion) var(--motion-ease);
}

/* ── Welcome compact peer-id row ──────────────────────────────────── */

.welcome-peer-compact {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 3px 12px 3px 4px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 999px;
    margin: 0 auto 20px;
    width: fit-content;
    max-width: 100%;
    transition: border-color var(--transition-normal);
}

.welcome-peer-compact:hover {
    border-color: var(--accent);
}

.welcome-peer-compact__label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
    flex-shrink: 0;
}

.welcome-peer-compact .peer-id-text {
    font-size: 11px;
    color: var(--text-secondary);
    user-select: all;
    letter-spacing: 0.02em;
}

.welcome-peer-compact__copy {
    padding: 2px 10px;
    font-size: 11px;
    font-weight: 500;
    text-transform: lowercase;
}

/* ── Welcome tabs (create / join) ─────────────────────────────────── */

.welcome-tabs {
    display: flex;
    gap: 4px;
    padding: 4px;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: var(--radius);
    margin-bottom: 16px;
}

.welcome-tab-btn {
    flex: 1;
    padding: 10px 16px;
    background: transparent;
    border: none;
    border-radius: var(--radius-s);
    color: var(--ink-2);
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.01em;
    transition:
        color var(--motion) var(--motion-ease),
        background var(--motion-fast) var(--motion-ease);
    -webkit-tap-highlight-color: transparent;
}

.welcome-tab-btn:hover:not(.active) {
    color: var(--ink-1);
    background: var(--bg-2);
}

.welcome-tab-btn.active {
    background: var(--bg-3);
    color: var(--ink-0);
    box-shadow: var(--shadow-1);
    position: relative;
}

.welcome-tab-btn.active::after {
    content: "";
    position: absolute;
    left: 20%;
    right: 20%;
    bottom: 4px;
    height: 2px;
    background: var(--moss-2);
    border-radius: 1px;
}

.welcome-tab-panel {
    animation: willow-pop-in var(--motion) var(--motion-ease);
}

.welcome-tab-panel .welcome-option {
    background: var(--bg-main);
    border-radius: var(--radius);
    padding: 24px;
    border: 1px solid var(--border);
}

/* ── Pinned messages panel ─────────────────────────────────────── */

.pinned-panel {
    background: var(--bg-sidebar);
    border-bottom: 1px solid var(--border);
    max-height: 300px;
    overflow-y: auto;
    animation: pinnedSlideDown 0.2s ease-out;
}

@keyframes pinnedSlideDown {
    from { max-height: 0; opacity: 0; }
    to { max-height: 300px; opacity: 1; }
}

.pinned-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 16px;
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    background: var(--bg-sidebar);
    z-index: 1;
}

.pinned-header h3 {
    font-size: 13px;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    margin: 0;
}

.pinned-list {
    padding: 8px;
}

.pinned-item {
    background: var(--bg-main);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 10px 12px;
    margin-bottom: 8px;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.pinned-item:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.pinned-item:last-child {
    margin-bottom: 0;
}

.pinned-meta {
    margin-bottom: 4px;
}

.pinned-author {
    font-weight: 600;
    font-size: 13px;
    color: var(--author-local);
}

.pinned-body {
    font-size: 13px;
    line-height: 1.4;
    color: var(--text-primary);
    margin-bottom: 8px;
    max-height: 80px;
    overflow: hidden;
    position: relative;
}

/* Fade out overflow text */
.pinned-body::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 20px;
    background: linear-gradient(transparent, var(--bg-main));
    pointer-events: none;
}

.pinned-body .message-link {
    color: var(--accent);
}

.pinned-jump {
    font-size: 11px;
    font-weight: 600;
    color: var(--accent);
    background: var(--accent-subtle);
    padding: 4px 10px;
    border-radius: 4px;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.pinned-jump:hover {
    background: var(--accent);
    color: white;
}

.pinned-toggle {
    background: transparent;
    border: none;
    color: var(--text-muted);
    font-size: 16px;
    cursor: pointer;
    padding: 6px 8px;
    border-radius: 6px;
    transition: color var(--transition-fast), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
    min-width: 32px;
    min-height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.pinned-toggle:hover {
    color: var(--text-primary);
    background: var(--bg-input);
}

/* ── Voice Controls ──────────────────────────────────────────────── */

.voice-controls {
    padding: 10px 12px;
    background: var(--accent-green-glow);
    border-top: 1px solid var(--border);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    border-radius: 0;
    position: relative;
}

/* Connected state: subtle green glow */
.voice-controls::before {
    content: '';
    position: absolute;
    inset: 0;
    background: linear-gradient(90deg, var(--accent-green-glow), transparent);
    pointer-events: none;
    border-radius: inherit;
}

.voice-status {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 12px;
    color: var(--online);
    font-weight: 600;
    position: relative;
    z-index: 1;
}

.voice-channel-name {
    color: var(--text-secondary);
    font-weight: 400;
}

.voice-buttons {
    display: flex;
    gap: 4px;
    position: relative;
    z-index: 1;
}

.voice-btn {
    background: var(--bg-input);
    border: 1px solid var(--border);
    font-size: 16px;
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast), box-shadow var(--transition-fast);
    color: var(--text-secondary);
    -webkit-tap-highlight-color: transparent;
}

.voice-btn:hover {
    background: var(--bg-message-hover);
    border-color: var(--text-muted);
}

.voice-btn.muted, .voice-btn.deafened {
    color: var(--danger);
    border-color: var(--danger);
    background: var(--danger-glow);
    box-shadow: 0 0 8px var(--danger-glow);
}

.voice-btn.disconnect {
    color: var(--danger);
    border-color: var(--danger);
}

.voice-btn.disconnect:hover {
    background: var(--danger-glow);
    box-shadow: 0 0 8px var(--danger-glow);
}

/* Voice channel in sidebar */
.voice-channel {
    padding: 7px 12px;
    cursor: pointer;
    color: var(--text-muted);
    border-radius: 6px;
    transition: background var(--transition-fast), color var(--transition-fast);
    margin-left: 4px;
    -webkit-tap-highlight-color: transparent;
}

.voice-channel:hover {
    background: var(--bg-message-hover);
    color: var(--text-secondary);
}

.voice-channel-header {
    display: flex;
    align-items: center;
    gap: 6px;
}

.voice-channel-icon {
    font-size: 14px;
}

.voice-channel-name-sidebar {
    font-size: 14px;
}

.voice-participants-list {
    padding-left: 24px;
    margin-top: 4px;
}

.voice-participant {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 2px 0;
    font-size: 12px;
    color: var(--text-secondary);
}

.voice-participant .status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--online);
}

/* ── Selection highlight (for tap-to-select-all on peer ID) ─────── */

::selection {
    background: var(--accent-glow);
    color: var(--text-primary);
}

::-moz-selection {
    background: var(--accent-glow);
    color: var(--text-primary);
}

/* ── Confirm Dialog ─────────────────────────────────────────────── */
.confirm-overlay {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg);
    backdrop-filter: var(--backdrop-blur);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    animation: fade-in 0.15s ease;
}
.confirm-dialog {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 24px;
    max-width: 400px;
    width: 90%;
    box-shadow: var(--shadow-lg);
    animation: scale-in 0.15s ease;
}
.confirm-dialog h3 { margin-bottom: 8px; font-size: 16px; font-weight: 600; }
.confirm-dialog p { color: var(--text-secondary); font-size: 14px; margin-bottom: 20px; line-height: 1.5; }
.confirm-actions { display: flex; justify-content: flex-end; gap: 8px; }
@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes scale-in { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }

/* ── Settings Tabs ──────────────────────────────────────────────── */

.settings-tabs {
    display: flex;
    gap: 0;
    padding: 0 20px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 0;
    background: transparent;
}

.settings-tabs .tab-btn {
    position: relative;
    padding: 12px 20px;
    background: transparent;
    border: none;
    border-bottom: 2px solid transparent;
    color: var(--text-muted);
    cursor: pointer;
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.01em;
    transition: color var(--transition-normal), border-color var(--transition-normal), background var(--transition-fast);
    -webkit-tap-highlight-color: transparent;
}

.settings-tabs .tab-btn:hover {
    color: var(--text-secondary);
    background: rgba(255, 255, 255, 0.03);
}

.settings-tabs .tab-btn.active {
    color: var(--text-primary);
    border-bottom-color: var(--accent);
    box-shadow: 0 2px 8px var(--accent-glow);
}

/* ── Settings Breadcrumb / Header ──────────────────────────────── */

.settings-panel .server-settings-header {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 20px;
    border-bottom: 1px solid var(--border);
}

.settings-panel .server-settings-header h2 {
    font-size: 15px;
    font-weight: 600;
    color: var(--text-secondary);
    margin: 0;
}

/* Tab content padding */
.settings-tab-content {
    padding: 20px;
}

/* Section spacing inside tabs */
.settings-tab-content .settings-section {
    margin-bottom: 20px;
}

.settings-tab-content .settings-section:last-child {
    margin-bottom: 0;
}

/* Command palette styles live in foundation.css. */

.search-toggle { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 4px 8px; transition: color var(--transition-fast); }
.search-toggle:hover { color: var(--text-primary); }

/* ── Peer ID Copy ───────────────────────────────────────────────── */

.copy-pid-btn { background: transparent; border: none; color: var(--text-muted); cursor: pointer; padding: 4px; font-size: 14px; transition: color var(--transition-fast); }
.copy-pid-btn:hover { color: var(--text-primary); }
.copied-tooltip { position: absolute; background: var(--accent); color: white; font-size: 11px; padding: 3px 8px; border-radius: 4px; white-space: nowrap; animation: tooltip-fade 1.5s ease forwards; pointer-events: none; }
@keyframes tooltip-fade { 0%, 70% { opacity: 1; } 100% { opacity: 0; } }

/* ── Context Menu ────────────────────────────────────────────────── */

.context-menu-overlay { position: fixed; inset: 0; z-index: 998; display: none; }
.context-menu-overlay.open { display: block; }
.context-menu { position: fixed; background: var(--bg-elevated); border: 1px solid var(--border); border-radius: 8px; box-shadow: var(--shadow-lg); padding: 4px; min-width: 160px; z-index: 999; display: none; animation: scale-in 0.1s ease; }
.context-menu.open { display: block; }
.context-menu-item { display: block; width: 100%; padding: 8px 12px; background: transparent; border: none; color: var(--text-primary); cursor: pointer; font-family: inherit; font-size: 13px; text-align: left; border-radius: 4px; transition: background var(--transition-fast); }
.context-menu-item:hover { background: var(--bg-message-hover); }
.context-menu-item.danger { color: var(--danger); }
.context-menu-item.danger:hover { background: var(--danger-glow); }

/* ── Participant Tile ───────────────────────────────────────────── */

.participant-tile {
    position: relative;
    border-radius: 16px;
    overflow: hidden;
    aspect-ratio: 16 / 9;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease, transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
    border: 2px solid rgba(255, 255, 255, 0.06);
    box-shadow: 0 4px 24px rgba(0, 0, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.04);
    animation: tile-enter 0.4s cubic-bezier(0.2, 0, 0.2, 1) backwards;
}

/* Stagger tile entrance animations */
.participant-tile:nth-child(1) { animation-delay: 0s; }
.participant-tile:nth-child(2) { animation-delay: 0.06s; }
.participant-tile:nth-child(3) { animation-delay: 0.12s; }
.participant-tile:nth-child(4) { animation-delay: 0.18s; }
.participant-tile:nth-child(5) { animation-delay: 0.24s; }
.participant-tile:nth-child(6) { animation-delay: 0.3s; }

.participant-tile:hover {
    transform: scale(1.02);
    border-color: rgba(255, 255, 255, 0.12);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), inset 0 1px 0 rgba(255, 255, 255, 0.06);
}

.participant-tile.speaking {
    border-color: var(--online);
    box-shadow: 0 0 0 3px var(--accent-green-glow), 0 0 16px var(--accent-green-glow), 0 4px 24px rgba(0, 0, 0, 0.4);
    animation: speaking-pulse 1.8s ease-in-out infinite;
}

.participant-tile video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
    /* Subtle zoom to avoid black borders from webcam aspect ratios */
    transform: scale(1.01);
}

.participant-tile video.screen-share {
    object-fit: contain;
    background: #0a0a0c;
    transform: none;
}

/* Mirror local camera feed (feels natural like a mirror) */
.participant-tile.local-camera video { transform: scaleX(-1); }

.tile-avatar {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 48px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.85);
    text-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
    /* Subtle noise texture overlay for visual richness */
    position: relative;
}

.tile-avatar::after {
    content: '';
    position: absolute;
    inset: 0;
    background: radial-gradient(ellipse at 30% 20%, rgba(255,255,255,0.06) 0%, transparent 60%);
    pointer-events: none;
}

.tile-name {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    padding: 10px 14px;
    background: linear-gradient(transparent 0%, rgba(0, 0, 0, 0.5) 40%, rgba(0, 0, 0, 0.7) 100%);
    font-size: 13px;
    font-weight: 500;
    color: rgba(255, 255, 255, 0.95);
    letter-spacing: 0.01em;
    display: flex;
    align-items: center;
    gap: 6px;
}

/* Small "sharing screen" or "camera" indicator next to name */
.tile-name .tile-source-badge {
    font-size: 10px;
    background: rgba(255, 255, 255, 0.15);
    padding: 1px 6px;
    border-radius: 4px;
    color: rgba(255, 255, 255, 0.7);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.tile-muted-badge {
    position: absolute;
    bottom: 10px;
    right: 10px;
    width: 26px;
    height: 26px;
    background: rgba(237, 66, 69, 0.9);
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    color: white;
    backdrop-filter: blur(4px);
    box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
}

@keyframes speaking-pulse {
    0%, 100% { box-shadow: 0 0 0 3px var(--accent-green-glow), 0 0 16px var(--accent-green-glow), 0 4px 24px rgba(0, 0, 0, 0.4); }
    50% { box-shadow: 0 0 0 5px var(--accent-green-glow), 0 0 24px var(--accent-green-glow), 0 4px 24px rgba(0, 0, 0, 0.4); }
}

@keyframes tile-enter {
    from { opacity: 0; transform: scale(0.92) translateY(8px); }
    to { opacity: 1; transform: scale(1) translateY(0); }
}

/* ── Call Page ──────────────────────────────────────────────────── */

.call-page {
    display: flex;
    flex-direction: column;
    height: 100%;
    /* Deep ambient gradient — signals "you're in a live session" */
    background:
        radial-gradient(ellipse at 50% 40%, rgba(88, 101, 242, 0.04) 0%, transparent 60%),
        radial-gradient(ellipse at center, #16161a 0%, #0e0e12 100%);
    animation: call-page-enter 0.3s ease;
}

@keyframes call-page-enter {
    from { opacity: 0; }
    to { opacity: 1; }
}

.call-top-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 20px;
    flex-shrink: 0;
    border-bottom: 1px solid rgba(255, 255, 255, 0.04);
}

.call-channel-name {
    font-weight: 600;
    font-size: 15px;
    color: var(--text-primary);
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Subtle live dot next to channel name */
.call-live-dot {
    width: 8px;
    height: 8px;
    background: var(--online);
    border-radius: 50%;
    animation: live-dot-pulse 2s ease-in-out infinite;
}

@keyframes live-dot-pulse {
    0%, 100% { opacity: 1; box-shadow: 0 0 0 0 var(--accent-green-glow); }
    50% { opacity: 0.7; box-shadow: 0 0 0 4px var(--accent-green-glow); }
}

.call-participant-count {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid rgba(255, 255, 255, 0.06);
    border-radius: 12px;
    padding: 3px 12px;
    font-size: 12px;
    color: var(--text-secondary);
    font-weight: 500;
}

.call-timer {
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    font-size: 13px;
    font-family: 'IBM Plex Mono', monospace;
    letter-spacing: 0.02em;
}

.call-layout-toggle {
    background: transparent;
    border: 1px solid rgba(255, 255, 255, 0.08);
    color: var(--text-muted);
    cursor: pointer;
    padding: 6px 8px;
    border-radius: 8px;
    font-size: 16px;
    display: flex;
    align-items: center;
    transition: all var(--transition-fast);
}
.call-layout-toggle:hover {
    color: var(--text-primary);
    border-color: rgba(255, 255, 255, 0.15);
    background: rgba(255, 255, 255, 0.04);
}

.call-grid {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 12px;
    padding: 20px;
    align-content: center;
    overflow-y: auto;
}

/* Single participant: constrain width so it doesn't stretch full-screen */
.call-grid.single-participant {
    justify-content: center;
}
.call-grid.single-participant .participant-tile {
    max-width: 640px;
}

/* Two participants: equal side-by-side */
.call-grid.two-participants {
    grid-template-columns: 1fr 1fr;
}

/* Focus layout */
.call-grid.focus {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.call-grid.focus .participant-tile.focused {
    flex: 1;
    min-height: 0;
    aspect-ratio: auto;
}

.call-thumbnails {
    display: flex;
    gap: 8px;
    overflow-x: auto;
    padding: 4px 0;
    flex-shrink: 0;
    /* Subtle fade at edges for scroll indication */
    mask-image: linear-gradient(90deg, transparent 0%, black 16px, black calc(100% - 16px), transparent 100%);
}

.call-thumbnails .participant-tile {
    width: 160px;
    min-width: 160px;
    height: 100px;
    flex-shrink: 0;
    border-radius: 10px;
    aspect-ratio: auto;
}

/* Control strip — frosted glass floating bar */
.call-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    flex-shrink: 0;
}

.call-controls-bar {
    display: flex;
    align-items: center;
    gap: 6px;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-radius: 20px;
    padding: 8px 12px;
    border: 1px solid rgba(255, 255, 255, 0.06);
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
}

.call-btn {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: none;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    transition: all 0.15s ease;
    position: relative;
}

.call-btn:hover {
    background: rgba(255, 255, 255, 0.14);
    transform: scale(1.06);
}

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

.call-btn.active {
    background: var(--accent);
    color: white;
    box-shadow: 0 0 12px var(--accent-glow);
}

.call-btn.muted {
    background: rgba(237, 66, 69, 0.2);
    color: var(--danger);
}
.call-btn.muted:hover { background: rgba(237, 66, 69, 0.3); }

/* Disconnect button — wider red pill */
.call-btn.disconnect {
    background: var(--danger);
    color: white;
    border-radius: 24px;
    width: auto;
    padding: 0 20px;
    gap: 6px;
    font-size: 14px;
    font-weight: 500;
}
.call-btn.disconnect:hover {
    background: var(--danger-hover);
    box-shadow: 0 0 16px var(--danger-glow);
}

/* Separator between control groups */
.call-controls-separator {
    width: 1px;
    height: 24px;
    background: rgba(255, 255, 255, 0.08);
    margin: 0 4px;
}

/* Tooltip on hover */
.call-btn[title]::after {
    content: attr(title);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    transform: translateX(-50%);
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-size: 11px;
    padding: 4px 8px;
    border-radius: 6px;
    white-space: nowrap;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.15s ease;
    box-shadow: var(--shadow-md);
    border: 1px solid var(--border);
}
.call-btn[title]:hover::after { opacity: 1; }

@media (max-width: 900px) {
    .call-btn { width: 52px; height: 52px; }
    .call-btn[title]::after { display: none; } /* No tooltips on mobile */
    .call-grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 8px; padding: 8px; }
    .call-controls-bar { padding: 6px 10px; }
    .call-top-bar { padding: 10px 12px; }
}

/* ── Join Page ─────────────────────────────────────────────────────── */

.join-page {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--bg-main);
    z-index: 100;
    transition: opacity 0.3s cubic-bezier(0.4, 0, 0.2, 1),
                transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
.join-page.leaving {
    opacity: 0;
    transform: scale(0.98);
    pointer-events: none;
}
.join-page-ambient {
    position: absolute;
    inset: 0;
    background:
        radial-gradient(ellipse at 50% 40%, var(--accent-glow) 0%, transparent 60%);
    opacity: 0.5;
    pointer-events: none;
}
.join-card {
    position: relative;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 16px;
    padding: 40px 32px 32px;
    max-width: 400px;
    width: 90%;
    text-align: center;
    box-shadow: var(--shadow-lg);
    animation: scale-in 0.2s ease;
}
.join-card-brand {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 13px;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    text-transform: lowercase;
    margin-bottom: 24px;
}
.join-card-server {
    font-size: 28px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 0 0 4px;
    line-height: 1.2;
}
.join-card-inviter {
    color: var(--text-muted);
    font-size: 14px;
    margin: 0 0 28px;
}
.join-card-inviter strong {
    color: var(--text-secondary);
}
.join-card-field {
    text-align: left;
    margin-bottom: 20px;
}
.join-card-field label {
    display: block;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-bottom: 6px;
}
.join-card-field input {
    width: 100%;
    padding: 10px 12px;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: 8px;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 15px;
    box-sizing: border-box;
    outline: none;
    transition: border-color var(--transition-fast);
}
.join-card-field input:focus {
    border-color: var(--accent);
}
.join-card-field input:disabled {
    opacity: 0.5;
}
.join-card-btn {
    width: 100%;
    padding: 12px;
    font-size: 15px;
    font-weight: 600;
    border-radius: 8px;
    cursor: pointer;
    transition: all var(--transition-normal);
}
.join-card-btn.connecting {
    cursor: default;
    position: relative;
    border: 2px solid var(--accent);
    background: transparent;
    color: var(--accent);
    animation: join-pulse 2s ease-in-out infinite;
}
@keyframes join-pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
    50% { box-shadow: 0 0 0 8px transparent; }
}
.join-card-hint {
    color: var(--text-muted);
    font-size: 13px;
    margin: 12px 0 0;
}
.join-card-error {
    color: var(--danger);
    font-size: 14px;
    margin: 0 0 12px;
}

/* ── Invite Link Management ────────────────────────────────────────── */

.btn-accent-green {
    background: var(--accent-green);
    color: white;
    border: none;
    padding: 10px 20px;
    border-radius: 8px;
    font-weight: 600;
    cursor: pointer;
    transition: background var(--transition-fast);
}
.btn-accent-green:hover {
    background: var(--accent-green-hover);
}
.invite-link-list {
    margin-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.invite-link-item {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 8px 12px;
    background: var(--bg-input);
    border-radius: 8px;
    font-size: 13px;
}
.invite-link-item.expired {
    opacity: 0.4;
    text-decoration: line-through;
}
.invite-link-uses {
    font-family: 'IBM Plex Mono', monospace;
    font-size: 12px;
    background: var(--bg-main);
    padding: 2px 8px;
    border-radius: 4px;
    color: var(--text-muted);
}
.invite-link-age {
    flex: 1;
    color: var(--text-muted);
    font-size: 12px;
}

/* `<details>` disclosure for the per-link max-uses + expiration inputs.
   Collapsed by default so the common "create link with defaults" flow stays
   a single click. */
.invite-link-options {
    margin-top: 10px;
    font-size: 13px;
}
.invite-link-options > summary {
    cursor: pointer;
    color: var(--text-muted);
    user-select: none;
    padding: 4px 0;
}
.invite-link-options > summary:hover {
    color: var(--text-primary);
}
.invite-link-options__row {
    display: flex;
    gap: 16px;
    margin-top: 8px;
    flex-wrap: wrap;
}
.invite-link-options__label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    color: var(--text-muted);
    font-size: 12px;
}
.invite-link-options__max-uses,
.invite-link-options__expires {
    padding: 4px 8px;
    background: var(--bg-input);
    border: 1px solid var(--border-subtle);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 13px;
}
.invite-link-options__max-uses {
    width: 80px;
}

/* ── Trust-verification — SAS grid + badges + add-friend dialog ──── */
/* Phase 1d. Spec: docs/specs/2026-04-19-ui-design/trust-verification.md */

/* Screen-reader-only utility (used by #trust-live-region and similar). */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
}

.sas-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-family: var(--font-sans, 'IBM Plex Sans', system-ui, sans-serif);
    font-weight: 500;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
}
.sas-label--md { font-size: 11.5px; margin-top: 14px; }
.sas-label--sm { font-size: 10px;   margin-top: 12px; }
.sas-label--you  .sas-label__text { color: var(--moss-2); }
.sas-label--peer .sas-label__text { color: var(--ink-3); }
.sas-label__icon { display: inline-flex; align-items: center; }
.sas-label__icon--matched  svg { color: var(--ok); }
.sas-label__icon--mismatch svg { color: var(--warn); }

.sas-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    border: 1px solid var(--line);
    border-radius: 12px;
    background: transparent;
    padding: 8px;
    transition: border-color var(--motion) var(--motion-ease, ease-out);
}
.sas-grid--md { gap: 6px; padding: 10px; }
.sas-grid--sm { gap: 5px; padding: 8px;  }
.sas-grid--you {
    border-left: 2px solid var(--moss-2);
}
.sas-grid--matched {
    border-color: var(--moss-2);
}
.sas-grid--mismatch {
    border-color: var(--warn);
    border-style: dashed;
    border-width: 1.5px;
}

.sas-cell {
    display: flex;
    align-items: center;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 8px;
    transition: border-color var(--motion) var(--motion-ease, ease-out);
}
.sas-grid--md .sas-cell { padding: 10px 12px; gap: 6px; }
.sas-grid--sm .sas-cell { padding: 8px;       gap: 4px; }
.sas-grid--matched  .sas-cell { border-color: var(--ok);    border-width: 1px; }
.sas-grid--mismatch .sas-cell { border-color: var(--warn);  border-style: dashed; border-width: 1.5px; }

.sas-cell__num {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    color: var(--ink-4);
    user-select: none;
}
.sas-grid--md .sas-cell__num { font-size: 10.5px; }
.sas-grid--sm .sas-cell__num { font-size: 9px;    }

.sas-cell__word {
    font-family: var(--font-mono, 'JetBrains Mono', monospace);
    color: var(--ink-0);
    font-weight: 500;
    letter-spacing: 0.01em;
}
.sas-grid--md .sas-cell__word { font-size: 14px; }
.sas-grid--sm .sas-cell__word { font-size: 12px; }

/* Shimmer skeleton while the session key is being derived. */
@keyframes sas-shimmer {
    0%   { opacity: 0.35; }
    50%  { opacity: 0.65; }
    100% { opacity: 0.35; }
}
.sas-cell--loading {
    animation: sas-shimmer 1200ms ease-in-out infinite;
}

/* ── Trust badges ─────────────────────────────────────────────────── */
.trust-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    box-sizing: border-box;
}
.trust-badge--disk {
    width: 14px;
    height: 14px;
    border-radius: 999px;
}
.trust-badge--disk-12 {
    width: 12px;
    height: 12px;
    border-radius: 999px;
}
.trust-badge--verified {
    background: var(--moss-1);
    color: var(--ink-0);
}
.trust-badge--verified svg { color: var(--moss-3); }
.trust-badge--unverified {
    background: transparent;
    border: 1.5px dashed var(--warn);
    color: var(--warn);
    font-family: var(--font-mono, monospace);
    font-size: 9px;
    line-height: 1;
}
.trust-badge--pending {
    background: transparent;
    color: var(--warn);
    font-family: var(--font-mono, monospace);
    font-size: 10px;
}
.trust-badge--new {
    background: color-mix(in oklab, var(--moss-1) 60%, transparent);
    color: var(--moss-3);
}
.trust-badge--new svg { color: var(--moss-3); }
.trust-badge--downgrade {
    background: transparent;
    border: 1.5px dashed var(--warn);
    color: var(--warn);
}
.trust-badge--pill {
    width: auto;
    padding: 3px 8px 3px 7px;
    border-radius: 999px;
    background: color-mix(in oklab, var(--bg-0) 60%, transparent);
    color: var(--moss-3);
    font-family: var(--font-mono, monospace);
    font-size: 11px;
    gap: 4px;
    backdrop-filter: blur(6px);
}
.trust-badge--pill.trust-badge--unverified {
    color: var(--warn);
    background: color-mix(in oklab, var(--bg-0) 60%, transparent);
}
.trust-badge--tile-corner {
    background: color-mix(in oklab, var(--bg-0) 60%, transparent);
    padding: 2px;
    border-radius: 999px;
}

.trust-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 8px;
    border-radius: 999px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--warn);
    font-family: var(--font-mono, monospace);
    font-size: 11px;
    cursor: pointer;
    min-height: 22px;
}
.trust-chip:hover { background: var(--bg-3); }
.trust-chip:focus-visible { outline: none; box-shadow: var(--focus-ring); }
@media (max-width: 720px) {
    .trust-chip {
        min-height: 44px;
        min-width: 44px;
        padding: 10px 14px;
    }
}

/* ── Add-friend dialog (compare-fingerprints flow) ────────────────── */
.add-friend__backdrop {
    position: fixed;
    inset: 0;
    background: var(--overlay-bg, rgba(0, 0, 0, 0.6));
    backdrop-filter: var(--backdrop-blur, blur(4px));
    z-index: 1100;
}
.add-friend__dialog {
    position: fixed;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    z-index: 1101;
}
.add-friend__card {
    pointer-events: auto;
    width: min(880px, 94vw);
    max-height: 92vh;
    overflow: auto;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-l, 18px);
    box-shadow: var(--shadow-2, 0 24px 60px rgba(0, 0, 0, 0.35));
    padding: 24px;
    display: flex;
    flex-direction: column;
    gap: 20px;
}
.add-friend__title {
    font-family: var(--font-serif, 'Playfair Display', serif);
    font-size: 28px;
    font-style: italic;
    color: var(--ink-0);
    margin: 0;
}
.add-friend__intro {
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.55;
    max-width: 720px;
    margin: 0;
}
.add-friend__grid {
    display: grid;
    gap: 20px;
    grid-template-columns: 1fr 1fr;
}
@media (max-width: 720px) {
    .add-friend__grid { grid-template-columns: 1fr; }
    .add-friend__grid > .add-friend__card-peer { order: -1; }
}
.add-friend__panel {
    display: flex;
    flex-direction: column;
    gap: 12px;
    padding: 16px;
    background: var(--bg-0);
    border: 1px solid var(--line);
    border-radius: var(--radius, 12px);
}
.add-friend__panel-head {
    display: flex;
    align-items: center;
    gap: 10px;
}
.add-friend__avatar {
    width: 36px; height: 36px;
    border-radius: 999px;
    background: var(--bg-2);
    color: var(--ink-1);
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
@media (max-width: 720px) {
    .add-friend__avatar { width: 32px; height: 32px; }
}
.add-friend__identity { display: flex; flex-direction: column; }
.add-friend__identity-label { color: var(--ink-1); font-weight: 500; font-size: 14px; }
.add-friend__identity-meta  { color: var(--ink-3); font-size: 12px; margin-top: 2px; }
.add-friend__ctas {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    justify-content: flex-end;
}
@media (max-width: 720px) {
    .add-friend__ctas { flex-direction: column; align-items: stretch; }
}
.add-friend__cta-primary {
    background: var(--moss-2);
    color: #14130f;
    border: none;
    border-radius: var(--radius-s, 8px);
    padding: 10px 18px;
    font-weight: 500;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 40px;
}
.add-friend__cta-primary:hover { background: var(--moss-3); }
.add-friend__cta-primary:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.add-friend__cta-secondary {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--ink-2);
    border-radius: var(--radius-s, 8px);
    padding: 10px 18px;
    font-weight: 500;
    cursor: pointer;
    min-height: 40px;
}
.add-friend__cta-secondary:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.add-friend__reassurance {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    color: var(--ink-3);
    font-size: 12px;
    line-height: 1.6;
    max-width: 720px;
}
.add-friend__reassurance svg { color: var(--ink-3); flex-shrink: 0; margin-top: 2px; }

/* Mobile: sheet treatment. The bottom-sheet primitive owns its own
   rise animation; we just tweak padding and the peer-card-first order. */
.add-friend__card--mobile {
    width: 100%;
    max-width: 100vw;
    border-radius: var(--radius-l, 18px) var(--radius-l, 18px) 0 0;
}

/* Confirm-match / confirm-mismatch panel replacements. */
.add-friend__confirm {
    display: flex;
    flex-direction: column;
    gap: 10px;
}
.add-friend__confirm-title {
    font-family: var(--font-serif, 'Playfair Display', serif);
    font-size: 22px;
    font-style: italic;
    color: var(--ink-0);
    margin: 0;
}
.add-friend__confirm-body {
    color: var(--ink-1);
    font-size: 14px;
    line-height: 1.55;
    max-width: 520px;
    margin: 0;
}

/* ── Long-press ring (mobile avatar) ──────────────────────────────── */
.sas-press-ring {
    position: absolute;
    inset: -3px;
    border-radius: 999px;
    border: 2px solid var(--moss-2);
    pointer-events: none;
    opacity: 0;
    transform: scale(0.8);
    transition: opacity var(--motion-fast) var(--motion-ease, ease-out),
                transform var(--motion) var(--motion-ease, ease-out);
}
.sas-press-ring--growing {
    opacity: 1;
    transform: scale(1);
}
.sas-press-ring--armed {
    border-color: var(--moss-3);
}
@media (prefers-reduced-motion: reduce) {
    .sas-press-ring { transform: none !important; }
    .sas-press-ring--growing { opacity: 1; }
}

.long-press-avatar {
    position: relative;
    display: inline-flex;
}
.long-press-avatar > :focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: 999px;
}

/* ── Holder pill + holder list ────────────────────────────────────── */
.holder-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 10px;
    border-radius: 999px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink-2);
    font-family: var(--font-mono, monospace);
    font-size: 11.5px;
    cursor: pointer;
    min-height: 22px;
}
.holder-pill:hover { background: var(--bg-3); }
.holder-pill[aria-pressed="true"],
.holder-pill--active { background: var(--moss-1); color: var(--ink-0); }
.holder-pill:focus-visible { outline: none; box-shadow: var(--focus-ring); }
@media (max-width: 720px) {
    .holder-pill { min-height: 44px; padding: 10px 14px; }
}
.holder-pill svg { color: var(--ink-3); }

.holder-list {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 12px;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: var(--radius, 12px);
    box-shadow: var(--shadow-2, 0 12px 32px rgba(0, 0, 0, 0.3));
    min-width: 280px;
}
.holder-list__title {
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
    margin: 0 0 4px 0;
}
.holder-list__row {
    display: flex;
    align-items: center;
    gap: 10px;
}
.holder-list__avatar {
    width: 28px;
    height: 28px;
    border-radius: 999px;
    background: var(--bg-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-weight: 600;
    color: var(--ink-1);
    font-size: 12px;
}
.holder-list__name {
    flex: 1;
    color: var(--ink-1);
    font-size: 13px;
}
.holder-list__rotation {
    font-family: var(--font-mono, monospace);
    font-size: 11px;
    color: var(--ink-4);
}
.holder-list__self {
    margin-top: 6px;
    padding: 10px 12px;
    background: var(--bg-2);
    border-radius: var(--radius-s, 8px);
    color: var(--ink-2);
    font-size: 12px;
}

.crypto-strip {
    display: flex;
    gap: 10px;
    padding: 6px 12px;
    color: var(--ink-3);
    font-family: var(--font-mono, monospace);
    font-size: 11px;
    border-bottom: 1px solid var(--line);
    background: var(--bg-1);
}

/* ── Downgrade / re-verify banner ─────────────────────────────────── */
.downgrade-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    padding: 12px 14px;
    background: color-mix(in oklab, var(--warn) 12%, var(--bg-1));
    border: 1px dashed var(--warn);
    border-radius: var(--radius, 12px);
    color: var(--ink-1);
    margin: 12px;
}
.downgrade-banner__icon svg { color: var(--warn); }
.downgrade-banner__copy { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 200px; }
.downgrade-banner__title { color: var(--ink-0); font-size: 14.5px; font-weight: 500; }
.downgrade-banner__body  { color: var(--ink-1); font-size: 14px; line-height: 1.5; }
.downgrade-banner__actions { display: flex; gap: 8px; flex-shrink: 0; }

/* Participant tile corner placement. */
.tile-trust-corner {
    position: absolute;
    top: 6px;
    left: 6px;
    z-index: 2;
}

/* Holder pill slot in the channel header. */
.mph-holder {
    position: relative;
    display: inline-flex;
    align-items: center;
    margin-right: 10px;
}
.mph-holder-popover {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 40;
}

/* Live region is visually hidden but must preserve announcement layout. */
#trust-live-region { position: absolute; }

/* ── Reduced Motion ──────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
    }
    .sas-grid { transition: none; }
    .sas-cell { transition: none; }
    .sas-press-ring { transition: opacity var(--motion-fast) ease; transform: none; }
}

/* ── Phase 2a · density-aware message padding ──────────────────────────── */
/*
 * `.message` consumes the `--msg-pad` foundation token so density-cozy /
 * density-balanced / density-dense variants (see `foundation.css`) drive
 * row height uniformly. Collapsed (grouped) rows compress to a 1px block
 * pad so runs of same-author messages stay visually tight without losing
 * the inline-hover timestamp surface added below.
 */
.message { padding: var(--msg-pad); }
.message.grouped { padding-block: 1px; }

/* Collapsed-row hover timestamp. The span lives inside the collapsed
 * MessageView where the avatar column would be; CSS hides it off-hover
 * so it only surfaces when the user targets the row. */
.message .run-hover-ts {
    position: absolute;
    right: 8px;
    top: 50%;
    transform: translateY(-50%);
    font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
    font-size: 10px;
    line-height: 1;
    color: var(--ink-3);
    background: color-mix(in oklab, var(--bg-0) 85%, transparent);
    padding: 2px 6px;
    border-radius: 4px;
    opacity: 0;
    transition: opacity var(--transition-fast);
    pointer-events: none;
    user-select: none;
    z-index: 1;
}
.message.grouped:hover .run-hover-ts {
    opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
    .message .run-hover-ts { transition: none; }
}

/* ── Phase 2a · day separator ──────────────────────────────────────────── */
/*
 * Renders between messages whose local dates differ. Centered em-dashed
 * label flanked by 1px rules that flex to fill the row. Copy in the
 * `<em>` is built as `— {label} —` by the component; the CSS here only
 * lays out geometry + typography. Spec:
 * `docs/specs/2026-04-19-ui-design/message-row.md` §Day separator.
 */
.day-separator {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 18px 24px 10px;
}
.day-separator .rule {
    flex: 1;
    height: 1px;
    background: var(--line);
}
.day-separator em {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 11px;
    color: var(--ink-3);
    text-transform: uppercase;
    letter-spacing: 1.2px;
    flex: 0 0 auto;
}
@media (max-width: 720px) {
    .day-separator { padding: 16px 16px 8px; }
}

/* ── Mention pill (phase 2a task 3) ─────────────────────────────────
   Rendered inline inside `.message .body` by `parse_mentions`. Peer
   variant uses moss colour-mix; self variant uses amber. Foundation
   tokens only (`--moss-1/2/3`, `--amber`, `--amber-soft`, `--bg-2`,
   `--radius-s`) — see `foundation.css`. */
.mention-pill {
    display: inline-flex;
    align-items: baseline;
    padding: 1px 6px;
    border-radius: var(--radius-s, 5px);
    font: inherit;
    font-weight: 500;
    cursor: pointer;
    background: color-mix(in oklab, var(--moss-2) 22%, var(--bg-2));
    color: var(--moss-3);
    border: 1px solid var(--moss-1);
    vertical-align: baseline;
}
.mention-pill--self {
    background: color-mix(in oklab, var(--amber) 28%, var(--bg-2));
    color: var(--amber);
    border-color: var(--amber-soft);
}

/* Phase 2a Task 4 — Self-mention row highlight.
   Per `docs/specs/2026-04-19-ui-design/message-row.md` §Row states and
   §Self-mention row highlight: 8% amber row tint + 2px amber left rule
   when `mentions_me(msg, local)` is true. Applied as a modifier so it
   composes with `.message.grouped` (collapsed rows still carry the
   amber cue on every row of the run). */
.message.message--mention {
    background: color-mix(in oklab, var(--amber) 8%, transparent);
    box-shadow: inset 2px 0 0 var(--amber);
}

/* Phase 2a Task 6 — Pinned row marker.
   Per `docs/specs/2026-04-19-ui-design/message-row.md` §Pins — "pin is
   a quiet mark": a 1px amber left rule (not the 2px accent used by
   mentions / whispers) plus a `pinned` badge in the author meta row.
   Pinned rows always break a run so the badge is visible (see
   `components/chat.rs` run-break predicate). */
.message.message--pinned {
    box-shadow: inset 1px 0 0 var(--amber);
}
/* When a row is both a self-mention and pinned, let the mention's
   2 px rule win (stronger cue). The amber colour is shared, so the
   visual is a single uninterrupted amber rule. */
.message.message--pinned.message--mention {
    box-shadow: inset 2px 0 0 var(--amber);
}

.pinned-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0 6px;
    font-size: 11px;
    color: var(--amber);
    border: 1px solid var(--amber-soft);
    border-radius: 9999px;
    line-height: 1.6;
    vertical-align: middle;
}
.pinned-badge svg {
    width: 12px;
    height: 12px;
}

/* ── Queue notes — phase 2a task 7 ─────────────────────────────────
   Spec: `docs/specs/2026-04-19-ui-design/message-row.md` §Queue notes
   / §Copy queue notes.
   * `message--pending` (local-author Pending) dims the row to 0.7
     opacity with a 180 ms transition, so delivery ack will fade the
     row back to full opacity when the projection flips queue_note
     back to None.
   * `.queue-note` inline hint below the body — italic 11.5 px, with
     `--amber` for LateArrival (paired with a 10 px hourglass glyph)
     and `--ink-3` for Pending (no glyph).
   * `.queued-badge` is the compact meta-row badge paired with
     pinned-badge; hourglass glyph + literal "queued" text,
     `--ink-3` on `--line`-bordered pill (spec §Badges). */
.message.message--pending {
    opacity: 0.7;
    transition: opacity 180ms ease-out;
}

.queue-note {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 2px;
    font-style: italic;
    font-size: 11.5px;
}
.queue-note--late { color: var(--amber); }
.queue-note--pending { color: var(--ink-3); }
.queue-note svg { width: 10px; height: 10px; }

.queued-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0 6px;
    font-size: 11px;
    color: var(--ink-3);
    border: 1px solid var(--line);
    border-radius: 9999px;
    line-height: 1.6;
    vertical-align: middle;
}
.queued-badge svg { width: 12px; height: 12px; }

/* ── Whisper hand-off placeholder — phase 2a task 8 ────────────────
   Spec: `docs/specs/2026-04-19-ui-design/message-row.md` §Whisper
   hand-off. Reserves the row styling surface so that when
   `whisper-mode.md` lands and the projection flips
   `DisplayMessage.whisper` to `true`, the row renders the violet
   rule, tinted background, and italic body described by the spec
   without additional work. Whisper rows never collapse into a run
   (see the run-break predicate in `components/chat.rs`), so the
   `whisper-badge` in the meta row is always visible. */
.message.message--whisper {
    box-shadow: inset 2px 0 0 var(--whisper);
    background: color-mix(in oklab, var(--whisper) 8%, transparent);
}
.message.message--whisper .body {
    color: var(--ink-2);
    font-style: italic;
}

.whisper-badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0 6px;
    font-size: 11px;
    color: var(--whisper);
    border: 1px solid var(--whisper);
    background: color-mix(in oklab, var(--whisper) 12%, transparent);
    border-radius: 9999px;
    line-height: 1.6;
    vertical-align: middle;
}
.whisper-badge svg { width: 12px; height: 12px; }

/* ── Code — inline + fenced (phase 2a task 5) ───────────────────────
   Spec: `docs/specs/2026-04-19-ui-design/message-row.md` §Inline
   artefacts (fenced code + inline code paragraphs) and §Code.
   * Inline: mono pill on `--bg-2` / `--line` / `--ink-1`, 3 px radius,
     `0 4px` padding. Parsed from single-backtick spans.
   * Fenced: `<pre>` on `--bg-0` with `--line` border, 8 px radius,
     `8px 12px` padding, mono M (12 px), `--ink-2`, `white-space:
     pre-wrap`, `max-width: 520px`. Fence language parsed but unused
     in v1 (no syntax highlighting).
   * Copy IconBtn 24×24 pinned top-right, revealed on block hover on
     desktop; always visible on mobile for tap surface. Icon flips to
     a check for 900 ms after copy — driven by the `copied` signal
     in `FencedCodeBlock`, not a CSS transition.
   * Mobile overrides (spec §Message row — mobile): mono 11 px,
     `6px 10px` padding. */
.code-inline {
    font-family: var(--font-mono, monospace);
    font-size: 0.85em;
    padding: 0 4px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 3px;
    color: var(--ink-1);
}
.code-fenced {
    position: relative;
    background: var(--bg-0);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 8px 12px;
    margin-top: 8px;
    max-width: 520px;
    font-family: var(--font-mono, monospace);
    font-size: 12px;
    line-height: 1.5;
    color: var(--ink-2);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.code-fenced > code {
    background: none;
    border: none;
    padding: 0;
    color: inherit;
    font: inherit;
}
.code-copy-btn {
    position: absolute;
    top: 6px;
    right: 6px;
    width: 24px;
    height: 24px;
    padding: 0;
    display: none;
    align-items: center;
    justify-content: center;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 4px;
    color: var(--ink-2);
    cursor: pointer;
}
.code-fenced:hover .code-copy-btn {
    display: flex;
}
@media (max-width: 720px) {
    .code-fenced {
        font-size: 11px;
        padding: 6px 10px;
    }
    /* Mobile has no hover — expose the copy button as a tap surface. */
    .code-copy-btn {
        display: flex;
    }
}

/* ── Phase 2a — Empty / cleared / loading states ─────────────────────
   Message-list empty surfaces, per
   `docs/specs/2026-04-19-ui-design/message-row.md` §Empty / loading
   states. Three variants: never-had-messages (leaf + copy), cleared
   (after deletions), and the loading skeleton. The `shimmer` keyframe
   lives in `foundation.css` and is auto-disabled under reduced motion
   so skeletons degrade to static `--bg-2` rectangles. */

.chat-empty,
.chat-cleared {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 60vh;
    padding: 32px 24px;
    text-align: center;
    color: var(--ink-2);
}

.chat-empty__art {
    color: var(--willow);
    margin-bottom: 20px;
    line-height: 0;
}
.chat-empty__art .icon-leaf svg {
    width: 48px;
    height: 48px;
}

.chat-empty__headline,
.chat-cleared__headline {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 18px;
    color: var(--ink-0);
    margin: 0 0 8px 0;
    font-weight: 500;
}

.chat-empty__subtext {
    font-size: 13px;
    color: var(--ink-2);
    margin: 0;
    max-width: 36ch;
}

.chat-skeleton {
    padding: 12px 24px;
    display: flex;
    flex-direction: column;
    gap: 10px;
    /* First real message fades the skeleton out over 180 ms per spec.
       Removed from the DOM on the next render tick, so the opacity
       transition only fires when the loading branch itself is about
       to unmount — reduced-motion honours foundation's blanket 0ms
       transition override. */
    transition: opacity 180ms ease-out;
}

.chat-skeleton-row {
    display: flex;
    gap: 12px;
    align-items: flex-start;
}

.chat-skeleton__avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--bg-2);
    flex-shrink: 0;
}

.chat-skeleton__bars {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding-top: 4px;
}

.chat-skeleton__bar {
    height: 10px;
    background: var(--bg-2);
    border-radius: 4px;
}

.chat-skeleton__bar--name { width: 18%; }
.chat-skeleton__bar--body { width: 74%; }

/* Shimmer animation: only enabled when motion is allowed. The
   `shimmer` keyframe is defined in `foundation.css`. Reduced-motion
   users see the static `--bg-2` rectangles defined above. */
@media (prefers-reduced-motion: no-preference) {
    .chat-skeleton__avatar,
    .chat-skeleton__bar {
        background: linear-gradient(
            90deg,
            var(--bg-2) 0%,
            var(--bg-3) 40%,
            var(--bg-2) 80%
        );
        background-size: 400px 100%;
        background-repeat: no-repeat;
        animation: shimmer 1.6s linear infinite;
    }
}

/* ── Phase 2e · Local search ─────────────────────────────────────── */

.search-surface {
    position: fixed;
    inset: 0;
    background: var(--bg-1);
    display: flex;
    flex-direction: column;
    z-index: 900;
    animation: willow-pop-in var(--motion, 220ms) var(--motion-ease, ease-out);
}

.search-form {
    padding: 16px 20px 12px;
    border-bottom: 1px solid var(--line-soft);
    position: sticky;
    top: 0;
    background: var(--bg-1);
    z-index: 2;
}

.search-input {
    width: 100%;
    height: 44px;
    padding: 0 14px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-m);
    color: var(--ink-0);
    font: 15px var(--font-ui);
    outline: none;
    transition: opacity 120ms ease-out;
}

.search-input:focus-visible {
    box-shadow: var(--focus-ring);
}

.search-input::placeholder {
    color: var(--ink-3);
}

.search-input.is-debouncing {
    opacity: 0.85;
}

.scope-chip-wrap {
    position: relative;
    display: inline-block;
    margin: 8px 20px 4px;
}

.scope-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 4px 8px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    color: var(--moss-3);
    font: 11px / 1 var(--font-mono);
    letter-spacing: 0.5px;
    cursor: pointer;
}

.scope-chip:focus-visible {
    box-shadow: var(--focus-ring);
    outline: none;
}

.scope-chip-chevron {
    display: inline-flex;
    transition: transform 120ms;
}

.scope-chip[aria-expanded="true"] .scope-chip-chevron {
    transform: rotate(180deg);
}

.scope-chip-popover {
    position: absolute;
    left: 0;
    top: calc(100% + 6px);
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: var(--radius-m);
    box-shadow: var(--shadow-2);
    padding: 4px;
    min-width: 180px;
    z-index: 10;
}

.scope-chip-popover-option {
    display: flex;
    width: 100%;
    padding: 8px 12px;
    background: transparent;
    border: none;
    color: var(--ink-2);
    font: 13px var(--font-ui);
    text-align: left;
    cursor: pointer;
}

.scope-chip-popover-option[aria-selected="true"] {
    color: var(--moss-3);
}

.scope-chip-popover-option:disabled {
    color: var(--ink-4);
    cursor: not-allowed;
}

.scope-chip-popover-option:hover:not(:disabled) {
    background: var(--bg-2);
}

@media (prefers-reduced-motion: reduce) {
    .search-surface {
        animation: none;
    }
    .scope-chip-chevron {
        transition: none;
    }
}

.search-results {
    flex: 1;
    overflow-y: auto;
    padding: 8px 0;
}

.search-group-header {
    display: flex;
    align-items: baseline;
    gap: 6px;
    padding: 12px 20px 4px;
    color: var(--ink-3);
    font: italic 14px var(--font-display);
}

.search-group-count {
    font: 11px var(--font-mono);
    color: var(--ink-4);
}

.search-result-row {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    width: 100%;
    min-height: 44px;
    padding: 10px 20px;
    background: transparent;
    border: none;
    color: var(--ink-1);
    text-align: left;
    cursor: pointer;
    transition: background 120ms ease-out;
}

.search-result-row:hover {
    background: var(--bg-2);
}

.search-result-row.is-selected {
    background: var(--bg-2);
    box-shadow: inset 2px 0 0 var(--moss-3);
}

.search-result-row:focus-visible {
    box-shadow: var(--focus-ring);
    outline: none;
}

.search-result-context {
    font: 11px var(--font-mono);
    color: var(--ink-3);
}

.search-result-container {
    font-family: var(--font-display);
    font-style: italic;
    color: var(--ink-2);
}

.search-result-excerpt {
    font: 13px / 1.5 var(--font-ui);
    color: var(--ink-1);
    display: -webkit-box;
    -webkit-line-clamp: 3;
    -webkit-box-orient: vertical;
    overflow: hidden;
    text-overflow: ellipsis;
}

.search-result-excerpt mark {
    background: color-mix(in oklab, var(--moss-3) 18%, transparent);
    color: inherit;
    text-decoration: underline;
    text-decoration-thickness: 1.5px;
    padding: 0;
}

.search-result-arrow {
    position: absolute;
    right: 20px;
    top: 12px;
    color: var(--ink-3);
}

@media (max-width: 720px) {
    .search-result-arrow {
        display: none;
    }
}

.search-streaming-banner {
    padding: 6px 20px;
    font: italic 12px var(--font-display);
    color: var(--ink-3);
}

.search-recents {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    padding: 12px 20px;
}

.search-recent-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    max-width: 180px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    color: var(--ink-2);
    font: 12px var(--font-mono);
    cursor: pointer;
}

.search-recent-chip:hover {
    background: var(--bg-3);
}

.search-recent-clear {
    align-self: center;
    background: transparent;
    border: none;
    color: var(--ink-3);
    font: 11px var(--font-mono);
    cursor: pointer;
    padding: 0 8px;
}

.search-empty-never {
    padding: 32px 20px;
    text-align: center;
    color: var(--ink-3);
    font: 12px var(--font-mono);
}

.search-privacy-footer {
    padding: 8px 20px;
    color: var(--ink-3);
    font: 11px var(--font-mono);
    border-top: 1px solid var(--line-soft);
    background: var(--bg-1);
}

.search-pull-down-bar {
    height: 0;
    overflow: hidden;
    background: var(--bg-2);
    transition: height var(--motion, 220ms) var(--motion-ease, ease-out);
}

.search-pull-down-bar.is-revealed {
    height: 44px;
}

.search-pull-down-hint {
    width: 100%;
    height: 44px;
    background: transparent;
    border: none;
    color: var(--ink-3);
    font: 12px var(--font-mono);
    cursor: pointer;
}

@media (prefers-reduced-motion: reduce) {
    .search-pull-down-bar {
        transition: none;
    }
}
/* ── Phase 2b sync-queue surfaces ────────────────────────────────────── */

/* Offline strip — amber status line, 36 px desktop / 40 px mobile. */
.offline-strip {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    height: 36px;
    padding: 0 14px;
    background: var(--bg-2);
    color: var(--ink-1);
    border: 0;
    border-top: 1px solid var(--amber-soft);
    border-bottom: 1px solid var(--amber-soft);
    font-size: 13px;
    cursor: pointer;
    text-align: left;
    transition: background 140ms ease;
}
.offline-strip:hover { background: var(--bg-3); }
.offline-strip:focus-visible {
    outline: 2px solid var(--focus-ring, var(--moss-3));
    outline-offset: -2px;
}
.offline-strip .icon { color: var(--amber); font-size: 11px; }
.offline-strip__summary { flex: 1; font-variant-numeric: tabular-nums; }
.offline-strip__chevron { color: var(--ink-3); font-size: 12px; }
.offline-strip--flash {
    background: var(--moss-0);
    transition: background 240ms ease;
}
@media (max-width: 720px) {
    .offline-strip { height: 40px; }
    .offline-strip__chevron { display: none; }
}
@media (prefers-reduced-motion: reduce) {
    .offline-strip, .offline-strip--flash { transition: opacity 120ms ease; }
}

/* Queue pill — amber inline badge on letters / member rows. */
.queue-pill {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    min-height: 20px;
    background: transparent;
    color: var(--amber);
    border: 1px solid var(--amber-soft);
    border-radius: 999px;
    font-size: 11px;
    font-variant-numeric: tabular-nums;
    cursor: pointer;
}
.queue-pill:hover { background: rgba(201, 155, 85, 0.08); }
.queue-pill:focus-visible {
    outline: 2px solid var(--focus-ring, var(--moss-3));
    outline-offset: 2px;
}
.queue-pill .icon { font-size: 9px; }
@media (max-width: 720px) {
    .queue-pill {
        padding: 14px 6px;   /* ≥ 44x44 hit target */
        min-height: 44px;
    }
}

/* Inline queue note — below message body. */
.inline-note {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    margin-top: 4px;
    padding-left: 38px; /* align with body gutter past avatar column */
    font-family: "Fraunces", serif;
    font-style: italic;
    font-size: 13px;
    color: var(--ink-3);
}
.inline-note--queued .icon { color: var(--amber); }
.inline-note--just-delivered {
    color: var(--ink-2);
}
.inline-note--just-delivered .icon { color: var(--moss-3); }
.inline-note--inbound-held .icon { color: var(--moss-2); }

/* Reconnection toast — top-centre moss accent. */
.reconnection-toast {
    position: fixed;
    top: 14px;
    left: 50%;
    transform: translateX(-50%);
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: var(--bg-2);
    color: var(--ink-0);
    border: 1px solid var(--moss-1);
    border-radius: 10px;
    box-shadow: var(--shadow-2, 0 6px 20px rgba(0, 0, 0, 0.35));
    font-size: 13px;
    z-index: 9000;
    animation: willow-pop-in 180ms ease-out;
}
.reconnection-toast__icon { color: var(--moss-3); font-size: 14px; }
.reconnection-toast__dismiss {
    margin-left: 4px;
    background: transparent;
    color: var(--ink-2);
    border: 0;
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
}
@keyframes willow-pop-in {
    from { opacity: 0; transform: translate(-50%, -6px); }
    to   { opacity: 1; transform: translate(-50%, 0); }
}
@media (prefers-reduced-motion: reduce) {
    .reconnection-toast { animation: none; transition: opacity 120ms ease; }
}

/* Welcome-back banner — 48 px moss accent, persists until dismissed. */
.welcome-back-banner {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 48px;
    padding: 0 14px;
    background: var(--moss-0);
    color: var(--ink-1);
    border-bottom: 1px solid var(--moss-1);
    font-size: 13px;
}
.welcome-back-banner__glyph {
    color: var(--willow, var(--moss-3));
    font-size: 14px;
    flex-shrink: 0;
}
.welcome-back-banner__label { flex: 1; }
.welcome-back-banner__dismiss {
    background: transparent;
    color: var(--ink-2);
    border: 0;
    cursor: pointer;
    font-size: 16px;
    line-height: 1;
}

/* Sync-queue view — full-surface component mounted in right rail or mobile route. */
.sync-queue-view {
    display: flex;
    flex-direction: column;
    gap: 12px;
    height: 100%;
    padding: 16px;
    background: var(--bg-1);
    color: var(--ink-1);
    overflow-y: auto;
}
.sync-queue-view__header {
    display: flex;
    align-items: flex-start;
    gap: 8px;
}
.sync-queue-view__close {
    background: transparent;
    color: var(--ink-2);
    border: 0;
    font-size: 18px;
    cursor: pointer;
    line-height: 1;
}
.sync-queue-view__titles { flex: 1; }
.sync-queue-view__title {
    margin: 0;
    font-family: "Fraunces", serif;
    font-style: italic;
    font-size: 18px;
    color: var(--ink-0);
}
.sync-queue-view__subtitle {
    margin: 2px 0 0;
    font-size: 10.5px;
    color: var(--ink-3);
}
.sync-queue-view__relay { font-size: 14px; }
.sync-queue-view__relay--ok   { color: var(--moss-3); }
.sync-queue-view__relay--warn { color: var(--amber); animation: willowPulse 1.8s ease-in-out infinite; }
.sync-queue-view__relay--idle { color: var(--ink-3); }

/* ── Relay signal button + popover (Phase 2b Task 14) ─────────────── */
.relay-signal-wrap { position: relative; display: inline-flex; }
.relay-signal-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    color: var(--ink-3);
    font-size: 14px;
}
.relay-signal-button:focus-visible { outline: 2px solid var(--focus-ring, var(--moss-3)); outline-offset: 2px; }
.relay-signal-button--ok   { color: var(--moss-3); }
.relay-signal-button--warn { color: var(--amber); animation: willowPulse 2s ease-in-out infinite; opacity: 0.7; }
.relay-signal-button--idle { color: var(--ink-3); cursor: default; }

.relay-popover {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 20;
    min-width: 220px;
    max-width: 280px;
    padding: 12px 14px;
    background: var(--bg-2);
    border: 1px solid var(--line, #2a2822);
    border-radius: var(--radius, 10px);
    box-shadow: var(--shadow-1, 0 6px 20px rgba(0, 0, 0, 0.3));
    color: var(--ink-1);
    font-size: 12px;
}
.relay-popover__header {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 10px;
    color: var(--ink-2);
    font-size: 11px;
}
.relay-popover__status { color: var(--ink-1); font-size: 12px; }
.relay-popover__body {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 4px 12px;
    margin: 0 0 10px;
    font-size: 11px;
    color: var(--ink-2);
}
.relay-popover__body dt, .relay-popover__body dd { margin: 0; }
.relay-popover__mono { font-variant-numeric: tabular-nums; color: var(--ink-1); }
.relay-popover__settings-link {
    display: block;
    width: 100%;
    padding: 6px 8px;
    background: transparent;
    border: 0;
    border-top: 1px solid var(--line-soft, var(--line));
    text-align: left;
    color: var(--moss-3);
    font-size: 11.5px;
    cursor: pointer;
}
.relay-popover__settings-link:hover { color: var(--moss-4); }
.relay-popover__backdrop {
    position: fixed;
    inset: 0;
    z-index: 19;
    background: transparent;
    border: 0;
    padding: 0;
    cursor: default;
}

@media (prefers-reduced-motion: reduce) {
    .relay-signal-button--warn { animation: none; opacity: 0.75; }
}

@media (max-width: 720px) {
    .relay-popover {
        position: fixed;
        left: 12px;
        right: 12px;
        top: auto;
        bottom: 12px;
        max-width: none;
    }
}

.sync-queue-view__status {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    background: var(--bg-2);
    border: 1px solid var(--line, #2a2822);
    border-radius: 14px;
}
.sync-queue-view__dot {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 12px;
    height: 12px;
    border-radius: 999px;
    background: var(--moss-2);
    color: var(--moss-4);
    font-size: 8px;
}
.sync-queue-view__dot--pulsing { animation: willowPulse 1.6s ease-in-out infinite; }
.sync-queue-view__dot--drained { background: var(--moss-2); }
.sync-queue-view__status-label { flex: 1; color: var(--ink-1); font-size: 13px; }
.sync-queue-view__status-count { color: var(--ink-2); font-size: 12px; font-variant-numeric: tabular-nums; }

@keyframes willowPulse {
    0%, 100% { opacity: 0.7; transform: scale(1); }
    50%      { opacity: 1; transform: scale(1.08); }
}
@media (prefers-reduced-motion: reduce) {
    .sync-queue-view__dot--pulsing,
    .sync-queue-view__relay--warn {
        animation: none;
        opacity: 0.7;
    }
}

.sync-queue-view__tabs {
    display: flex;
    gap: 4px;
    border-bottom: 1px solid var(--line, #2a2822);
}
.sync-queue-view__tab {
    padding: 8px 14px;
    background: transparent;
    color: var(--ink-2);
    border: 0;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    font-size: 13px;
}
.sync-queue-view__tab--active {
    color: var(--ink-0);
    border-bottom-color: var(--moss-2);
}

.sync-queue-view__rows {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.sync-queue-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 8px;
    border-radius: 8px;
}
.sync-queue-row:focus-visible {
    outline: 2px solid var(--focus-ring, var(--moss-3));
}
.sync-queue-row__name { color: var(--ink-1); font-size: 13px; }
.sync-queue-row__count { margin-left: auto; }

.sync-queue-view__arrivals {
    margin-top: 6px;
    padding-top: 10px;
    border-top: 1px solid var(--line, #2a2822);
}
.sync-queue-view__arrivals-title {
    margin: 0 0 6px;
    font-size: 11px;
    color: var(--ink-3);
    text-transform: lowercase;
}
.sync-queue-arrival {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 4px;
}
.sync-queue-arrival__pill {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    color: var(--moss-3);
    border: 1px solid var(--moss-1);
    border-radius: 999px;
    font-size: 11px;
}

.sync-queue-view__footer {
    display: flex;
    gap: 8px;
    padding-top: 10px;
    border-top: 1px solid var(--line, #2a2822);
}
.sync-queue-view__retry {
    padding: 8px 14px;
    background: var(--moss-1);
    color: var(--moss-4);
    border: 0;
    border-radius: 8px;
    cursor: pointer;
    font-size: 13px;
}
.sync-queue-view__retry:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}
.sync-queue-view__mark-read {
    padding: 8px 12px;
    background: transparent;
    color: var(--ink-2);
    border: 1px solid var(--line, #2a2822);
    border-radius: 8px;
    cursor: pointer;
    font-size: 13px;
}
.sync-queue-view__footnote {
    margin: 4px 0 0;
    font-size: 11px;
    color: var(--ink-3);
    display: flex;
    align-items: center;
    gap: 6px;
/* ── Phase 2c · Profile card ────────────────────────────────────────── */
/* Spec: docs/specs/2026-04-19-ui-design/profile-card.md §Peer view. */

.profile-card {
    position: relative;
    background: var(--bg-1);
    border-radius: 12px;
    overflow: hidden;
    font-family: var(--sans);
    color: var(--ink-1);
    display: flex;
    flex-direction: column;
    padding-bottom: 12px;
}

.profile-card__banner {
    position: relative;
    height: 72px;
    overflow: hidden;
    flex-shrink: 0;
}
.profile-card__crest {
    width: 100%;
    height: 100%;
    display: block;
}
@media (max-width: 720px) {
    .profile-card__banner { height: 92px; }
}

/* Badge pill on banner top-left. */
.profile-card__badge {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 3px 9px;
    font-size: 11px;
    font-weight: 500;
    color: var(--warn);
    background: color-mix(in oklab, var(--bg-0) 60%, transparent);
    backdrop-filter: blur(8px);
    border: 1px dashed var(--warn);
    border-radius: 999px;
    cursor: pointer;
}

/* Close button top-right (desktop only). */
.profile-card__close {
    position: absolute;
    top: 8px;
    right: 8px;
    z-index: 2;
    width: 28px;
    height: 28px;
    background: color-mix(in oklab, var(--bg-0) 60%, transparent);
    backdrop-filter: blur(8px);
    border: 1px solid var(--line-soft);
    border-radius: 999px;
    color: var(--ink-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
}
@media (max-width: 720px) {
    .profile-card__close { display: none; }
}

/* Avatar overlapping banner. */
.profile-card__avatar {
    position: relative;
    width: 64px;
    height: 64px;
    border-radius: 50%;
    margin: -32px 0 0 16px;
    border: 3px solid var(--bg-1);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--bg-0);
    font-family: var(--display);
    font-size: 28px;
    z-index: 1;
}
.profile-card__avatar-initial {
    font-weight: 500;
    line-height: 1;
}
@media (max-width: 720px) {
    .profile-card__avatar { width: 84px; height: 84px; margin-top: -42px; }
    .profile-card__avatar-initial { font-size: 36px; }
}

.profile-card__name {
    font-family: var(--display);
    font-style: italic;
    font-size: 20px;
    padding: 8px 16px 0 16px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
@media (max-width: 720px) {
    .profile-card__name { font-size: 24px; }
}

.profile-card__pronouns {
    display: inline-block;
    margin: 0 16px;
    padding: 2px 8px;
    font-size: 12px;
    color: var(--ink-3);
    border: 1px solid var(--line-soft);
    border-radius: 999px;
}

.profile-card__handle {
    padding: 4px 16px 0 16px;
    font-family: var(--mono);
    font-size: 12px;
    color: var(--ink-3);
}
.profile-card__handle-sep { color: var(--ink-4); }
.profile-card__handle-nick-label { color: var(--moss-3); }
.profile-card__handle-nick { color: var(--ink-2); }

.profile-card__status {
    padding: 6px 16px 0 16px;
}

.profile-card__bio {
    padding: 10px 16px 0 16px;
    font-size: 13px;
    line-height: 1.55;
    color: var(--ink-1);
}
@media (max-width: 720px) {
    .profile-card__bio { font-size: 14.5px; }
}

.profile-card__tagline {
    padding: 4px 16px 0 16px;
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-3);
}

.profile-card__pinned {
    margin: 10px 16px 0 16px;
    padding: 6px 10px;
    border-left: 2px solid var(--moss-2);
}
.profile-card__pinned--empty {
    border-left-color: var(--line-soft);
    color: var(--ink-4);
    font-style: italic;
    font-size: 12px;
}
.profile-card__pinned-label {
    display: block;
    font-family: var(--mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
    margin-bottom: 4px;
}
.profile-card__pinned-body {
    font-family: var(--display);
    font-style: italic;
    font-size: 14px;
    color: var(--ink-1);
    margin: 0;
}

.profile-card__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin: 10px 16px 0 16px;
    align-items: center;
}
.profile-card__chips-label {
    font-family: var(--mono);
    font-size: 10px;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
    margin-right: 4px;
}
.profile-card__chip {
    padding: 2px 8px;
    font-size: 11px;
    color: var(--ink-2);
    background: var(--bg-2);
    border: 1px solid var(--line-soft);
    border-radius: 6px;
}

.profile-card__meta {
    margin: 12px 16px 0 16px;
    padding-top: 10px;
    border-top: 1px solid var(--line-soft);
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.profile-card__meta-row {
    display: flex;
    gap: 8px;
    font-size: 11px;
}
.profile-card__meta-label {
    font-family: var(--mono);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--ink-3);
    min-width: 76px;
}
.profile-card__meta-value { color: var(--ink-2); }
.profile-card__meta-fingerprint {
    font-family: var(--mono);
    color: var(--warn);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.profile-card__actions-primary {
    display: flex;
    gap: 8px;
    padding: 14px 16px 0 16px;
}
.profile-card__action {
    flex: 1 1 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 8px 10px;
    font-size: 12px;
    color: var(--ink-1);
    background: var(--bg-2);
    border: 1px solid var(--line-soft);
    border-radius: 8px;
    cursor: pointer;
    min-height: 44px;
}
.profile-card__action--primary {
    width: 100%;
    background: var(--moss-2);
    color: var(--bg-0);
    border-color: var(--moss-3);
    font-weight: 500;
}
@media (max-width: 720px) {
    .profile-card__actions-primary {
        flex-direction: column;
    }
    .profile-card__action {
        width: 100%;
    }
}

.profile-card__actions-secondary {
    display: flex;
    gap: 10px;
    justify-content: space-between;
    align-items: center;
    padding: 10px 16px 0 16px;
    margin-top: 10px;
    border-top: 1px solid var(--line-soft);
    min-height: 44px;
}
.profile-card__actions-secondary--self {
    justify-content: center;
}
.profile-card__link {
    background: none;
    border: none;
    color: var(--ink-2);
    font-size: 11px;
    padding: 8px 4px;
    cursor: pointer;
}
.profile-card__link:hover { color: var(--ink-1); }
.profile-card__link--danger { color: var(--warn); }
.profile-card__self-caption {
    font-family: var(--mono);
    font-size: 11px;
    color: var(--ink-3);
}

.nickname-editor__input {
    font: 12px/1.4 var(--mono);
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 2px 6px;
    color: var(--ink-1);
    min-width: 80px;
}

/* Phase 2c · member-name-btn strips UA button chrome so the visual is
   unchanged. Pairs with the member-item click target in member_list.rs. */
.member-name-btn {
    background: none;
    border: none;
    padding: 0;
    font: inherit;
    text-align: left;
    cursor: pointer;
    color: inherit;
}
.member-name-btn:focus-visible {
    outline: 2px solid var(--moss-2);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ── Composer (Phase 3a, T5 shell) ───────────────────────────────────
 *
 * Minimal style approximation of `docs/specs/2026-04-19-ui-design/composer.md`
 * §Desktop compose surface; later tasks (T9–T15) refine to spec
 * (mobile-pill variant, meta row, offline tint, mention popover, …).
 */

.composer {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 12px;
    box-shadow: var(--shadow-1);
    padding: 8px 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

/* Phase 3a, T10 — offline tint per `composer.md` §Offline state.
 * Background softens to a 10 % `--amber` mix over `--bg-2`. The amber
 * meta row owns the icon + copy colour swap; the wrapper just shifts
 * the surface tone so the user can feel the queue without losing the
 * pill silhouette. Reconnecting reuses the same tint because the queue
 * is still the truthful destination for sent messages. */
.composer--offline {
    background: color-mix(in oklab, var(--amber) 10%, var(--bg-2));
}

.composer__row {
    display: flex;
    align-items: flex-end;
    gap: 8px;
}

.composer__textarea {
    flex: 1;
    width: 100%;
    background: transparent;
    border: 0;
    color: var(--ink-0);
    font-size: 14px;
    line-height: 1.45em;
    min-height: 1.45em;
    outline: none;
    resize: none;
    overflow-y: auto;
    font-family: inherit;
}

.composer__textarea::placeholder {
    color: var(--ink-3);
}

.composer__send {
    background: var(--moss-1);
    color: var(--moss-4);
    border: 0;
    border-radius: 8px;
    padding: 6px 10px;
    font: inherit;
    font-size: 13px;
    cursor: pointer;
    flex-shrink: 0;
    transition: opacity var(--motion-fast, 120ms) ease;
}

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

/* Attach + emoji buttons (Phase 3a, T15 — spec §Desktop compose
 * surface upper row). Stub clicks in v1; the real file dialog and
 * emoji picker drop in via Phases 3b / 3c. Visually unobtrusive so
 * they don't fight the textarea for attention — `--ink-3` like the
 * meta-row icons. The buttons live before / after the textarea in
 * the row so the spec's "Attach → textarea → emoji → send" order
 * holds. */
.composer__attach,
.composer__emoji {
    background: transparent;
    border: 0;
    color: var(--ink-3);
    padding: 4px;
    cursor: pointer;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    line-height: 0;
    transition: color var(--motion-fast, 120ms) ease;
}

.composer__attach:hover,
.composer__emoji:hover {
    color: var(--ink-1);
}

/* ── Composer reply bar (Phase 3a, T7) ────────────────────────────────
 *
 * Spec: `docs/specs/2026-04-19-ui-design/composer.md` §Reply preview.
 * Lives above the composer, top-radius only so the bottom edge fuses
 * visually with the composer pill below. 2 px `--moss-2` left rule,
 * `replying to` label, parent author italic, single-line body
 * preview, flex spacer, `cancel` text button.
 */
.composer__reply-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-bottom: 0;
    border-radius: 10px 10px 0 0;
}

.composer__reply-bar-rule {
    flex-shrink: 0;
    width: 2px;
    align-self: stretch;
    background: var(--moss-2);
    border-radius: 1px;
}

/* The preview body is a button so it's keyboard-focusable; we strip
 * the UA chrome and lay its children inline instead. */
.composer__reply-bar-preview {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: baseline;
    gap: 6px;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    overflow: hidden;
}

.composer__reply-bar-label {
    color: var(--ink-3);
    font-size: 12px;
    flex-shrink: 0;
}

.composer__reply-bar-author {
    color: var(--ink-1);
    font-style: italic;
    font-size: 13px;
    flex-shrink: 0;
}

.composer__reply-bar-body {
    color: var(--ink-2);
    font-size: 13px;
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.composer__reply-bar-cancel {
    flex-shrink: 0;
    background: transparent;
    border: 0;
    padding: 2px 4px;
    color: var(--ink-2);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
    transition: color var(--motion-fast, 120ms) ease;
}

.composer__reply-bar-cancel:hover,
.composer__reply-bar-cancel:focus-visible {
    color: var(--ink-0);
}

/* Reply-bar lives directly above the composer pill — drop the
 * pill's top corners + top border so the two surfaces fuse. */
.composer__reply-bar + .composer {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

/* ── Composer edit bar (Phase 3a, T8) ────────────────────────────────
 *
 * Spec: `docs/specs/2026-04-19-ui-design/composer.md` §Edit mode.
 * Slim hint above the composer: `editing message · esc to cancel`
 * (12 px, `--ink-3`) plus a small `cancel` text button. Send-button
 * label flip to `save` is owned by the parent `<Composer>`.
 */
.composer__edit-bar {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 12px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-bottom: 0;
    border-radius: 10px 10px 0 0;
    color: var(--ink-3);
    font-size: 12px;
}

.composer__edit-bar-text {
    flex: 1;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.composer__edit-bar-cancel {
    flex-shrink: 0;
    background: transparent;
    border: 0;
    padding: 2px 4px;
    color: var(--ink-2);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
    transition: color var(--motion-fast, 120ms) ease;
}

.composer__edit-bar-cancel:hover,
.composer__edit-bar-cancel:focus-visible {
    color: var(--ink-0);
}

/* Edit bar fuses with the composer pill below the same way the
 * reply bar does. */
.composer__edit-bar + .composer {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

/* ── Composer meta row (Phase 3a, T9) ────────────────────────────────
 *
 * Spec: `docs/specs/2026-04-19-ui-design/composer.md` §Desktop compose
 * surface — Meta row, §Mobile compose surface, §Offline state.
 * Renders beneath the textarea+button row. Three forms:
 *
 *   Desktop online — `lock · sealed with grove-keys · ear · hold shift
 *                     to whisper` (with `shift` in mono `--whisper`).
 *   Mobile online  — `lock · sealed to {N} peers in grove · ear · tap
 *                     ear to whisper`.
 *   Offline        — `hourglass · offline · queuing messages` in
 *                     `--amber` (replaces both online forms).
 */
.composer__meta {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--ink-3);
    /* Hint-size copy — matches the reply/edit bar's 12 px convention,
     * which is the project's de-facto "hint" size until the
     * foundation pins a `--text-hint` token. */
    font-size: 12px;
    line-height: 1.4;
}

.composer__meta-icon {
    display: inline-flex;
    align-items: center;
    color: var(--ink-3);
    flex-shrink: 0;
}

.composer__meta-icon .icon {
    width: 12px;
    height: 12px;
}

.composer__meta-text {
    color: var(--ink-3);
    white-space: nowrap;
}

.composer__meta-sep {
    color: var(--ink-4);
    flex-shrink: 0;
}

.composer__meta-spacer {
    flex: 1;
}

/* `shift` keycap in the desktop whisper hint — mono, `--whisper`,
 * borderless to keep the row visually quiet (spec §Composer meta:
 * "shift in mono `--whisper`"). */
.composer__kbd {
    font-family: var(--font-mono, ui-monospace, monospace);
    color: var(--whisper);
    font-size: inherit;
    padding: 0;
    background: transparent;
    border: 0;
}

.composer__meta--offline {
    color: var(--amber);
}

.composer__meta--offline .composer__meta-icon,
.composer__meta--offline .composer__meta-text {
    color: var(--amber);
}

/* ── Composer typing indicator (Phase 3a, T11) ──────────────────────────
 *
 * Spec: `composer.md` §Typing indicator. Sits at the very top of the
 * composer wrapper. Padding is 4px/24px on desktop and 8px/14px on
 * mobile (selector below `data-shell="mobile"` overrides the desktop
 * defaults — same pattern used by the meta row). The 3-dot
 * `willowPulse` cluster is staggered 0 / 200 / 400 ms via the
 * `:nth-child` rules. The `--empty` modifier collapses the row so it
 * doesn't claim layout when no peers are typing.
 *
 * Foundation tokens only: `--ink-2` for the label, `--ink-3` for the
 * dots. The italic font matches the spec's `font-display` italic
 * affordance — `--font-display` is a foundation variable that falls
 * back to the system serif stack on platforms without the custom
 * face. */
.composer__typing-indicator {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 24px;
    font-family: var(--font-display, serif);
    font-style: italic;
    font-size: 12px;
    color: var(--ink-2);
    min-height: 20px;
}

[data-shell="mobile"] .composer__typing-indicator {
    padding: 8px 14px;
}

.composer__typing-indicator--empty {
    /* Collapse to zero height so the composer doesn't shift on each
     * typing-ping update. The pluralisation label stays in the DOM
     * (rendered as the empty string) so reactive subscriptions don't
     * tear down and rebuild on every transition. */
    display: none;
}

.composer__typing-dots {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    /* Match the dot block height so the row's vertical centre aligns
     * with the label baseline. */
    line-height: 0;
}

.composer__typing-dot {
    width: 4px;
    height: 4px;
    border-radius: 50%;
    background: var(--ink-3);
    animation: willowPulse 1.4s infinite ease-in-out;
    /* `display: inline-block` so width/height take effect on the
     * empty `<span>` we render. */
    display: inline-block;
}

.composer__typing-dot:nth-child(2) {
    animation-delay: 200ms;
}

.composer__typing-dot:nth-child(3) {
    animation-delay: 400ms;
}

@media (prefers-reduced-motion: reduce) {
    /* Spec §Motion: `willowPulse` becomes a static opacity dot.
     * Foundation already gates other `willowPulse` consumers via the
     * same media query — this rule mirrors them so the typing dots
     * participate without copying the foundation logic. */
    .composer__typing-dot {
        animation: none;
        opacity: 1;
    }
}

.composer__typing-label {
    color: var(--ink-2);
}

/* Screen-reader-only aria-live region for the typing indicator
 * (Phase 3a, T12). Visually hidden but still announced by AT —
 * standard SR-only pattern (1px box clipped out of view). The
 * companion `.composer__typing-label` span carries `aria-hidden`
 * so screen readers only consume this throttled region. Spec
 * `composer.md` §Screen reader flow: "at most once per 5 s". */
.composer__typing-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

/* ── Message-row flash (T7 — scroll-to-parent affordance) ──────────────
 *
 * Triggered by the chat view after `on_jump_to_parent` fires from the
 * reply bar. The class is added for ~180 ms and then removed; the
 * keyframe is `--moss-2`-tinted so it reads as the same accent the
 * left rule on the reply bar uses.
 */
@keyframes willow-row-flash {
    0%   { background-color: color-mix(in oklab, var(--moss-2) 22%, transparent); }
    100% { background-color: transparent; }
}

.message-row--flash,
.message.flash {
    animation: willow-row-flash 180ms ease-out;
}

@media (prefers-reduced-motion: reduce) {
    .message-row--flash,
    .message.flash {
        animation: none;
        background-color: color-mix(in oklab, var(--moss-2) 12%, transparent);
        transition: background-color 180ms ease;
    }
}

/* ── Mention autocomplete popover (Phase 3a — T13/T14) ─────────────────
 *
 * Anchored above the composer at the position computed by the parent
 * (textarea bounding rect + spec offset). The popover floats — we use
 * `position: fixed` so it doesn't get clipped by the chat scroll
 * container, and rely on the inline `top` / `left` written by
 * `<MentionAutocomplete>` for placement.
 *
 * Spec `composer.md` §Mention autocomplete:
 *   - `--bg-1` background, `--line` border, radius 10 px, `--shadow-2`.
 *   - Max 8 rows visible; scrolls above when the list overflows.
 */
.mention-popover {
    position: fixed;
    z-index: 60;
    min-width: 220px;
    max-width: 320px;
    max-height: 200px;
    overflow-y: auto;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: var(--shadow-2);
    padding: 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.mention-popover__row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 8px;
    background: transparent;
    border: 0;
    border-radius: 6px;
    color: var(--ink-1);
    font: inherit;
    text-align: left;
    cursor: pointer;
    transition: background-color var(--motion-fast) ease;
}

.mention-popover__row:hover,
.mention-popover__row--selected {
    background: var(--bg-2);
}

.mention-popover__row--channel {
    /* Distinguish the synthetic `@channel` row with the moss accent
     * the rest of the composer already uses for "addresses everyone".
     * Lit up by T14. */
    color: var(--moss-2);
}

.mention-popover__avatar {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    background: var(--bg-2);
    flex: 0 0 auto;
}

.mention-popover__display {
    color: var(--ink-1);
    flex: 0 1 auto;
}

.mention-popover__handle {
    color: var(--ink-3);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 0.85em;
    flex: 0 1 auto;
}

.mention-popover__presence-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--ink-3);
    margin-left: auto;
    flex: 0 0 auto;
}

.mention-popover__presence-dot--here {
    background: var(--moss-2);
}

.mention-popover__presence-dot--away,
.mention-popover__presence-dot--queued,
.mention-popover__presence-dot--gone {
    background: var(--ink-3);
}

/* ── Phase 2d ephemeral kind chip ───────────────────────────────────── */

.kind-chip {
    display: inline-flex;
    align-items: center;
    height: 16px;
    padding: 2px 6px;
    border: 1px solid var(--line-soft, var(--line));
    border-radius: var(--radius-s);
    color: var(--ink-3);
    font-family: var(--font-mono);
    font-size: 11px;
    line-height: 1;
    background: transparent;
    user-select: none;
}

/* ── Phase 2d dormant ephemeral row ─────────────────────────────────── */
.channel-item--dormant .channel-row-name {
    color: var(--ink-2);
}

/* ── Phase 2d archives surface ──────────────────────────────────────── */
.archives-pane { padding: 8px; }
.archives-subgroup-header {
    color: var(--ink-3);
    font-family: var(--font-ui);
    font-size: 11.5px;
    text-transform: uppercase;
    letter-spacing: 0.1em;
    margin: 4px 0;
}
.archives-subgroup { list-style: none; padding: 0; margin: 0; }
.archives-row {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 8px;
    align-items: center;
    padding: 6px 8px;
    color: var(--ink-2);
}
.archives-row-name {
    font-family: var(--font-ui);
    font-size: 13px;
    color: var(--ink-2);
}
.archives-revive-link {
    background: transparent;
    border: none;
    color: var(--moss);
    font-family: var(--font-ui);
    font-size: 12px;
    cursor: pointer;
    padding: 0;
}
.archives-revive-link:hover { text-decoration: underline; }

/* ── Phase 2d read-only banner inside archived channel ──────────────── */
.read-only-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 16px;
    background: var(--bg-1);
    border-bottom: 1px solid var(--line);
    color: var(--ink-2);
    font-family: var(--font-ui);
    font-size: 13px;
}
.read-only-banner-text {
    flex: 1;
}
.read-only-banner-expand {
    background: transparent;
    border: 1px solid var(--line);
    color: var(--moss);
    padding: 4px 12px;
    border-radius: var(--radius-s);
    font-family: var(--font-ui);
    font-size: 12px;
    cursor: pointer;
}
.input-row--hidden {
    display: none;
}

/* ── Phase 2d temp-channel create form ──────────────────────────────── */
.temp-create {
    display: grid;
    grid-template-columns: auto 80px auto;
    gap: 8px;
    align-items: center;
    margin-top: 6px;
    grid-column: 1 / -1;
}
.temp-create-label,
.temp-create-suffix {
    color: var(--ink-2);
    font-family: var(--font-ui);
    font-size: 13px;
}
.temp-create input[type="number"] {
    background: transparent;
    border: 1px solid var(--line);
    border-radius: var(--radius-s);
    color: var(--ink-1);
    font-family: var(--font-mono);
    font-size: 12px;
    padding: 2px 6px;
    width: 64px;
}
.temp-create-helper {
    grid-column: 1 / -1;
    color: var(--ink-3);
    font-family: var(--font-ui);
    font-size: 12px;
    margin: 4px 0 0 0;
}
.tree-slot--temp {
    display: grid;
    grid-template-columns: auto 1fr auto auto;
    grid-auto-rows: auto;
    align-items: center;
    gap: 4px;
}

/* ── Phase 3b inline attachments ─────────────────────────────────────────
 *
 * Spec: docs/specs/2026-04-19-ui-design/files-inline.md.
 * Foundation tokens only — no new hex.
 */

.attachment {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    padding: 10px 12px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 10px;
    color: var(--ink-0);
    font-family: var(--font-ui);
    font-size: 14px;
    max-width: 420px;
}

@media (max-width: 720px) {
    .attachment {
        max-width: 100%;
    }
}

.attachment__icon {
    flex: 0 0 auto;
    width: 24px;
    height: 24px;
    color: var(--ink-2);
}

.attachment__icon svg {
    width: 100%;
    height: 100%;
}

.attachment__meta {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.attachment__filename {
    color: var(--ink-0);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.attachment__size {
    color: var(--ink-3);
    font-size: 12px;
}

.attachment__warning {
    color: var(--amber);
    font-size: 12px;
    margin-top: 2px;
}

.attachment__download {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 8px;
    color: var(--ink-2);
    cursor: pointer;
    padding: 6px;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.attachment__download:hover,
.attachment__download:focus-visible {
    color: var(--ink-0);
    border-color: var(--moss-2);
    outline: none;
}

.attachment__download svg {
    width: 16px;
    height: 16px;
}

/* ── Image variant ─────────────────────────────────────────────────────── */

.attachment--image {
    flex-direction: column;
    align-items: flex-start;
    padding: 0;
    background: transparent;
    border: none;
    max-width: 380px;
    gap: 6px;
}

@media (max-width: 720px) {
    .attachment--image {
        max-width: 280px;
    }
}

.attachment__image-link {
    display: block;
    line-height: 0;
}

.attachment__image {
    display: block;
    width: 100%;
    height: auto;
    max-width: 380px;
    border-radius: 10px;
}

@media (max-width: 720px) {
    .attachment__image {
        max-width: 280px;
    }
}

.attachment__caption {
    color: var(--ink-3);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 12px;
    line-height: 1.4;
}

/* ── Voice-note card ──────────────────────────────────────────────
 * Spec: docs/specs/2026-04-19-ui-design/files-inline.md §Voice note.
 * `--bg-2` card on `--line` border, radius 10 px, 10/12 padding,
 * max-width 420 px desktop. Play/pause IconBtn (32x32, --moss-2),
 * waveform strip (24 px tall, --moss-1 bars on --bg-1, --moss-2
 * progress fill), elapsed/total timer in font-mono / 11 px / --ink-3
 * with mm:ss / mm:ss format.
 */

.attachment--voice-note {
    background: var(--bg-2);
    border: 1px solid var(--line);
    border-radius: 10px;
    padding: 10px 12px;
    max-width: 420px;
    display: flex;
    align-items: center;
    gap: 12px;
}

@media (max-width: 720px) {
    .attachment--voice-note {
        max-width: 100%;
    }
}

.attachment__voice-toggle {
    width: 32px;
    height: 32px;
    flex-shrink: 0;
    border-radius: 16px;
    border: 1px solid var(--moss-2);
    background: transparent;
    color: var(--moss-2);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: background var(--transition-fast), color var(--transition-fast);
}

.attachment__voice-toggle:hover,
.attachment__voice-toggle:focus-visible {
    background: rgba(66, 92, 61, 0.18);
    color: var(--ink-0);
    outline: none;
}

.attachment__voice-toggle .icon {
    font-size: 14px;
}

.attachment__voice-body {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.attachment__voice-waveform {
    width: 100%;
    height: 24px;
    display: block;
    background: var(--bg-1);
    border-radius: 4px;
}

.attachment__voice-bar {
    fill: var(--moss-1);
}

.attachment__voice-bar--played {
    fill: var(--moss-2);
}

.attachment__voice-timer {
    color: var(--ink-3);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 11px;
    font-variant-numeric: tabular-nums;
}

.attachment__voice-audio {
    /* Native controls suppressed — the card drives play/pause via the
       toggle button. The element stays focusable for screen readers
       so they still announce state changes. */
    display: none;
}

/* ── Phase 3c — emoji picker, pinned panel, header pin badge ───────────
 *
 * Spec: docs/specs/2026-04-19-ui-design/reactions-pins.md.
 * Foundation tokens only — no new hex.
 */

.emoji-picker {
    width: 320px;
    height: 360px;
    background: var(--bg-1);
    border: 1px solid var(--line);
    border-radius: 10px;
    box-shadow: var(--shadow-2);
    display: flex;
    flex-direction: column;
    padding: 8px;
    gap: 8px;
}

.emoji-picker__search {
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 8px;
    color: var(--ink-0);
    font-family: var(--font-mono, ui-monospace, monospace);
    font-size: 12px;
    padding: 6px 8px;
}

.emoji-picker__search:focus-visible {
    border-color: var(--moss-2);
    outline: none;
}

.emoji-picker__grid {
    flex: 1 1 auto;
    overflow-y: auto;
    display: grid;
    grid-template-columns: repeat(8, 1fr);
    gap: 2px;
    align-content: start;
}

.emoji-picker__cell {
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    padding: 4px;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}

.emoji-picker__cell:hover,
.emoji-picker__cell:focus-visible {
    background: var(--bg-2);
    outline: none;
}

.emoji-picker__cell--selected {
    border-color: var(--moss-2);
    background: var(--bg-2);
}

.emoji-picker__category-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    border-top: 1px solid var(--line);
    padding-top: 6px;
}

.emoji-picker__category-label {
    color: var(--ink-3);
    font-family: var(--font-ui);
    font-size: 11px;
    text-transform: lowercase;
}

/* ── Pinned-panel entry layout ─────────────────────────────────────────── */

.pinned-entry {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--line);
}

.pinned-entry__meta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    color: var(--ink-2);
    font-size: 12px;
}

.pinned-entry__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    background: var(--bg-2);
    color: var(--ink-0);
    font-weight: 500;
    font-size: 12px;
    flex: 0 0 auto;
}

.pinned-entry__author {
    color: var(--ink-0);
    font-weight: 500;
}

.pinned-entry__when {
    color: var(--ink-3);
    font-size: 11px;
    margin-left: auto;
}

.pinned-entry__body {
    color: var(--ink-1);
    font-size: 13px;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

/*
 * `pinned by {name} · {when}` footer per spec
 * `docs/specs/2026-04-19-ui-design/reactions-pins.md`
 * §Pinned panel contents (line 123): --ink-3, 10 px, mono `when`.
 */
.pinned-entry__footer {
    color: var(--ink-3);
    font-family: var(--font-ui);
    font-size: 10px;
    margin-top: 4px;
}

.pinned-entry__footer-when {
    font-family: var(--font-mono);
}

.pinned-entry__actions {
    display: inline-flex;
    gap: 8px;
    margin-top: 4px;
}

.pinned-entry__jump,
.pinned-entry__unpin {
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 6px;
    color: var(--ink-2);
    cursor: pointer;
    padding: 2px 8px;
    font-family: var(--font-ui);
    font-size: 11px;
}

.pinned-entry__jump:hover,
.pinned-entry__jump:focus-visible {
    color: var(--ink-0);
    border-color: var(--moss-2);
    outline: none;
}

.pinned-entry__unpin:not([disabled]):hover,
.pinned-entry__unpin:not([disabled]):focus-visible {
    color: var(--ink-0);
    border-color: var(--amber);
    outline: none;
}

.pinned-entry__unpin[disabled] {
    color: var(--ink-3);
    cursor: not-allowed;
    opacity: 0.5;
}

.pinned-empty {
    color: var(--ink-3);
    font-family: var(--font-display, var(--font-ui));
    font-style: italic;
    font-size: 13px;
    padding: 12px;
}

/* ── Header pin IconBtn — amber tint + count badge ──────────────────── */

.action-btn--lit {
    color: var(--amber);
}

.action-btn__count--pin {
    background: var(--amber);
    color: var(--bg-1);
}

/* ── Phase 3c.2 — emoji picker mount anchors ────────────────────────────
 *
 * The picker popover is absolutely-positioned so it floats above the
 * row / composer instead of pushing layout. Click-away dismissal is
 * the picker's own Escape callback (wired by the host components).
 */

.composer__emoji-picker-anchor,
.message-emoji-picker-anchor {
    position: absolute;
    z-index: 60;
}

.composer__emoji-picker-anchor {
    /* Above the composer pill, anchored to the right edge so the
     * smile button stays under it. */
    bottom: 100%;
    right: 0;
    margin-bottom: 6px;
}

.message-emoji-picker-anchor {
    /* Below the hover toolbar's smile button — the toolbar floats at
     * top: -14px above the row, so the picker drops just under it. */
    top: 28px;
    right: 8px;
}

/* ── Phase 3c.3 — reactions strip + add-reaction chip ──────────────────
 *
 * Spec: docs/specs/2026-04-19-ui-design/reactions-pins.md §Reactions.
 * Foundation tokens only.
 */

.reactions-strip {
    display: flex;
    flex-wrap: wrap;
    gap: 5px;
    margin-top: 6px;
}

.reaction-pill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--bg-2);
    border: 1px solid var(--line);
    color: var(--ink-1);
    font-size: 12px;
    cursor: pointer;
    line-height: 1;
}

@media (max-width: 720px) {
    .reaction-pill {
        font-size: 11px;
    }
}

.reaction-pill:hover,
.reaction-pill:focus-visible {
    border-color: var(--ink-3);
    outline: none;
}

.reaction-pill--reacted {
    border-color: var(--moss-1);
    background: color-mix(in oklab, var(--moss-2) 18%, var(--bg-2));
}

.reaction-pill__count {
    color: var(--ink-2);
    font-weight: 500;
}

/* Add-reaction chip — desktop hover-only per spec. Hidden on mobile
 * because the action sheet exposes the same flow. */
.add-reaction-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 2px 8px;
    border-radius: 999px;
    background: transparent;
    border: 1px dashed var(--line);
    color: var(--ink-3);
    cursor: pointer;
    opacity: 0;
    transition: opacity 120ms;
}

.message:hover .add-reaction-chip,
.message:focus-within .add-reaction-chip,
.add-reaction-chip:focus-visible {
    opacity: 1;
}

.add-reaction-chip:hover {
    color: var(--ink-1);
    border-color: var(--ink-3);
}

@media (max-width: 720px) {
    .add-reaction-chip {
        display: none;
    }
}

@media (prefers-reduced-motion: reduce) {
    .add-reaction-chip {
        transition: none;
    }
}


