@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Sora:wght@800&display=swap');

/* ─── Design Tokens ─── */
:root {
    --bg-primary: #f8f9fc;
    --bg-primary-rgb: 248, 249, 252; /* same colour, comma-separated, for use in rgba() */
    --bg-secondary: #ffffff;
    --bg-tertiary: #f0f1f5;
    --bg-elevated: #ffffff;
    --bg-glass: rgba(0, 0, 0, 0.02);
    --bg-glass-hover: rgba(0, 0, 0, 0.04);

    --text-primary: #1a1a2e;
    --text-secondary: #6b7084;
    --text-muted: #9ca3b4;

    --accent: #2fb383;
    --accent-glow: rgba(47, 179, 131, 0.15);
    --accent-soft: rgba(47, 179, 131, 0.08);
    --accent-gradient: linear-gradient(135deg, #2fb383, #34d399);

    --border: rgba(0, 0, 0, 0.08);
    --border-subtle: rgba(0, 0, 0, 0.04);

    --radius-sm: 8px;
    --radius-md: 12px;
    --radius-lg: 16px;
    --radius-xl: 24px;
    --radius-full: 9999px;

    --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.06);
    --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.08);
    --shadow-glow: 0 0 30px var(--accent-glow);

    --transition: 200ms cubic-bezier(0.4, 0, 0.2, 1);

    /* Tooltip chip — dark slate on light theme for a classic high-contrast look. */
    --tooltip-bg: #1f2733;
    --tooltip-fg: #f4f6fa;
}

/* ─── Dark theme tokens ─── */
[data-theme="dark"] {
    --bg-primary:   #0f1419;
    --bg-primary-rgb: 15, 20, 25;
    --bg-secondary: #161b22;
    --bg-tertiary:  #1e242c;
    --bg-elevated:  #1a2028;
    --bg-glass:       rgba(255, 255, 255, 0.03);
    --bg-glass-hover: rgba(255, 255, 255, 0.06);

    --text-primary:   #e6edf3;
    --text-secondary: #9aa4b1;
    --text-muted:     #6b7280;

    /* Accent stays the same — works on both backgrounds */
    --accent-glow: rgba(47, 179, 131, 0.28);
    --accent-soft: rgba(47, 179, 131, 0.14);

    --border:        rgba(255, 255, 255, 0.08);
    --border-subtle: rgba(255, 255, 255, 0.04);

    --shadow-sm: 0 1px 2px  rgba(0, 0, 0, 0.4);
    --shadow-md: 0 4px 16px rgba(0, 0, 0, 0.45);
    --shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.55);

    /* Slightly lifted slate so the tooltip reads as elevated against the dark UI. */
    --tooltip-bg: #2b3543;
    --tooltip-fg: #f4f6fa;

    color-scheme: dark;
}

/* ─── Custom scrollbars — visible in both themes ─── */
:root {
    --scrollbar-thumb:       rgba(0, 0, 0, 0.18);
    --scrollbar-thumb-hover: rgba(0, 0, 0, 0.32);
}

[data-theme="dark"] {
    --scrollbar-thumb:       rgba(255, 255, 255, 0.18);
    --scrollbar-thumb-hover: rgba(255, 255, 255, 0.32);
}

/* Firefox */
* {
    scrollbar-width: thin;
    scrollbar-color: var(--scrollbar-thumb) transparent;
}

/* WebKit / Chromium / Edge / Safari */
*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

*::-webkit-scrollbar-track {
    background: transparent;
}

*::-webkit-scrollbar-thumb {
    background: var(--scrollbar-thumb);
    border: 2px solid transparent;
    background-clip: padding-box;
    border-radius: 8px;
    transition: background-color 0.15s ease;
}

*::-webkit-scrollbar-thumb:hover {
    background: var(--scrollbar-thumb-hover);
    background-clip: padding-box;
}

*::-webkit-scrollbar-corner {
    background: transparent;
}

/* ─── Reset & Base ─── */
*, *::before, *::after {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
    font-family: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
    font-size: 15px;
    line-height: 1.6;
    color: var(--text-primary);
    background: var(--bg-primary);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

#app {
    height: 100%;
}

/* ─── Scrollbar ─── */
::-webkit-scrollbar {
    width: 6px;
}
::-webkit-scrollbar-track {
    background: transparent;
}
::-webkit-scrollbar-thumb {
    background: rgba(0, 0, 0, 0.1);
    border-radius: var(--radius-full);
}
::-webkit-scrollbar-thumb:hover {
    background: rgba(0, 0, 0, 0.18);
}

/* ─── Layout ─── */
.app-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
    overflow: hidden;
}

/* When not logged in, the entire app shell behind the login overlay is blurred and
   non-interactive. The blur sells the "locked" feel without hiding the brand entirely. */
.app-shell.locked {
    filter: blur(8px) saturate(0.85);
    pointer-events: none;
    user-select: none;
    transition: filter 0.4s ease;
}

/* ─── Login screen ─── */
/* ─── Sign-in page — the Atlas recipe: accent wash, drifting ribbon, hero + card, Docned footer ─── */
.auth-page {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    /* A single accent wash from the top-left corner, fading out into the ground. --bg-secondary is
       white in light mode and the elevated surface in dark, so the page follows the theme. */
    background-color: var(--bg-secondary);
    background-image: radial-gradient(120% 90% at 0% 0%, rgba(47, 179, 131, 0.14) 0%, rgba(47, 179, 131, 0) 55%);
    overflow: auto;
    animation: login-fade-in 0.28s ease-out;
}
@keyframes login-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}
.auth-swirl {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    opacity: 0.2;
    pointer-events: none;
}
[data-theme="dark"] .auth-swirl { opacity: 0.3; }
.auth-swirl-layer { transform-box: fill-box; transform-origin: center; will-change: transform; }
.auth-swirl-layer.a { animation: swirl-drift-a 48s ease-in-out infinite; }
@keyframes swirl-drift-a {
    0%   { transform: translate(-50px, 12px) scaleY(1); }
    50%  { transform: translate(50px, -16px) scaleY(1.06); }
    100% { transform: translate(-50px, 12px) scaleY(1); }
}
@media (prefers-reduced-motion: reduce) {
    .auth-swirl-layer.a { animation: none; }
    .auth-page, .auth-card { animation: none; }
}
.auth-center, .auth-footer { position: relative; z-index: 1; }
.auth-center {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 56px;
    padding: 48px 32px;
    max-width: 1040px;
    width: 100%;
    margin: 0 auto;
}
.auth-hero { flex: 1; min-width: 0; max-width: 480px; }
.auth-brand {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0 0 18px;
}
.auth-logo { width: 44px; height: 44px; flex-shrink: 0; }
.auth-title {
    font: 600 30px/1.2 'Inter', system-ui, sans-serif;
    letter-spacing: -0.02em;
    color: var(--text-primary);
    margin: 0;
}
.auth-body { font-size: 14.5px; line-height: 1.65; color: var(--text-secondary); margin: 0 0 12px; }
.auth-body.muted { color: var(--text-muted); font-size: 13px; }
.auth-rule { width: 48px; height: 3px; border-radius: var(--radius-full); background: var(--accent-gradient); margin: 6px 0 18px; }

.auth-card {
    width: 380px;
    flex-shrink: 0;
    padding: 32px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-lg);
    animation: auth-in 0.3s ease-out;
}
@keyframes auth-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.auth-card-title { font: 600 20px 'Inter', system-ui, sans-serif; letter-spacing: -0.015em; color: var(--text-primary); margin: 0 0 4px; }
.auth-card-sub { font-size: 13px; color: var(--text-muted); margin: 0 0 22px; }
.auth-form .settings-label { display: block; }
.auth-gap { margin-top: 16px; }
.auth-error {
    margin: 0 0 16px;
    padding: 8px 12px;
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.3);
    border-radius: var(--radius-sm);
    color: #b91c1c;
    font-size: 12.5px;
}
[data-theme="dark"] .auth-error { color: #fca5a5; }
.auth-submit {
    width: 100%;
    margin-top: 22px;
    padding: 11px 16px;
    border: none;
    border-radius: var(--radius-sm);
    background: var(--accent-gradient);
    color: #ffffff;
    font: 600 14px 'Inter', system-ui, sans-serif;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    transition: transform 0.15s ease, box-shadow 0.15s ease, opacity 0.15s ease;
}
.auth-submit:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 6px 14px var(--accent-glow), 0 2px 4px rgba(0, 0, 0, 0.06);
}
.auth-submit:active:not(:disabled) { transform: translateY(0); }
.auth-submit:disabled               { opacity: 0.5; cursor: not-allowed; }

.auth-footer {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 16px 24px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted);
}
.auth-footer-version { font-weight: 600; color: var(--text-secondary); }
.auth-footer-logo { height: 22px; opacity: 0.75; }
.auth-footer-logo.dark { display: none; }
[data-theme="dark"] .auth-footer-logo.light { display: none; }
[data-theme="dark"] .auth-footer-logo.dark { display: inline; }

@media (max-width: 860px) {
    .auth-center { flex-direction: column; gap: 28px; padding: 32px 20px; }
    .auth-hero { max-width: 420px; text-align: center; }
    .auth-brand { justify-content: center; }
    .auth-rule { margin-left: auto; margin-right: auto; }
    .auth-card { width: 100%; max-width: 420px; }
}

.app-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 24px;
    height: 56px;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
    backdrop-filter: blur(20px);
}

.app-logo {
    display: flex;
    align-items: center;
    gap: 12px;
}

.app-logo-svg {
    height: 36px;
    width: 36px;
    display: block;
    flex-shrink: 0;
}

.app-logo-icon {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    background: var(--accent-gradient);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    color: white;
    font-weight: 700;
    box-shadow: var(--shadow-glow);
}

.app-logo-text {
    /* Matches the marketing site's header wordmark — Sora, heavy weight, wide uppercase tracking. */
    font-family: 'Sora', 'Inter', system-ui, sans-serif;
    font-size: 16px;
    font-weight: 800;
    letter-spacing: 0.32em;
    text-transform: uppercase;
    color: var(--text-primary);
}

.app-logo-info {
    display: flex;
    flex-direction: column;
    line-height: 1.2;
}

.powered-by {
    font-size: 11px;
    color: var(--text-muted);
    letter-spacing: 0.02em;
}

.powered-by-name {
    font-weight: 600;
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.app-header-status {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: 12px;
    color: var(--text-muted);
}

/* ─── User avatar + dropdown menu (right side of the app bar) ─── */
.app-header-user {
    position: relative;
    display: flex;
    align-items: center;
}
.app-header-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    font: 600 13px 'Inter', system-ui, sans-serif;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--bg-elevated);
    cursor: pointer;
    user-select: none;
    flex-shrink: 0;
    transition: box-shadow 0.12s ease, transform 0.12s ease;
}
.app-header-avatar:hover                       { box-shadow: 0 0 0 3px var(--accent-soft); }
.app-header-user.open .app-header-avatar       { box-shadow: 0 0 0 3px var(--accent-soft); }

.app-header-user-menu {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    z-index: 60;
    min-width: 220px;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12),
                0 2px 6px  rgba(0, 0, 0, 0.06);
    animation: app-header-user-in 0.14s ease-out;
}
@keyframes app-header-user-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0);    }
}

/* Header strip showing the signed-in user's avatar + email */
.app-header-user-meta {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px 12px;
}
.app-header-user-meta-avatar {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    background: var(--accent-soft);
    color: var(--accent);
    font: 600 13px 'Inter', system-ui, sans-serif;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
}
.app-header-user-meta-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.app-header-user-meta-name {
    font: 500 13.5px 'Inter', system-ui, sans-serif;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.app-header-user-meta-email {
    font-size: 11.5px;
    color: var(--text-muted);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.app-header-user-menu-divider {
    height: 1px;
    background: var(--border-subtle);
    margin: 0 4px 4px;
}

.app-header-user-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: 500 13.5px 'Inter', system-ui, sans-serif;
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.app-header-user-menu-item:hover { background: var(--accent-soft); color: var(--accent); }
.app-header-user-menu-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    flex-shrink: 0;
    transition: color 0.12s ease;
}
.app-header-user-menu-item:hover .app-header-user-menu-icon { color: var(--accent); }

.app-header-user-backdrop {
    position: fixed;
    inset: 0;
    z-index: 50;
    background: transparent;
}

.status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #22c55e;
    box-shadow: 0 0 8px rgba(34, 197, 94, 0.4);
}

.status-dot.indexing {
    background: #f59e0b;
    box-shadow: 0 0 8px rgba(245, 158, 11, 0.4);
    animation: pulse 2s ease-in-out infinite;
}

@keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.reindex-btn {
    padding: 4px 12px;
    font-size: 12px;
    font-family: inherit;
    font-weight: 500;
    color: var(--text-secondary);
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: var(--transition);
}

.reindex-btn:hover {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}

.app-body {
    flex: 1;
    display: flex;
    min-height: 0;
}

.app-main {
    flex: 1;
    overflow: hidden;
    min-width: 0;
}

/* ─── Sidebar (recent chats) ─── */
.chat-sidebar {
    width: 260px;
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    background: var(--bg-secondary, #f7f7f8);
    border-right: 1px solid var(--border-subtle);
    overflow: hidden;
}

/* Split control: primary "New chat" + caret to open extra options menu.
   No `overflow: hidden` here — the dropdown menu is absolutely positioned BELOW the split
   and would otherwise be clipped. Rounded corners are applied to the inner buttons instead. */
.sidebar-new-split {
    position: relative;
    display: flex;
    margin: 14px 12px 8px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    transition: border-color 0.15s ease;
}

.sidebar-new-split:hover {
    border-color: var(--accent);
}

.sidebar-new-chat {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 14px;
    background: transparent;
    border: none;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    text-align: left;
    border-radius: calc(var(--radius-md) - 1px);
    transition: background-color 0.15s ease, color 0.15s ease;
}

.sidebar-new-chat:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

.sidebar-new-chat-icon {
    font-size: 18px;
    line-height: 1;
    color: var(--accent);
}

.sidebar-new-caret {
    width: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    border-left: 1px solid var(--border);
    color: var(--text-secondary);
    cursor: pointer;
    /* Round only the side that touches the container's right edge */
    border-radius: 0 calc(var(--radius-md) - 1px) calc(var(--radius-md) - 1px) 0;
    transition: background-color 0.15s ease, color 0.15s ease;
    padding: 0;
}

.sidebar-new-split:hover .sidebar-new-caret {
    border-left-color: var(--accent);
}

.sidebar-new-caret:hover,
.sidebar-new-split.open .sidebar-new-caret {
    background: var(--accent-soft);
    color: var(--accent);
}

.sidebar-new-caret svg {
    transition: transform 0.18s ease;
}

.sidebar-new-split.open .sidebar-new-caret svg {
    transform: rotate(180deg);
}

/* Dropdown menu hanging off the split button */
.sidebar-new-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    padding: 4px;
    z-index: 30;
    animation: sidebar-new-menu-in 0.14s ease-out;
}

@keyframes sidebar-new-menu-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0);    }
}

.sidebar-new-menu-item {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.12s ease;
}

.sidebar-new-menu-item:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

.sidebar-new-menu-icon {
    width: 18px;
    height: 18px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
    flex-shrink: 0;
}

.sidebar-new-menu-item:hover .sidebar-new-menu-icon {
    color: var(--accent);
}

/* Invisible click-anywhere-else dismisser */
.sidebar-new-menu-backdrop {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: transparent;
}

.sidebar-list {
    flex: 1;
    overflow-y: auto;
    padding: 6px 8px 16px;
}

.sidebar-empty {
    padding: 12px 14px;
    font-size: 12px;
    color: var(--text-muted);
    text-align: center;
}

.sidebar-group-label {
    padding: 14px 12px 4px;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
}

.sidebar-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 12px;
    margin: 1px 0;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-size: 13px;
    text-decoration: none;
    transition: background-color 0.12s ease, color 0.12s ease;
    position: relative;
}

.sidebar-item:hover {
    background: var(--accent-soft);
    color: var(--text-primary);
}

.sidebar-item.active {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 500;
}

.sidebar-item-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.sidebar-item-delete {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    border-radius: 4px;
    opacity: 0;
    transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
    padding: 0;
}

.sidebar-item:hover .sidebar-item-delete,
.sidebar-item.active .sidebar-item-delete {
    opacity: 1;
}

.sidebar-item-delete:hover {
    background: rgba(239, 68, 68, 0.15);
    color: #ef4444;
}

/* ─── Sidebar bottom toolbar ─── */
.sidebar-footer {
    flex-shrink: 0;
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 6px;
    padding: 8px 10px;
    border-top: 1px solid var(--border-subtle);
    background: var(--bg-secondary, #f7f7f8);
}

.sidebar-footer-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    cursor: pointer;
    transition: var(--transition);
}

.sidebar-footer-btn:hover {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}

.sidebar-footer-btn svg {
    flex-shrink: 0;
}

/* ─── Settings dialog ─── */
/* `.modal-card` defines its own width later in this stylesheet, so we need a higher
   specificity selector here to win without juggling source order. */
.modal-card.settings-dialog {
    width: 820px;
    max-width: calc(100vw - 32px);
}

/* ─── Vaults dialog ─── */
.modal-card.vaults-dialog {
    width: 960px;
    max-width: calc(100vw - 32px);
    /* Fixed height — tall enough for ~3 rows of datasource cards; the collection grid scrolls
       beyond that. Flex column so only the grid flexes while the chrome stays put. */
    height: 720px;
    max-height: calc(100vh - 32px);
    display: flex;
    flex-direction: column;
}

/* Keep the dialog chrome fixed; only the collection grid flexes + scrolls. */
.modal-card.vaults-dialog > .modal-title,
.modal-card.vaults-dialog > .manage-tabs,
.modal-card.vaults-dialog > .modal-body,
.modal-card.vaults-dialog > .vaults-error,
.modal-card.vaults-dialog > .modal-actions {
    flex-shrink: 0;
}
/* The loading placeholder fills the space so the footer stays pinned to the bottom. */
.modal-card.vaults-dialog > .vaults-empty {
    flex: 1 1 auto;
}
/* The System tab panel fills the remaining height and scrolls inside, so its own Save button can't
   collide with the pinned Done footer. */
.modal-card.vaults-dialog > .settings-tab-panel-scroll {
    flex: 1 1 auto;
    min-height: 0;
}
/* Breathing space + a divider above the dialog's Done footer so it isn't crowded by tab content. */
.modal-card.vaults-dialog > .modal-actions {
    margin-top: 12px;
    padding-top: 14px;
    border-top: 1px solid var(--border-subtle);
}

/* ─── New-report dialog ─── */
/* Fixed-size dialog so it doesn't balloon as the link panel grows; sidebar scrolls
   internally instead. Definite height also lets the Syncfusion viewer in the right
   pane resolve its Height="100%". */
.modal-card.report-dialog {
    width: 1080px;
    max-width: calc(100vw - 32px);
    height: 640px;
    max-height: calc(100vh - 48px);
    display: flex;
    flex-direction: column;
}

/* Header row above the two-column layout. Holds the title + Atelier badge on the
   left, and the close (x) on the right. Replaces the bare h2 the dialog used to ship. */
.modal-header-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 12px;
}
.modal-header-row .modal-title { margin: 0; }   /* row owns the spacing */

.modal-title-with-badge {
    display: flex;
    align-items: center;
    gap: 10px;
}

.modal-title-badge {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--accent);
    background: var(--accent-soft);
    padding: 3px 8px;
    border-radius: 999px;
}

.modal-close-x {
    width: 32px;
    height: 32px;
    border-radius: var(--radius-sm);
    border: none;
    background: transparent;
    color: var(--text-muted);
    display: grid;
    place-items: center;
    cursor: pointer;
    transition: var(--transition);
    flex-shrink: 0;
}
.modal-close-x:hover {
    background: var(--bg-glass-hover);
    color: var(--text-primary);
}

.report-layout {
    flex: 1 1 auto;
    display: grid;
    grid-template-columns: 340px 1fr;
    gap: 20px;
    margin: 8px 0 14px;
    min-height: 0;     /* allow grid children to shrink below content size */
}

