/* Spheric Capital — Production Library
   Dark warm background, forest-green accent, Fraunces + DM Sans.
   Brand tokens mirror demo/static/style.css so the production app
   reads as a continuation of the demo, not a separate visual world. */

@import url('https://fonts.googleapis.com/css2?family=DM+Sans:ital,wght@0,400;0,500;0,600;0,700;1,400&family=Fraunces:ital,opsz,wght@0,9..144,300;0,9..144,500;0,9..144,700;1,9..144,300&display=swap');

/* ── Theme tokens ──
   Default + dark palette share one :root rule so anything not explicit
   falls back to dark (matches the prior single-theme behaviour).
   Light theme only overrides the colour tokens, leaving spacing /
   radius / shadow inherited. The active theme is set via the
   data-theme attribute on <html>, which is read/written by the
   Account-menu toggle and persisted in localStorage. */
:root,
:root[data-theme="dark"] {
    --accent:        #2D5A3D;
    --accent-light:  #3a7a52;
    --accent-muted:  rgba(45,90,61,0.25);
    --accent-text:   #6abf82;
    --bg:            #0F0F0E;
    --bg-raised:     #1A1918;
    --bg-card:       #1F1E1D;
    --bg-input:      #141413;
    --ink:           #E8E6DF;
    --ink-soft:      #A8A49C;
    --ink-faint:     #6B6760;
    --amber:         #C8943E;
    --amber-muted:   rgba(200,148,62,0.15);
    --amber-text:    #E8B34A;
    --red:           #D94444;
    --red-muted:     rgba(217,68,68,0.15);
    --border:        #2E2D2A;
    --border-light:  #252422;
    --radius:        6px;
    --shadow:        0 1px 4px rgba(0,0,0,0.3);
    --shadow-lg:     0 8px 24px rgba(0,0,0,0.5);

    /* Spacing scale */
    --space-xs:  4px;
    --space-sm:  8px;
    --space-md:  12px;
    --space-lg:  16px;
    --space-xl:  24px;
    --space-2xl: 32px;

    /* Scroll system */
    --scroll-thumb:  var(--border);
    --scroll-track:  transparent;
}

:root[data-theme="light"] {
    /* Linen-paper feel: a muted, slightly-darkened-from-white page
       that mirrors the dark theme's warmth inverted. Cards are a
       softer cream (not pure white) so nothing feels harsh or
       clinical. The forest-green accent from dark mode stays intact;
       the palette just flips to the light side while keeping the
       same tonal temperament. */
    --accent:        #2D5A3D;                        /* forest green — same as dark */
    --accent-light:  #3a7a52;
    --accent-muted:  rgba(45,90,61,0.10);
    --accent-text:   #2D5A3D;
    --bg:            #E8E3D5;                        /* soft linen / oatmeal */
    --bg-raised:     #F0EBDE;                        /* raised surface — lighter */
    --bg-card:       #F2EEE2;                        /* cream cards, not white */
    --bg-input:      #F8F4E9;                        /* inputs brighter so they read as active */
    --ink:           #2A2520;                        /* warm near-black, soft */
    --ink-soft:      #5C5448;
    --ink-faint:     #8F8776;
    --amber:         #8B5A1A;
    --amber-muted:   rgba(139,90,26,0.10);
    --amber-text:    #6E451A;
    --red:           #A92E2E;
    --red-muted:     rgba(169,46,46,0.08);
    --border:        #BFB7A2;                        /* visible but muted */
    --border-light:  #D4CDB8;
    --shadow:        0 1px 2px rgba(42,37,32,0.05);
    --shadow-lg:     0 6px 20px rgba(42,37,32,0.10);
}

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

/* ── Universal box ──
   Base surface for cards, panels, rows — everything with bg-card + border. */
.box {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}
/* Subtle elevation in light mode — cards lift off the warm-paper bg.
   Skipped in dark mode where shadows don't register on dark-on-dark. */
:root[data-theme="light"] .box { box-shadow: var(--shadow); }
.box--dashed  { border-style: dashed; }
.box--interactive {
    transition: border-color 0.15s, background 0.15s;
    cursor: pointer;
}
.box--interactive:hover {
    border-color: var(--accent-text);
    background: var(--bg-raised);
}

/* ── Universal pinned bar ──
   Bottom action bars, compose bars, selection trays. */
.pinned-bar {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
    padding: 10px 16px;
    background: var(--bg-raised);
    display: flex;
    align-items: center;
    gap: var(--space-lg);
}

/* ── Universal scroll container ──
   Add .scroll-box to any overflow-y element for: thin scrollbar,
   overscroll containment, and automatic scroll-fade indicators. */
.scroll-box {
    overflow-y: auto;
    min-height: 0;
    scrollbar-width: thin;
    scrollbar-color: var(--scroll-thumb) var(--scroll-track);
    overscroll-behavior-y: contain;
}

/* Page-level scroll: autohide pattern.
   Transparent by default, JS toggles .scrolling on activity / edge hover. */
main {
    scrollbar-width: thin;
    scrollbar-color: transparent transparent;
    transition: scrollbar-color 0.3s;
    overscroll-behavior-y: none;
}
main.scrolling {
    scrollbar-color: var(--scroll-thumb) var(--scroll-track);
}

html, body {
    overflow: hidden;
    height: 100vh;
}
body {
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    background: var(--bg);
    color: var(--ink);
    display: flex;
    flex-direction: column;
    line-height: 1.65;
    font-size: 15px;
    -webkit-font-smoothing: antialiased;
}

a {
    color: var(--accent-text);
    text-decoration: none;
    transition: color 0.15s, opacity 0.15s;
}
a:hover { opacity: 0.8; }

/* ─── Header (copied shape from demo/templates/base.html) ─── */
header {
    background: var(--bg);
    border-bottom: 1px solid var(--border);
    position: sticky;
    top: 0;
    z-index: 1000;
}
.header-inner {
    max-width: 1000px;
    margin: 0 auto;
    padding: 24px 24px 20px;
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 24px;
}
.header-brand { display: flex; flex-direction: column; }
.subtitle {
    font-family: 'Fraunces', Georgia, serif;
    font-size: 20px;
    font-weight: 500;
    color: var(--ink);
    margin-bottom: 2px;
}
.logo {
    font-family: 'DM Sans', sans-serif;
    font-size: 11px;
    font-weight: 700;
    color: var(--ink-faint);
    letter-spacing: 1.5px;
}
.header-nav {
    display: flex;
    gap: 20px;
    align-items: center;
}
.header-nav a {
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-soft);
    border-bottom: none;
    letter-spacing: 0.2px;
}
.header-nav a:hover { color: var(--accent-text); }

/* ─── Main layout — header+footer pinned, main scrolls ─── */
main {
    max-width: 1000px;
    margin: 0 auto;
    padding: 24px 24px 16px;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    width: 100%;
    display: flex;
    flex-direction: column;
}

/* Generic pinned-top / scroll-area pattern.
   Use .page-fixed-top for controls that stay visible,
   .page-scroll-area for the content that scrolls. */
/* Fixed-height header zone above page content. Same height across pages
   (Library, Draft, Brief, Chat) so docs don't shift vertically when
   switching tabs. */
.page-fixed-top {
    flex-shrink: 0;
    min-height: 46px;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
}
.page-scroll-area {
    flex: 1;
    position: relative;
    scrollbar-gutter: stable;
}

/* ── Universal rail layout ──
   Two-column shell: main content + right rail with filters / actions.
   Used by Generate, Brief, Library, Chat. Rail collapses below content
   on narrow viewports. */