/* Section dividers in the sidebar — "SOURCE" / "SHARE" labels with a trailing rule. */
.report-section-divider {
    display: flex;
    align-items: center;
    gap: 10px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.report-section-divider::after {
    content: "";
    flex: 1 1 auto;
    height: 1px;
    background: var(--border-subtle);
}

/* "Configured" status chip on the right side of the secured-link trigger when a
   link has actually been created (not just when the panel is open). */
.report-link-trigger-status {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    font-weight: 500;
    color: var(--accent);
}

/* Status pills sitting over the preview pane (top-right). Pointer events disabled
   so they never intercept clicks targeting the underlying viewer / iframe. */
.preview-toolbar {
    position: absolute;
    top: 10px;
    right: 10px;
    z-index: 5;
    display: flex;
    gap: 6px;
    pointer-events: none;
}
.preview-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-subtle);
    border-radius: 999px;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-secondary);
    box-shadow: var(--shadow-sm);
    white-space: nowrap;
}
.preview-pill .dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-glow);
}

.report-sidebar {
    display: flex;
    flex-direction: column;
    gap: 14px;
    min-height: 0;
}

/* The Share section gets its own overflow:auto so the link panel — the only thing
   tall enough to need scrolling — owns the scroll. Keeping overflow off the outer
   sidebar means the Source dropdowns above sit in a non-clipping context: their
   absolute-positioned menus can extend freely instead of being trapped inside the
   sidebar's scroll boundary. */
.report-sidebar-scroll {
    overflow-y: auto;
    min-height: 0;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
    padding-right: 6px;
}

/* Settings fields globally carry margin-bottom 16px so they stack nicely inside the
   Settings dialog. The report sidebar uses a flex `gap` instead, so the per-field
   margin compounds with the gap and produces ~40px of dead space between dropdowns.
   Direct-child scope only — settings-fields nested inside .report-link-panel still
   rely on the global margin for their own stacking. */
.report-sidebar > .settings-field {
    margin: 0;
}

/* The dropdowns in this dialog (blueprint / folder / language / rendering) only need
   vertical scrolling — long blueprint or folder names should ellipsis, not produce a
   horizontal scrollbar. The base .custom-dropdown-menu sets overflow-y:auto which
   browsers extend to overflow-x:auto too in computed style, so we pin overflow-x
   explicitly here. */
.report-dialog .custom-dropdown-menu {
    overflow-x: hidden;
}

.report-preview-pane {
    position: relative;   /* anchors the absolute .preview-toolbar pills */
    display: flex;
    flex-direction: column;
    min-height: 0;
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

/* Syncfusion wraps its viewer in its own div — make sure that wrapper fills the pane
   so Height="100%" on the viewer resolves properly. */
.report-preview-pane > .e-pdfviewer,
.report-preview-pane > div {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
}

.report-preview-frame {
    flex: 1 1 auto;
    width: 100%;
    border: none;
    display: block;
    background: #fff;
    min-height: 0;
}

.report-preview-placeholder {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 24px;
    text-align: center;
    color: var(--text-muted);
    font-size: 13px;
    line-height: 1.55;
}

.report-preview-placeholder.error {
    color: #b91c1c;
}

/* "Generating document…" — animated paper sheet whose text lines sequentially draw
   in, hold briefly, then reset. Mirrors the chart-loading pattern (stroke-dashoffset
   sweep with the accent colour) but the imagery is a report-style paper sheet.
   Designed to be hypnotic-but-quiet — not attention-grabbing. */
.report-preview-placeholder.report-generating {
    color: var(--accent);
    gap: 16px;
}

.report-doc-anim {
    width: 60px;
    height: 76px;
    overflow: visible;
}

.report-doc-sheet,
.report-doc-fold {
    opacity: 0.4;
}

.report-doc-line {
    stroke-linecap: round;
    /* dasharray > longest line (48u) so we can hide/reveal each line via dashoffset */
    stroke-dasharray: 60;
    stroke-dashoffset: 60;
    opacity: 0.3;
    animation: report-line-fill 3s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

.report-doc-line.l1 { animation-delay: 0.00s; }
.report-doc-line.l2 { animation-delay: 0.35s; }
.report-doc-line.l3 { animation-delay: 0.70s; }
.report-doc-line.l4 { animation-delay: 1.05s; }

@keyframes report-line-fill {
    0%, 100% { stroke-dashoffset: 60; opacity: 0.25; }
    20%      { stroke-dashoffset: 0;  opacity: 1; }
    70%      { stroke-dashoffset: 0;  opacity: 1; }
    90%      { stroke-dashoffset: -60; opacity: 0.25; }
}

.report-generating-label {
    color: var(--accent);
    font-size: 13px;
    font-weight: 500;
    letter-spacing: 0.01em;
}

/* Respect users who've asked the OS for reduced motion — keep the icon + label visible
   but pin every line to "fully drawn", no movement. */
@media (prefers-reduced-motion: reduce) {
    .report-doc-line {
        animation: none;
        stroke-dashoffset: 0;
        opacity: 1;
    }
}

.report-status {
    padding: 12px 14px;
    border-radius: var(--radius-sm);
    background: var(--bg-glass);
    border: 1px dashed var(--border);
    font-size: 13px;
    color: var(--text-secondary);
}

.report-status.error {
    background: rgba(185, 28, 28, 0.06);
    border-color: rgba(185, 28, 28, 0.4);
    color: #b91c1c;
}

/* Blueprint selector — styled on top of the existing .custom-dropdown skeleton. Trigger
   shows the chosen blueprint's name with a small muted "type · format" caption below;
   menu items mirror the same two-line layout plus a left-aligned icon (document for
   PDF blueprints, envelope for communications). */
.blueprint-dropdown .custom-dropdown-trigger {
    padding: 8px 12px;
    height: auto;
    min-height: 40px;
    text-align: left;
}

.blueprint-dropdown .custom-dropdown-value {
    text-align: left;
}

.blueprint-dropdown .blueprint-name {
    display: block;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.blueprint-dropdown .blueprint-meta {
    display: block;
    font-size: 11.5px;
    color: var(--text-muted);
    margin-top: 1px;
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.blueprint-dropdown.open .custom-dropdown-trigger .blueprint-name,
.blueprint-dropdown .custom-dropdown-trigger:hover .blueprint-name {
    color: var(--accent);
}

.blueprint-dropdown.open .custom-dropdown-trigger .blueprint-meta,
.blueprint-dropdown .custom-dropdown-trigger:hover .blueprint-meta {
    color: var(--accent);
    opacity: 0.75;
}

.blueprint-placeholder {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 13px;
}

.blueprint-dropdown .blueprint-menu {
    max-height: 280px;
    overflow-y: auto;
}

/* Scoped under .blueprint-dropdown to outrank the base .custom-dropdown-item rules
   (which live further down the file and would otherwise win on source order — that's
   why the body span was being pushed to the right by flex justify-content). */
.blueprint-dropdown .blueprint-item {
    display: grid;
    grid-template-columns: 18px 1fr auto;
    align-items: center;
    gap: 10px;
    padding: 8px 10px;
    text-align: left;
    justify-content: start;
}

.blueprint-dropdown .blueprint-item-icon {
    grid-column: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--text-secondary);
}

.blueprint-dropdown .blueprint-item.selected .blueprint-item-icon,
.blueprint-dropdown .blueprint-item:hover .blueprint-item-icon {
    color: var(--accent);
}

.blueprint-dropdown .blueprint-item-body {
    grid-column: 2;
    min-width: 0;     /* let the children's ellipsis kick in */
    text-align: left;
    justify-self: start;
}

.blueprint-dropdown .blueprint-item .blueprint-meta {
    color: var(--text-muted);
}

.blueprint-dropdown .blueprint-item:hover .blueprint-meta,
.blueprint-dropdown .blueprint-item.selected .blueprint-meta {
    color: var(--accent);
    opacity: 0.75;
}

.blueprint-dropdown .blueprint-item-check {
    grid-column: 3;
}

.report-link-section {
    border-top: 1px solid var(--border-subtle);
    padding-top: 14px;
}

.report-link-trigger {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 10px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
}

.report-link-trigger:hover,
.report-link-trigger.open {
    border-color: var(--accent);
    color: var(--accent);
}

.report-link-panel {
    margin-top: 12px;
    padding: 14px;
    background: var(--bg-glass);
    border-radius: var(--radius-md);
    border: 1px solid var(--border-subtle);
}

.report-link-output {
    display: flex;
    align-items: stretch;
    gap: 8px;
    flex-wrap: wrap;
}

.report-link-output .settings-input {
    flex: 1 1 100%;     /* full row in the narrower sidebar */
    font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 12px;
    min-width: 0;
}

.report-link-output .modal-btn {
    flex: 0 0 auto;
}

.vaults-layout {
    display: grid;
    grid-template-columns: 260px 1fr;
    gap: 24px;
    margin: 4px 0 18px;
    height: 540px;
}

/* Trash icon on each non-default folder row in the list — same hover-reveal pattern as
   `.sidebar-item-delete`, but a clearer destructive affordance for irreversible folder deletes. */
.vaults-item-delete {
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: none;
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: 4px;
    opacity: 0;
    transition: opacity 0.12s ease, background-color 0.12s ease, color 0.12s ease;
    padding: 0;
    align-self: center;
}
.vaults-item:hover .vaults-item-delete,
.vaults-item.active .vaults-item-delete { opacity: 1; }
.vaults-item-delete:hover {
    background: rgba(239, 68, 68, 0.15);
    color: #ef4444;
}
.vaults-sidebar {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding-right: 12px;
    border-right: 1px solid var(--border-subtle);
    overflow-y: auto;
}

.vaults-empty {
    padding: 14px;
    color: var(--text-muted);
    font-size: 13px;
}

.vaults-item {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: var(--transition);
    width: 100%;
}
.vaults-item:hover                   { color: var(--text-primary); background: var(--bg-glass-hover); }
.vaults-item.active                  { color: var(--accent); background: var(--accent-soft); }
.vaults-item-icon                    { color: var(--text-muted); flex-shrink: 0; padding-top: 1px; display: inline-flex; }
.vaults-item.active .vaults-item-icon { color: var(--accent); }
.vaults-item-body                    { display: flex; flex-direction: column; gap: 3px; min-width: 0; flex: 1; }
.vaults-item-name {
    font-weight: 500;
    color: inherit;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.vaults-item-meta {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 11.5px;
    color: var(--text-muted);
}

.vaults-new {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 12px;
    margin-top: 8px;
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    cursor: pointer;
    transition: var(--transition);
}
.vaults-new:hover {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}

.vaults-editor {
    min-width: 0;
    overflow-y: auto;
    padding-right: 4px;
}
.vaults-empty-state {
    color: var(--text-muted);
    font-size: 13px;
    padding: 24px 0;
}

/* Status block in the editor pane */
.vault-status-card {
    margin: 8px 0 14px;
    padding: 10px 12px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
}
.vault-status-row {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    font-size: 13px;
    color: var(--text-secondary);
}
.vault-status-text { flex: 1; min-width: 0; }
.vault-status-text strong { color: var(--text-primary); font-weight: 600; }
.vault-status-when { color: var(--text-muted); margin-left: 4px; }

/* Inline error message inside the editor */
.vaults-error {
    margin: 8px 0 0;
    padding: 8px 12px;
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.3);
    border-radius: var(--radius-sm);
    color: #b91c1c;
    font-size: 12.5px;
}
[data-theme="dark"] .vaults-error { color: #fca5a5; }

.vaults-delete-confirm {
    background: #ef4444;
    border-color: #ef4444;
}
.vaults-delete-confirm:hover {
    background: #dc2626;
    border-color: #dc2626;
    box-shadow: 0 6px 14px rgba(239, 68, 68, 0.3);
}

/* ─── Datasources collection (card grid) ───
   Replaces the old sidebar+editor split: each datasource is a card; clicking one opens the
   settings modal (.ds-editor-body lives inside a standard .modal-card). */
.ds-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(236px, 1fr));
    align-content: start;
    gap: 12px;
    margin: 4px 0 16px;
    /* Fill the remaining height of the fixed dialog and scroll once the cards overflow.
       min-height:0 lets the grid shrink below its content so the overflow actually scrolls. */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    /* A little bottom room so the last row isn't jammed against the footer when the grid scrolls. */
    padding: 2px 2px 8px;
}

.ds-card {
    display: flex;
    flex-direction: column;
    gap: 8px;
    padding: 14px;
    min-height: 138px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    text-align: left;
    cursor: pointer;
    transition: var(--transition);
}
.ds-card:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}

.ds-card-top {
    display: flex;
    align-items: center;
    gap: 8px;
}
.ds-card-icon {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--text-secondary);
}
.ds-card-name {
    flex: 1;
    min-width: 0;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ds-card-badge {
    flex-shrink: 0;
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    background: var(--bg-glass);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-full);
    padding: 1px 7px;
}
.ds-card-sub {
    flex-shrink: 0;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-secondary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ds-card-status {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-top: auto;
    font-size: 12.5px;
    color: var(--text-secondary);
    min-width: 0;
    flex-shrink: 0;
}
.ds-card-status > span:last-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.ds-card-status-err { color: #b91c1c; }
[data-theme="dark"] .ds-card-status-err { color: #fca5a5; }

.ds-card-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 2px;
    flex-shrink: 0;
}
.ds-card-delete {
    margin-left: auto;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    cursor: pointer;
    border-radius: var(--radius-sm);
    padding: 0;
    transition: var(--transition);
}
.ds-card-delete:hover {
    background: rgba(239, 68, 68, 0.15);
    border-color: rgba(239, 68, 68, 0.4);
    color: #ef4444;
}

/* Dashed "add" tile, sized to match the cards */
.ds-card-new {
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 138px;
    border: 1px dashed var(--border);
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
}
.ds-card-new:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-soft);
}

/* Scroll area inside the datasource settings modal so a long form (Therefore fields) fits */
.ds-editor-body {
    max-height: min(62vh, 560px);
    overflow-y: auto;
    margin: 6px 0 4px;
    padding-right: 4px;
}

/* Status dot — error variant for the indexing card */
.status-dot.error {
    background: #ef4444;
    box-shadow: 0 0 8px rgba(239, 68, 68, 0.4);
}

/* Inline chip button — thin pill used for "Re-index" */
.btn-chip {
    padding: 4px 12px;
    font: 500 12px 'Inter', system-ui, sans-serif;
    color: var(--text-secondary);
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: var(--transition);
}
.btn-chip:hover:not(:disabled) {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}
.btn-chip:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

/* Two-column layout: vertical tab list on the left, active panel on the right */
.settings-tabs-layout {
    display: grid;
    grid-template-columns: 168px 1fr;
    gap: 22px;
    margin: 4px 0 22px;
    height: 440px;
}

.settings-tabs {
    display: flex;
    flex-direction: column;
    gap: 2px;
    padding-right: 16px;
    border-right: 1px solid var(--border-subtle);
}

.settings-tab {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: var(--transition);
}

.settings-tab:hover:not(.active) {
    background: var(--bg-tertiary);
    color: var(--text-primary);
}

.settings-tab.active {
    background: var(--accent-soft);
    color: var(--accent);
    font-weight: 600;
}

.settings-tab svg {
    flex-shrink: 0;
}

.settings-tab-panel {
    min-width: 0; /* allow children with their own min-width to shrink correctly */
    overflow: visible; /* let the language dropdown popover escape without triggering a panel scrollbar */
    animation: settings-tab-fade 0.18s ease-out;
}

/* Tabs whose content is taller than the fixed 440px panel scroll within it. Can't live on
   the base .settings-tab-panel (overflow:visible there lets dropdown popovers escape), so it's
   opt-in per tab. The padding-right keeps text off the scrollbar. */
.settings-tab-panel-scroll {
    overflow-y: auto;
    padding-right: 8px;
}

/* About tab: brand + lead are pinned, only the disclaimer scrolls. */
.settings-tab-panel-about {
    overflow: hidden;
    padding-right: 0;
    display: flex;
    flex-direction: column;
}

.about-layout {
    display: flex;
    flex-direction: column;
    height: 100%;
    min-height: 0;
}

.about-layout > .info-brand,
.about-layout > .info-section:not(.about-disclaimer-scroll) {
    flex: 0 0 auto;
}

.about-disclaimer-scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding-right: 6px;
}

@keyframes settings-tab-fade {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0);   }
}

.settings-field {
    position: relative;
    margin-bottom: 16px;
}

.settings-field:last-of-type {
    margin-bottom: 22px;
}

.settings-label {
    display: block;
    margin-bottom: 6px;
    font-size: 12px;
    font-weight: 600;
    color: var(--text-secondary);
    letter-spacing: 0.02em;
}

.settings-input {
    width: 100%;
    padding: 9px 12px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.4;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
    box-sizing: border-box;
}

.settings-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.settings-textarea {
    resize: none;
    height: 110px;
    line-height: 1.5;
}

/* ─── Custom dropdown (matches the sidebar's new-chat dropdown look) ─── */
.custom-dropdown {
    position: relative;
}

.custom-dropdown-trigger {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}

.custom-dropdown-trigger:hover,
.custom-dropdown.open .custom-dropdown-trigger {
    border-color: var(--accent);
    color: var(--accent);
}

.custom-dropdown-trigger:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.custom-dropdown-trigger svg {
    flex-shrink: 0;
    transition: transform 0.18s ease;
    color: var(--text-secondary);
}

.custom-dropdown.open .custom-dropdown-trigger svg {
    transform: rotate(180deg);
    color: var(--accent);
}

.custom-dropdown-value {
    flex: 1;
    text-align: left;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.custom-dropdown-menu {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    right: 0;
    z-index: 30;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    animation: custom-dropdown-in 0.14s ease-out;
    max-height: 280px;
    overflow-y: auto;
}

@keyframes custom-dropdown-in {
    from { opacity: 0; transform: translateY(-4px); }
    to   { opacity: 1; transform: translateY(0);    }
}

.custom-dropdown-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    text-align: left;
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}

.custom-dropdown-item:hover {
    background: var(--accent-soft);
    color: var(--accent);
}

.custom-dropdown-item.selected {
    color: var(--accent);
}

.custom-dropdown-item svg {
    flex-shrink: 0;
}

/* Click-outside dismisser — invisible overlay covering the rest of the dialog */
.custom-dropdown-backdrop {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: transparent;
}

.settings-hint-block {
    display: block;
    margin-top: 6px;
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-muted);
}

.settings-description {
    margin: 16px 2px 0;
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-muted);
}

.settings-check {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    cursor: pointer;
    user-select: none;
}

.settings-check input[type="checkbox"] {
    appearance: none;
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    margin: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 4px;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease, box-shadow 0.15s ease;
    flex-shrink: 0;
    position: relative;
}

.settings-check input[type="checkbox"]:hover {
    border-color: var(--accent);
}

.settings-check input[type="checkbox"]:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

.settings-check input[type="checkbox"]:checked {
    background: var(--accent);
    border-color: var(--accent);
}

.settings-check input[type="checkbox"]:checked::after {
    content: "";
    position: absolute;
    left: 4px;
    top: 1px;
    width: 5px;
    height: 9px;
    border: solid #fff;
    border-width: 0 2px 2px 0;
    transform: rotate(45deg);
}

.settings-check-label {
    font-size: 13.5px;
    color: var(--text-primary);
    font-weight: 500;
}

/* Segmented control — a small inline row of mutually-exclusive options (e.g. the prompt's
   Low / Medium / High search depth). */