.page-rail-layout {
    display: flex;
    flex: 1;
    min-height: 0;
    gap: 0;
}
.page-rail-content {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
    padding-right: 12px;
}
.page-rail {
    width: 280px;
    flex-shrink: 0;
    border-left: 1px solid var(--border);
    padding: 16px 16px 12px 20px;
    display: flex;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
    background: var(--bg);
}
.rail-section {
    margin-bottom: var(--space-lg);
    min-width: 0;
    flex-shrink: 0;
}
.rail-section--fill {
    flex: 1 1 0%;
    display: flex;
    flex-direction: column;
    min-height: 80px;
    overflow: hidden;
    margin-bottom: var(--space-md);
}
.rail-heading {
    font-size: 11px;
    font-weight: 700;
    color: var(--ink-faint);
    text-transform: uppercase;
    letter-spacing: 1px;
    margin-bottom: 8px;
}
.rail-presets {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 4px;
}
.rail-presets .chip {
    text-align: center;
    padding: 5px 8px;
    font-size: 12px;
    width: 100%;
    box-sizing: border-box;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.rail-presets .preset-vendor-select {
    grid-column: 1 / -1;
    width: 100%;
    margin-top: 2px;
    padding: 5px 8px;
    font-size: 12px;
}
.rail-meta {
    font-size: 12px;
    color: var(--ink-faint);
    display: flex;
    flex-direction: row;
    align-items: baseline;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 10px;
    font-variant-numeric: tabular-nums;
}
.rail-meta .tray-count {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
}
.rail-meta .tray-warning {
    font-size: 11px;
    font-weight: 600;
    margin-top: 4px;
}
.rail-selected-list {
    flex: 1;
    overflow-y: auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding-right: 4px;
}
.rail-selected-empty {
    font-size: 12px;
    color: var(--ink-faint);
    font-style: italic;
    padding: 4px 0;
}
.rail-selected-item {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 3px 6px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 11px;
    line-height: 1.2;
    min-width: 0;
}
.rail-selected-item .doc-vendor-pill {
    flex-shrink: 0;
    font-size: 10px;
    padding: 1px 5px;
}
.rail-selected-title {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--ink-soft);
    min-width: 0;
}
.rail-selected-remove {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--ink-faint);
    cursor: pointer;
    padding: 0 2px;
    font-size: 14px;
    line-height: 1;
}
.rail-selected-remove:hover { color: var(--red); }
.rail-action {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
    padding-top: 12px;
    margin-top: 4px;
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.rail-action .btn { width: 100%; }

/* Narrow viewport: rail wraps under content */
@media (max-width: 900px) {
    .page-rail-layout { flex-direction: column; }
    .page-rail {
        width: 100%;
        border-left: none;
        border-top: 1px solid var(--border);
        padding: 12px 16px;
    }
    .rail-section--fill { flex: 0 0 auto; }
    .rail-selected-list { max-height: 120px; }
}

/* Scroll indicator: fade gradient at top/bottom of scrollable areas.
   --fade-bg lets containers on raised surfaces override the gradient color. */
.scroll-fade-wrap {
    --fade-bg: var(--bg);
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}
.scroll-fade-wrap::after {
    content: '';
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 32px;
    background: linear-gradient(transparent, var(--fade-bg));
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
}
.scroll-fade-wrap.has-more-below::after { opacity: 1; }
.scroll-fade-wrap::before {
    content: '';
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 24px;
    background: linear-gradient(var(--fade-bg), transparent);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
    z-index: 1;
}
.scroll-fade-wrap.has-more-above::before { opacity: 1; }
/* Override fade-bg for containers on raised surfaces */
.chat-sidebar .scroll-fade-wrap,
.draft-area-visible .scroll-fade-wrap { --fade-bg: var(--bg-raised); }
/* Collapse the wrap when its scroll child is hidden (e.g., inactive tabs) —
   otherwise the wrap keeps flex: 1 and steals space from visible siblings. */
.scroll-fade-wrap:has(> [style*="display: none"]),
.scroll-fade-wrap:has(> [style*="display:none"]),
.scroll-fade-wrap:has(> [hidden]) {
    display: none;
}

h1, h2, h3 {
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 500;
    color: var(--ink);
    line-height: 1.25;
}
h1 { font-size: 28px; margin-bottom: 4px; }
h2 { font-size: 22px; margin-bottom: 4px; }
h3 { font-size: 17px; margin-bottom: 4px; }

.page-desc {
    font-size: 14px;
    color: var(--ink-faint);
    margin-bottom: 24px;
}

/* ─── Search bar ─── */
.search-form {
    display: flex;
    gap: 10px;
    margin-bottom: 24px;
}
.search-input {
    flex: 1;
    padding: 12px 16px;
    background: var(--bg-input);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    outline: none;
}
.search-input:focus {
    border-color: var(--accent-text);
    background: var(--bg-raised);
}
.search-input::placeholder { color: var(--ink-faint); }

/* ─── Filter chips ─── */
.filter-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 14px;
    align-items: center;
    justify-content: flex-start;
}
.filter-label {
    font-size: 11px;
    font-weight: 600;
    color: var(--ink-faint);
    letter-spacing: 1px;
    text-transform: uppercase;
    margin-right: 12px;
    min-width: 70px;           /* fixed column so all chip rows line up */
    display: inline-block;
    text-align: left;
}
.chip {
    background: var(--bg-card);
    color: var(--ink-soft);
    font-size: 13px;
    font-weight: 500;
    padding: 6px 14px;
    border-radius: 20px;
    border: 1px solid var(--border);
    transition: all 0.15s;
}
.chip:hover {
    border-color: var(--accent-text);
    color: var(--ink);
}
.chip.active {
    background: var(--accent-muted);
    border-color: var(--accent);
    color: var(--accent-text);
}