.seg-control {
    display: inline-flex;
    padding: 3px;
    gap: 2px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.seg-opt {
    appearance: none;
    border: none;
    background: transparent;
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    padding: 6px 16px;
    border-radius: calc(var(--radius-sm) - 3px);
    cursor: pointer;
    transition: background 0.15s ease, color 0.15s ease;
}

.seg-opt:hover {
    color: var(--text-primary);
}

.seg-opt.active {
    background: var(--accent);
    color: #fff;
}

/* ───────────────────────── Model comparison (admin /compare) ───────────────────────── */
.compare-wrap {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding: 16px 20px 0;
    gap: 12px;
}

.compare-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 10px 14px;
    background: var(--accent-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
}

.compare-bar-text { display: flex; flex-direction: column; gap: 2px; }
.compare-bar-title { font-size: 13.5px; font-weight: 700; color: var(--text-primary); }
.compare-bar-hint { font-size: 12px; color: var(--text-secondary); }

.compare-bar-actions {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 8px;
}
.compare-exit,
.compare-clear {
    appearance: none;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 600;
    padding: 7px 14px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease;
}
.compare-exit:hover,
.compare-clear:hover { border-color: var(--accent); color: var(--accent); }
.compare-exit:disabled,
.compare-clear:disabled { opacity: 0.5; cursor: not-allowed; }

.compare-grid {
    flex: 1;
    min-height: 0;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px;
}

.compare-pane {
    display: flex;
    flex-direction: column;
    min-height: 0;
    position: relative;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    background: var(--bg-elevated);
    /* visible (not hidden) so the model-combo dropdown in the header can overlap the body below
       without being clipped; the body has its own overflow for scrolling. */
    overflow: visible;
}

.compare-pane-header {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    flex-wrap: wrap;
}
.compare-pane-side {
    font-size: 12px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}
.compare-provider { padding: 2px; }
.compare-provider .seg-opt { padding: 5px 12px; font-size: 12px; }
.compare-provider .seg-opt:disabled { opacity: 0.4; cursor: not-allowed; }
.compare-pane-header .model-combo { flex: 1; min-width: 140px; }

/* Model combobox — a styled suggestion dropdown that still accepts free-typed text. */
.model-combo { position: relative; display: block; }
.model-combo-input { width: 100%; padding: 7px 28px 7px 10px; font-size: 13px; }
.model-combo-caret {
    position: absolute;
    top: 50%;
    right: 8px;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    background: transparent;
    border: none;
    padding: 0;
    color: var(--text-secondary);
    cursor: pointer;
    transition: transform 0.18s ease, color 0.15s ease;
}
.model-combo.open .model-combo-caret { transform: translateY(-50%) rotate(180deg); }
.model-combo-caret:hover { color: var(--accent); }

.model-combo-menu {
    position: absolute;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    z-index: 40;
    max-height: 240px;
    overflow-y: auto;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-md, 0 8px 24px rgba(0, 0, 0, 0.18));
}
.model-combo-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    background: transparent;
    border: none;
    border-radius: calc(var(--radius-sm) - 2px);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    text-align: left;
    cursor: pointer;
    transition: background 0.12s ease, color 0.12s ease;
}
.model-combo-item:hover { background: var(--accent-soft); color: var(--accent); }
.model-combo-item.selected { color: var(--accent); font-weight: 600; }
.model-combo-backdrop {
    position: fixed;
    inset: 0;
    z-index: 39;
    background: transparent;
}

.compare-pane-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    padding: 14px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}
.compare-pane-empty {
    color: var(--text-secondary);
    font-size: 13px;
    font-style: italic;
    margin: auto;
    text-align: center;
}

.compare-msg { display: flex; flex-direction: column; gap: 5px; }
.compare-msg.user .compare-msg-sender { color: var(--accent); }
.compare-msg-sender {
    font-size: 11.5px;
    font-weight: 700;
    color: var(--text-secondary);
}
.compare-msg.user .message-content {
    background: var(--accent-soft);
    border-radius: var(--radius-sm);
    padding: 8px 12px;
}

.compare-tokens {
    display: flex;
    gap: 6px;
    flex-wrap: wrap;
    margin-top: 2px;
}
.compare-token {
    display: inline-flex;
    align-items: center;
    gap: 3px;
    font-size: 11px;
    font-weight: 600;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--bg-subtle, rgba(127, 127, 127, 0.12));
    border: 1px solid var(--border);
    color: var(--text-secondary);
}
.compare-token.in { color: var(--accent); }
.compare-token.out { color: var(--text-primary); }
.compare-token.time { color: var(--text-primary); }
.compare-token.muted { font-weight: 500; font-style: italic; }

.compare-pane-badge {
    position: absolute;
    top: 10px;
    right: 12px;
    background: var(--accent);
    color: #fff;
    font-size: 11.5px;
    font-weight: 700;
    padding: 4px 10px;
    border-radius: 999px;
    box-shadow: var(--shadow-glow);
}

.compare-pick {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    padding: 12px;
    /* Lift the bar clear of the chat-input area's fade-out gradient (.chat-input-area::before,
       ~33px) so the buttons aren't washed out by the transparent overlay. */
    margin-bottom: 38px;
    flex-wrap: wrap;
}
.compare-pick-label { font-size: 13px; font-weight: 600; color: var(--text-primary); margin-right: 4px; }
.compare-pick.decided { color: var(--text-secondary); font-size: 13px; }
.compare-pick-btn {
    appearance: none;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 600;
    padding: 9px 18px;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: border-color 0.15s ease, background 0.15s ease, color 0.15s ease;
}
.compare-pick-btn:hover { border-color: var(--accent); background: var(--accent-soft); color: var(--accent); }
.compare-pick-btn.tie { font-weight: 500; }

.compare-error {
    margin: 0 12px 12px;
    padding: 9px 12px;
    border-radius: var(--radius-sm);
    background: rgba(220, 38, 38, 0.08);
    border: 1px solid rgba(220, 38, 38, 0.25);
    color: #dc2626;
    font-size: 12.5px;
}

.settings-description-top {
    margin: 4px 2px 12px;
}

.settings-description em {
    color: var(--text-secondary);
    font-style: normal;
    font-weight: 600;
}

.settings-hint-block em {
    color: var(--text-secondary);
    font-style: normal;
    font-weight: 600;
}

.settings-hint {
    position: absolute;
    bottom: 6px;
    right: 10px;
    font-size: 11px;
    color: var(--text-muted);
    pointer-events: none;
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
}

/* ─── Info / About dialog ─── */
.modal-card.info-dialog {
    width: 520px;
}

.info-brand {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 18px;
    padding-bottom: 16px;
    border-bottom: 1px solid var(--border-subtle);
}

.info-logo {
    width: 44px;
    height: 44px;
    flex-shrink: 0;
    filter: drop-shadow(0 2px 8px var(--accent-glow));
}

.info-brand-title {
    margin: 0;
    font-size: 18px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}

.info-section {
    margin-bottom: 18px;
}

.info-section:last-of-type {
    margin-bottom: 22px;
}

.info-copyright {
    font-size: 13px;
    color: var(--text-muted);
    margin: 0 0 14px;
    line-height: 1.7;
}

.info-lead {
    font-size: 14px;
    color: var(--text-secondary);
    margin: 0;
    line-height: 1.55;
}

.info-copyright strong {
    color: var(--text-primary);
}

.info-heading {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.info-section p {
    font-size: 13.5px;
    line-height: 1.6;
    color: var(--text-secondary);
    margin: 0 0 10px;
}

.info-section p:last-child {
    margin-bottom: 0;
}

.info-section p strong {
    color: var(--text-primary);
    font-weight: 600;
}

/* ─── Quick-suggestions editor (in Settings dialog) ─── */
.suggestions-editor {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.suggestion-row {
    display: grid;
    grid-template-columns: 140px 1fr;
    gap: 6px;
}

.suggestion-label-input {
    font-weight: 500;
}

.suggestion-prompt-input {
    color: var(--text-secondary);
}

/* ─── Theme picker (Auto / Light / Dark) ─── */
.theme-picker {
    display: flex;
    gap: 6px;
    padding: 4px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
}

.theme-option {
    flex: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 8px 10px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: var(--transition);
}

.theme-option:hover:not(.selected) {
    color: var(--text-primary);
    background: var(--bg-elevated);
}

.theme-option.selected {
    background: var(--bg-elevated);
    color: var(--accent);
    border-color: var(--accent);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
}

.theme-option svg {
    flex-shrink: 0;
}

/* ─── Chat Container ─── */
.chat-wrapper {
    display: flex;
    flex-direction: column;
    height: 100%;
}

/* ─── Prompt-library "save" mode ───
   Toggled by the bookmark button in the sidebar footer. While on:
     1. The chat surface uses a copy/save cursor on user messages only.
     2. Hovering a user bubble paints a rotating gradient ring around the *content bubble*
        (not the whole row, so the avatar and the page background stay clean).
     3. Clicking a user bubble exits the mode (and — eventually — saves the prompt).
   The conic gradient is rotated by animating a typed @property variable, then masked to a
   ring with mask-composite so only the border-shaped band of the gradient is visible. */
@property --prompt-glow-angle {
    syntax: '<angle>';
    initial-value: 0deg;
    inherits: false;
}

/* Selection is user-only. The cursor change scopes itself to user message rows. */
.chat-wrapper.prompt-selecting .message.user {
    cursor: copy;
}

/* The bubble is the content block — what reads as a "chat bubble". On selection-mode
   hover we add a touch of padding so the bubble visually expands into a chip shape, then
   trace a rotating gradient ring around its perimeter via the mask-composite trick. */
.chat-wrapper.prompt-selecting .message.user .message-content {
    position: relative;
    border-radius: 14px;
    padding: 6px 10px;
    margin: -6px -10px;          /* keep the text's vertical position; horizontal lines may
                                    re-wrap slightly because the box is now padded — that's
                                    deliberate, the bubble visually grows into a chip. */
    transition: background-color 0.2s ease;
}

.chat-wrapper.prompt-selecting .message.user .message-content::before {
    content: "";
    position: absolute;
    inset: -2px;
    border-radius: inherit;
    padding: 2px;
    background: conic-gradient(
        from var(--prompt-glow-angle),
        rgba(47, 179, 131, 0)   0deg,
        rgba(47, 179, 131, 0.9) 90deg,
        #5eead4                180deg,
        rgba(47, 179, 131, 0.9) 270deg,
        rgba(47, 179, 131, 0)  360deg);
    /* mask trick: keep only the perimeter ring, drop the inner fill, so the bubble's
       content is never covered by the gradient. */
    -webkit-mask:
        linear-gradient(#000 0 0) content-box,
        linear-gradient(#000 0 0);
    -webkit-mask-composite: xor;
            mask-composite: exclude;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.18s ease;
    /* Soft outer halo around the ring */
    filter: drop-shadow(0 0 6px var(--accent-glow));
}

.chat-wrapper.prompt-selecting .message.user .message-content:hover::before {
    opacity: 1;
    animation: prompt-glow-rotate 3s linear infinite;
}

/* Subtle accent tint behind the bubble on hover so the rotating ring reads as belonging
   to *this* bubble specifically. */
.chat-wrapper.prompt-selecting .message.user .message-content:hover {
    background: var(--accent-soft);
}

@keyframes prompt-glow-rotate {
    to { --prompt-glow-angle: 360deg; }
}

/* Active state on the sidebar footer bookmark button when selection mode is armed */
.sidebar-footer-btn.active {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent);
}

/* ─── Prompt-library flight animation ───
   When the user clicks a bubble in selection mode, JS clones it into a fixed-positioned
   chip that animates toward the bookmark button in the sidebar footer. The chip shrinks
   to a dot at the target, then the target pulses to confirm "saved". */
.prompt-flight-ghost {
    position: fixed;
    z-index: 3000;
    padding: 6px 12px;
    background: var(--accent-soft);
    color: var(--accent);
    border: 1.5px solid var(--accent);
    border-radius: 14px;
    font: 500 14px 'Inter', system-ui, sans-serif;
    line-height: 1.4;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    box-shadow: 0 8px 28px var(--accent-glow), 0 2px 6px rgba(0, 0, 0, 0.08);
    pointer-events: none;
    will-change: transform, opacity;
    transform-origin: center center;
    /* The transition is what drives the flight; transforms + opacity + radius are set in JS
       after a reflow, so the chip slides + shrinks + rounds into a dot at the icon. */
    transition:
        transform 0.6s cubic-bezier(0.5, 0, 0.2, 1),
        opacity 0.6s ease,
        border-radius 0.6s ease;
}

/* Pulse on the bookmark button when the ghost arrives */
@keyframes save-prompt-pulse {
    0%   { transform: scale(1);    box-shadow: 0 0 0 0   var(--accent-glow); }
    50%  { transform: scale(1.25); box-shadow: 0 0 0 8px var(--accent-glow); }
    100% { transform: scale(1);    box-shadow: 0 0 0 0   transparent;        }
}
.save-prompt-pulse {
    animation: save-prompt-pulse 0.55s ease-out;
}

/* ─── Messages ─── */
.chat-messages {
    flex: 1;
    overflow-y: auto;
    /* Clip horizontal overflow so a wide table or long URL inside a message can't push the
       scroll container wider than the viewport (which would render the vertical scrollbar
       off-screen on mobile). Wide content gets its own internal scroll where appropriate
       (see .message-content table / pre). */
    overflow-x: hidden;
    padding: 12px 0 16px;
    display: flex;
    flex-direction: column;
    gap: 4px;
    /* Allow flex children to shrink below their intrinsic content width so this overflow
       rule actually fires instead of being defeated by a min-width: auto child. */
    min-width: 0;
}

.new-chat-bar {
    display: flex;
    justify-content: flex-end;
    padding-bottom: 6px;
}

.new-chat-btn {
    padding: 5px 14px;
    font-size: 12px;
    font-family: inherit;
    font-weight: 500;
    color: var(--text-secondary);
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: var(--transition);
}

.new-chat-btn:hover:not(:disabled) {
    color: var(--accent);
    border-color: var(--accent);
    background: var(--accent-soft);
}

.new-chat-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.message {
    display: flex;
    gap: 14px;
    padding: 16px 40px;
    max-width: 1190px;
    width: 100%;
    margin-left: auto;
    margin-right: auto;
    animation: messageIn 300ms ease-out;
}

@keyframes messageIn {
    from { opacity: 0; transform: translateY(8px); }
    to { opacity: 1; transform: translateY(0); }
}

.message-avatar {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: var(--radius-sm);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
    margin-top: 2px;
}

.message.user .message-avatar {
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    font-weight: 600;
}

.message.assistant .message-avatar {
    background: transparent;
    padding: 0;
}

.message.assistant .message-avatar svg {
    width: 100%;
    height: 100%;
    display: block;
    filter: drop-shadow(0 2px 6px var(--accent-glow));
}

/* ─── Chat bubble alignment ───
   User → right (avatar on the far right, content in a bubble).
   Ventura → left (avatar on the far left, content full-width plain text).        */
.message.user {
    flex-direction: row-reverse;
}

.message.user .message-body {
    flex: 0 1 auto;
    max-width: 75%;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
}

.message.user .message-sender {
    text-align: right;
}

.message.user .message-content {
    background: var(--accent-gradient);
    border: none;
    color: #ffffff;
    padding: 10px 16px;
    border-radius: 18px 18px 4px 18px;
    max-width: 100%;
    word-wrap: break-word;
    box-shadow: 0 2px 8px rgba(47, 179, 131, 0.22);
}

.message.user .message-content p:last-child {
    margin-bottom: 0;
}

/* Inline elements inside the user bubble — pull them onto the accent background  */
.message.user .message-content strong,
.message.user .message-content em {
    color: #ffffff;
}

.message.user .message-content a {
    color: #ffffff;
    text-decoration: underline;
    text-underline-offset: 2px;
}

.message.user .message-content code {
    background: rgba(255, 255, 255, 0.18);
    color: #ffffff;
    border-color: rgba(255, 255, 255, 0.25);
}

/* The "You" label above the bubble — give it the accent colour so the whole right column
   visually reads as one unit. */
.message.user .message-sender {
    color: var(--accent);
}

.message-body {
    flex: 1;
    min-width: 0;
}

.message-sender {
    font-size: 13px;
    font-weight: 600;
    margin-bottom: 6px;
    color: var(--text-primary);
}

.message.assistant .message-sender {
    background: var(--accent-gradient);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
}

.message-content {
    font-size: 14.5px;
    line-height: 1.7;
    color: var(--text-primary);
    /* Break very long unbroken tokens (URLs, hash strings, etc.) so they don't push the
       message bubble wider than its parent. */
    overflow-wrap: anywhere;
    word-break: break-word;
}

.message-content p {
    margin-bottom: 12px;
}
.message-content p:last-child {
    margin-bottom: 0;
}

.message-content strong {
    font-weight: 600;
    color: var(--text-primary);
}

.message-content code {
    background: var(--bg-tertiary);
    padding: 2px 7px;
    border-radius: 5px;
    font-size: 13px;
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    border: 1px solid var(--border);
}

.message-content pre {
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 16px;
    overflow-x: auto;
    margin: 12px 0;
}

.message-content pre code {
    background: none;
    padding: 0;
    border: none;
}

.message-content table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    margin: 16px 0;
    font-size: 13.5px;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.message-content thead {
    background: var(--bg-tertiary);
}

.message-content th {
    text-align: left;
    font-weight: 600;
    padding: 12px 16px;
    border-bottom: 2px solid var(--border);
    color: var(--text-secondary);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    white-space: nowrap;
}

.message-content td {
    padding: 11px 16px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: top;
}

.message-content tr:last-child td {
    border-bottom: none;
}

.message-content tbody tr:hover {
    background: var(--accent-soft);
}

.message-content tbody tr:nth-child(even) {
    background: rgba(0, 0, 0, 0.015);
}

.message-content tbody tr:nth-child(even):hover {
    background: var(--accent-soft);
}

.message-content ul, .message-content ol {
    padding-left: 20px;
    margin: 8px 0;
}

.message-content li {
    margin: 4px 0;
}

/* ─── HTML tables (rendered by AI) ─── */
.message-content table {
    width: 100%;
    margin: 16px 0;
    border-collapse: separate;
    border-spacing: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    box-shadow: var(--shadow-sm);
    font-size: 14px;
    line-height: 1.5;
}

.message-content table thead {
    background: var(--bg-tertiary);
}

.message-content table th {
    padding: 10px 14px;
    text-align: left;
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}

.message-content table td {
    padding: 12px 14px;
    border-bottom: 1px solid var(--border-subtle);
    vertical-align: top;
    color: var(--text-primary);
}

.message-content table tbody tr:last-child td {
    border-bottom: none;
}

.message-content table tbody tr:hover td {
    background: var(--accent-soft);
}

.message-content table td br {
    line-height: 1.8;
}

/* ─── Chart rendering ─── */
.chart-wrapper,
.chart-placeholder.chart-rendered {
    display: block;
    position: relative;
    width: 100%;
    max-width: 720px;
    height: 340px;
    margin: 16px 0;
    padding: 14px;
    background: var(--bg-elevated);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
}

.chart-error {
    margin: 12px 0;
    padding: 10px 14px;
    background: rgba(239, 68, 68, 0.08);
    border: 1px solid rgba(239, 68, 68, 0.3);
    border-radius: var(--radius-sm);
    color: #b91c1c;
    font-size: 13px;
}

/* ─── Chart expand button + fullscreen modal ─── */
.chart-expand-btn {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 28px;
    height: 28px;
    padding: 0;
    border-radius: var(--radius-sm);
    background: var(--bg-elevated);
    border: 1px solid var(--border-subtle);
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s ease, background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
    z-index: 5;
    backdrop-filter: blur(2px);
}

.chart-placeholder.chart-rendered:hover .chart-expand-btn,
.chart-wrapper:hover .chart-expand-btn {
    opacity: 1;
}

.chart-expand-btn:hover,
.chart-expand-btn:focus-visible {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
    opacity: 1;
    outline: none;
}

.chart-modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.62);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 5vh 5vw;
    animation: chart-modal-backdrop-in 0.18s ease-out;
}

@keyframes chart-modal-backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.chart-modal {
    /* Explicit landscape dimensions — Chart.js measures the canvas container at creation
       time. A flex-sized "100%" sometimes hasn't resolved yet, so the chart squishes to a
       square. Hard-coded vw/vh removes the ambiguity. */
    position: relative;
    box-sizing: border-box;
    width: 90vw;
    height: 90vh;
    max-width: 1400px;
    background: var(--bg-elevated);
    border-radius: var(--radius-lg);
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.35), 0 8px 16px rgba(0, 0, 0, 0.12);
    animation: chart-modal-in 0.22s cubic-bezier(0.4, 0, 0.2, 1);
    overflow: hidden;
}

@keyframes chart-modal-in {
    from { opacity: 0; transform: scale(0.96); }
    to   { opacity: 1; transform: scale(1);    }
}

.chart-modal-close {
    position: absolute;
    top: 14px;
    right: 14px;
    width: 36px;
    height: 36px;
    padding: 0;
    border-radius: var(--radius-sm);
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition);
    z-index: 2;
}

.chart-modal-close:hover {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}

/* Absolutely positioned so Chart.js's canvas-parent measurement is unambiguous: width =
   modal-width - 48px, height = modal-height - 84px. No flex calculations to confuse. */
.chart-modal-canvas-wrap {
    position: absolute;
    top: 60px;
    left: 24px;
    right: 24px;
    bottom: 24px;
    box-sizing: border-box;
}

.chart-modal-canvas-wrap canvas {
    display: block;
    /* Chart.js manages width/height itself via inline styles — don't override here */
}

/* Inline pill shown while the AI is still streaming a chart block — small, calm,
   gets out of the way as soon as the closing fence arrives and the real chart renders. */
.chart-loading {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0;
    padding: 8px 14px;
    background: var(--accent-soft);
    border: 1px solid transparent;
    border-radius: var(--radius-full);
    color: var(--accent);
    font-size: 13px;
    font-weight: 500;
}

.chart-loading-line {
    width: 44px;
    height: 14px;
    color: var(--accent);
    overflow: visible;
}

.chart-loading-line polyline {
    /* Total path length is roughly 220 — animate a 60-unit "highlight" sweeping along. */
    stroke-dasharray: 60 220;
    stroke-dashoffset: 280;
    animation: chart-line-draw 1.6s cubic-bezier(0.4, 0, 0.2, 1) infinite;
}

@keyframes chart-line-draw {
    from { stroke-dashoffset: 280; }
    to   { stroke-dashoffset: 0;   }
}

.chart-loading-text {
    color: var(--accent);
    letter-spacing: 0.01em;
}

.chart-placeholder {
    /* Briefly visible between Markdig render and JS render — no content, no height */
    display: none;
}

/* Safety net: if any chart code block slips through (e.g. AI uses a different fence label),
   hide the raw JSON instead of dumping it on the user. */
pre:has(> code.language-chart) { display: none; }
code.language-chart { display: none; }

/* ─── Confirmation modal (re-index, future destructive actions) ─── */
/* ─── Shared-link layout / SharedReport page ─── */
/* Definite-height chain — Syncfusion's PDF viewer needs every ancestor to have a real
   height for its own Height="100%" to resolve, so we pin the shell to 100vh and let
   flex shrink the inner sections from there. min-height: 0 on the flex children is
   necessary to defeat the default min-content min-height that would otherwise overflow. */
.shared-shell {
    height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--bg-primary);
    color: var(--text-primary);
    overflow: hidden;
}

.shared-header {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    padding: 14px 24px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-secondary);
}

.shared-brand {
    display: flex;
    align-items: center;
    gap: 10px;
}

.shared-logo {
    width: 26px;
    height: 26px;
}

.shared-brand-text {
    font-size: 15px;
    font-weight: 600;
    letter-spacing: -0.01em;
    color: var(--text-primary);
}

.shared-main {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    padding: 24px;
    min-height: 0;
}

.shared-report-wrapper {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    min-height: 0;
}

.shared-card {
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 28px 32px;
    width: 400px;
    max-width: calc(100vw - 32px);
    box-shadow: var(--shadow-md);
    margin-top: 8vh;
}

.shared-card-title {
    margin: 0 0 6px;
    font-size: 17px;
    font-weight: 600;
    color: var(--text-primary);
}

/* The Generating stage reuses .report-preview-placeholder (flex: 1 1 auto) inside the
   fixed-width .shared-card. Override the flex sizing so the card hugs its contents
   instead of stretching, and centre the animation. */
.shared-card-generating {
    display: flex;
    justify-content: center;
}

.shared-card-generating .report-preview-placeholder {
    flex: 0 0 auto;
    padding: 8px 0;
}

.shared-card-text {
    margin: 0;
    font-size: 13px;
    line-height: 1.55;
    color: var(--text-secondary);
}

.shared-form {
    margin-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.shared-form-error {
    font-size: 12px;
    color: #b91c1c;
}

.shared-form-submit {
    margin-top: 6px;
    align-self: stretch;
}

.shared-doc-header {
    width: 100%;
    max-width: 1100px;
    margin: 0 auto 12px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 0 4px;
}

.shared-doc-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}

/* Optional sender note shown above the document — sized like a quiet info card. */
.shared-doc-message {
    width: 100%;
    max-width: 1100px;
    margin: 0 auto 10px;
    padding: 12px 14px;
    background: var(--accent-soft);
    border: 1px solid var(--accent-glow);
    border-radius: var(--radius-md);
    color: var(--text-primary);
    font-size: 13px;
    line-height: 1.55;
    white-space: pre-wrap;
}

.shared-doc-download {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 12.5px;
    font-weight: 500;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
}

.shared-doc-download:hover {
    border-color: var(--accent);
    color: var(--accent);
    transform: translateY(-1px);
    box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
}

.shared-doc-download:active {
    transform: translateY(0);
}

/* The viewer frame stretches to fill the remaining viewport. min-height: 0 lets the
   flex item shrink below its content size; without it Syncfusion's internal layout
   pushes the parent past 100vh. */
.shared-doc-frame {
    flex: 1 1 auto;
    width: 100%;
    max-width: 1100px;
    margin: 0 auto;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.shared-doc-iframe {
    flex: 1 1 auto;
    width: 100%;
    border: none;
    background: #fff;
}

/* Syncfusion renders its viewer inside a wrapper element with the e-pdfviewer class.
   That wrapper needs to fill the .shared-doc-frame so its own Height="100%" works. */
.shared-doc-frame > .e-pdfviewer,
.shared-doc-frame > div {
    flex: 1 1 auto;
    min-height: 0;
}

.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.45);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
    animation: modal-backdrop-in 0.18s ease-out;
}

@keyframes modal-backdrop-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.modal-card {
    width: 460px;
    max-width: calc(100vw - 32px);
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 22px 24px 18px;
    box-shadow: 0 24px 60px rgba(0, 0, 0, 0.22), 0 4px 12px rgba(0, 0, 0, 0.08);
    animation: modal-card-in 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}

@keyframes modal-card-in {
    from { opacity: 0; transform: scale(0.96) translateY(10px); }
    to   { opacity: 1; transform: scale(1)    translateY(0);   }
}

.modal-title {
    margin: 0 0 10px;
    font-size: 17px;
    font-weight: 600;
    color: var(--text-primary);
    letter-spacing: -0.01em;
}

.modal-body {
    margin: 0 0 22px;
    font-size: 14px;
    line-height: 1.55;
    color: var(--text-secondary);
}

.modal-body strong {
    color: var(--text-primary);
    font-weight: 600;
}

.modal-actions {
    display: flex;
    justify-content: flex-end;
    gap: 8px;
}

.modal-btn {
    padding: 8px 16px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: 13px;
    font-weight: 500;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
}

.modal-btn:hover {
    border-color: var(--text-secondary);
    color: var(--text-primary);
}

.modal-btn-primary {
    background: var(--accent-gradient);
    border: none;
    color: #ffffff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.modal-btn-primary:hover {
    color: #ffffff;
    border: none;
    transform: translateY(-1px);
    box-shadow: 0 6px 14px var(--accent-glow), 0 2px 4px rgba(0, 0, 0, 0.06);
}

.modal-btn-primary:active {
    transform: translateY(0);
}

/* A disabled action must read as unavailable — the widget editor holds its primary button
   disabled until the form is valid, so an unstyled one would look clickable but do nothing. */
.modal-btn:disabled,
.modal-btn-primary:disabled {
    opacity: 0.45;
    cursor: default;
}
.modal-btn:disabled:hover {
    border-color: var(--border);
    color: var(--text-secondary);
}
.modal-btn-primary:disabled:hover {
    transform: none;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

/* ─── PDF viewer slide-in panel ─── */
.pdf-viewer-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(20, 22, 30, 0.45);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.22s ease, visibility 0s linear 0.22s;
    z-index: 90;
}

.pdf-viewer-backdrop.open {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.22s ease;
}

.pdf-viewer-panel {
    position: fixed;
    top: 0;
    right: 0;
    bottom: 0;
    width: min(880px, 70vw);
    background: var(--bg-elevated);
    border-left: 1px solid var(--border);
    transform: translateX(100%);
    transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
    z-index: 100;
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.pdf-viewer-panel.open {
    transform: translateX(0);
}

.pdf-viewer-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 14px 18px;
    border-bottom: 1px solid var(--border-subtle);
    background: var(--bg-tertiary);
    flex-shrink: 0;
}

.pdf-viewer-title-area {
    display: flex;
    align-items: baseline;
    gap: 10px;
    min-width: 0;
}

.pdf-viewer-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.pdf-viewer-page {
    font-size: 12px;
    color: var(--text-muted);
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    flex-shrink: 0;
}

.pdf-viewer-close {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    border: 1px solid var(--border);
    background: var(--bg-elevated);
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
    flex-shrink: 0;
}

.pdf-viewer-close:hover {
    border-color: var(--accent);
    color: var(--accent);
    background: var(--accent-soft);
}

.pdf-toolbar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 8px 14px;
    background: var(--bg-tertiary);
    border-bottom: 1px solid var(--border-subtle);
    flex-shrink: 0;
    flex-wrap: wrap;
}

.pdf-tb-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    background: transparent;
    border: 1px solid transparent;
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition);
    padding: 0;
}

.pdf-tb-btn:hover:not(:disabled) {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}

.pdf-tb-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}

.pdf-tb-page {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0 4px;
    font-size: 13px;
    color: var(--text-secondary);
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
}

.pdf-tb-page-input {
    width: 48px;
    height: 28px;
    padding: 0 6px;
    text-align: center;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    color: var(--text-primary);
    border-radius: var(--radius-sm);
    font-family: inherit;
    font-size: 13px;
    -moz-appearance: textfield;
}

.pdf-tb-page-input::-webkit-outer-spin-button,
.pdf-tb-page-input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;
}

.pdf-tb-page-input:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 2px var(--accent-soft);
}

.pdf-tb-page-total {
    color: var(--text-muted);
}

.pdf-tb-divider {
    width: 1px;
    height: 22px;
    background: var(--border);
    margin: 0 6px;
}

.pdf-tb-zoom {
    min-width: 50px;
    text-align: center;
    font-size: 13px;
    color: var(--text-secondary);
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
}

.pdf-viewer-body {
    flex: 1;
    min-height: 0;
    overflow: hidden;
    background: var(--bg-secondary);
    position: relative;
}

.pdf-viewer-empty {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--text-muted);
    font-size: 14px;
}

.pdf-viewer-error {
    position: absolute;
    bottom: 16px;
    left: 16px;
    right: 16px;
    padding: 10px 14px;
    background: rgba(239, 68, 68, 0.1);
    border: 1px solid rgba(239, 68, 68, 0.4);
    color: #b91c1c;
    border-radius: var(--radius-sm);
    font-size: 13px;
}

/* ─── Citation links (inline [N] in answers) ─── */
.citation-link {
    position: relative;
    display: inline-block;
    color: var(--accent);
    text-decoration: none;
    font-weight: 600;
    font-size: 0.85em;
    padding: 2px 5px;
    margin: 0 1px;
    border-radius: 4px;
    background: var(--accent-soft);
    transition: background-color 0.12s ease, color 0.12s ease, transform 0.12s ease;
    cursor: pointer;
    line-height: 1.2;
    vertical-align: baseline;
}

.citation-link:hover {
    background: var(--accent);
    color: #ffffff;
    transform: translateY(-1px);
    text-decoration: none;
}

.citation-link:active {
    transform: translateY(0);
}

/* ─── Custom hover tooltip on citation links (replaces native title) ─── */
.citation-link[data-tooltip]::after,
.citation-link[data-tooltip]::before {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    pointer-events: none;
    opacity: 0;
    transform: translate(-50%, 4px);
    transition: opacity 0.14s ease, transform 0.14s ease;
    z-index: 50;
}

.citation-link[data-tooltip]::after {
    content: attr(data-tooltip);
    padding: 6px 10px;
    font-size: 12px;
    font-weight: 500;
    line-height: 1.3;
    color: var(--bg-elevated);
    background: var(--text-primary);
    border-radius: 6px;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.16), 0 1px 3px rgba(0, 0, 0, 0.08);
    letter-spacing: 0.01em;
}

.citation-link[data-tooltip]::before {
    content: "";
    bottom: calc(100% + 3px);
    width: 0;
    height: 0;
    border: 5px solid transparent;
    border-top-color: var(--text-primary);
}

.citation-link[data-tooltip]:hover::after,
.citation-link[data-tooltip]:hover::before,
.citation-link[data-tooltip]:focus-visible::after,
.citation-link[data-tooltip]:focus-visible::before {
    opacity: 1;
    transform: translate(-50%, 0);
    transition-delay: 0.18s;
}

/* Highlight pulse on the source card when a citation is clicked */
@keyframes source-card-pulse {
    0%   { box-shadow: 0 0 0 0 var(--accent-glow);  border-color: var(--accent); }
    50%  { box-shadow: 0 0 0 8px var(--accent-glow); border-color: var(--accent); }
    100% { box-shadow: 0 0 0 0 transparent;          border-color: var(--border-subtle); }
}

.source-card.source-highlight {
    animation: source-card-pulse 1.6s ease-out;
}

/* ─── Answer rating (thumbs up / down) ─── */
.message-rate {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 4px;
    margin-top: 12px;
}

/* Time to answer, left of the thumbs. Quiet by design — the same muted tone as an unpressed thumb,
   tabular digits so "9.8 s" and "12.4 s" line up across answers, a little air before the buttons. */
.message-rate-time {
    font-size: 12px;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
    margin-right: 6px;
    white-space: nowrap;
}

.message-rate-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    background: none;
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.12s ease, background-color 0.12s ease,
                border-color 0.12s ease, transform 0.12s ease;
}

.message-rate-btn:hover {
    background: var(--bg-tertiary);
    color: var(--text-secondary);
}

.message-rate-btn:active {
    transform: scale(0.9);
}

/* Active up — accent green; only the thumb colours in (no border/background) to read as "selected". */
.message-rate-btn.up.active {
    color: var(--accent);
}

.message-rate-btn.up.active svg {
    fill: var(--accent);
    stroke: var(--accent);
}

/* Active down — muted red; only the thumb colours in (no border/background). */
.message-rate-btn.down.active {
    color: #e5484d;
}

.message-rate-btn.down.active svg {
    fill: #e5484d;
    stroke: #e5484d;
}

/* Full-screen confetti overlay — non-interactive, painted above everything. */
.vbi-confetti-canvas {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    pointer-events: none;
    z-index: 9999;
}

/* ─── Source citations (RAG) ─── */
.sources {
    margin-top: 16px;
    padding-top: 14px;
    border-top: 1px solid var(--border-subtle);
}

.sources-label {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.08em;
    margin-bottom: 8px;
    /* button reset — the label doubles as the collapse toggle */
    padding: 0;
    background: none;
    border: none;
    font-family: inherit;
    cursor: pointer;
    transition: color 0.12s ease;
}

.sources-label:hover {
    color: var(--text-secondary);
}

.sources.collapsed .sources-label {
    margin-bottom: 0;
}

.sources-chevron {
    transition: transform 0.15s ease;
}

.sources.collapsed .sources-chevron {
    transform: rotate(-90deg);
}

.sources-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 5px;
    border-radius: 8px;
    background: var(--border-subtle);
    color: var(--text-muted);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0;
}

.sources-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.source-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 8px 12px;
    width: 100%;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    font-size: 13px;
    font-family: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.12s ease, background-color 0.12s ease, box-shadow 0.12s ease;
}

.source-card:hover {
    border-color: var(--accent);
    background: var(--bg-elevated);
    box-shadow: var(--shadow-sm);
}

.source-card:active {
    transform: translateY(1px);
}

.source-page {
    font-size: 11px;
    font-weight: 500;
    color: var(--text-muted);
    flex-shrink: 0;
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
}

.source-open-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--accent);
    flex-shrink: 0;
    opacity: 0.55;
    transition: opacity 0.15s ease, transform 0.15s ease;
}

.source-card:hover .source-open-icon {
    opacity: 1;
    transform: translateX(2px);
}

/* Download icon nudges down rather than right on hover. */
.source-card:hover .source-open-icon.download {
    transform: translateY(2px);
}

.source-docno {
    flex-shrink: 0;
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    font-size: 11px;
    font-weight: 500;
    color: var(--text-muted);
    white-space: nowrap;
}

/* ─── System settings panel (Manage dialog) ─── */
.settings-section-heading {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    margin: 18px 0 10px;
    padding-bottom: 6px;
    border-bottom: 1px solid var(--border-subtle);
}
.settings-section-heading:first-child {
    margin-top: 0;
}
.settings-saved-note {
    font-size: 12.5px;
    color: var(--accent);
    margin: 4px 0 0;
}

/* ─── AI models: per-role provider + model grid ─── */
.ai-role-grid {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 6px 0 4px;
}
.ai-role-head,
.ai-role-row {
    display: grid;
    /* Provider column wide enough for "Microsoft Foundry" without wrapping or clipping. */
    grid-template-columns: 96px 200px 1fr;
    gap: 10px;
    align-items: center;
}
.ai-role-head {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
    padding: 0 2px 2px;
}
.ai-role-name {
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
}
/* Tighten the inputs inside a row so the three controls line up at the same height. */
.ai-role-row .settings-input {
    padding: 7px 10px;
    font-size: 13px;
}
/* The provider picker is the app's custom dropdown (fully-styled menu) sized to the row. */
.ai-role-row .ai-role-dd .custom-dropdown-trigger {
    padding: 7px 10px;
    font-size: 13px;
}
.ai-embed-warning {
    margin-top: 8px;
    color: var(--text-secondary);
}

/* ─── Therefore datasource conditions editor + lexicon editor (same row-editor shape) ─── */
.thr-conditions,
.thr-workflows,
.lexicon-rows {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 6px;
}
/* Workflow rows are a two-column table (ProcessNo, Description) plus the remove button. The
   process number is a short integer, so it gets a fixed narrow column and the description takes
   the rest — keeping the header labels aligned over their inputs. */
.thr-workflow-row {
    display: grid;
    grid-template-columns: 110px 1fr 28px;
    align-items: center;
    gap: 6px;
}
.thr-workflow-row .settings-input { min-width: 0; }
.thr-workflow-head {
    font-size: 11.5px;
    font-weight: 600;
    letter-spacing: 0.02em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.thr-condition-row {
    display: flex;
    align-items: center;
    gap: 6px;
}
.thr-condition-row .settings-input {
    flex: 1;
    min-width: 0;
}
/* Lexicon rows give the key a fixed column so the descriptions line up and get the space. */
.lexicon-row {
    display: grid;
    grid-template-columns: 180px auto 1fr 28px;
    align-items: center;
    gap: 6px;
}
.lexicon-row .settings-input { min-width: 0; }
.thr-condition-eq,
.lexicon-eq {
    color: var(--text-muted);
    font-weight: 600;
    flex-shrink: 0;
}
.thr-condition-remove,
.lexicon-remove {
    flex-shrink: 0;
    width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border-subtle);
    background: transparent;
    color: var(--text-muted);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.thr-condition-remove:hover,
.lexicon-remove:hover {
    background: rgba(239, 68, 68, 0.15);
    border-color: rgba(239, 68, 68, 0.4);
    color: #ef4444;
}
/* ── Therefore "Index fields" tab: which index-data fields Ventura keeps ── */

.thr-fields-error {
    color: #d9534f;
    font-size: 12.5px;
}

.thr-field-group {
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 10px 12px;
    margin-bottom: 10px;
    background: var(--bg-glass);
}

/* Sticky inside .thr-fields-scroll so the category name and the All / None / Reload chips stay
   put while a long field list scrolls under them. Needs an OPAQUE background: the group's own
   tint is translucent, and rows would show through as they pass underneath. The negative margin
   bleeds the bar out to the group's edges so nothing slips past it at the sides. */
.thr-field-group-head {
    position: sticky;
    top: 0;
    z-index: 1;
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: -10px -12px 8px;
    padding: 9px 12px 8px;
    background: var(--bg-tertiary);
    border-bottom: 1px solid var(--border-subtle);
    border-radius: var(--radius-md) var(--radius-md) 0 0;
}

.thr-field-group-name {
    font-weight: 600;
    font-size: 13.5px;
    color: var(--text-primary);
}

.thr-field-cat {
    color: var(--text-muted);
    font-weight: 400;
    font-size: 12px;
}

/* Sits right of the name so "6 of 61" reads as the headline fact about the category. */
.thr-field-count {
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    margin-right: auto;
}

.thr-field-bulk {
    background: none;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    color: var(--text-secondary);
    font-size: 11.5px;
    padding: 2px 10px;
    cursor: pointer;
    font-family: inherit;
}
.thr-field-bulk:hover { border-color: var(--accent); color: var(--accent); }
.thr-field-bulk:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* The tab fills the editor body and does not scroll; .thr-fields-scroll below is the one scroll
   region. Two nested scrollbars — one on the field list, one on the tab — is what a long category
   produced before, and neither of them was obviously the one to drag. */
/* Two classes deliberately: .settings-field:last-of-type sets a 22px bottom margin, which
   out-specifies a single class. That margin sits OUTSIDE height:100%, so on its own it pushed the
   tab past the body and put the second scrollbar straight back. */
.settings-field.thr-fields-tab {
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-bottom: 0;
}
/* Sized to its content, shrinking to a scroller only when the fields outgrow the space. Stretching
   it to fill would leave a short category — nine fields — floating above a band of empty panel with
   the help text stranded at the very bottom. The label and help text never shrink, so the panel is
   the only thing that gives. */
.thr-fields-scroll {
    flex: 0 1 auto;
    min-height: 0;
    overflow-y: auto;
}
.thr-fields-tab > .settings-label,
.thr-fields-tab > .settings-description,
.thr-fields-tab > .thr-fields-error {
    flex: none;
}

/* Columns rather than one long list: a big category runs to a hundred-odd fields, and a single
   column would make the panel scroll far further than anyone wants to drag. No cap of its own —
   the scroll belongs to the panel above. */
.thr-field-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 2px 14px;
}