/* ─── Document list ─── */
.doc-list {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.doc-row-link {
    text-decoration: none;
    color: inherit;
    border-bottom: none;
    display: block;
    /* Pair with .doc-row width:100% so the link stretches edge-to-
       edge and the hover/click area matches the visible row. */
    width: 100%;
}
.doc-row-link:hover { border-bottom: none; }
/* doc-row self-contains .box properties because it appears in 9 templates */
.doc-row {
    display: grid;
    grid-template-columns: 44px 1fr auto auto;
    gap: 12px;
    align-items: center;
    padding: 7px 12px;
    /* Always fill the parent width. Without this, rows in some
       ancestor layouts (tab-panes, narrow scroll-boxes, first-render
       before JS hydration) were shrinking to content width, making
       history lists look "half as wide" compared to a later render
       of the same page. width: 100% + box-sizing: border-box pins
       rows to the list's full width across chat / brief / drafts. */
    width: 100%;
    box-sizing: border-box;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    transition: border-color 0.15s, background 0.15s, transform 0.05s;
    cursor: pointer;
}
.doc-row:hover {
    border-color: var(--accent-text);
    background: var(--bg-raised);
}
.doc-row:active { transform: scale(0.998); }
/* .doc-row--no-badge: variant for lists without a type-badge column
   (chat sessions, research briefs). Drops the 44px first column that
   normally holds a type badge. Use instead of scattering inline
   grid-template-columns overrides in templates. */
.doc-row--no-badge { grid-template-columns: 1fr auto auto; }
.type-badge {
    background: var(--border);
    color: var(--ink-soft);
    font-size: 10px;
    font-weight: 700;
    text-align: center;
    padding: 6px 8px;
    border-radius: 4px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    min-width: 46px;
}
.type-badge.pdf     { background: #c0392b; color: white; }
.type-badge.xlsx,
.type-badge.xls     { background: #1e6641; color: white; }
.type-badge.docx,
.type-badge.doc     { background: #1e4e8c; color: white; }
.type-badge.csv     { background: #7a5c1c; color: white; }
.type-badge.body    { background: var(--ink-faint); color: var(--bg); }

/* Main column: subject (big) + filename-row (smaller) + optional snippet */
.doc-main {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.doc-subject {
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    font-weight: 600;
    color: var(--ink);
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.doc-filename-row {
    font-size: 12px;
    color: var(--ink-faint);
    display: flex;
    gap: 10px;
    align-items: baseline;
    flex-wrap: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    margin-top: 2px;
}
.doc-filename-row .doc-filename {
    color: var(--ink-soft);
    font-weight: 500;
    font-size: 12px;
    font-family: 'DM Sans', sans-serif;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 320px;
    /* Never shrink — "1 source" / "3 sources" should always render in
       full, even when paired with a long preview text on the same row.
       Without this, flex would squeeze it to "1 sourc…". Only the
       .doc-sender (preview) should shrink. */
    flex-shrink: 0;
}
.doc-filename-row .doc-filename::before {
    content: "📄 ";
    font-size: 11px;
    margin-right: 2px;
}
.doc-filename-row .doc-sender {
    color: var(--ink-faint);
    /* Match the subject row's truncation — when the sender is long
       (Mailgun bounce VERP addresses especially) it should end with
       "…" at the container edge, not a hard chop. The `min-width: 0`
       is required for text-overflow to kick in inside a flex item. */
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.doc-filename-row .doc-sender::before {
    content: "· ";
    opacity: 0.6;
    margin-right: 2px;
}
.doc-snippet {
    font-size: 12px;
    color: var(--ink-soft);
    margin-top: 4px;
    line-height: 1.45;
    overflow: hidden;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow-wrap: anywhere;
    word-break: break-word;
    /* Collapse the literal newlines that come back from the FTS5 snippet */
    white-space: normal;
    min-width: 0;
    max-width: 100%;
}
.doc-snippet mark {
    background: var(--amber-muted);
    color: var(--amber-text);
    padding: 0 2px;
    border-radius: 2px;
}

/* Vendor pill on the right — text is centered, the pill box fits
   its content exactly (no fixed min-width) so it ends where the
   text ends. */
.doc-vendor-pill {
    background: var(--accent-muted);
    color: var(--accent-text);
    border: 1px solid var(--accent);
    padding: 6px 14px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.2px;
    white-space: nowrap;
    text-align: center;
    align-self: center;
}
.doc-vendor-pill--none {
    background: transparent;
    color: var(--ink-faint);
    border-color: var(--border);
    font-style: italic;
    font-weight: 500;
}

/* Row-action buttons (admin panel — Remove / Resend on each row) */
.btn-row-action {
    padding: 8px 14px;
    background: var(--bg-raised);
    color: var(--ink-soft);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.2px;
    font-family: 'DM Sans', sans-serif;
    cursor: pointer;
    transition: border-color 0.15s, color 0.15s, background 0.15s;
    white-space: nowrap;
    align-self: center;
}
.btn-row-action:hover {
    border-color: var(--accent-text);
    color: var(--ink);
    background: var(--bg-card);
}
.btn-row-action--danger {
    color: var(--red);
    border-color: var(--red-muted);
}
.btn-row-action--danger:hover {
    border-color: var(--red);
    color: var(--red);
    background: var(--red-muted);
}
.btn-row-action-placeholder {
    padding: 8px 14px;
    font-size: 11px;
    font-style: italic;
    color: var(--ink-faint);
    align-self: center;
    white-space: nowrap;
}

/* Far-right stack: status + size/pages + date, each on its own line,
   tabular-nums for clean right alignment. */
.doc-right-stack {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 4px;
    min-width: 120px;
    font-variant-numeric: tabular-nums;
}
.doc-right-stack .status-tag { align-self: flex-end; }
.doc-size-line {
    font-size: 11px;
    color: var(--ink-faint);
    white-space: nowrap;
}

/* Per-email "Select all / Deselect" toggle in picker group headers.
   Kept intentionally quiet — sits under the date line, flips label
   based on how many children are currently checked. */
.select-all-btn {
    align-self: flex-end;
    background: transparent;
    border: 1px solid var(--border-light);
    color: var(--ink-faint);
    font-family: 'DM Sans', sans-serif;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    padding: 2px 8px;
    border-radius: 4px;
    cursor: pointer;
    white-space: nowrap;
    transition: color 0.12s, border-color 0.12s, background 0.12s;
}
.select-all-btn:hover {
    color: var(--ink);
    border-color: var(--accent-text);
}
.select-all-btn--active {
    color: var(--accent-text);
    border-color: var(--accent-text);
}
.doc-date-line {
    font-size: 11px;
    color: var(--ink-faint);
    white-space: nowrap;
}

/* ─── Status tags ─── */
.status-tag {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 3px;
    letter-spacing: 0.5px;
    text-transform: uppercase;
}
.status-tag.queued     { background: var(--amber-muted); color: var(--amber-text); }
.status-tag.processing { background: var(--amber-muted); color: var(--amber-text); }
.status-tag.generating {
    background: var(--amber-muted);
    color: var(--amber-text);
    /* Pulsing dot + animated opacity so users can visually distinguish
       "still working" from "done" at a glance in the history list. */
    position: relative;
    padding-left: 18px;
    animation: status-pulse 1.6s ease-in-out infinite;
}
.status-tag.generating::before {
    content: '';
    position: absolute;
    left: 7px;
    top: 50%;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--amber-text);
    transform: translateY(-50%);
    box-shadow: 0 0 0 0 var(--amber-text);
    animation: status-pulse-dot 1.6s ease-in-out infinite;
}
@keyframes status-pulse {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0.55; }
}
@keyframes status-pulse-dot {
    0%   { box-shadow: 0 0 0 0 rgba(200, 148, 62, 0.55); }
    70%  { box-shadow: 0 0 0 6px rgba(200, 148, 62, 0); }
    100% { box-shadow: 0 0 0 0 rgba(200, 148, 62, 0); }
}
.status-tag.done       { background: var(--accent-muted); color: var(--accent-text); }
.status-tag.draft      { background: var(--accent-muted); color: var(--accent-text); }
.status-tag.error      { background: var(--red-muted);    color: var(--red); }
.status-tag.failed     { background: var(--red-muted);    color: var(--red); }
/* Enhancement (tier-2 Docling markdown) skipped for this doc — amber not
   red because raw text extraction still succeeded and the doc is usable. */
.status-tag.enh-skipped{ background: var(--amber-muted);  color: var(--amber-text); cursor: help; }

/* ─── Empty state ─── */
.empty {
    text-align: center;
    padding: 80px 24px;
    color: var(--ink-faint);
    font-size: 14px;
    /* Tab-panes activate with display:flex (row), which would make
       a block child shrink to its content width. Explicit 100% so
       the empty state takes the full width of its parent whether
       that parent is flex-row, flex-column, or plain block. */
    width: 100%;
    box-sizing: border-box;
}

/* ─── Document detail view ─── */
.back-link {
    display: inline-block;
    font-size: 13px;
    color: var(--ink-soft);
    margin-bottom: 20px;
    border-bottom: none;
}
.back-link:hover { color: var(--accent-text); }
.doc-header {
    padding: 14px 16px;
    margin-bottom: 8px;
}
.doc-header h1 {
    font-size: 16px;
    margin-bottom: 6px;
    word-break: break-word;
}
.doc-header-meta {
    display: flex;
    flex-wrap: wrap;
    gap: 16px 32px;
    font-size: 13px;
    color: var(--ink-soft);
    margin-top: 16px;
}
.doc-header-meta span { display: flex; gap: 6px; }
.doc-header-meta strong {
    color: var(--ink-faint);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 11px;
}
.doc-text {
    padding: 16px;
    font-family: 'DM Sans', sans-serif;
    font-size: 13px;
    line-height: 1.75;
    color: var(--ink);
    white-space: pre-wrap;
    word-wrap: break-word;
}

/* ─── Extraction container on document detail ─── */
.extract-box {
    overflow: hidden;
}
.extract-box-bar {
    padding: 10px 16px;
    background: var(--bg-raised);
    border-bottom: 1px solid var(--border);
    font-size: 12px;
    font-weight: 700;
    color: var(--ink-soft);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.extract-panel {
    border-bottom: 1px solid var(--border);
}
.extract-panel:last-child { border-bottom: none; }
.extract-panel-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 16px;
    background: var(--bg-card);
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink);
    user-select: none;
    transition: background 0.1s;
}
.extract-panel-bar:hover { background: var(--bg-raised); }
.extract-panel-bar .chevron {
    transition: transform 0.2s;
    color: var(--ink-faint);
    font-size: 11px;
    margin-left: 8px;
}
.extract-panel.open .chevron { transform: rotate(90deg); }
.extract-panel-content {
    display: none;
    border-top: 1px solid var(--border-light);
}
.extract-panel.open .extract-panel-content { display: block; }
.extract-panel .doc-text {
    border: none;
    border-radius: 0;
    max-height: 50vh;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: var(--scroll-thumb) var(--scroll-track);
    overscroll-behavior-y: contain;
}

/* Legacy classes kept for compatibility */
.extract-section { margin-bottom: 28px; }
.extract-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 12px;
}
.extract-header h3 { margin: 0; }
.extract-tag {
    font-size: 11px;
    font-weight: 600;
    padding: 4px 10px;
    border-radius: 20px;
    letter-spacing: 0.3px;
    text-transform: uppercase;
    font-family: 'DM Sans', sans-serif;
    white-space: nowrap;
}
.extract-tag--fast {
    background: var(--bg-raised);
    color: var(--ink-soft);
    border: 1px solid var(--border);
}
.extract-tag--enhanced {
    background: var(--accent-muted);
    color: var(--accent-text);
    border: 1px solid var(--accent);
}
.extract-tag--pending {
    background: var(--amber-muted);
    color: var(--amber-text);
    border: 1px solid var(--amber);
    display: inline-flex;
    align-items: center;
    gap: 8px;
}
.extract-tag--failed {
    background: var(--red-muted);
    color: var(--red);
    border: 1px solid var(--red);
}
.pending-dot {
    display: inline-block;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--amber-text);
    animation: pending-pulse 1.4s ease-in-out infinite;
}
@keyframes pending-pulse {
    0%, 100% { opacity: 0.3; transform: scale(0.8); }
    50%      { opacity: 1.0; transform: scale(1.2); }
}

.enhance-loading {
    padding: 28px;
    display: flex;
    align-items: center;
    gap: 16px;
}
.enhance-spinner {
    width: 28px;
    height: 28px;
    border: 3px solid var(--border);
    border-top-color: var(--accent-text);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
    flex-shrink: 0;
}
@keyframes spin {
    to { transform: rotate(360deg); }
}

/* ── Upload-from-machine inline status ──
   Single live-updating line with a small spinning dot next to it
   instead of a pile of stacked "still processing…" lines. Kept
   compact so it fits inside the rail's narrow 280px column. */
.ufm-status-live {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 4px 0;
    font-size: 12px;
    color: var(--ink-soft);
}
.ufm-status-spinner {
    width: 12px;
    height: 12px;
    border: 2px solid var(--border);
    border-top-color: var(--accent-text);
    border-radius: 50%;
    animation: spin 0.9s linear infinite;
    flex-shrink: 0;
}
.ufm-status-done { color: var(--accent-text); }
.enhance-loading-text {
    font-size: 13px;
    color: var(--ink-soft);
    line-height: 1.5;
}
.enhance-loading-text small {
    color: var(--ink-faint);
    font-size: 11px;
}

/* ─── Login form ─── */
.login-wrap {
    width: 100%;
    max-width: 440px;
    margin: 64px auto;
}
.login-form {
    padding: 36px 36px 28px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    display: flex;
    flex-direction: column;
    gap: 14px;
    /* Match heights between login (short) and signup (tall): content-driven
       with a floor so a short form never collapses below a reasonable size. */
    min-height: 360px;
    justify-content: center;
}
.login-form h1 { text-align: center; font-size: 24px; }
.login-form .btn { margin-top: 8px; }
.login-form h1 { text-align: center; margin-bottom: 8px; }
.login-form label {
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-faint);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.login-form input {
    padding: 12px 14px;
    background: var(--bg-input);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    outline: none;
}
.login-form input:focus {
    border-color: var(--accent-text);
    background: var(--bg-raised);
}
.login-error {
    color: var(--red);
    font-size: 13px;
    text-align: center;
    padding: 8px;
    background: var(--red-muted);
    border-radius: var(--radius);
}

/* ─── Buttons ─── */
.btn {
    padding: 12px 24px;
    border-radius: var(--radius);
    font-size: 14px;
    font-weight: 600;
    cursor: pointer;
    border: none;
    transition: background 0.15s, opacity 0.15s;
    font-family: 'DM Sans', sans-serif;
    letter-spacing: 0.2px;
    display: inline-block;
    text-align: center;
}
/* .btn-primary styling now lives in the kit (kit/css/components.css).
   Dropped the local duplicate here once the submodule was bumped to
   pick up denovoworks/denovo-kit PR #3 (white text on green). */
.btn:disabled, .btn[disabled] {
    opacity: 0.4;
    cursor: not-allowed;
    pointer-events: none;
}
.btn-secondary {
    background: var(--bg-card);
    color: var(--ink-soft);
    border: 1px solid var(--border);
}
.btn-secondary:hover { background: var(--bg-raised); color: var(--ink); }

/* Chat list primary CTA — match the Generate Brief / Generate Draft
   look exactly. Spheric's .btn is `display: inline-block` (vs kit's
   inline-flex) so an <a class="btn btn-primary"> was rendering with
   a slightly different vertical rhythm than the generate buttons (both
   lived inside .rail-action with width:100%). Normalise to inline-flex
   + explicit min-height here. */
.chat-new-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 40px;
    text-decoration: none;
}

/* ─── Footer ─── */
footer {
    max-width: 1000px;
    margin: 0 auto;
    padding: 8px 24px;
    border-top: 1px solid var(--border);
    font-size: 10px;
    color: var(--ink-faint);
    text-align: center;
    letter-spacing: 0.5px;
    flex-shrink: 0;
    width: 100%;
}

/* ─── Document picker (shared by generate + chat) ─── */
.picker-container {
    display: flex;
    flex-direction: column;
    min-height: 0;
    flex: 1;
    overflow: hidden;
}
.picker-top { flex-shrink: 0; }
.picker-scroll {
    flex: 1;
    scrollbar-gutter: stable;
}
/* Selection tray is a direct child of picker-container, pinned at bottom */
.doc-picker-list .doc-row {
    grid-template-columns: 28px 48px 1fr auto auto;
}
.doc-checkbox-col {
    display: flex;
    align-items: center;
    justify-content: center;
}
.doc-checkbox-col input[type="checkbox"] {
    width: 18px;
    height: 18px;
    accent-color: var(--accent-text);
    cursor: pointer;
}
.doc-picker-row { cursor: pointer; }
.doc-picker-row:has(input:checked) .doc-row {
    border-color: var(--accent);
    background: rgba(45,90,61,0.08);
}

.selection-tray {
    /* extends .pinned-bar via HTML class */
}
/* When picker is used inside a page that has its own action bar,
   hide the picker's built-in tray */
.has-own-action-bar .selection-tray { display: none !important; }

/* Consistent pinned bottom bars — now use .pinned-bar base class */
.bottom-action-bar {
    /* extends .pinned-bar via HTML class */
}
.tray-count {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
}
.tray-tokens {
    font-size: 12px;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}
.tray-warning {
    font-size: 12px;
    font-weight: 600;
}
.selection-tray .btn { margin-left: auto; }

.preset-vendor-wrap {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.preset-vendor-select {
    padding: 6px 10px;
    background: var(--bg-input);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: 'DM Sans', sans-serif;
    font-size: 12px;
}

/* ─── Draft output (generate + draft detail) ─── */
.draft-output {
    padding: 24px;
    font-size: 14px;
    line-height: 1.75;
    color: var(--ink);
    flex: 1;
    margin-bottom: 0;
}
.draft-output h1 { color: var(--accent-text); margin: 0 0 16px; font-size: 24px; font-family: 'Fraunces', serif; font-weight: 600; }
.draft-output h2 { color: var(--accent-text); margin: 24px 0 12px; font-size: 20px; }
.draft-output h3 { color: var(--ink); margin: 20px 0 10px; font-size: 17px; }
.draft-output h4 { color: var(--ink-soft); margin: 16px 0 8px; font-size: 15px; }
.draft-output strong { color: var(--ink); }
/* padding-left keeps list markers (both bullets and numbers) INSIDE the
   box. The global `* { padding: 0 }` reset strips default <ol>/<ul>
   padding, so without this the "1." / "2." numerals render flush to the
   container's left edge and appear to spill out. */
.draft-output ul,
.draft-output ol { padding-left: 28px; margin: 8px 0; }
.draft-output li { margin: 4px 0; }
.draft-output blockquote {
    margin: 12px 0;
    padding: 4px 14px;
    border-left: 3px solid var(--accent);
    color: var(--ink-soft);
    font-style: italic;
}
.draft-output code {
    background: var(--bg-raised);
    color: var(--ink);
    padding: 1px 6px;
    border-radius: 3px;
    font-size: 0.9em;
}
.draft-output pre {
    background: var(--bg-raised);
    color: var(--ink);
    padding: 12px 14px;
    border-radius: var(--radius);
    margin: 12px 0;
    overflow-x: auto;
    font-size: 0.9em;
}
.draft-output pre code { background: transparent; padding: 0; }

.draft-area-hidden { display: none !important; }
.draft-area-visible {
    display: flex !important;
    flex: 1;
    flex-direction: column;
    min-height: 0;
    overflow: hidden;
}

.draft-header {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 24px 0 12px;
}
.draft-header h3 { margin: 0; }
.streaming-status {
    font-size: 12px;
    color: var(--amber-text);
    font-weight: 400;
}

.draft-actions, .draft-actions-bar {
    /* extends .pinned-bar via HTML class */
    gap: 12px;
    margin-top: 0;
}

.draft-detail-header {
    margin-bottom: 8px;
}
.draft-detail-header h2 {
    margin: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    min-width: 0;
    max-width: 100%;
}
.draft-meta {
    display: flex;
    align-items: center;
    gap: 16px;
    font-size: 13px;
    color: var(--ink-soft);
    margin-left: auto;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.draft-error {
    color: var(--red);
    padding: 16px;
    background: var(--red-muted);
    border-radius: var(--radius);
}

.source-appendix {
    margin-top: 28px;
    padding-top: 20px;
    border-top: 1px solid var(--border);
}
.source-appendix h3 {
    font-size: 16px;
    color: var(--ink-soft);
    margin-bottom: 12px;
}

.streaming-cursor {
    display: inline-block;
    width: 8px;
    height: 16px;
    background: var(--accent-text);
    animation: cursor-blink 0.8s infinite;
    vertical-align: text-bottom;
    margin-left: 2px;
}
@keyframes cursor-blink {
    0%, 100% { opacity: 1; }
    50%      { opacity: 0; }
}

/* ─── Tabs ─── */
.tab-row {
    display: flex;
    gap: 0;
    border-bottom: 1px solid var(--border);
    margin-bottom: 16px;
}
.tab-btn {
    padding: 10px 20px;
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-faint);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    letter-spacing: 0.2px;
    transition: color 0.15s, border-color 0.15s;
}
.tab-btn:hover { color: var(--ink-soft); }
.tab-btn.active {
    color: var(--accent-text);
    border-bottom-color: var(--accent-text);
}

/* ─── Account dropdown ─── */
.nav-account-wrap {
    position: relative;
    display: inline-flex;   /* flex so baseline of the button aligns
                               to sibling <a> which are rendered as
                               flex items inside .header-nav. */
    align-items: center;
    vertical-align: baseline;
}
.nav-account-btn {
    /* Match sibling <a> tags — <button> has browser-default padding,
       line-height, and flex-shrink that push the label ~2px below
       the other nav links. Zero them out. */
    padding: 0;
    margin: 0;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-soft);
    background: none;
    border: none;
    cursor: pointer;
    font-family: 'DM Sans', sans-serif;
    letter-spacing: 0.2px;
    vertical-align: baseline;
}
.nav-account-btn:hover { color: var(--accent-text); }
.nav-account-menu {
    position: absolute;
    top: 100%;
    right: 0;
    margin-top: 8px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    min-width: 200px;
    padding: 8px 0;
    box-shadow: var(--shadow-lg);
    z-index: 2000;
}
.nav-account-menu a {
    display: block;
    padding: 8px 16px;
    font-size: 13px;
    color: var(--ink-soft);
    border-bottom: none;
}
.nav-account-menu a:hover { background: var(--bg-raised); color: var(--ink); }
.account-info {
    padding: 10px 16px;
    border-bottom: 1px solid var(--border);
    margin-bottom: 4px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.account-info strong { font-size: 14px; color: var(--ink); }
.account-info span { font-size: 12px; color: var(--ink-faint); }

/* ─── Account page ───
   Stacked-card layout shown at /account. Replaces the old header-
   dropdown menu — same contents (user info, theme toggle, costs, admin,
   logout) but as a real page. Cards stretch on desktop, full-bleed on
   mobile. */
.account-page {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    max-width: 520px;
    margin: 0 auto;
    padding-top: var(--space-md);
    width: 100%;
}
.account-link {
    display: inline-flex;
    align-items: center;
    color: var(--accent-text);
    font-size: 14px;
    font-weight: 500;
    text-decoration: none;
    padding: 6px 0;
    border-bottom: none;
}
.account-link:hover { color: var(--accent-light); border-bottom: none; }
.account-link--destructive { color: var(--red); }
.account-link--destructive:hover { color: var(--red); opacity: 0.85; }
/* The kit's theme toggle partial has its own styling; the account card
   just gives it breathing room. */
.account-page .card .theme-toggle { margin-top: var(--space-xs); }

/* ─── Chat ─── */
/* .chat-layout is an alias for .page-rail-layout — kept for backward compat */
.chat-layout {
    display: flex;
    gap: 0;
    flex: 1;
    min-height: 0;
}
.chat-main {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    min-height: 0;
}
/* Chat sidebar uses the same rail shape */
.chat-sidebar {
    width: 280px;
    flex-shrink: 0;
    border-left: 1px solid var(--border);
    padding: 16px 16px 12px 20px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    background: var(--bg);
}
.sidebar-tray-scroll {
    flex: 1;
}
.sidebar-actions {
    flex-shrink: 0;
    border-top: 1px solid var(--border);
    padding-top: 12px;
    margin-top: 12px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}
.sidebar-heading {
    margin-bottom: 12px;
    color: var(--ink-soft);
    font-size: 14px;
}

.chat-messages {
    flex: 1;
    padding: 16px 16px 8px 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

/* Message wrapper — copy button + bubble side by side */
.chat-msg-wrapper {
    display: flex;
    gap: 6px;
    align-items: flex-start;
    position: relative;
}
.chat-msg-wrapper.user {
    flex-direction: row-reverse;
    align-self: flex-end;
    max-width: 85%;
}
.chat-msg-wrapper.assistant {
    max-width: 100%;
}

.msg-copy-btn {
    flex-shrink: 0;
    background: none;
    border: none;
    color: var(--ink-faint);
    cursor: pointer;
    padding: 4px;
    border-radius: 4px;
    opacity: 0;
    transition: opacity 0.15s;
    margin-top: 6px;
}
.chat-msg-wrapper:hover .msg-copy-btn { opacity: 0.5; }
.msg-copy-btn:hover { opacity: 1 !important; background: var(--bg-raised); }

.chat-msg { min-width: 0; }
.msg-time {
    font-size: 10px;
    color: var(--ink-faint);
    margin-top: 4px;
    letter-spacing: 0.2px;
    font-variant-numeric: tabular-nums;
}
.chat-msg.user .msg-time { text-align: right; }
.msg-body {
    font-size: 14px;
    line-height: 1.65;
    word-wrap: break-word;
}
.chat-msg.user .msg-body {
    padding: 10px 14px;
    background: var(--accent-muted);
    border: 1px solid var(--accent);
    border-radius: 12px;
    border-bottom-right-radius: 4px;
    white-space: pre-wrap;
    /* Pin typography so user bubbles don't balloon when the web font
       isn't resolved yet — same issue as the assistant bubble fix. */
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    font-size: 14px;
    line-height: 1.65;
    max-width: 100%;
    overflow-wrap: break-word;
    word-wrap: break-word;
}
.chat-msg.assistant .msg-body {
    color: var(--ink);
    /* Pin the font + size so rendering is consistent regardless of
       which web font state the browser is in. Without this, the
       inherited font chain could resolve to a different fallback
       on tab-return, making bubbles render much larger. */
    font-family: 'DM Sans', -apple-system, BlinkMacSystemFont, sans-serif;
    font-size: 14px;
    line-height: 1.65;
    /* Constrain width so streamed content can't push past the
       chat column regardless of what marked renders. */
    max-width: 100%;
    overflow-wrap: break-word;
    word-wrap: break-word;
}
.chat-msg.assistant .msg-body h1,
.chat-msg.assistant .msg-body h2,
.chat-msg.assistant .msg-body h3 { margin-top: 12px; }
.chat-msg.assistant .msg-body p { margin: 6px 0; }
.chat-msg.assistant .msg-body ul,
.chat-msg.assistant .msg-body ol { padding-left: 20px; margin: 6px 0; }
.chat-msg.assistant .msg-body li { margin: 2px 0; }
.chat-msg.assistant .msg-body strong { color: var(--ink); }
/* If the model's output happens to have 4+ leading spaces on a line,
   markdown treats it as a code block and renders it with <pre><code>.
   Monospace + no-wrap blew out chat bubbles to the right edge and
   reflowed the whole layout. Force them to word-wrap and stay inside
   the column — still obviously "code-looking" but readable. */
.chat-msg.assistant .msg-body pre,
.chat-msg.assistant .msg-body code {
    font-size: 13px;
    max-width: 100%;
    white-space: pre-wrap;
    word-wrap: break-word;
    overflow-wrap: anywhere;
}
.chat-msg.assistant .msg-body pre {
    background: var(--bg-card);
    border: 1px solid var(--border-light);
    border-radius: 6px;
    padding: 8px 12px;
    margin: 6px 0;
    overflow-x: auto;
}
.chat-msg.assistant .msg-body code {
    background: var(--bg-card);
    padding: 1px 4px;
    border-radius: 3px;
}
.chat-msg.assistant .msg-body pre code {
    background: transparent;
    padding: 0;
}

.chat-compose {
    /* extends .pinned-bar via HTML class */
    gap: 10px;
    padding: 10px 16px 8px 0;
    align-items: flex-end;
}
.chat-input {
    flex: 1;
    padding: 10px 14px;
    background: var(--bg-input);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: 'DM Sans', sans-serif;
    font-size: 14px;
    resize: none;
    outline: none;
    min-height: 40px;
    max-height: 180px;
    overflow-y: auto;
}
.chat-input:focus {
    border-color: var(--accent-text);
    background: var(--bg-raised);
}

/* Session-document item in the chat sidebar — two-line layout:
     line 1: [title ellipsized]          [vendor pill]
     line 2: [type badge] Initial / Added before msg N */
.tray-doc-item {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 8px 10px;
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    text-decoration: none;
    color: inherit;
    transition: border-color 0.15s, background 0.15s;
    min-width: 0;
}
.tray-doc-item:hover {
    border-color: var(--accent-text);
    background: var(--bg-raised);
    border-bottom-color: var(--accent-text);
}
.tray-doc-row-top {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.tray-doc-row-bot {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.tray-doc-title {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 13px;
    color: var(--ink);
    font-weight: 500;
}
.tray-doc-origin {
    font-size: 11px;
    color: var(--ink-faint);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.sidebar-tray-scroll {
    display: flex;
    flex-direction: column;
    gap: 6px;
}

@media (max-width: 800px) {
    .chat-layout { flex-direction: column; height: auto; }
    .chat-sidebar { width: 100%; border-left: none; border-top: 1px solid var(--border); }
}

/* Modal CSS lives in vendor/denovo-kit/kit/css/components.css (the kit's
   .modal-overlay / .modal-content / .modal-header / .modal-close /
   .modal-body / .modal-footer + the body.modal-open guard). DO NOT
   re-define those here. The legacy block that lived here through
   2026-05-20 had .modal-overlay { display: flex } WITHOUT the
   .is-open requirement -- it overrode the kit's correct `display: none`
   default and showed the MandateSpec modal on every intake-page revisit
   for an already-locked engagement. The fix is to delete the block
   entirely; the kit's rules are loaded earlier AND are now no longer
   overridden, so denovoModal.open() / close() flip the visibility
   correctly via .is-open. */

/* ─── Costs ─── */
/* ─── Email groups (library) ─── */
.email-group {
    overflow: hidden;
    transition: border-color 0.15s;
}
.email-group:hover { border-color: var(--accent-text); }
.email-group-bar {
    display: grid;
    grid-template-columns: 16px 1fr auto auto;
    /* gap matches .doc-row (chat/brief/draft) so library rows feel
       like members of the same family. The explicit margin-right on
       .doc-vendor-pill below gives the pill extra breathing room from
       the date column (which used to require a larger gap). */
    gap: 12px;
    align-items: center;
    padding: 7px 12px;
    cursor: pointer;
    user-select: none;
}
/* Belt-and-suspenders — explicit margin on the pill so the spacing
   holds even on browsers / layouts that ignore grid gap under
   certain conditions. */
.email-group-bar .doc-vendor-pill {
    margin-right: 8px;
}
.email-group-bar .chevron {
    font-size: 10px;
    color: var(--ink-faint);
    transition: transform 0.2s;
}
.email-group.open .email-group-bar .chevron { transform: rotate(90deg); }
.email-group-content {
    display: none;
    border-top: 1px solid var(--border-light);
}
.email-group.open .email-group-content { display: block; }
/* Nested child rows under an expanded email. Intentionally smaller
   than the parent .email-group-bar / .doc-row:
     - font-size: 13px (vs 14px parent) signals "child" visually.
     - padding-left: 38px indents children so the type-badge aligns
       with where the chevron sits in the 16px parent column plus
       padding; don't "clean up" this number without checking alignment.
     - Tighter vertical padding (5px vs 7px) keeps the nested group
       from dominating the list. */
.email-sub-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 12px 5px 38px;
    font-size: 13px;
    color: var(--ink-soft);
    border-bottom: 1px solid var(--border-light);
    transition: background 0.1s;
}
.email-sub-row:last-child { border-bottom: none; }
.email-sub-row:hover { background: var(--bg-raised); }

/* Select-all header row inside an expanded email group.
   Right-aligned button, no hover highlight (it's an action, not an
   item), tighter vertical padding than regular sub-rows. */
.email-sub-row--header {
    justify-content: flex-end;
    padding: 6px 12px;
    background: var(--bg-input);
    border-bottom: 1px solid var(--border-light);
}
.email-sub-row--header:hover { background: var(--bg-input); }
label.email-sub-row { cursor: pointer; }
label.email-sub-row input[type="checkbox"] {
    width: 16px;
    height: 16px;
    accent-color: var(--accent-text);
    cursor: pointer;
    flex-shrink: 0;
}
/* Pin the picker-row checkbox to an exact 16px with zero margin so the
   unselectable row's padding-left: 64px (= 38 base + 16 checkbox + 10
   gap) actually lines up. Without this, the browser default (~13px +
   ~7px asymmetric margin) pushes the selectable rows' badge to the
   right and the eml badge ends up visibly misaligned. */
.picker-doc-row .doc-check {
    width: 16px;
    height: 16px;
    margin: 0;
    flex-shrink: 0;
    accent-color: var(--accent-text);
    cursor: pointer;
}
.email-sub-row:has(input:checked) {
    background: rgba(45,90,61,0.08);
}
.email-sub-link {
    display: flex;
    align-items: center;
    gap: 10px;
    flex: 1;
    min-width: 0;
    color: var(--ink-soft);
    border-bottom: none;
    transition: color 0.1s;
}
.email-sub-link:hover { color: var(--accent-text); border-bottom: none; }
.email-sub-label {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ─── Home ─── */
.home-main {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 24px;
}
.home-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
    max-width: 480px;
    width: 100%;
}
.home-grid--two {
    grid-template-columns: repeat(2, 1fr);
    max-width: 880px;
}
@media (max-width: 720px) {
    .home-grid--two { grid-template-columns: 1fr; max-width: 480px; }
}
.home-card {
    display: flex;
    align-items: center;
    gap: 20px;
    padding: 28px 24px;
    text-decoration: none;
    color: var(--ink);
    transition: border-color 0.15s, background 0.15s, transform 0.05s;
}
.home-card:hover {
    border-color: var(--accent);
    background: var(--bg-raised);
    border-bottom-color: var(--accent);
}
.home-card:active { transform: scale(0.998); }
.home-card-icon {
    flex-shrink: 0;
    width: 52px;
    height: 52px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--accent-muted);
    border-radius: var(--radius);
}
.home-card-body h3 {
    font-size: 18px;
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 500;
    margin-bottom: 4px;
}
.home-card-body p {
    font-size: 13px;
    color: var(--ink-soft);
    line-height: 1.5;
    margin: 0;
}
.home-card-arrow {
    margin-left: auto;
    font-size: 20px;
    color: var(--ink-faint);
    flex-shrink: 0;
}
.home-card:hover .home-card-arrow { color: var(--accent-text); }

/* ─── Costs ─── */
.costs-top-row {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 16px;
    margin-bottom: 24px;
}
.cost-card {
    padding: 20px;
}
.cost-card--total {
    border-color: var(--accent);
    background: rgba(45,90,61,0.06);
}
.cost-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--ink-soft);
    margin-bottom: 6px;
}
.cost-sublabel {
    font-size: 11px;
    color: var(--ink-faint);
    margin-top: 6px;
}
.cost-amount {
    font-size: 26px;
    font-weight: 700;
    color: var(--ink);
    font-family: 'DM Sans', sans-serif;
    font-variant-numeric: tabular-nums;
    line-height: 1;
}
.cost-card--total .cost-amount { color: var(--accent-text); }
/* Stacked sublabel lines on cost cards — tighter than the 6px default
   so three-or-more stats don't push the card height too much. */
.cost-sublabel + .cost-sublabel { margin-top: 3px; }

/* ── Token meter (chat compose bar) ──────────────────────────────────
   Colour states mirror the per-turn token budget:
     default → under TOKEN_WARN_THRESHOLD (50K)
     amber   → between warn and ~180K (90% of 200K context)
     red     → approaching / at context window ceiling
   Also applied to the .rail-meta tokens counter in the Add-Docs modal
   so the two places that show token counts look the same. */
.token-meter {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: 6px 12px;
    font-size: 12px;
    color: var(--ink-soft);
    border-top: 1px solid var(--border-light);
    border-bottom: 1px solid var(--border-light);
    background: var(--bg-card);
}
.token-meter-label {
    font-weight: 600;
    color: var(--ink-faint);
    text-transform: uppercase;
    font-size: 10px;
    letter-spacing: 0.5px;
}
.token-meter-value { font-variant-numeric: tabular-nums; }
.token-meter-hint {
    margin-left: auto;
    font-size: 11px;
    color: var(--ink-faint);
    font-style: italic;
}
.token-meter--amber { color: #c78a2a; }
.token-meter--amber .token-meter-label { color: #c78a2a; }
.token-meter--red { color: #b85c5c; }
.token-meter--red .token-meter-label { color: #b85c5c; }

/* ── Chat error bubble ───────────────────────────────────────────────
   Assistant turns that failed (rate limit, context overflow, SDK
   timeout) are persisted with the ERROR_MARKER prefix so the user can
   see on reload what went wrong. Template renders them with the
   .chat-msg--error class instead of the normal assistant bubble. */
.chat-msg--error {
    background: rgba(184, 92, 92, 0.08);
    border: 1px solid rgba(184, 92, 92, 0.3);
    color: #b85c5c;
}
/* Streaming resume bubble: an assistant row found in STREAMING_MARKER
   state at page-load. Frontend polls the status endpoint until the
   row finalises. Kept visually muted so users recognise it's not
   done yet. */
.chat-msg--streaming {
    background: var(--bg-raised);
    border: 1px dashed var(--border);
}
/* Error bubble body needs explicit padding — the generic .chat-msg
   rule doesn't carry enough breathing room for the red-tinted error
   content, which previously ran flush against the bubble border. */
.chat-msg--error .msg-body {
    color: #b85c5c;
    padding: 10px 14px;
}
.msg-error-prefix {
    display: inline-block;
    margin-right: 8px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    font-size: 10px;
    background: #b85c5c;
    color: #fff;
    /* Prior 1px vertical padding made caps like "TURN FAILED:" crowd the
       badge border. 3px gives the letters room without enlarging the
       badge visually. line-height pins the inner box so descenders on
       mixed case (if someone changes the label) don't bleed out. */
    padding: 3px 8px;
    border-radius: 3px;
    vertical-align: middle;
    line-height: 1.4;
}
.msg-error-hint {
    color: #8a4a4a;
    font-style: italic;
    font-size: 12px;
}
/* One-click recovery on a failed turn. Re-sends the preceding user
   message with the current model-picker selection (user can switch
   before clicking). Minimal visual weight so the error itself stays
   the primary thing the user reads. */
.msg-retry-btn {
    display: inline-block;
    margin-top: 8px;
    padding: 3px 10px;
    font-size: 12px;
    background: transparent;
    color: #b85c5c;
    border: 1px solid #b85c5c;
    border-radius: 3px;
    cursor: pointer;
}
.msg-retry-btn:hover {
    background: #b85c5c;
    color: #fff;
}
/* Model badge on assistant bubbles — sits next to the timestamp. Muted
   so it reads as metadata, not a UI affordance. */
.msg-model-badge {
    margin-left: 4px;
    color: var(--ink-soft, #888);
    font-size: 11px;
    text-transform: lowercase;
    letter-spacing: 0.3px;
}

/* ── Picker: attached-doc badge ──────────────────────────────────────
   Docs already in a chat session render with this badge and the row
   gets .picker-doc-row--attached (dimmed, disabled checkbox). Gives
   the user visible context instead of silently hiding the row. */
.picker-doc-row--attached {
    opacity: 0.55;
    pointer-events: auto; /* allow link click but checkbox is disabled */
}
.picker-doc-row--attached .doc-check { cursor: not-allowed; }
.attached-badge {
    display: inline-block;
    margin-left: 8px;
    padding: 1px 6px;
    font-size: 9px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    background: var(--border);
    color: var(--ink-soft);
    border-radius: 3px;
}

.costs-chart-section {
    padding: 24px;
}
.costs-chart-section h3 {
    font-size: 14px;
    color: var(--ink-soft);
    margin-bottom: 16px;
}
.chart-bars {
    display: flex;
    gap: 4px;
    align-items: flex-end;
    height: 280px;
    border-bottom: 1px solid var(--border-light);
    padding-bottom: 4px;
}
.chart-col {
    flex: 1;
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    align-items: center;
    min-width: 0;
}
/* chart-bar-wrap previously had `flex: 1; height: 150px;`. In a
   column-flex parent with no fixed outer height, `flex: 1` resolves
   flex-basis to 0 and height:150px is ignored, collapsing the wrap
   to 0 — every bar rendered as just its 2px min-height stub
   regardless of its `height: X%` pct. Drop the flex and use a plain
   height so the percentage is against something real. */
.chart-bar-wrap {
    width: 100%;
    display: flex;
    align-items: flex-end;
    justify-content: center;
    height: 240px;
}
.chart-bar {
    width: 80%;
    max-width: 40px;
    background: var(--accent);
    border-radius: 3px 3px 0 0;
    min-height: 2px;
    position: relative;
    transition: height 0.3s;
}
.chart-bar:hover { background: var(--accent-light); }
.chart-bar-label {
    position: absolute;
    top: -18px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 9px;
    color: var(--ink-faint);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}
.chart-date {
    font-size: 10px;
    color: var(--ink-faint);
    margin-top: 6px;
    white-space: nowrap;
}
/* ── Capacity picker ──
   Segmented 3-button control (Light / Medium / Heavy) placed to the
   left of the primary action button (Generate Draft / Generate Brief /
   Start Session / Send). Default: Light. Choice does NOT persist
   across page navigations — cost-safety default.

   Each button carries data-capacity; backend/llm_fallback.py resolves
   the tier's primary → fallback1 → fallback2 chain at request time. */
.capacity-picker {
    display: inline-flex;
    align-items: stretch;
    background: var(--bg-input);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    height: 40px;
    font-family: 'DM Sans', sans-serif;
    font-variant-numeric: tabular-nums;
}
.capacity-btn {
    background: transparent;
    color: var(--ink-faint);
    border: none;
    padding: 0 14px;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.5px;
    cursor: pointer;
    transition: background 0.15s, color 0.15s;
    border-right: 1px solid var(--border);
}
.capacity-btn:last-child { border-right: none; }
.capacity-btn:hover { color: var(--ink); background: var(--bg-card); }
.capacity-btn.is-active {
    background: var(--accent);
    color: #ffffff;
}
.capacity-btn.is-active:hover { background: var(--accent); }
/* In the rail action area, stretch the picker to full width above the btn */
.rail-action .capacity-picker { width: 100%; }
.rail-action .capacity-btn { flex: 1; }

/* Force the primary CTA to own its stacking context so nothing in the
   rail above it (capacity picker hover/focus outlines, pseudo-element
   spacers, transient upload-status rows, etc.) can end up visually or
   pointer-events-wise on top of the top few pixels of the button.
   Reported symptom: "if I go a bit down on the button it works" — i.e.
   the upper strip of the button was receiving clicks that resolved to
   a sibling rather than the button itself. z-index:1 is enough to
   guarantee the button wins any same-level stacking contest, and
   isolation:isolate contains it from outside z-index stacks. The button
   is still `position: static` laid out; z-index only kicks in because
   we also set position:relative. */
.rail-action .btn-primary,
.sidebar-actions .btn-primary,
#send-btn,
#add-docs-confirm {
    position: relative;
    z-index: 1;
    isolation: isolate;
}

.costs-pricing-note {
    margin-top: 16px;
    font-size: 11px;
    color: var(--ink-faint);
    padding-top: 12px;
    border-top: 1px solid var(--border-light);
    display: flex;
    flex-direction: column;
    gap: 14px;
    font-variant-numeric: tabular-nums;
}
.costs-pricing-row strong { color: var(--ink-soft); }
.pricing-tier { display: flex; flex-direction: column; gap: 4px; }
.pricing-tier-heading {
    font-weight: 700;
    font-size: 10px;
    letter-spacing: 1.5px;
    text-transform: uppercase;
    color: var(--accent-text);
    margin-bottom: 2px;
}
.pricing-role {
    display: inline-block;
    min-width: 74px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: 0.5px;
    text-transform: uppercase;
    color: var(--ink-faint);
}
/* Small badge marking whether a tier slot runs the model in thinking
   mode. Same per-token rate, but a thinking run typically emits 2–3×
   more output tokens per request, so the effective cost is higher —
   users need to see this next to the price. */
.pricing-reasoning {
    display: inline-block;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.5px;
    color: var(--amber-text);
    padding: 1px 5px;
    background: var(--amber-muted);
    border-radius: 3px;
    margin: 0 2px;
}

/* ─── Responsive ─── */
@media (max-width: 640px) {
    .header-inner { flex-direction: column; align-items: flex-start; gap: 16px; }
    .header-nav { width: 100%; }
    .doc-row {
        grid-template-columns: 48px 1fr;
        gap: 10px;
    }
    .doc-size, .doc-date { grid-column: 2; text-align: left; }
    main { padding: 24px 16px 60px; }
}

/* ── Modals (Ask-for-change + Versions) ── */
.modal-desc {
    font-size: 13px;
    color: var(--ink-soft);
    margin: 0 0 12px;
    line-height: 1.5;
}
.modal-body .correction-input {
    width: 100%;
    min-height: 100px;
    padding: 10px 14px;
    background: var(--bg-input);
    color: var(--ink);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    font-family: inherit;
    font-size: 14px;
    line-height: 1.5;
    resize: vertical;
    box-sizing: border-box;
}
.modal-body .correction-input:focus {
    outline: none;
    border-color: var(--accent-text);
}
.modal-actions {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 12px;
    margin-top: 14px;
    flex-wrap: wrap;
}
.modal-error {
    margin-top: 10px;
    padding: 8px 12px;
    border: 1px solid var(--red);
    border-radius: 4px;
    color: var(--red);
    font-size: 13px;
    background: var(--red-muted);
}

/* ── Versions modal — per-row actions ── */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.55);
    display: none;
    align-items: center;
    justify-content: center;
    z-index: 100;
}
.modal-backdrop.open { display: flex; }
.modal-panel {
    background: var(--bg-card);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: 20px 24px;
    width: min(560px, 92vw);
    max-height: 80vh;
    overflow-y: auto;
    box-shadow: var(--shadow-lg);
}
.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 14px;
}
.modal-title { font-size: 16px; color: var(--ink); margin: 0; }
.modal-close {
    background: none;
    border: none;
    color: var(--ink-soft);
    font-size: 24px;
    line-height: 1;
    padding: 0;
    cursor: pointer;
}
.modal-close:hover { color: var(--ink); }
.version-header {
    font-size: 13px;
    color: var(--ink-soft);
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
}
.version-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
.version-row {
    background: transparent;
    border: 1px solid var(--border-light);
    border-radius: 4px;
    padding: 10px 12px;
    text-align: left;
    cursor: pointer;
    color: var(--ink);
    font: inherit;
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    gap: 12px;
}
.version-row:hover { background: var(--bg-raised); border-color: var(--border); }
.version-row.current {
    border-left: 3px solid var(--accent-text);
    background: var(--accent-muted);
}
.version-row .v-label {
    font-size: 13px;
    overflow: hidden;
    text-overflow: ellipsis;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
}
.version-row .v-date {
    font-size: 11px;
    color: var(--ink-soft);
    white-space: nowrap;
    flex-shrink: 0;
}
.version-row .v-err { color: var(--red); }

/* View / Copy (or placeholder) pair — equal width, pixel-touching.
   Applies uniformly to draft and brief version lists. */
.version-row .v-actions {
    display: flex;
    flex-shrink: 0;
    gap: 0;
    align-items: stretch;
}
.version-row .v-actions > * {
    min-width: 64px;
    padding: 6px 12px;
    font-size: 12px;
    text-align: center;
    border-radius: 0;
    box-sizing: border-box;
}
.version-row .v-actions > *:first-child {
    border-top-left-radius: var(--radius);
    border-bottom-left-radius: var(--radius);
}
.version-row .v-actions > *:last-child {
    border-top-right-radius: var(--radius);
    border-bottom-right-radius: var(--radius);
}
/* Kill the duplicate 1px where two bordered buttons meet so they read
   as one connected group rather than two separate buttons with a gap. */
.version-row .v-actions > * + * {
    margin-left: -1px;
}
/* Placeholder (errored / generating row) sized to match a real button
   so every row lines up visually in the modal list. */
.version-row .v-actions .btn-row-action-placeholder {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    color: var(--ink-faint);
    background: var(--bg-input);
    font-style: italic;
}

.versions-count {
    display: inline-block;
    min-width: 18px;
    padding: 0 6px;
    margin-left: 4px;
    background: var(--accent-muted);
    color: var(--accent-text);
    border-radius: 9px;
    font-size: 11px;
    line-height: 18px;
    text-align: center;
}
.versions-count:empty { display: none; }

/* ── History row delete button ──
   The × chip lives OUTSIDE the card's right edge so the date/status
   stack inside the card never has to dodge it. The wrapper reserves a
   40px gutter on its right; the card itself keeps its normal padding
   so the inner layout is undisturbed; the button sits in the reserved
   gutter and is absolutely-positioned at the wrapper's right edge.
   Hidden until hover/focus, so the default list stays clean.
   .email-group-wrap shares the same pattern for the admin-only
   library row delete. */
.doc-row-wrap,
.email-group-wrap {
    position: relative;
    padding-right: 40px;
}
.doc-row-wrap .doc-row { padding-right: 16px; }
.email-group-wrap:hover .btn-row-delete,
.email-group-wrap .btn-row-delete:focus { opacity: 1; outline: none; }
.btn-row-delete {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent;
    border: 1px solid var(--red);
    color: var(--red);
    border-radius: 4px;
    font-size: 18px;
    line-height: 1;
    cursor: pointer;
    opacity: 0;
    transition: opacity 0.15s, background 0.15s, color 0.15s;
    z-index: 2;
}
.doc-row-wrap:hover .btn-row-delete,
.btn-row-delete:focus {
    opacity: 1;
    outline: none;
}
.btn-row-delete:hover {
    background: var(--red);
    color: #fff;
}

/* ── Theme toggle (Account menu) ── */
.theme-toggle {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 14px;
    background: transparent;
    border: none;
    color: var(--ink);
    font: inherit;
    font-size: 14px;
    text-align: left;
    cursor: pointer;
}
.theme-toggle:hover { background: var(--bg-raised); }
.theme-toggle:focus { outline: none; background: var(--bg-raised); }
.theme-icon { flex-shrink: 0; }
.theme-icon--sun  { color: #E5A93C; }
.theme-icon--moon { color: var(--ink-soft); }
/* Show only the icon for the theme we'd switch *to*. When dark active,
   show sun (clicking turns it on). When light active, show moon. */
:root[data-theme="dark"]  .theme-icon--moon { display: none; }
:root[data-theme="light"] .theme-icon--sun  { display: none; }
/* Default (no attribute) = dark palette = show sun. */
:root:not([data-theme="light"]) .theme-icon--moon { display: none; }

/* pinned-bar right-aligner — named replacement for inline
   margin-left:auto so mobile can override without !important. */
.pinned-bar-right { margin-left: auto; }

/* ── Mobile layout fixes (doc-row lists, library email groups, pinned bars).
   Uses kit's 1023px breakpoint so iPad-portrait also gets the single-column
   treatment. The 640px block above stays for smallest-screen-only tweaks. ── */
@media (max-width: 1023px) {
    /* Lists without a type-badge column (prompts / chats / briefs / drafts):
       collapse right-side metadata below the main content instead of
       fighting for horizontal space. */
    .doc-row--no-badge { grid-template-columns: 1fr; row-gap: 4px; }
    .doc-row--no-badge .doc-right-stack {
        grid-column: 1;
        justify-self: start;
        flex-direction: row;
        align-items: center;
        gap: 10px;
        min-width: 0;
    }

    /* Two-line title clamp beats one-line ellipsis on mobile. Same
       webkit-box pattern as .doc-snippet (see above). */
    .doc-subject {
        white-space: normal;
        overflow: hidden;
        text-overflow: clip;
        display: -webkit-box;
        -webkit-line-clamp: 2;
        -webkit-box-orient: vertical;
    }
    /* Sender / usage / filename row: wrap instead of truncate. */
    .doc-filename-row {
        flex-wrap: wrap;
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }
    .doc-filename-row .doc-sender {
        white-space: normal;
        overflow: visible;
        text-overflow: clip;
    }
    .doc-filename-row .doc-filename { max-width: none; }

    /* Library email group bar: collapse 4-col grid to 2-col and wrap the
       vendor pill + date/attachments stack below the subject. */
    .email-group-bar { grid-template-columns: 16px 1fr; row-gap: 6px; }
    .email-group-bar .doc-vendor-pill {
        grid-column: 1 / -1;
        justify-self: start;
        margin-right: 0;
    }
    .email-group-bar .doc-right-stack {
        grid-column: 1 / -1;
        flex-direction: row;
        align-items: center;
        gap: 10px;
        min-width: 0;
    }

    /* Prompt detail pinned bar (usage text + filename): allow wrapping so
       the filename can't be pushed off-screen by a long usage string. */
    .draft-actions-bar.pinned-bar { flex-wrap: wrap; gap: 6px 12px; }
    .draft-actions-bar .doc-date-line {
        white-space: normal;
        overflow-wrap: anywhere;
    }
    .draft-actions-bar .pinned-bar-right { margin-left: 0; }
}

/* ── Mobile parity: restore access to nav + library filters <1024px.
   Kit's layout-mobile.css hides the desktop header (.header-inner,
   .header-nav) and the .page-rail, expecting apps to supply their own
   mobile nav slot and duplicate rail content inside main. These rules
   are the Spheric-specific glue for that pattern. Desktop is untouched —
   layout-desktop.css (loaded earlier) hides .mobile-bottom-nav and
   .mobile-only on ≥1024px. ── */
@media (max-width: 1023px) {
    /* Account pill inside .mobile-bottom-nav is a <button>, not an <a>,
       so kit's `.mobile-bottom-nav a` styling doesn't reach it. Mirror the
       kit rules here to keep all six pills visually uniform. */
    .mobile-bottom-nav button.mobile-bottom-nav-account {
        flex: 1;
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        gap: 2px;
        padding: 8px 4px;
        color: var(--ink-faint);
        font-family: var(--font-sans);
        font-size: 10px;
        font-weight: 600;
        letter-spacing: 0.3px;
        text-transform: uppercase;
        border: none;
        background: none;
        cursor: pointer;
        min-height: 44px;
    }
    .mobile-bottom-nav button.mobile-bottom-nav-account .icon {
        font-size: 22px;
        line-height: 1;
    }
    .mobile-bottom-nav button.mobile-bottom-nav-account:hover { color: var(--ink-soft); }

    /* Account dropdown becomes a bottom-sheet anchored just above the
       bottom-nav on mobile. The desktop rules (position:absolute; top:100%;
       right:0 — see ~line 1425) are useless here because the header that
       they anchor to is display:none under this breakpoint. */
    .nav-account-menu {
        position: fixed;
        left: 8px;
        right: 8px;
        top: auto;
        bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + 8px);
        min-width: 0;
        max-height: 60vh;
        overflow-y: auto;
        z-index: 1001; /* above .mobile-bottom-nav (z-index 999) */
    }

    /* Library filters duplicated inside main. Two vertical sections —
       search trigger on top, preset chips below — with a full-width
       vendor select that slides in when "By vendor" is active. */
    .lib-mobile-filters {
        display: flex;
        flex-direction: column;
        gap: 10px;
        padding: 0 0 10px;
        border-bottom: 1px solid var(--border);
        margin-bottom: 12px;
    }
    .lib-mobile-filters .search-input {
        width: 100%;
        padding: 10px 14px;
        cursor: pointer;
        box-sizing: border-box;
    }
    .lib-mobile-filters .rail-presets {
        grid-template-columns: repeat(4, 1fr);
    }
    .lib-mobile-filters .rail-presets .chip {
        /* Override the fixed-width ellipsis-truncation from the desktop
           rail (see ~line 294) — mobile has more horizontal room and the
           labels fit naturally once the grid is 4-up. */
        white-space: nowrap;
        overflow: visible;
        text-overflow: clip;
    }
    .lib-mobile-filters .preset-vendor-select {
        grid-column: 1 / -1;
    }

    /* Library rail content is duplicated inside main as .lib-mobile-filters,
       so hide the desktop rail on mobile to avoid showing the same search
       box + preset chips twice. Other pages' rails (chat/brief/draft) are
       untouched — they still wrap under content per the existing 900px
       breakpoint around line 395. */
    #library-rail { display: none; }

    /* ── Kill nested scroll containers on mobile ──
       Desktop uses an inner .page-scroll-area + .scroll-box to keep the
       .page-fixed-top bar (back link, action buttons, tab row) visible
       while the content below it scrolls independently. On mobile the
       kit's <main> is already the page scroll container — nesting a
       second one inside means the outer main never grows past viewport
       height and the user has to find the inner box to scroll. Let main
       handle all scrolling; the whole page-fixed-top scrolls up with
       the content, which is fine on a phone. Same logic for
       .chat-messages (chat session detail) and the prompts tab-pane
       scroll-box. */
    main .page-scroll-area,
    main .chat-messages.scroll-box,
    main .tab-pane .scroll-box {
        overflow: visible;
        flex: 0 0 auto;
        min-height: 0;
    }
    /* .page-rail-layout / .chat-layout force `flex: 1` on themselves on
       desktop so the right rail can stretch. On mobile the children
       should wrap to content, not fight main for height. */
    main .page-rail-layout,
    main .chat-layout {
        flex: 0 0 auto;
        display: block;
        min-height: 0;
    }
    main .page-rail-content,
    main .chat-main {
        flex: 0 0 auto;
        display: block;
    }

    /* ── Costs page — 4-card top row collapses to 2-col on mobile ──
       The inline style that used to hard-set 4 columns was removed in
       favour of this class so the grid is actually responsive. */
    .costs-top-row--four { grid-template-columns: 1fr 1fr; }
    /* At very narrow viewports (< 420px) even 2 cards feel crammed; go
       single-column so the dollar amount doesn't wrap awkwardly. */
    @media (max-width: 419px) {
        .costs-top-row--four { grid-template-columns: 1fr; }
    }

    /* Daily-cost chart on phone: fit the viewport. No horizontal scroll
       — bars shrink to share the width, the bar-width cap drops, the
       gap tightens, and labels go smaller. 30 days × ~340px container
       with 2px gap leaves ~9px per column, which works with 80%-width
       bars at <= 20px cap + slim 8px/9px labels. */
    .costs-chart-section .chart-bars {
        overflow: hidden;
        gap: 2px;
    }
    .costs-chart-section .chart-bar {
        max-width: 20px;
    }

    /* Extracted-text panels cap at 50vh on desktop so the page stays
       compact. On mobile that cap hides most of the text inside a
       nested scroll box and users can't tell content exists. Drop the
       cap so the panel grows to content and the whole page scrolls
       naturally via main. */
    .extract-panel .doc-text {
        max-height: none;
        overflow: visible;
    }

    /* ── Chat compose bar — pinned to viewport bottom on mobile ──
       Desktop lays out [textarea | capacity picker | Send] in a single
       row; at 375px the textarea gets squeezed to near-zero width
       (user reported "can't see the prompt box"). Two fixes here:
         (a) flex-wrap so textarea takes row 1 full-width, capacity
             picker + Send share row 2.
         (b) position:fixed at the bottom of the viewport (above the
             .mobile-bottom-nav) so the compose is always visible even
             though chat-sidebar content (Session Documents, Add, New
             session) flows after it in the DOM. Messages scroll
             behind the fixed bar; .chat-messages gets bottom-padding
             equal to compose+meter height so nothing is hidden. */
    .chat-compose.pinned-bar {
        flex-wrap: wrap;
        gap: 8px;
        padding: 10px 16px;
        position: fixed;
        left: 0;
        right: 0;
        bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom));
        z-index: 998;
        background: var(--bg-raised);
        border-top: 1px solid var(--border);
    }
    .token-meter {
        position: fixed;
        left: 0;
        right: 0;
        bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + 114px);
        z-index: 998;
        background: var(--bg-raised);
        padding: 6px 16px;
        border-top: 1px solid var(--border);
        margin: 0;
    }
    /* Reserve space so the bottom of messages + the sidebar below them
       don't hide behind the fixed compose+meter combo. 114px (compose)
       + 36px (meter) + 10px gap ≈ 160px. Scoped via :has() to pages
       that actually have a chat-compose (chat session detail only);
       other pages keep their natural bottom spacing. */
    main:has(.chat-compose) {
        padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + 160px);
    }
    .chat-compose .chat-input {
        flex: 1 1 100%;
        min-width: 0;
    }
    .chat-compose .capacity-picker {
        flex: 1 1 auto;
        min-width: 0;
    }
    .chat-compose .btn#send-btn {
        flex: 0 0 auto;
        min-width: 72px;
    }

    /* ── Costs daily-cost chart — fit viewport, no horizontal scroll ──
       Columns share the container width. Slim labels, same tabular-nums.
       At very narrow viewports the labels would pile up — hide every
       other one so nothing overlaps. */
    .costs-chart-section .chart-col {
        flex: 1 1 0;
        min-width: 0;
    }
    .costs-chart-section .chart-date {
        font-size: 9px;
    }
    .costs-chart-section .chart-bar-label {
        font-size: 8px;
    }
    @media (max-width: 500px) {
        .costs-chart-section .chart-col:nth-child(even) .chart-date {
            visibility: hidden;
        }
    }

    /* ── Draft / brief detail pages — keep last source doc above the
       fixed bottom nav. The kit's <main>::after spacer plus safe-area
       isn't always enough once .source-appendix is the last element
       with its own 28px margin-top; forcing extra bottom padding on
       the scroll-area makes sure the card is never visually clipped. */
    .page-scroll-area {
        padding-bottom: calc(var(--bottom-nav-h) + env(safe-area-inset-bottom) + var(--space-lg));
    }

    /* ── Rail visibility on mobile for draft/brief/chat-new ──
       Kit hides .page-rail by default on mobile (display:none in
       layout-mobile.css). The picker/brief/chat-new pages want the rail
       VISIBLE on mobile and rendered ABOVE the email picker — so users
       see search → presets → selected → capacity + generate first, then
       the scrollable picker below. #library-rail stays hidden (it has
       its own .mobile-only duplicate at the top of the page). */
    main #picker-rail,
    main #brief-rail,
    main #chat-new-rail {
        display: flex;
        order: -1;
        width: 100%;
        border-left: none;
        border-top: none;
        border-bottom: 1px solid var(--border);
        padding: 12px 16px;
        overflow: visible;
    }
    main #picker-rail .rail-section--fill,
    main #brief-rail  .rail-section--fill,
    main #chat-new-rail .rail-section--fill {
        flex: 0 0 auto;
    }
    main #picker-rail .rail-selected-list,
    main #brief-rail  .rail-selected-list,
    main #chat-new-rail .rail-selected-list {
        max-height: 140px;
    }

    /* ── Equal capacity-button widths in chat compose ──
       Segmented picker (Light / Medium / Heavy) renders with the button's
       natural label width by default, so Heavy is visibly wider than the
       other two. Force equal flex shares inside the chat compose bar. */
    .chat-compose .capacity-picker .capacity-btn {
        flex: 1;
        padding: 0 6px;
        min-width: 0;
    }

    /* ── Chat messages: prevent horizontal overflow ──
       Long URLs, wide inline code, or pre blocks can push the message
       body past the viewport. Force wrapping so the page stays the
       viewport width. scroll-to-bottom in chat.html now uses
       scrollIntoView so this doesn't break the auto-scroll path. */
    .chat-messages {
        overflow-x: hidden;
        width: 100%;
    }
    .chat-msg .msg-body {
        word-break: break-word;
        overflow-wrap: anywhere;
    }
    .chat-msg .msg-body pre,
    .chat-msg .msg-body code {
        white-space: pre-wrap;
        max-width: 100%;
        overflow-x: auto;
    }

    /* ── Mobile email-picker unselectable-row alignment ──
       Kit's doc_picker inline-styles a 16px spacer next to the checkbox.
       On mobile-Safari the default checkbox appearance introduces
       sub-pixel centering drift that makes the badge of an unselectable
       row sit a hair higher than the selectable rows. Pin both spacer
       and checkbox to identical box model + align-self: center so they
       vertically register on the same baseline. */
    .email-sub-row--unselectable .unselectable-spacer {
        width: 16px !important;
        height: 16px;
        flex: 0 0 16px !important;
        align-self: center;
    }
    .picker-doc-row .doc-check,
    label.email-sub-row input[type="checkbox"] {
        width: 16px;
        height: 16px;
        flex: 0 0 16px;
        align-self: center;
        margin: 0;
        padding: 0;
        box-sizing: border-box;
    }
}

@media (min-width: 1024px) {
    /* Desktop keeps the original 4-column layout for the costs cards.
       Written with min-width (not max-width) so the base .costs-top-row
       2-col default works at tablet widths too. */
    .costs-top-row--four {
        grid-template-columns: repeat(4, 1fr);
    }
}