.thr-field-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 3px 4px;
    border-radius: var(--radius-sm);
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
    min-width: 0;
}
.thr-field-item:hover { background: var(--bg-glass-hover); }
/* The checkbox itself comes from .settings-check on the same label — the app's custom control,
   shared with every other checkbox in the dialog. Nothing to add here. */

.thr-field-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.thr-field-type {
    margin-left: auto;
    font-size: 10.5px;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
    flex: none;
}

.thr-condition-add,
.lexicon-add {
    align-self: flex-start;
    font-size: 12.5px;
    font-weight: 500;
    color: var(--accent);
    background: transparent;
    border: 1px dashed var(--border);
    border-radius: var(--radius-sm);
    padding: 5px 10px;
    cursor: pointer;
}
.thr-condition-add:hover,
.lexicon-add:hover {
    background: var(--accent-soft);
    border-color: var(--accent);
}

.source-num {
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    font-size: 11px;
    font-weight: 600;
    color: var(--accent);
    background: var(--accent-soft);
    padding: 2px 6px;
    border-radius: 3px;
    min-width: 28px;
    text-align: center;
}

.source-name {
    flex: 1;
    color: var(--text-primary);
    font-weight: 500;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.source-download {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    border-radius: var(--radius-sm);
    background: var(--accent-soft);
    color: var(--accent);
    text-decoration: none;
    font-size: 14px;
    font-weight: 700;
    transition: var(--transition);
    line-height: 1;
}

.source-download:hover {
    background: var(--accent-gradient);
    color: white;
    box-shadow: var(--shadow-glow);
}

/* Small thumbnail shown on image source cards, left of the [N] badge. */
.source-thumb {
    width: 34px;
    height: 34px;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-subtle);
    background: var(--bg-secondary);
}

/* ─── Inline photos in an answer ─── */
/* Image sources the answer cited render as thumbnails below the text; click → lightbox. */
.message-photos {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 14px;
}

.message-photo {
    padding: 0;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--bg-secondary);
    cursor: zoom-in;
    overflow: hidden;
    line-height: 0;
    transition: border-color 0.12s ease, box-shadow 0.12s ease, transform 0.12s ease;
}

.message-photo:hover {
    border-color: var(--accent);
    box-shadow: var(--shadow-sm);
}

.message-photo:active {
    transform: translateY(1px);
}

.message-photo img {
    display: block;
    max-width: 240px;
    max-height: 240px;
    width: auto;
    height: auto;
    object-fit: cover;
}

/* ─── Photo lightbox ─── */
.lightbox-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(15, 23, 42, 0.78);
    z-index: 2200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 4vh 4vw;
    cursor: zoom-out;
    animation: chart-modal-backdrop-in 0.18s ease-out;
}

.lightbox-img {
    max-width: 100%;
    max-height: 100%;
    object-fit: contain;
    border-radius: var(--radius-md);
    box-shadow: 0 30px 80px rgba(0, 0, 0, 0.45);
    cursor: default;
    animation: chart-modal-in 0.22s cubic-bezier(0.4, 0, 0.2, 1);
}

.lightbox-close {
    position: fixed;
    top: 18px;
    right: 18px;
    width: 40px;
    height: 40px;
    padding: 0;
    border-radius: var(--radius-sm);
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    color: var(--text-secondary);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: var(--transition);
    z-index: 2;
}

.lightbox-close:hover {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}


/* ─── Typing indicator ─── */
.typing-indicator {
    display: inline-flex;
    gap: 4px;
    padding: 4px 0;
}

/* What the assistant is doing right now, under the typing dots. Quiet by design — it is
   reassurance while the model works, not content, and it is replaced the moment the answer
   starts arriving. Each new step fades in so a changing line reads as progress. */
.progress-step {
    font-size: 13px;
    color: var(--text-muted);
    margin-top: 2px;
    animation: progress-step-in 0.25s ease-out;
}

@keyframes progress-step-in {
    from { opacity: 0; transform: translateY(2px); }
    to   { opacity: 1; transform: translateY(0); }
}

.typing-indicator span {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--accent);
    animation: typing 1.4s infinite;
}

.typing-indicator span:nth-child(2) { animation-delay: 0.2s; }
.typing-indicator span:nth-child(3) { animation-delay: 0.4s; }

@keyframes typing {
    0%, 60%, 100% { opacity: 0.2; transform: scale(0.8); }
    30% { opacity: 1; transform: scale(1); }
}

/* ─── Streaming cursor ─── */
/* Inline pulsing dot that sits at the end of the latest token while a response is being
   generated. It's injected into the rendered HTML by AppendStreamingCursor() so it appears
   inline with the last text rather than on its own line. The base styling already looks
   "alive" (filled accent + glow) so even when the animation resets between chunks the user
   never sees a dead/static dot. */
.streaming-cursor {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-left: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 8px var(--accent-glow), 0 0 2px var(--accent);
    vertical-align: middle;
    animation: streaming-cursor-pulse 1.1s ease-in-out infinite;
    /* Slight visual lift so it doesn't sit on the text baseline awkwardly */
    transform: translateY(-1px);
}

@keyframes streaming-cursor-pulse {
    0%, 100% { opacity: 1; transform: translateY(-1px) scale(1); }
    50%      { opacity: 0.4; transform: translateY(-1px) scale(0.6); }
}

/* ─── Empty State ─── */
.chat-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 24px;
    padding: 40px 20px;
}

/* Each child of .chat-empty animates in with a tiny stagger so the empty screen feels
   alive instead of just popping in. The chip stagger is layered on top further down. */
.empty-icon,
.empty-title,
.empty-subtitle,
.suggestions,
.prompt-cards,
.prompt-browse-link {
    opacity: 0;
    transform: translateY(8px);
    animation: empty-in 0.42s cubic-bezier(0.4, 0, 0.2, 1) forwards;
}

.empty-icon       { animation-delay: 0.00s; }
.empty-title      { animation-delay: 0.08s; }
.empty-subtitle   { animation-delay: 0.16s; }
.suggestions      { animation-delay: 0.24s; }
.prompt-cards     { animation-delay: 0.24s; }
.prompt-browse-link { animation-delay: 0.32s; }

@keyframes empty-in {
    to { opacity: 1; transform: translateY(0); }
}

.empty-icon {
    width: 80px;
    height: 80px;
    display: block;
    filter: drop-shadow(0 6px 18px var(--accent-glow));
}

.empty-title {
    font-size: 22px;
    font-weight: 600;
    letter-spacing: -0.02em;
    text-align: center;
    max-width: 600px;
}

.empty-subtitle {
    font-size: 14px;
    color: var(--text-secondary);
    text-align: center;
    max-width: 500px;
}

.suggestions {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    justify-content: center;
    max-width: 700px;
}

.suggestion-chip {
    padding: 8px 16px;
    font-size: 13px;
    color: var(--text-secondary);
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
    /* Per-chip stagger — layered on top of the parent .suggestions fade-in.
       The parent appears first; then each chip pops in 60ms apart. */
    opacity: 0;
    transform: translateY(6px) scale(0.96);
    animation: chip-in 0.36s cubic-bezier(0.4, 0, 0.2, 1) forwards;
    transition: color 0.15s ease, background-color 0.15s ease,
                border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.suggestion-chip:nth-child(1) { animation-delay: 0.30s; }
.suggestion-chip:nth-child(2) { animation-delay: 0.36s; }
.suggestion-chip:nth-child(3) { animation-delay: 0.42s; }
.suggestion-chip:nth-child(4) { animation-delay: 0.48s; }
.suggestion-chip:nth-child(n+5) { animation-delay: 0.54s; }

@keyframes chip-in {
    to { opacity: 1; transform: translateY(0) scale(1); }
}

.suggestion-chip:hover {
    color: var(--text-primary);
    background: var(--bg-glass-hover);
    border-color: var(--accent);
    box-shadow: 0 0 20px var(--accent-glow);
    transform: translateY(-1px);
}

/* ─── Prompt library cards on the empty screen ─── */
.prompt-cards {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 12px;
    width: 100%;
    max-width: 720px;
}
.prompt-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    padding: 14px 16px;
    text-align: left;
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    cursor: pointer;
    font-family: inherit;
    transition: color 0.15s ease, background-color 0.15s ease,
                border-color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}
.prompt-card:hover:not(:disabled) {
    background: var(--bg-glass-hover);
    border-color: var(--accent);
    box-shadow: 0 0 20px var(--accent-glow);
    transform: translateY(-1px);
}
.prompt-card:disabled { opacity: 0.6; cursor: default; }
.prompt-card-title {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
}
.prompt-card-desc {
    font-size: 12.5px;
    color: var(--text-secondary);
    line-height: 1.4;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}
.prompt-card-scope {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    margin-top: 2px;
    font-size: 11.5px;
    color: var(--text-muted);
}
.prompt-browse-link {
    background: none;
    border: none;
    color: var(--accent);
    font: 500 13px inherit;
    cursor: pointer;
    padding: 4px 8px;
}
.prompt-browse-link:hover { text-decoration: underline; }

/* Clarifying-question option chips — rendered under an assistant message when the AI asked
   the user to disambiguate. Left-aligned (not centred like the empty-state suggestions) and
   allowed to wrap, since clarification options are full phrases rather than short prompts. */
.clarify-options {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 14px;
}

.clarify-options .suggestion-chip {
    white-space: normal;
    text-align: left;
}

/* ─── Workflow confirmation ───
   Deliberately NOT chips. A clarification chip is one of several equally-safe ways to refine a
   question; these two buttons decide whether an irreversible action runs in Therefore, so the
   approve button is a solid primary and the decline sits beside it as an equal, easy choice —
   never a faint afterthought the user has to hunt for. */
/* The list the action will actually run on, rendered from the tool result rather than the answer
   text. Quiet but unmistakable — it is a manifest to check, not a second copy of the answer. */
.confirm-manifest {
    margin-top: 14px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-glass);
    padding: 10px 14px;
}
.confirm-manifest-head {
    font-size: 12.5px;
    color: var(--text-secondary);
    margin-bottom: 6px;
}
.confirm-manifest-head span { color: var(--text-muted); }
.confirm-manifest-list {
    margin: 0;
    padding-left: 18px;
    max-height: 260px;
    overflow-y: auto;
    font-size: 13px;
    color: var(--text-primary);
}
.confirm-manifest-list li { margin: 2px 0; }

.confirm-options {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 14px;
}

.confirm-btn {
    padding: 9px 18px;
    font-size: 13px;
    font-weight: 600;
    font-family: inherit;
    border-radius: var(--radius-full);
    cursor: pointer;
    border: 1px solid transparent;
    transition: background-color 0.15s ease, border-color 0.15s ease,
                color 0.15s ease, box-shadow 0.15s ease, transform 0.15s ease;
}

.confirm-btn.approve {
    color: #fff;
    background: var(--accent);
    border-color: var(--accent);
}
.confirm-btn.approve:hover {
    box-shadow: 0 0 20px var(--accent-glow);
    transform: translateY(-1px);
}

.confirm-btn.decline {
    color: var(--text-secondary);
    background: var(--bg-glass);
    border-color: var(--border);
}
.confirm-btn.decline:hover {
    color: var(--text-primary);
    background: var(--bg-glass-hover);
    border-color: var(--border-strong, var(--border));
    transform: translateY(-1px);
}

/* ─── Input Area ─── */
/* Input area:
   - Spans the full width of the chat column (so the background + fade can mask content
     scrolling behind it across the whole width).
   - The actual input bubble inside is centered and capped narrower than the chat area,
     so it's easier to scan and matches modern chat UI conventions.
   - A gradient pseudo-element sits ABOVE the area, fading from transparent to the page
     background, so messages scroll cleanly out of view rather than colliding hard against
     the input bar. */
.chat-input-area {
    width: 100%;
    padding: 8px 40px 24px;
    flex-shrink: 0;
    background: var(--bg-primary);
    position: relative;
}

.chat-input-area::before {
    content: '';
    position: absolute;
    bottom: 100%;
    left: 0;
    right: 0;
    height: 33px;
    background: linear-gradient(to bottom,
                                rgba(var(--bg-primary-rgb), 0)    0%,
                                rgba(var(--bg-primary-rgb), 0.85) 60%,
                                var(--bg-primary)                  100%);
    pointer-events: none;
}

.chat-input-container {
    position: relative;
    display: flex;
    align-items: flex-end;
    gap: 10px;
    padding: 6px 6px 6px 6px;
    max-width: 980px;
    margin: 0 auto;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-xl);
    transition: var(--transition);
    box-shadow: var(--shadow-sm);
}

/* ─── Vault selector inside the chat input ─── */
.chat-input-vault {
    position: relative;
    align-self: stretch;
    display: flex;
    align-items: center;
    flex-shrink: 0;
}
.chat-input-vault-trigger {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 100%;
    padding: 8px 12px;
    background: var(--bg-tertiary);
    border: 1px solid transparent;
    border-radius: calc(var(--radius-xl) - 6px);
    color: var(--text-secondary);
    font: 500 13px 'Inter', system-ui, sans-serif;
    cursor: pointer;
    transition: var(--transition);
    white-space: nowrap;
    max-width: 220px;
}
.chat-input-vault-trigger:hover:not(:disabled) {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent);
}
.chat-input-vault.open .chat-input-vault-trigger {
    color: var(--accent);
    background: var(--accent-soft);
    border-color: var(--accent);
}
.chat-input-vault-trigger:disabled {
    cursor: default;
    opacity: 0.85;
}
.chat-input-vault.locked .chat-input-vault-trigger {
    background: transparent;
    border: 1px dashed var(--border);
    color: var(--text-muted);
}
.chat-input-vault-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 140px;
}

.chat-input-vault-menu {
    position: absolute;
    bottom: calc(100% + 6px);
    left: 0;
    z-index: 30;
    min-width: 200px;
    /* overflow stays visible so the subfolder flyout can escape to the side; the inner
       list owns the scroll instead. */
    overflow: visible;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    animation: chat-input-vault-in 0.14s ease-out;
}
.chat-input-vault-list {
    max-height: 280px;
    overflow-y: auto;
}
@keyframes chat-input-vault-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0);   }
}

.chat-input-vault-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    width: 100%;
    padding: 9px 12px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: 500 13.5px 'Inter', system-ui, sans-serif;
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.chat-input-vault-item:hover         { background: var(--accent-soft); color: var(--accent); }
.chat-input-vault-item.selected      { color: var(--accent); }
.chat-input-vault-backdrop {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: transparent;
}

/* ─── Folder row trailing icons (check / partial dot / subfolder chevron) ─── */
.chat-input-vault-item-end {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
.chat-input-vault-chevron {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    margin: -4px -6px -4px 0;   /* enlarge hit area without growing the row */
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    cursor: pointer;
    transition: color 0.12s ease, background-color 0.12s ease;
}
.chat-input-vault-chevron:hover { color: var(--accent); background: var(--accent-soft); }
.chat-input-vault-chevron.open  { color: var(--accent); }

/* ─── Subfolder flyout — a cascading panel beside the folder menu ─── */
.chat-input-vault-submenu {
    position: absolute;
    left: calc(100% + 6px);
    bottom: 0;
    z-index: 31;
    min-width: 200px;
    max-width: 300px;
    max-height: 320px;
    overflow-y: auto;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    animation: chat-input-vault-in 0.14s ease-out;
}
.chat-input-vault-submenu-head {
    padding: 6px 10px 8px;
    margin-bottom: 2px;
    border-bottom: 1px solid var(--border);
    color: var(--text-muted);
    font: 600 11px 'Inter', system-ui, sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ─── Folder tree: disclosure caret + nested subfolder rows ─── */
.chat-input-vault-treerow {
    display: flex;
    align-items: center;
    gap: 2px;
}
.chat-input-vault-treerow .chat-input-vault-item { flex: 1; min-width: 0; }
.chat-input-vault-treerow .chat-input-vault-item span:first-child {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.chat-input-vault-disc {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-muted);
    cursor: pointer;
    transition: transform 0.12s ease, color 0.12s ease, background-color 0.12s ease;
}
.chat-input-vault-disc:hover { color: var(--accent); background: var(--accent-soft); }
.chat-input-vault-disc.open  { transform: rotate(90deg); }
.chat-input-vault-disc-spacer {
    flex-shrink: 0;
    width: 20px;
    height: 20px;
}
.chat-input-vault-subitem { font-size: 13px; color: var(--text-secondary); }
.chat-input-vault-partial {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--accent);
    opacity: 0.65;
}

/* ─── Prompt library: input-row picker (reuses the folder-menu look) ─── */
.chat-input-prompts {
    position: relative;
    align-self: stretch;
    display: flex;
    align-items: center;
    flex-shrink: 0;
}
/* ─── Prompt flyout: macOS-dock "fan" ─── */
/* No panel chrome — the rows float as a fan of thumbnails + dark pill labels, springing up out
   of the trigger which sits at the menu's bottom-left. */
.chat-input-prompts-menu {
    left: -6px;
    min-width: 0;
    max-width: none;
    max-height: none;
    overflow: visible;
    padding: 0 0 4px;
    background: none;
    border: none;
    box-shadow: none;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
    transform-origin: bottom left;
    animation: dock-flyout-in 0.2s cubic-bezier(0.34, 1.4, 0.64, 1);
}
@keyframes dock-flyout-in {
    from { opacity: 0; transform: translateY(6px) scale(0.94); }
    to   { opacity: 1; transform: translateY(0) scale(1); }
}

/* Each fan row is just a floating pill button — no chrome of its own. */
.chat-input-prompts-menu .chat-input-prompt-item {
    display: flex;
    width: auto;
    max-width: 320px;
    padding: 0;
    background: none;
    border: none;
    cursor: pointer;
    /* Final resting transform — leant out along the fan arc by --arc. The entrance animation
       interpolates to this same value so the row settles into the fan, no `forwards` needed. */
    transform: translateX(var(--arc, 0px));
    animation: dock-item-in 0.36s cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
    animation-delay: calc(var(--i, 0) * 0.045s);
}
@keyframes dock-item-in {
    from { opacity: 0; transform: translate(0, 16px) scale(0.85); }
    60%  { opacity: 1; }
    to   { opacity: 1; transform: translate(var(--arc, 0px), 0) scale(1); }
}

/* Pill label — the floating dark lozenge. Hover gives a subtle dock-style lift + magnify. */
.chat-input-prompt-pill {
    max-width: 300px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    padding: 8px 15px;
    background: var(--tooltip-bg);
    color: var(--tooltip-fg);
    font: 600 12.5px 'Inter', system-ui, sans-serif;
    letter-spacing: 0.01em;
    border-radius: 999px;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.22);
    transform-origin: left center;
    transition: transform 0.16s cubic-bezier(0.34, 1.56, 0.64, 1),
                background-color 0.14s ease, box-shadow 0.16s ease;
}
.chat-input-prompt-item:hover .chat-input-prompt-pill,
.chat-input-prompt-item:focus-visible .chat-input-prompt-pill {
    background: var(--accent);
    color: #fff;
    transform: scale(1.06);
    box-shadow: 0 6px 18px var(--accent-glow);
}
.chat-input-prompt-more .chat-input-prompt-pill {
    color: var(--accent);
    font-weight: 700;
}
.chat-input-prompt-more:hover .chat-input-prompt-pill { color: #fff; }

/* Empty-state — a single floating card (no rows to fan). */
.chat-input-prompts-menu .chat-input-prompts-empty {
    align-self: flex-start;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
}

/* Tiny dock-icon bounce on the trigger when the flyout opens. */
.chat-input-prompts.open .chat-input-prompts-trigger {
    animation: dock-trigger-bounce 0.34s cubic-bezier(0.34, 1.56, 0.64, 1);
}
@keyframes dock-trigger-bounce {
    0%   { transform: translateY(0); }
    40%  { transform: translateY(-3px); }
    100% { transform: translateY(0); }
}

@media (prefers-reduced-motion: reduce) {
    .chat-input-prompts-menu,
    .chat-input-prompts-menu .chat-input-prompt-item,
    .chat-input-prompt-item:hover .chat-input-prompt-pill,
    .chat-input-prompts.open .chat-input-prompts-trigger {
        animation: none;
        transition: none;
    }
}
.chat-input-prompts-group {
    padding: 8px 12px 4px;
    font: 600 11px 'Inter', system-ui, sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}
.chat-input-prompts-empty {
    padding: 12px;
    font-size: 12.5px;
    color: var(--text-muted);
    line-height: 1.4;
    max-width: 240px;
}
.chat-input-prompt-item { justify-content: space-between; }
.chat-input-prompt-title { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-input-prompt-scope {
    flex-shrink: 0;
    margin-left: 8px;
    font-size: 11px;
    color: var(--text-muted);
}
/* The prompts trigger is a <button> reusing the attach (label) look — strip the native
   button chrome (grey fill + border) so only the circular icon-button styling shows. */
.chat-input-prompts-trigger {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: none;
    padding: 0;
    font: inherit;
}
.chat-input-prompts-trigger:hover {
    background: var(--accent-soft);
}
/* "More…" row that opens the full picker dialog. */
.chat-input-prompt-more {
    justify-content: center;
    color: var(--accent);
    font-weight: 600;
    margin-top: 2px;
}

/* ─── Prompt library dialog: optional-field hint + subfolder checklist ─── */
.settings-optional {
    font-weight: 400;
    font-size: 12px;
    color: var(--text-muted);
}
.prompt-subfolders {
    max-height: 200px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.prompt-subfolder-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 5px 6px;
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
    border-radius: var(--radius-sm);
}
.prompt-subfolder-row:hover { background: var(--accent-soft); }
.prompt-subfolder-row input { accent-color: var(--accent); flex-shrink: 0; }

/* ─── Folders & Universes dialog: tab strip ─── */
.manage-tabs {
    display: flex;
    gap: 4px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--border);
    overflow-x: auto;
    scrollbar-width: none;
}
.manage-tabs::-webkit-scrollbar { height: 0; }
.manage-tab {
    appearance: none;
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    padding: 8px 14px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text-muted);
    cursor: pointer;
    /* A tab label is one line by definition — a two-line tab breaks the strip's baseline and
       makes the underline sit under half of it. If the strip runs out of room, scroll it. */
    white-space: nowrap;
    flex: none;
}
.manage-tab:hover { color: var(--text-primary); }
.manage-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* ─── Universe editor: datasource (folder) checklist ─── */
.universe-sources {
    display: flex;
    flex-direction: column;
    gap: 6px;
    max-height: 320px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.universe-source {
    border-radius: var(--radius-sm);
    padding: 4px 6px;
}
.universe-source.member { background: var(--accent-soft); }
.universe-source-head { margin: 0; }
.universe-source-note {
    margin: 4px 0 2px 26px;
    font-size: 12px;
}
.universe-source-tree {
    margin: 6px 0 4px 26px;
    max-height: 180px;
}

/* ─── Universe editor: wider modal + user / manager assignment checklists ─── */
.modal-card.universe-editor {
    width: min(820px, 94vw);
    max-width: 94vw;
}
/* Fixed height (not min/max) so the dialog stays the exact same size on every tab — taller
   tabs scroll inside the body rather than growing the modal. */
.modal-card.universe-editor .ds-editor-body,
/* Wider than the base modal: the editor carries six tabs, and at the default 460px the strip
   wraps — "Index fields" broke onto a second line. The extra width also lets the index-field
   checklist run three columns instead of one. */
.modal-card.datasource-editor {
    width: 760px;
    max-width: calc(100vw - 32px);
}
.modal-card.datasource-editor .ds-editor-body {
    height: min(68vh, 440px);
    overflow-y: auto;
}
.universe-assign-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
    max-height: 200px;
    overflow-y: auto;
    padding: 4px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.universe-assign-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 5px 6px;
    border-radius: var(--radius-sm);
    cursor: pointer;
}
.universe-assign-row:hover { background: var(--accent-soft); }
.universe-assign-name { flex: 1 1 auto; font-size: 13px; }
.universe-assign-role {
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--text-muted);
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: 999px;
    padding: 1px 8px;
}

/* ─── Chat input: universe picker rows ─── */
.chat-input-universe-body {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
    text-align: left;
}
.chat-input-universe-name {
    font-size: 13px;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.chat-input-universe-meta {
    font-size: 11px;
    color: var(--text-muted);
}
.chat-input-universe-create {
    appearance: none;
    background: none;
    border: none;
    padding: 0;
    margin: 0 2px;
    color: var(--accent);
    font: inherit;
    cursor: pointer;
    text-decoration: underline;
}

/* ─── Prompt picker dialog (the "More…" full browse) ─── */
.prompt-picker-dialog { max-width: 520px; width: 100%; }
.prompt-picker-search { margin-bottom: 12px; }
.prompt-picker-list {
    max-height: 50vh;
    overflow-y: auto;
    margin: 0 -4px;
    padding: 0 4px;
}
.prompt-picker-group {
    padding: 10px 6px 4px;
    font: 600 11px 'Inter', system-ui, sans-serif;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-muted);
}
.prompt-picker-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 3px;
    width: 100%;
    padding: 10px 12px;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-md);
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    transition: background-color 0.12s ease, border-color 0.12s ease;
}
.prompt-picker-item:hover { background: var(--accent-soft); border-color: var(--accent); }
.prompt-picker-item-title { font-size: 14px; font-weight: 600; color: var(--text-primary); }
.prompt-picker-item-desc {
    font-size: 12.5px;
    color: var(--text-secondary);
    line-height: 1.4;
}

/* ─── Paperclip / attachment trigger ─── */
.chat-input-attach {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    align-self: center;
    /* Pull closer to the vault selector to its left — they read as a single "left tools"
       cluster rather than three evenly-spaced controls. */
    margin-left: -4px;
    margin-bottom: 0;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    transition: var(--transition);
}
.chat-input-attach:hover {
    color: var(--accent);
    background: var(--accent-soft);
}
/* Hide the native file input — the surrounding <label> is the visible click target */
.chat-input-attach-file {
    position: absolute;
    width: 0;
    height: 0;
    opacity: 0;
    pointer-events: none;
}

/* ─── Effort selector (Low / Medium / High) ─── */
.chat-input-effort {
    position: relative;
    align-self: center;
    flex-shrink: 0;
    /* Tighter against the send button to its right — same "right cluster" treatment as
       the paperclip's negative margin against the vault selector. */
    margin-right: -4px;
}
.chat-input-effort-trigger {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    transition: var(--transition);
}
.chat-input-effort-trigger:hover,
.chat-input-effort.open .chat-input-effort-trigger {
    color: var(--accent);
    background: var(--accent-soft);
}

/* ─── Microphone / voice dictation ─── */
.chat-input-mic {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    align-self: center;
    width: 30px;
    height: 30px;
    /* Tuck against the send button to its right, mirroring the effort selector. */
    margin-right: -2px;
    background: transparent;
    border: none;
    border-radius: 50%;
    color: var(--text-muted);
    cursor: pointer;
    transition: var(--transition);
}
.chat-input-mic:hover:not(:disabled) {
    color: var(--accent);
    background: var(--accent-soft);
}
.chat-input-mic:disabled {
    opacity: 0.4;
    cursor: default;
}
/* While recording: solid red with a soft pulsing halo so it reads as "live". */
.chat-input-mic.recording {
    color: #fff;
    background: #ef4444;
    animation: mic-pulse 1.4s ease-in-out infinite;
}
.chat-input-mic.recording:hover:not(:disabled) {
    color: #fff;
    background: #dc2626;
}
@keyframes mic-pulse {
    0%   { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.45); }
    70%  { box-shadow: 0 0 0 7px rgba(239, 68, 68, 0); }
    100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0); }
}

/* ─── Custom tooltips ─── */
/* A single floating chip (created once in JS) that replaces the browser's plain native title
   tooltip. The JS controller borrows each element's `title`, positions this chip, and restores
   the title on mouse-out. An arrow points back at the trigger via data-placement. */
.vtt {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 4000;
    max-width: 260px;
    padding: 6px 10px;
    background: var(--tooltip-bg);
    color: var(--tooltip-fg);
    font-size: 12px;
    font-weight: 500;
    line-height: 1.45;
    letter-spacing: 0.01em;
    text-align: center;
    white-space: normal;
    border-radius: 7px;
    box-shadow: var(--shadow-lg);
    pointer-events: none;
    opacity: 0;
    transform: translateY(3px);
    transition: opacity 0.12s ease, transform 0.12s ease;
}
.vtt.visible {
    opacity: 1;
    transform: translateY(0);
}
/* Arrow — a small rotated square tucked under the chip, flipped when placed below the trigger. */
.vtt::after {
    content: "";
    position: absolute;
    width: 8px;
    height: 8px;
    background: var(--tooltip-bg);
    transform: rotate(45deg);
}
.vtt[data-placement="top"]::after,
.vtt[data-placement="bottom"]::after {
    left: var(--vtt-arrow, 50%);
    margin-left: -4px;
}
.vtt[data-placement="top"]::after    { bottom: -4px; }
.vtt[data-placement="bottom"]::after { top: -4px; }
.vtt[data-placement="right"]::after,
.vtt[data-placement="left"]::after {
    top: var(--vtt-arrow-y, 50%);
    margin-top: -4px;
}
.vtt[data-placement="right"]::after { left: -4px; }
.vtt[data-placement="left"]::after  { right: -4px; }

.chat-input-effort-menu {
    position: absolute;
    bottom: calc(100% + 6px);
    right: 0;
    z-index: 30;
    min-width: 200px;
    padding: 4px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.12), 0 2px 6px rgba(0, 0, 0, 0.06);
    animation: chat-input-effort-in 0.14s ease-out;
}
@keyframes chat-input-effort-in {
    from { opacity: 0; transform: translateY(4px); }
    to   { opacity: 1; transform: translateY(0);   }
}

.chat-input-effort-item {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    gap: 4px 10px;
    width: 100%;
    padding: 8px 12px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    color: var(--text-primary);
    font: 500 13.5px 'Inter', system-ui, sans-serif;
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.chat-input-effort-item:hover    { background: var(--accent-soft); color: var(--accent); }
.chat-input-effort-item.selected { color: var(--accent); }
.chat-input-effort-name          { grid-column: 1; }
.chat-input-effort-hint {
    grid-column: 1 / -1;
    font: 400 11.5px 'Inter', system-ui, sans-serif;
    color: var(--text-muted);
}
.chat-input-effort-item:hover .chat-input-effort-hint    { color: var(--accent); opacity: 0.8; }
.chat-input-effort-item.selected .chat-input-effort-hint { color: var(--accent); opacity: 0.8; }
.chat-input-effort-item svg      { grid-column: 2; grid-row: 1; }

.chat-input-effort-backdrop {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: transparent;
}

/* ─── Slash-command autocomplete popup ─── */
.chat-command-popup {
    position: absolute;
    bottom: calc(100% + 8px);
    left: 0;
    z-index: 40;
    width: 100%;
    max-width: 460px;
    padding: 5px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: 0 12px 28px rgba(0, 0, 0, 0.14), 0 2px 6px rgba(0, 0, 0, 0.07);
    animation: chat-input-effort-in 0.14s ease-out;
}
.chat-command-popup-header {
    padding: 5px 10px 6px;
    font-size: 10.5px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    color: var(--text-muted);
}
.chat-command-item {
    display: flex;
    align-items: baseline;
    gap: 9px;
    width: 100%;
    padding: 7px 10px;
    background: transparent;
    border: none;
    border-radius: var(--radius-sm);
    cursor: pointer;
    text-align: left;
    transition: background-color 0.12s ease;
}
.chat-command-item:hover {
    background: var(--accent-soft);
}
.chat-command-name {
    flex-shrink: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 13px;
    font-weight: 600;
    color: var(--accent);
}
.chat-command-arg {
    flex-shrink: 0;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 11.5px;
    color: var(--text-muted);
}
.chat-command-desc {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 12.5px;
    color: var(--text-secondary);
}

/* ─── Attachment chips above the input ─── */
.chat-attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    max-width: 980px;
    margin: 0 auto 8px;
    padding: 0 12px;
}
.chat-attachment-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 6px 4px 10px;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    font: 500 12.5px 'Inter', system-ui, sans-serif;
    color: var(--text-primary);
    max-width: 280px;
}
.chat-attachment-chip.loading { color: var(--text-secondary); }
.chat-attachment-chip.error {
    border-color: rgba(239, 68, 68, 0.4);
    color: #b91c1c;
}
[data-theme="dark"] .chat-attachment-chip.error { color: #fca5a5; }

.chat-attachment-icon { color: var(--text-muted); flex-shrink: 0; display: inline-flex; }
.chat-attachment-chip.error .chat-attachment-icon { color: #ef4444; }

/* Thumbnail preview for image attachments, in place of the file icon. */
.chat-attachment-thumb {
    width: 22px;
    height: 22px;
    flex-shrink: 0;
    object-fit: cover;
    border-radius: 4px;
    border: 1px solid var(--border-subtle);
}

.chat-attachment-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
}
.chat-attachment-error {
    font-size: 11px;
    color: #ef4444;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

/* Small inline spinner for the loading state — same DNA as the .spinner from the style guide
   but sized to fit the chip's 14 px icon slot. */
.chat-attachment-spinner {
    display: inline-block;
    width: 12px;
    height: 12px;
    border: 1.5px solid var(--accent-soft);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: chat-attachment-spin 0.9s linear infinite;
    flex-shrink: 0;
}
@keyframes chat-attachment-spin { to { transform: rotate(360deg); } }

.chat-attachment-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 18px;
    height: 18px;
    background: transparent;
    border: none;
    color: var(--text-muted);
    border-radius: 50%;
    cursor: pointer;
    padding: 0;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.chat-attachment-remove:hover {
    background: rgba(239, 68, 68, 0.15);
    color: #ef4444;
}

.chat-input-container:focus-within {
    border-color: rgba(47, 179, 131, 0.4);
    box-shadow: 0 0 0 3px var(--accent-soft), var(--shadow-md);
}

.chat-input {
    flex: 1;
    background: transparent;
    border: none;
    outline: none;
    color: var(--text-primary);
    font-family: inherit;
    font-size: 14.5px;
    line-height: 1.5;
    padding: 8px 0;
    resize: none;
    min-height: 24px;
    max-height: 200px;
    overflow-y: auto;
}

.chat-input::placeholder {
    color: var(--text-muted);
}

.send-btn {
    width: 36px;
    height: 36px;
    padding: 0;
    border: none;
    border-radius: 12px;
    background: var(--accent-gradient);
    color: #ffffff;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    line-height: 0;
    transition: transform 0.15s ease,
                box-shadow 0.18s ease,
                background-color 0.18s ease,
                color 0.18s ease;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
}

.send-btn:hover:not(:disabled) {
    transform: translateY(-1px);
    box-shadow: 0 6px 14px var(--accent-glow), 0 2px 4px rgba(0, 0, 0, 0.06);
}

.send-btn:active:not(:disabled) {
    transform: translateY(0);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
    transition-duration: 0.05s;
}

.send-btn:disabled {
    background: var(--bg-tertiary);
    color: var(--text-muted);
    cursor: not-allowed;
    box-shadow: none;
    opacity: 1;
}

/* ─── Stop button — replaces send while a response is streaming.
   Same accent colour as the send button so the swap feels like one button changing
   mode (send → stop) rather than two different controls. The pulsing ring signals
   "something is in progress, click to abort." ─── */
.send-btn.stop-btn {
    background: var(--accent-gradient);
    color: #ffffff;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.08);
    animation: stop-btn-pulse 1.6s ease-in-out infinite;
}

.send-btn.stop-btn:hover {
    transform: translateY(-1px);
    box-shadow: 0 6px 14px var(--accent-glow), 0 2px 4px rgba(0, 0, 0, 0.06);
    animation-play-state: paused;
}

.send-btn.stop-btn:active {
    transform: translateY(0);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}

@keyframes stop-btn-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(47, 179, 131, 0.0), 0 1px 2px rgba(0, 0, 0, 0.08); }
    50%      { box-shadow: 0 0 0 5px var(--accent-soft), 0 1px 2px rgba(0, 0, 0, 0.08); }
}

/* ─── Blazor Overrides ─── */
.valid.modified:not([type=checkbox]) {
    outline: none;
}
.invalid {
    outline: 1px solid #e50000;
}
.blazor-error-boundary {
    background: #b32121;
    padding: 1rem;
    color: white;
    border-radius: var(--radius-md);
}
#blazor-error-ui {
    display: none;
    background: #fff3f3;
    border-top: 1px solid #fecaca;
    color: #991b1b;
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    padding: 12px 20px;
    z-index: 1000;
}

/* ─── Hamburger menu button (mobile only) ───
   Lives on the left of the header. Hidden on desktop (the sidebar is always visible there)
   and revealed on small screens via the responsive block below. */
.app-header-menu {
    display: none;        /* shown by media query */
    width: 36px;
    height: 36px;
    margin-right: 8px;
    padding: 0;
    background: transparent;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    color: var(--text-secondary);
    cursor: pointer;
    align-items: center;
    justify-content: center;
    transition: var(--transition);
    flex-shrink: 0;
}
.app-header-menu:hover {
    color: var(--accent);
    background: var(--accent-soft);
}

/* Backdrop dimmer behind the sidebar drawer — only visible while drawer is open + on mobile */
.app-body-backdrop {
    display: none;         /* enabled by the media query */
    position: fixed;
    inset: 56px 0 0 0;     /* below the header */
    background: rgba(15, 23, 42, 0.45);
    z-index: 90;
    animation: app-body-backdrop-fade 0.2s ease-out;
}
@keyframes app-body-backdrop-fade {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* ──────────────────────────────────────────────────────────────────────────
   ─── RESPONSIVE LAYOUT ── tablet & phone breakpoints
   ────────────────────────────────────────────────────────────────────────── */

/* Tablet (≤ 1024px) — narrow modals, tighter sidebars, smaller hero text */
@media (max-width: 1024px) {
    .modal-card.settings-dialog,
    .modal-card.vaults-dialog {
        width: calc(100vw - 32px);
    }
    .pdf-viewer-panel { width: min(640px, 90vw); }
}

/* Phone (≤ 768px) — sidebar becomes a drawer, dialogs go single-column / full-height */
@media (max-width: 768px) {

    /* ─── App header ─── */
    .app-header {
        padding: 0 12px;
    }
    .app-header-menu { display: inline-flex; }
    .app-logo-text   { display: none; }    /* logo SVG only — saves ~110 px */

    /* ─── Sidebar drawer ─── */
    .chat-sidebar {
        position: fixed;
        top: 56px;
        left: 0;
        bottom: 0;
        width: 280px;
        max-width: 80vw;
        z-index: 100;
        transform: translateX(-100%);
        transition: transform 0.28s cubic-bezier(0.4, 0, 0.2, 1);
        box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
    }
    .app-body.sidebar-open .chat-sidebar { transform: translateX(0); }

    .app-body-backdrop { display: block; }

    /* ─── Chat empty screen ─── */
    .chat-empty       { padding: 24px 16px; }
    .empty-icon       { width: 72px;  height: 72px;  }
    .empty-title      { font-size: 22px; }
    .empty-subtitle   { font-size: 13.5px; max-width: none; }
    .suggestions      { gap: 8px; }
    .suggestion-chip  { font-size: 12.5px; padding: 8px 12px; }

    /* ─── Chat messages ─── */
    .chat-messages    { padding: 12px 12px 16px; }
    .message          { gap: 8px; padding: 10px 4px; }
    .message-avatar   { width: 28px; height: 28px; font-size: 12px; }
    .message-avatar svg { width: 28px; height: 28px; }
    .message-content  { font-size: 14px; }
    .sources-list     { flex-direction: column; align-items: stretch; }

    /* Tables can be wider than the viewport once you have a few columns. Turn each one into
       a block-level scroll container so the user can swipe sideways within the table without
       the whole chat-messages region getting an off-screen horizontal scrollbar. */
    .message-content table {
        display: block;
        max-width: 100%;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* ─── Chat input area ─── */
    .chat-input-area {
        padding: 6px 12px 12px;
    }
    .chat-input-container {
        flex-wrap: wrap;
        padding: 6px;
        border-radius: var(--radius-lg);
    }
    .chat-input {
        flex: 1 1 100%;
        order: -1;          /* textarea above the row of action buttons */
        padding: 8px 4px;
        max-height: 160px;
    }
    .chat-input-vault-trigger { padding: 7px 10px; font-size: 12.5px; max-width: 160px; }
    .chat-input-vault-name    { max-width: 100px; }
    .chat-input-attach        { margin-left: 0; }
    /* Push effort + send to the right edge of the wrapped action row so the effort popover
       (anchored right:0 with min-width: 200px) lands fully on screen instead of bleeding off
       the left edge when its trigger sits in the middle of the row. */
    .chat-input-effort        { margin-right: 0; margin-left: auto; }
    .send-btn                 { width: 32px; height: 32px; }
    .chat-attachments         { padding: 0 12px; }

    /* ─── Settings dialog: switch from side-tabs to top-tabs on phone ─── */
    .modal-card.settings-dialog {
        width: 100%;
        max-width: 100%;
        height: 100vh;
        max-height: 100vh;
        border-radius: 0;
        padding: 16px 16px 12px;
    }
    .settings-tabs-layout {
        grid-template-columns: 1fr;
        gap: 12px;
        height: auto;
        min-height: 0;
    }
    .settings-tabs {
        flex-direction: row;
        overflow-x: auto;
        scrollbar-width: none;
        padding: 0 0 8px;
        border-right: none;
        border-bottom: 1px solid var(--border-subtle);
    }
    .settings-tabs::-webkit-scrollbar { display: none; }
    .settings-tab { flex-shrink: 0; }

    /* ─── Vaults dialog: single column ─── */
    .modal-card.vaults-dialog {
        width: 100%;
        max-width: 100%;
        height: 100vh;
        max-height: 100vh;
        border-radius: 0;
        padding: 16px 16px 12px;
    }
    .vaults-layout {
        grid-template-columns: 1fr;
        gap: 14px;
        height: auto;
    }
    .vaults-sidebar {
        max-height: 200px;
        overflow-y: auto;
        padding-right: 0;
        border-right: none;
        border-bottom: 1px solid var(--border-subtle);
        padding-bottom: 12px;
    }

    /* ─── Generic modal cards ─── */
    .modal-card {
        width: calc(100vw - 24px);
        padding: 18px 20px 14px;
    }

    /* ─── PDF viewer slides full screen ─── */
    .pdf-viewer-panel {
        width: 100vw;
        max-width: 100vw;
    }

    /* ─── Sign-in page: keep the card reachable above the on-screen keyboard ─── */
    .auth-page { overflow-y: auto; }
    .auth-center { align-items: flex-start; padding: 4vh 16px 24px; }

    /* ─── User dropdown sits closer to the right edge ─── */
    .app-header-user-menu { right: -4px; }
}

/* Very small phones (≤ 360px) — extreme compaction */
@media (max-width: 360px) {
    .app-header                { padding: 0 8px; }
    .chat-input-vault-name     { max-width: 70px; }
    .chat-input-vault-trigger  { padding: 6px 8px; }
}

/* ═══ Folder Auditor — health gauge & severity chips ═══════════════════════════════════
   The /audit report ends with a score gauge that is held back until the report has finished
   streaming, then sweeps to its score — the score lands as a deliberate reveal. */

/* The gauge card. */
.audit-health {
    --audit-color: var(--accent);
    --audit-tint:  var(--accent-soft);
    display: flex;
    align-items: center;
    gap: 20px;
    margin: 6px 0 18px;
    padding: 16px 22px 16px 18px;
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-left: 3px solid var(--audit-color);
    border-radius: var(--radius-lg);
    animation: audit-card-in 0.5s cubic-bezier(0.4, 0, 0.2, 1) both;
}

.audit-health--green { --audit-color: #2fb383; --audit-tint: rgba(47, 179, 131, 0.12); }
.audit-health--amber { --audit-color: #e0a106; --audit-tint: rgba(224, 161, 6, 0.13); }
.audit-health--red   { --audit-color: #e5484d; --audit-tint: rgba(229, 72, 77, 0.13); }

[data-theme="dark"] .audit-health--amber { --audit-color: #f5b417; }
[data-theme="dark"] .audit-health--red   { --audit-color: #f2585d; }

@keyframes audit-card-in {
    from { opacity: 0; transform: translateY(8px); }
}

/* Gauge — SVG donut with the score centred inside it. */
.audit-gauge-wrap {
    position: relative;
    width: 92px;
    height: 92px;
    flex-shrink: 0;
}

.audit-gauge {
    width: 92px;
    height: 92px;
    display: block;
    filter: drop-shadow(0 0 7px var(--audit-tint));
}

.audit-gauge-track {
    fill: none;
    stroke: var(--bg-glass-hover);
    stroke-width: 9;
}

.audit-gauge-fill {
    fill: none;
    stroke: var(--audit-color);
    stroke-width: 9;
    stroke-linecap: round;
    transform: rotate(-90deg);
    transform-origin: 60px 60px;
    stroke-dashoffset: var(--audit-offset);
    animation: audit-gauge-sweep 1.2s cubic-bezier(0.32, 0.9, 0.4, 1) 0.12s both;
}

@keyframes audit-gauge-sweep {
    from { stroke-dashoffset: var(--audit-dash); }
}

.audit-gauge-readout {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
}

.audit-gauge-score {
    font-size: 26px;
    font-weight: 750;
    line-height: 1;
    color: var(--audit-color);
    letter-spacing: -0.02em;
}

.audit-gauge-max {
    margin-top: 3px;
    font-size: 10px;
    font-weight: 600;
    line-height: 1;
    color: var(--text-muted);
}

/* Right column — caption, status label, severity tally. */
.audit-health-info {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.audit-health-caption {
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.audit-health-status {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 18px;
    font-weight: 700;
    color: var(--text-primary);
}

.audit-health-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--audit-color);
    box-shadow: 0 0 0 4px var(--audit-tint);
    flex-shrink: 0;
}

.audit-tally {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 7px;
    margin-top: 2px;
    font-size: 12.5px;
    font-weight: 600;
    color: var(--text-secondary);
}

.audit-tally-sep { color: var(--text-muted); }
.audit-tally--clean { color: var(--text-muted); font-weight: 500; }

.audit-tally-item::before {
    content: "";
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    margin-right: 5px;
    vertical-align: 0;
}
.audit-tally--critical::before { background: #e5484d; }
.audit-tally--warning::before  { background: #e0a106; }
.audit-tally--info::before     { background: #2fb383; }

/* Severity chips on each finding. */
.audit-sev {
    display: inline-block;
    margin-right: 6px;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    vertical-align: 1px;
    white-space: nowrap;
}
.audit-sev--critical { background: rgba(229, 72, 77, 0.15);  color: #e5484d; }
.audit-sev--warning  { background: rgba(224, 161, 6, 0.17);  color: #b07f08; }
.audit-sev--info     { background: rgba(47, 179, 131, 0.15); color: #2a9c72; }

[data-theme="dark"] .audit-sev--warning { color: #f5b417; }
[data-theme="dark"] .audit-sev--info    { color: #3fc794; }

@media (max-width: 480px) {
    .audit-health      { gap: 14px; padding: 14px 16px 14px 13px; }
    .audit-gauge-wrap,
    .audit-gauge       { width: 78px; height: 78px; }
    .audit-gauge-score { font-size: 23px; }
}

/* Respect reduced-motion — the gauge still shows its final score, just without the sweep. */
@media (prefers-reduced-motion: reduce) {
    .audit-health,
    .audit-gauge-fill { animation: none; }
}

/* ═══ Project Timeline — /timeline ═════════════════════════════════════════════════════
   A timeline rendered from a ```timeline JSON block: a central spine with events
   alternating left and right. The spine draws itself downward, then the nodes and cards
   cascade in one after another — the cascade is the reveal. */

/* Placeholder while the model streams the timeline block. */
.tl-loading {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 12px 0;
    padding: 8px 14px;
    background: var(--accent-soft);
    border-radius: var(--radius-full);
    color: var(--accent);
    font-size: 13px;
    font-weight: 500;
}

.tl-loading-icon { width: 15px; height: 30px; color: var(--accent); }
.tl-loading-dot  { animation: tl-dot-pulse 1.3s ease-in-out infinite; }
.tl-loading-icon circle:nth-of-type(2) { animation-delay: 0.16s; }
.tl-loading-icon circle:nth-of-type(3) { animation-delay: 0.32s; }

@keyframes tl-dot-pulse { 0%, 100% { opacity: 0.3; } 50% { opacity: 1; } }

.tl-empty {
    margin: 10px 0;
    padding: 14px 16px;
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    color: var(--text-secondary);
    font-size: 13.5px;
}

/* The timeline card. */
.tl {
    margin: 8px 0 18px;
    padding: 4px 16px 18px;
    background: var(--bg-glass);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    animation: tl-card-in 0.45s cubic-bezier(0.4, 0, 0.2, 1) both;
}

@keyframes tl-card-in { from { opacity: 0; transform: translateY(8px); } }

.tl-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 12px 4px 11px;
    margin-bottom: 10px;
    border-bottom: 1px solid var(--border-subtle);
}

.tl-head-count { font-size: 13px; font-weight: 700; color: var(--text-primary); }
.tl-head-span  { font-size: 12px; font-weight: 500; color: var(--text-muted); }

/* Body — a central spine with events alternating to its left and right. */
.tl-body {
    position: relative;
    padding: 10px 0 4px;
}

.tl-spine {
    position: absolute;
    left: 50%;
    margin-left: -1px;
    top: 4px;
    bottom: 6px;
    width: 2px;
    background: linear-gradient(to bottom,
        transparent, var(--border) 5%, var(--border) 95%, transparent);
    transform: scaleY(0);
    transform-origin: top;
    animation: tl-spine-draw 0.6s ease-out 0.1s forwards;
}

@keyframes tl-spine-draw { to { transform: scaleY(1); } }

.tl-row {
    --tl-color: #9ca3b4;
    display: grid;
    /* minmax(0,1fr) — not 1fr — so a long card can't blow its column out and shove the
       node (and its connector) off the centred spine. */
    grid-template-columns: minmax(0, 1fr) 44px minmax(0, 1fr);
    align-items: center;
    margin-bottom: 16px;
}
.tl-row:last-child { margin-bottom: 0; }

.tl-st--upcoming { --tl-color: #3b82f6; }
.tl-st--overdue  { --tl-color: #e5484d; }
.tl-st--expiring { --tl-color: #e0a106; }

/* Node — type icon in a status-coloured ring, centred on the spine. */
.tl-node {
    grid-column: 2;
    grid-row: 1;
    justify-self: center;
    z-index: 2;
    width: 38px;
    height: 38px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 16px;
    background: var(--bg-elevated);
    border: 2px solid var(--tl-color);
    border-radius: 50%;
    box-shadow: 0 2px 7px rgba(0, 0, 0, 0.14);
    opacity: 0;
    transform: scale(0.3);
    animation: tl-node-in 0.4s cubic-bezier(0.34, 1.45, 0.5, 1) both;
    animation-delay: calc(0.4s + var(--i) * 0.08s);
}

@keyframes tl-node-in { to { opacity: 1; transform: scale(1); } }

/* Card — alternates sides, joined to the node by a short connector. The explicit grid-row
   keeps the card on the same row as the node (a left-column card would otherwise be auto-
   placed onto a new row, dropping it below the node). */
.tl-card {
    position: relative;
    grid-row: 1;
    padding: 10px 13px 11px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    opacity: 0;
    animation: tl-card-in-x 0.45s cubic-bezier(0.34, 1.1, 0.5, 1) both;
    animation-delay: calc(0.46s + var(--i) * 0.08s);
}

.tl-row--left  .tl-card { grid-column: 1; margin-right: 12px; --tl-from: -14px; }
.tl-row--right .tl-card { grid-column: 3; margin-left: 12px;  --tl-from: 14px; }

@keyframes tl-card-in-x {
    from { opacity: 0; transform: translateX(var(--tl-from)); }
    to   { opacity: 1; transform: translateX(0); }
}

/* Connector from the card to the node. It runs long — all the way under the node — so the
   card and the circle always read as joined; the node (z-index 2) paints over the far end. */
.tl-card::before {
    content: "";
    position: absolute;
    top: 50%;
    margin-top: -1px;
    width: 40px;
    height: 2px;
    background: var(--tl-color);
    opacity: 0.6;
}
.tl-row--left  .tl-card::before { right: -40px; }
.tl-row--right .tl-card::before { left:  -40px; }

.tl-date {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.03em;
    text-transform: uppercase;
    color: var(--tl-color);
}

.tl-title {
    margin-top: 2px;
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    line-height: 1.35;
}

.tl-note {
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--text-secondary);
    line-height: 1.4;
}

.tl-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
}

.tl-doc {
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--text-muted);
}
.tl-doc::before { content: "📄 "; }

.tl-status {
    padding: 1px 8px;
    border-radius: var(--radius-full);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}
.tl-status--done     { background: var(--bg-glass-hover); color: var(--text-muted); }
.tl-status--upcoming { background: rgba(59, 130, 246, 0.15); color: #3b82f6; }
.tl-status--overdue  { background: rgba(229, 72, 77, 0.15);  color: #e5484d; }
.tl-status--expiring { background: rgba(224, 161, 6, 0.17);  color: #b07f08; }

[data-theme="dark"] .tl-status--expiring { color: #f5b417; }

/* "Today" marker — an accent pill sitting astride the spine. */
.tl-row--today {
    grid-template-columns: 1fr;
    justify-items: center;
    margin: 2px 0 16px;
}

.tl-today {
    z-index: 2;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 5px 13px 5px 10px;
    background: var(--accent-soft);
    border: 1px solid var(--accent-glow);
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--accent);
    opacity: 0;
    animation: tl-today-in 0.4s ease both;
    animation-delay: calc(0.46s + var(--i) * 0.08s);
}

@keyframes tl-today-in { to { opacity: 1; } }

.tl-today-dot {
    width: 9px;
    height: 9px;
    border-radius: 50%;
    background: var(--accent);
    animation: tl-today-pulse 2.2s ease-in-out infinite;
}

@keyframes tl-today-pulse {
    0%, 100% { box-shadow: 0 0 0 0 var(--accent-glow); }
    50%      { box-shadow: 0 0 0 6px transparent; }
}

/* Narrow screens — fall back to a single-sided timeline. */
@media (max-width: 560px) {
    .tl-spine { left: 21px; margin-left: 0; }
    .tl-row { grid-template-columns: 42px minmax(0, 1fr); }
    .tl-node { grid-column: 1; }
    .tl-row--left  .tl-card,
    .tl-row--right .tl-card {
        grid-column: 2;
        margin-left: 12px;
        margin-right: 0;
        --tl-from: 14px;
    }
    .tl-row--left  .tl-card::before,
    .tl-row--right .tl-card::before { left: -40px; right: auto; }
    .tl-row--today { justify-items: start; }
    .tl-today { margin-left: 1px; }
}

@media (prefers-reduced-motion: reduce) {
    .tl, .tl-spine, .tl-node, .tl-card, .tl-today, .tl-today-dot { animation: none; }
    .tl-node { opacity: 1; transform: scale(1); }
    .tl-card, .tl-today { opacity: 1; transform: none; }
    .tl-spine { transform: scaleY(1); }
}

/* ─── Settings: account block + password feedback ─── */
.settings-account {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 10px 12px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--bg-glass);
}
.settings-account-row {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    font-size: 13px;
}
.settings-account-row span { color: var(--text-muted); }
.settings-account-row strong { color: var(--text-primary); font-weight: 600; }
.settings-ok  { color: #15803d; }
.settings-err { color: #b91c1c; }
[data-theme="dark"] .settings-ok  { color: #86efac; }
[data-theme="dark"] .settings-err { color: #fca5a5; }

/* Role line under the name/email in the header avatar menu */
.app-header-user-meta-role {
    font-size: 11px;
    color: var(--accent);
    font-weight: 600;
}

/* ── Admin system-settings page (/admin/system) ─────────────────────────────
   Full-page host for the SystemSettingsPanel — a centered card in the main pane.
   The panel itself reuses the settings-dialog styles (.settings-field, .ai-role-grid…). */
.admin-page {
    height: 100%;
    overflow-y: auto;
    padding: 32px 20px;
}
.admin-page-card {
    max-width: 720px;
    margin: 0 auto;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 28px 32px;
}
/* Title on the left, Save on the right, sharing one line. The button is baseline-ish with the
   title rather than centred against the whole block, so it doesn't drift down next to the
   two-line subtitle. */
.admin-page-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 18px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--border-subtle);
}
.admin-page-head-text { min-width: 0; }
.admin-page-head-actions {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-shrink: 0;
}
.admin-page-head-actions .settings-saved-note { margin: 0; }

@media (max-width: 560px) {
    .admin-page-head { flex-direction: column; gap: 12px; }
    .admin-page-head-actions { align-self: flex-end; }
}
.admin-page-title {
    margin: 0 0 4px;
    font-size: 20px;
    font-weight: 700;
    color: var(--text-primary);
}
.admin-page-subtitle {
    margin: 0;
    font-size: 13px;
    color: var(--text-secondary);
}
.admin-page-footer {
    margin-top: 18px;
    padding-top: 14px;
    border-top: 1px solid var(--border-subtle);
}
.admin-page-back {
    font-size: 13px;
    color: var(--text-secondary);
    text-decoration: none;
}
.admin-page-back:hover { color: var(--text-primary); }

/* ═══ Widgets menu (chat input row) ════════════════════════════════════════════════════
   The trigger reuses .chat-input-attach; the flyout reuses the universe menu's panel and
   backdrop, widened so each row can carry a description under its name. */
.chat-input-widgets {
    position: relative;
    align-self: stretch;
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

/* .chat-input-attach is written for the paperclip <label>, so it carries no button reset —
   without this the browser paints its native chrome, which the 50% radius turns into a ring. */
.chat-input-widgets-trigger {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: none;
    padding: 0;
    font: inherit;
}
.chat-input-widgets-trigger:hover { background: var(--accent-soft); }
.chat-input-widgets.open .chat-input-widgets-trigger { color: var(--accent); }

.chat-input-widgets-menu {
    width: 286px;
    max-width: min(286px, calc(100vw - 32px));
    /* No inner scroll wrapper here (unlike the universe menu), so the panel owns the scroll —
       a long widget list must not run off the top of the viewport. */
    max-height: min(60vh, 420px);
    overflow-y: auto;
    padding: 4px;
}

.chat-input-widgets-head {
    padding: 7px 9px 6px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.chat-input-widget-item {
    display: flex;
    align-items: center;
    gap: 9px;
    width: 100%;
    padding: 7px 9px;
    background: none;
    border: none;
    border-radius: var(--radius-sm);
    text-align: left;
    cursor: pointer;
    transition: background 0.12s ease;
}

.chat-input-widget-item:hover:not(:disabled) { background: var(--bg-glass-hover); }
.chat-input-widget-item:disabled { opacity: 0.5; cursor: default; }

/* The icon is an author-chosen emoji, so it can't inherit the app's stroke-icon language.
   A tinted tile gives it a consistent footprint instead — every row lines up whatever the
   admin picked, and it stops the glyph floating loose against the panel. */
.chat-input-widget-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    background: var(--bg-glass-hover);
    border-radius: 8px;
    font-size: 14px;
    line-height: 1;
}
.chat-input-widget-item:hover:not(:disabled) .chat-input-widget-icon {
    background: var(--accent-soft);
}

.chat-input-widget-body {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.chat-input-widget-name {
    font-size: 13px;
    font-weight: 600;
    line-height: 1.3;
    color: var(--text-primary);
}

/* Two lines at most — an over-long custom description must not stretch the row out of
   rhythm with the others. */
.chat-input-widget-desc {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    font-size: 11.5px;
    line-height: 1.35;
    color: var(--text-muted);
}

/* ═══ Widget card grid — the Cards output style ════════════════════════════════════════
   A ```cards block rendered as a responsive grid. Cards cascade in, tinted by their tone. */
.cw { margin: 8px 0 18px; }

.cw-loading-icon { width: 15px; height: 15px; color: var(--accent); }
.cw-loading-pane { animation: tl-dot-pulse 1.3s ease-in-out infinite; }
.cw-loading-icon rect:nth-of-type(2) { animation-delay: 0.14s; }
.cw-loading-icon rect:nth-of-type(3) { animation-delay: 0.42s; }
.cw-loading-icon rect:nth-of-type(4) { animation-delay: 0.28s; }

.cw-group-title {
    margin: 14px 0 8px;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.cw-group-title:first-child { margin-top: 2px; }

.cw-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 10px;
}

.cw-card {
    --cw-color: var(--border);
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 12px 14px 13px;
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-left: 3px solid var(--cw-color);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-sm);
    opacity: 0;
    animation: cw-card-in 0.4s cubic-bezier(0.34, 1.1, 0.5, 1) both;
    animation-delay: calc(var(--i) * 0.05s);
}

@keyframes cw-card-in {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: translateY(0); }
}

.cw-card--good { --cw-color: #2fb383; }
.cw-card--warn { --cw-color: #e0a106; }
.cw-card--bad  { --cw-color: #e5484d; }

.cw-card-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 8px;
}

.cw-card-title {
    font-size: 13.5px;
    font-weight: 650;
    line-height: 1.35;
    color: var(--text-primary);
}

.cw-badge {
    flex-shrink: 0;
    padding: 2px 8px;
    border-radius: var(--radius-full);
    background: var(--bg-glass-hover);
    color: var(--cw-color);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
}
.cw-card--neutral .cw-badge { color: var(--text-secondary); }

.cw-card-body {
    font-size: 12.5px;
    line-height: 1.5;
    color: var(--text-secondary);
}

.cw-card-doc {
    margin-top: auto;
    padding-top: 3px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    font-weight: 500;
    color: var(--text-muted);
}
.cw-card-doc::before { content: "📄 "; }

@media (prefers-reduced-motion: reduce) {
    .cw-card { animation: none; opacity: 1; transform: none; }
    .cw-loading-pane { animation: none; }
}

/* ── Widget list (admin System settings) ────────────────────────────────────
   A table of configured widgets; the configuration itself lives in a dialog. Built as a
   grid rather than a <table> so the row can be a button and the columns can collapse on
   narrow screens. */
.widget-table {
    display: flex;
    flex-direction: column;
    margin: 10px 0;
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    overflow: hidden;
}

/* The head and each row are SEPARATE grid containers, so every track must be a fixed size —
   an `auto` actions column resolves to 0 in the empty header cell but ~130px in a row, which
   drags columns 2 and 3 out of line with their headers. Same padding on both, for the same
   reason. */
.widget-table-head,
.widget-table-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 92px 76px 132px;
    gap: 10px;
    align-items: center;
    padding: 8px 12px;
}

.widget-table-head {
    background: var(--bg-glass);
    border-bottom: 1px solid var(--border);
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.widget-table-row {
    border-bottom: 1px solid var(--border-subtle);
}
.widget-table-row:last-child { border-bottom: none; }
.widget-table-row:hover { background: var(--bg-glass); }
.widget-table-row.off .widget-table-icon,
.widget-table-row.off .widget-table-text { opacity: 0.55; }

.widget-table-empty {
    padding: 20px 12px;
    text-align: center;
    font-size: 13px;
    color: var(--text-muted);
}

/* The name cell is the row's edit affordance — a full-width transparent button. No horizontal
   padding: the icon has to start exactly where the "Widget" header does. */
.widget-table-main {
    display: flex;
    align-items: center;
    gap: 10px;
    min-width: 0;
    padding: 4px 0;
    background: none;
    border: none;
    text-align: left;
    cursor: pointer;
}

.widget-table-icon {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    background: var(--bg-glass-hover);
    border-radius: 8px;
    font-size: 15px;
    line-height: 1;
}

.widget-table-text {
    display: flex;
    flex-direction: column;
    gap: 1px;
    min-width: 0;
}

.widget-table-name {
    font-size: 13.5px;
    font-weight: 600;
    color: var(--text-primary);
}

.widget-table-desc {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 11.5px;
    color: var(--text-muted);
}

/* The badge is a pill with 8px of internal padding, so its header needs the same offset for the
   label to sit over the badge's TEXT rather than its left edge. */
.widget-table-head span:nth-child(2) { padding-left: 8px; }

.widget-style-badge {
    justify-self: start;
    padding: 2px 8px;
    background: var(--bg-glass-hover);
    border-radius: var(--radius-full);
    font-size: 11px;
    font-weight: 600;
    color: var(--text-secondary);
    white-space: nowrap;
}

.widget-status {
    font-size: 11.5px;
    font-weight: 600;
    color: var(--text-muted);
    white-space: nowrap;
}
.widget-status.on { color: #2a9c72; }
[data-theme="dark"] .widget-status.on { color: #3fc794; }

.widget-table-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 2px;
}

.widget-row-btn {
    padding: 4px 8px;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    cursor: pointer;
    transition: background-color 0.12s ease, color 0.12s ease;
}
.widget-row-btn:hover:not(:disabled) {
    background: var(--bg-glass-hover);
    color: var(--text-primary);
}
.widget-row-btn:disabled { opacity: 0.3; cursor: default; }

/* ── Widget editor dialog ───────────────────────────────────────────────── */
.widget-editor-dialog {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 560px;
    max-width: calc(100vw - 32px);
}

.widget-editor-body {
    max-height: 62vh;
    overflow-y: auto;
    padding-right: 4px;
}

/* Icon button and name field share one line. */
.widget-name-row {
    display: flex;
    align-items: center;
    gap: 8px;
}
.widget-name-row .settings-input { flex: 1 1 auto; min-width: 0; }

.widget-style-seg { flex-wrap: wrap; }

.widget-editor-hint {
    margin-right: auto;
    font-size: 12px;
    color: var(--text-muted);
}

@media (max-width: 620px) {
    /* Drop the badge and status columns — they're both visible in the dialog anyway. */
    .widget-table-head,
    .widget-table-row { grid-template-columns: minmax(0, 1fr) 132px; }
    .widget-table-head span:nth-child(2),
    .widget-table-head span:nth-child(3),
    .widget-style-badge,
    .widget-status { display: none; }
}

/* Opens the icon picker. Sized to match a .settings-input's height so the header row stays level. */
.widget-icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 40px;
    height: 38px;
    padding: 0;
    background: var(--bg-elevated);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}
.widget-icon-btn:hover {
    border-color: var(--accent);
    background: var(--accent-soft);
}
.widget-icon-btn:focus-visible {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-soft);
}

/* ═══ Data table — the Table output style ══════════════════════════════════════════════
   Chrome comes from the shared .message-content table rules; this only adds the numeric
   alignment, the unit hint in the header and the row count. */
.dt-wrap { margin: 8px 0 18px; overflow-x: auto; }
.dt-wrap .dt { margin: 0; }

/* Right-align numeric columns and use tabular figures so the digits line up column-wise —
   without it a sorted list of amounts doesn't visibly read as sorted. */
.message-content .dt td.dt-num,
.message-content .dt th.dt-num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.message-content .dt th .dt-unit {
    font-weight: 500;
    text-transform: none;
    letter-spacing: 0;
}

.dt-count {
    padding: 6px 2px 0;
    font-size: 11.5px;
    color: var(--text-muted);
}

/* ── Icon picker dialog ───────────────────────────────────────────────────── */
.icon-picker-dialog {
    display: flex;
    flex-direction: column;
    gap: 12px;
    width: 440px;
    max-width: calc(100vw - 32px);
}

.icon-picker-body {
    max-height: 46vh;
    overflow-y: auto;
    padding-right: 2px;
}

.icon-picker-group {
    margin: 10px 0 6px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.icon-picker-group:first-child { margin-top: 0; }

.icon-picker-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
    gap: 4px;
}

.icon-picker-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    aspect-ratio: 1;
    background: none;
    border: 1px solid transparent;
    border-radius: var(--radius-sm);
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    transition: background-color 0.12s ease, border-color 0.12s ease, transform 0.12s ease;
}
.icon-picker-cell:hover {
    background: var(--bg-glass-hover);
    transform: scale(1.12);
}
.icon-picker-cell.selected {
    background: var(--accent-soft);
    border-color: var(--accent);
}
.icon-picker-cell:focus-visible {
    outline: none;
    border-color: var(--accent);
}

.icon-picker-custom {
    padding-top: 10px;
    border-top: 1px solid var(--border-subtle);
}
.icon-picker-custom-row {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 5px;
}
.icon-picker-custom-row .settings-input {
    width: 70px;
    flex-shrink: 0;
    text-align: center;
    font-size: 18px;
}

@media (prefers-reduced-motion: reduce) {
    .icon-picker-cell:hover { transform: none; }
}


/* ===========================================================================
   Hidden test bench (/admin/testbench)

   Lives in app.css rather than its own stylesheet: a per-page <link> injected
   through HeadContent is a mechanism this app uses nowhere else, and an operator
   tool is not worth being the one place that relies on it. The extra bytes cost
   every user far less than a page that silently loads unstyled.

   Reuses the app's tokens and its .custom-dropdown skeleton so the bench looks
   like Ventura rather than something bolted on. The two-column answer layout is
   the point of the page — the reference and the model's answer have to be
   readable side by side, or grading is guesswork.
   =========================================================================== */

/* The app shell is `height: 100vh; overflow: hidden`, so a routable page owns its own scrolling
   or it simply cannot scroll — the same reason .admin-page sets height + overflow-y. Without this
   the bench looks fine until the first run produces enough results to overflow the viewport, and
   then the page is stuck. The inner wrapper carries the width and padding so the scrollbar sits at
   the edge of the window rather than inside the content column. */
.bench {
    height: 100%;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.bench-inner {
    max-width: 1240px;
    margin: 0 auto;
    padding: 2rem 1.5rem 5rem;
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
}

.bench-head {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}


.bench-head h1 {
    margin: 0;
    font-size: 1.7rem;
    letter-spacing: -0.02em;
    color: var(--text-primary);
}

.bench-back {
    color: var(--text-secondary);
    text-decoration: none;
    font-size: 0.9rem;
}
.bench-back:hover { color: var(--accent); }

.bench-panel {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-radius: var(--radius-lg);
    padding: 1.15rem 1.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.9rem;
    box-shadow: var(--shadow-sm);
}

.bench-panel h2 {
    margin: 0;
    font-size: 1.1rem;
    color: var(--text-primary);
}

/* Follows the reader down a long run so Stop and the progress counter stay reachable. */
.bench-controls {
    position: sticky;
    top: 0;
    z-index: 3;
    box-shadow: var(--shadow-md);
}

.bench-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.85rem;
    align-items: flex-end;
}

.bench-field {
    display: flex;
    flex-direction: column;
    gap: 0.28rem;
    min-width: 190px;
}
.bench-field.grow { flex: 1 1 240px; }

.bench-field > span {
    font-size: 0.7rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.bench-field input {
    background: var(--bg-primary);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 0.45rem 0.6rem;
    font-size: 0.9rem;
    font-family: inherit;
    line-height: 1.4;
    width: 100%;
}

/* The pickers are SelectDropdown (the app's .custom-dropdown skeleton), not native <select> —
   a native popup is drawn by the OS and CSS cannot reach it. The skeleton already sizes the
   trigger; all it lacks is a disabled state, which the bench needs because every control locks
   while a run is in flight. */
.bench-field .custom-dropdown-trigger:disabled {
    opacity: 0.55;
    cursor: not-allowed;
}
.bench-field .custom-dropdown-trigger:disabled:hover {
    border-color: var(--border);
    color: var(--text-primary);
}

.bench-field input:hover:not(:disabled) { border-color: var(--accent); }

.bench-field input:disabled { opacity: 0.55; cursor: not-allowed; }

.bench-field input:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
    border-color: var(--accent);
}

.bench-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem 1.1rem;
    font-size: 0.82rem;
    color: var(--text-secondary);
    border-top: 1px solid var(--border-subtle);
    padding-top: 0.75rem;
}
.bench-meta b {
    color: var(--text-muted);
    font-weight: 500;
    margin-right: 0.3rem;
}

.bench-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.55rem;
    align-items: center;
}

.bench-btn {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    padding: 0.45rem 1rem;
    font-size: 0.88rem;
    font-family: inherit;
    cursor: pointer;
    transition: background var(--transition), border-color var(--transition), color var(--transition);
}
.bench-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.bench-btn:disabled { opacity: 0.45; cursor: not-allowed; }
.bench-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.bench-btn.primary {
    background: var(--accent);
    border-color: var(--accent);
    color: #ffffff;
}
.bench-btn.primary:hover:not(:disabled) { filter: brightness(1.06); color: #ffffff; }

.bench-btn.danger { border-color: #d9534f; color: #d9534f; }
.bench-btn.danger:hover:not(:disabled) { background: rgba(217, 83, 79, 0.1); color: #d9534f; }

.bench-btn.ghost { background: transparent; }

.bench-btn.tiny { padding: 0.2rem 0.7rem; font-size: 0.76rem; }
.bench-btn.tiny.on-ok  { background: var(--accent); border-color: var(--accent); color: #fff; }
.bench-btn.tiny.on-bad { background: #d9534f; border-color: #d9534f; color: #fff; }

.bench-progress {
    font-size: 0.84rem;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}

.bench-alert {
    background: var(--bg-tertiary);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 0.8rem 0.95rem;
    font-size: 0.88rem;
    color: var(--text-secondary);
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.bench-alert.warn {
    border-color: rgba(217, 83, 79, 0.45);
    background: rgba(217, 83, 79, 0.07);
    color: var(--text-primary);
}
.bench-alert code { font-size: 0.85em; }

.bench-hint { margin: 0.2rem 0 0; font-size: 0.82rem; color: var(--text-muted); }
.bench-hint.warn { color: #c76a3c; }

.bench-dim { color: var(--text-muted); font-size: 0.8rem; }

/* ---- run header ---- */

.bench-scoreline {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: flex-start;
    justify-content: space-between;
}

.bench-stats {
    display: flex;
    flex-wrap: wrap;
    gap: 0.15rem 1.4rem;
    margin: 0;
}
.bench-stats dt {
    font-size: 0.66rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
}
.bench-stats dd {
    margin: 0;
    font-size: 1.05rem;
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
}
.bench-stats dd.ok  { color: var(--accent); }
.bench-stats dd.bad { color: #d9534f; }

.bench-traps { font-size: 0.84rem; color: var(--text-secondary); }
.bench-traps summary { cursor: pointer; color: var(--text-muted); }
.bench-traps ul { margin: 0.5rem 0 0; padding-left: 1.1rem; display: flex; flex-direction: column; gap: 0.35rem; }

/* ---- past runs ---- */

.bench-table-wrap { overflow-x: auto; }
.bench-table { border-collapse: collapse; width: 100%; font-size: 0.84rem; }
.bench-table th,
.bench-table td {
    padding: 0.45rem 0.7rem;
    text-align: left;
    border-bottom: 1px solid var(--border-subtle);
    white-space: nowrap;
}
.bench-table th {
    font-size: 0.68rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    color: var(--text-muted);
    font-weight: 500;
}
.bench-table td.num, .bench-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.bench-table tr.current { background: var(--accent-soft); }

.bench-link {
    background: none;
    border: none;
    color: var(--accent);
    cursor: pointer;
    font-size: 0.82rem;
    padding: 0 0.3rem;
    font-family: inherit;
}
.bench-link.danger { color: #d9534f; }
.bench-link:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

/* ---- one question ---- */

.bench-item {
    background: var(--bg-secondary);
    border: 1px solid var(--border);
    border-left: 3px solid var(--border);
    border-radius: var(--radius-md);
    padding: 0.9rem 1.1rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}
.bench-item.inverted { border-left-color: #c76a3c; }
.bench-item.pass     { border-left-color: var(--accent); }
.bench-item.fail     { border-left-color: #d9534f; }

.bench-item-head {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    flex-wrap: wrap;
}

.bench-num {
    font-size: 1rem;
    font-weight: 700;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

.bench-chip {
    font-size: 0.64rem;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    border-radius: var(--radius-sm);
    padding: 0.15rem 0.45rem;
}
.bench-chip.warn { background: rgba(199, 106, 60, 0.14); color: #c76a3c; }
.bench-chip.ok   { background: var(--accent-soft); color: var(--accent); }
.bench-chip.miss { background: rgba(217, 83, 79, 0.12); color: #d9534f; }

.bench-verdict { margin-left: auto; display: flex; gap: 0.35rem; }

.bench-question {
    margin: 0;
    font-size: 1rem;
    font-weight: 600;
    color: var(--text-primary);
}

.bench-answers {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.75rem;
}

.bench-answer {
    background: var(--bg-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 0.65rem 0.8rem;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    min-width: 0;
}
.bench-answer.reference { border-left: 2px solid var(--text-muted); }
.bench-answer.actual    { border-left: 2px solid var(--accent); }

.bench-lbl {
    font-size: 0.64rem;
    letter-spacing: 0.09em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.bench-text {
    font-size: 0.9rem;
    line-height: 1.55;
    color: var(--text-primary);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}
.bench-text.error { color: #d9534f; }

.bench-docs { display: flex; flex-wrap: wrap; gap: 0.3rem; align-items: center; }

.bench-doc {
    font-size: 0.7rem;
    font-family: ui-monospace, Consolas, monospace;
    background: var(--bg-tertiary);
    color: var(--text-secondary);
    border: 1px solid var(--border-subtle);
    border-radius: 4px;
    padding: 0.1rem 0.35rem;
    overflow-wrap: anywhere;
}
.bench-doc.hit {
    background: var(--accent-soft);
    color: var(--accent);
    border-color: var(--accent);
}

.bench-comment {
    background: var(--bg-primary);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-sm);
    padding: 0.4rem 0.6rem;
    font-size: 0.85rem;
    font-family: inherit;
    color: var(--text-primary);
}
.bench-comment:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

@media (max-width: 860px) {
    .bench-answers { grid-template-columns: 1fr; }
    .bench-verdict { margin-left: 0; }
}

/* ─── Provenance for analytical answers ───────────────────────────────────────
   An index-data answer cites nothing: there is no passage behind "6,426,000
   across 50 contracts". These chips are the only thing standing between a real
   total and an invented one, so they are built from the executed query rather
   than from the model's account of it. Quiet by default — this is a check, not
   a headline. */
.query-prov {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 10px;
}

.query-prov-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    max-width: 100%;
    padding: 3px 9px;
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    background: var(--bg-glass);
    color: var(--text-secondary);
    font-size: 11.5px;
    line-height: 1.5;
}

.query-prov-chip svg { flex: none; opacity: 0.6; }

.query-prov-what {
    font-family: ui-monospace, Consolas, monospace;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.query-prov-count {
    flex: none;
    padding-left: 6px;
    border-left: 1px solid var(--border);
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* ─── Microsoft Foundry connection (System settings → AI models) ──────────────
   A role on Foundry targets a DEPLOYMENT, so the model cell becomes a picker
   fed by the resource's own list. Everything here degrades to the plain input
   when that list cannot be read — listing is a convenience, not a gate. */

/* A Foundry role's model cell: the deployment picker with a reload button at its right. */
.foundry-model-cell {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}
.foundry-model-cell > :first-child { flex: 1 1 auto; min-width: 0; }
.foundry-refresh {
    width: 34px;
    height: 34px;
    font-size: 14px;
    color: var(--text-secondary);
}
.foundry-refresh:disabled { cursor: default; opacity: 0.6; }
.foundry-refresh.spinning svg { animation: foundry-spin 0.9s linear infinite; }
@keyframes foundry-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .foundry-refresh.spinning svg { animation: none; } }
.foundry-load-row {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}

.settings-btn {
    background: var(--bg-tertiary);
    color: var(--text-primary);
    border: 1px solid var(--border);
    border-radius: var(--radius-full);
    padding: 6px 14px;
    font-size: 13px;
    font-family: inherit;
    cursor: pointer;
    transition: border-color var(--transition), color var(--transition);
}
.settings-btn:hover:not(:disabled) { border-color: var(--accent); color: var(--accent); }
.settings-btn:disabled { opacity: 0.5; cursor: not-allowed; }
.settings-btn:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.foundry-error { color: #d9534f; }
[data-theme="dark"] .foundry-error { color: #fca5a5; }

/* A configured deployment the loaded resource does not report: shown, not silently reset, with a
   one-click way back to the list. Losing a working setting because the wrong resource was queried
   would be worse than the mismatch itself. */
.foundry-unknown {
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.foundry-unknown-clear {
    align-self: flex-start;
    background: none;
    border: none;
    padding: 0;
    color: #c76a3c;
    font-size: 11px;
    font-family: inherit;
    cursor: pointer;
    text-decoration: underline;
}
.foundry-unknown-clear:hover { color: var(--accent); }
.foundry-unknown-clear:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
