/* ============================================================
   Car Deal Tracker Dashboard — Dark Theme
   ============================================================ */

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

:root {
    --bg:           #0a0e17;
    --sidebar-bg:   #0d1520;
    --card-bg:      #1a2233;
    --card-hover:   #1f2a3d;
    --border:       #253147;
    --text-primary: #e0e0e0;
    --text-secondary: #888;
    --text-muted:   #556;
    --accent:       #4fc3f7;
    --accent-dim:   rgba(79, 195, 247, 0.15);
    --success:      #81c784;
    --warning:      #ffb74d;
    --danger:       #e57373;
    --sidebar-width: 200px;
    --sidebar-collapsed-width: 48px;
    --transition: 0.22s ease;

    /* Chip accent — the pink→purple pair used by the Deals chip filter bar
       and by the expanded-deal highlight. The -rgb twins exist because the
       accent is mostly used at low alpha and rgba() cannot take a hex var;
       keep each pair in step. */
    --chip-pink:        #d564a6;
    --chip-pink-rgb:    213, 100, 166;
    --chip-purple:      #8b5cf6;
    --chip-purple-rgb:  139, 92, 246;
}

html, body {
    height: 100%;
    background: var(--bg);
    color: var(--text-primary);
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    font-size: 14px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

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

a:hover {
    color: #81d4fa;
}

/* ── App Layout ───────────────────────────────────────────── */
.app-layout {
    display: flex;
    height: 100vh;
    overflow: hidden;
}

/* ── Sidebar ──────────────────────────────────────────────── */
.sidebar {
    width: var(--sidebar-width);
    min-width: var(--sidebar-width);
    background: var(--sidebar-bg);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    transition: width var(--transition), min-width var(--transition);
    overflow: hidden;
    position: relative;
    z-index: 10;
}

.sidebar.collapsed,
.sidebar-collapsed .sidebar {
    width: var(--sidebar-collapsed-width);
    min-width: var(--sidebar-collapsed-width);
}

/* ── Sidebar Header ───────────────────────────────────────── */
.sidebar-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 8px;
    height: 52px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}

.sidebar-logo {
    font-size: 14px;
    font-weight: 600;
    color: var(--accent);
    white-space: nowrap;
    overflow: hidden;
    letter-spacing: 0.02em;
}

.sidebar-logo-mini {
    font-size: 13px;
    font-weight: 700;
    color: var(--accent);
    white-space: nowrap;
    width: 100%;
    text-align: center;
}

.sidebar-toggle {
    background: none;
    border: 1px solid var(--border);
    color: var(--text-secondary);
    cursor: pointer;
    border-radius: 4px;
    width: 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    flex-shrink: 0;
    transition: background var(--transition), color var(--transition);
}

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

/* ── Sidebar Nav ──────────────────────────────────────────── */
.sidebar-nav {
    display: flex;
    flex-direction: column;
    padding: 8px 0;
    flex-shrink: 0;
}

.nav-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    color: var(--text-secondary);
    transition: background var(--transition), color var(--transition);
    white-space: nowrap;
    position: relative;
    border-left: 2px solid transparent;
}

.nav-item:hover {
    background: var(--card-bg);
    color: var(--text-primary);
    text-decoration: none;
}

.nav-item.active {
    color: var(--accent);
    background: var(--accent-dim);
    border-left-color: var(--accent);
}

.nav-icon {
    width: 20px;
    min-width: 20px;
    text-align: center;
    font-size: 15px;
    line-height: 1;
}

.nav-label {
    font-size: 13px;
    font-weight: 500;
    overflow: hidden;
    white-space: nowrap;
}

/* ── Badges ───────────────────────────────────────────────── */
.badge {
    margin-left: auto;
    background: var(--accent);
    color: #0a0e17;
    font-size: 10px;
    font-weight: 700;
    padding: 1px 6px;
    border-radius: 10px;
    line-height: 1.6;
    min-width: 18px;
    text-align: center;
}

.badge-dot {
    position: absolute;
    top: 8px;
    right: 8px;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--accent);
}

/* ── Sidebar Models ───────────────────────────────────────── */
.sidebar-models {
    flex: 1;
    overflow-y: auto;
    padding: 8px 0 16px;
    border-top: 1px solid var(--border);
    margin-top: 8px;
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.sidebar-models::-webkit-scrollbar {
    width: 4px;
}

.sidebar-models::-webkit-scrollbar-track {
    background: transparent;
}

.sidebar-models::-webkit-scrollbar-thumb {
    background: var(--border);
    border-radius: 2px;
}

.sidebar-section-label {
    font-size: 10px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    padding: 8px 12px 4px;
}

.model-filter {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 5px 12px;
    color: var(--text-secondary);
    font-size: 12px;
    transition: background var(--transition), color var(--transition);
}

.model-filter:hover {
    background: var(--card-bg);
    color: var(--text-primary);
    text-decoration: none;
}

.model-count {
    font-size: 11px;
    color: var(--text-muted);
    font-weight: 500;
}

/* ── Main Content ─────────────────────────────────────────── */
.main-content {
    flex: 1;
    overflow-y: auto;
    padding: 24px;
    background: var(--bg);
    scrollbar-width: thin;
    scrollbar-color: var(--border) transparent;
}

.main-content::-webkit-scrollbar {
    width: 6px;
}

.main-content::-webkit-scrollbar-track {
    background: transparent;
}

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

/* ── Page Header ──────────────────────────────────────────── */
.page-header {
    margin-bottom: 24px;
}

.page-header h1 {
    font-size: 22px;
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: 4px;
}

.page-header .subtitle {
    color: var(--text-secondary);
    font-size: 13px;
}

/* ── Cards ────────────────────────────────────────────────── */
.card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 16px;
    margin-bottom: 12px;
}

.card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 12px;
}

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

/* ── Listing Rows ─────────────────────────────────────────── */
.listing-row {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    margin-bottom: 6px;
    transition: background var(--transition), border-color var(--transition);
    cursor: pointer;
}

.listing-row:hover {
    background: var(--card-hover);
    border-color: #2e3f5a;
}

.listing-row.starred {
    border-left: 3px solid var(--warning);
}

/* Expanded row: lift it off the list so it's obvious which deal is open
   even after scrolling through the detail panel (#25). */
.listing-row.expanded {
    background: var(--card-hover);
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent), 0 0 14px rgba(79, 195, 247, 0.35);
}

/* A listing pulled in by ?open=<id> that the current filter/sort wouldn't
   otherwise show. Marked so its presence at the top of the list reads as
   deliberate rather than as the sort being broken. */
.listing-row.linked-listing {
    border-left: 3px solid var(--accent);
}
.linked-listing-note {
    font-size: 11px;
    color: var(--text-muted);
    padding: 6px 14px 0;
}

/* Expanded deal (issue #25): the open row + its detail read as ONE card in
   the pink/purple accent — gradient left rail, matching wash, faint glow.
   Declared after .starred / .linked-listing so the expanded rail wins their
   border-left at equal specificity while the row is open. */
.listing-row.expanded {
    position: relative;
    border-color: rgba(var(--chip-pink-rgb), 0.40);
    border-left: 1px solid rgba(var(--chip-pink-rgb), 0.40);
    background: linear-gradient(100deg, rgba(var(--chip-pink-rgb), 0.26), rgba(var(--chip-purple-rgb), 0.16) 60%, rgba(var(--chip-purple-rgb), 0.07));
    /* The glow is the midpoint of the two accents, not either one — kept
       literal on purpose so it stays the blend if a token is retuned. */
    box-shadow: 0 0 16px rgba(179, 96, 206, 0.30);
}
.listing-row.expanded::before {
    content: '';
    position: absolute;
    left: 0; top: 0; bottom: 0;
    width: 4px;
    /* Rounded to follow the row's 8px radius (inset by the 1px border) rather
       than clipping the row with overflow:hidden — the collection dropdown in
       the detail panel hangs past the row's bottom edge and would be cut off. */
    border-radius: 7px 0 0 7px;
    background: linear-gradient(180deg, var(--chip-pink), var(--chip-purple));
}
.listing-row.expanded .listing-row-inner {
    padding-left: 20px;
}
.listing-row.expanded:hover {
    background: linear-gradient(100deg, rgba(var(--chip-pink-rgb), 0.30), rgba(var(--chip-purple-rgb), 0.20) 60%, rgba(var(--chip-purple-rgb), 0.09));
}
/* The detail card blends into the expanded row's wash instead of floating
   as a second bordered card inside it. */
.listing-row.expanded .detail-card {
    background: transparent;
    border: none;
    margin-left: 6px;
}

.listing-row-inner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 12px 16px;
}

.star-btn {
    background: none !important;
    border: none !important;
    padding: 4px 8px !important;
    /* !important like the rest of this block: the button also carries
       .btn-sm, whose font-size: 12px is declared LATER in this file and was
       silently winning — the glyph never actually rendered at the size set
       here (the original 18px included). */
    font-size: 22px !important;
    flex-shrink: 0;
}

.listing-title {
    flex: 1;
    min-width: 0;
    font-size: 13px;
    font-weight: 500;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.listing-model {
    font-weight: 600;
}

.listing-year {
    font-size: 12px;
    color: var(--text-secondary);
    margin-left: 4px;
}

.listing-subtitle {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.listing-price-col {
    text-align: right;
    flex-shrink: 0;
}

.listing-price {
    font-size: 14px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
}

.listing-mileage {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    flex-shrink: 0;
    min-width: 80px;
    text-align: right;
}

.listing-mpg {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    flex-shrink: 0;
    min-width: 64px;
    text-align: right;
}

.listing-ppm {
    flex-shrink: 0;
    min-width: 72px;
    text-align: right;
    font-size: 13px;
    font-weight: 600;
}

.listing-ppm-unit {
    font-size: 10px;
    font-weight: 400;
    color: var(--text-muted);
}

.listing-location {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
    flex-shrink: 0;
    min-width: 100px;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.listing-score-col {
    flex-shrink: 0;
}

.listing-chevron {
    flex-shrink: 0;
    color: var(--text-muted);
    font-size: 11px;
}

.listing-meta {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
}

/* ── Score Badges ─────────────────────────────────────────── */
.score-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 12px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 12px;
    min-width: 36px;
    line-height: 1.6;
}

.score-badge.score-good {
    background: rgba(129, 199, 132, 0.15);
    color: var(--success);
    border: 1px solid rgba(129, 199, 132, 0.3);
}

.score-badge.score-neutral {
    background: rgba(255, 183, 77, 0.15);
    color: var(--warning);
    border: 1px solid rgba(255, 183, 77, 0.3);
}

.score-badge.score-bad {
    background: rgba(229, 115, 115, 0.15);
    color: var(--danger);
    border: 1px solid rgba(229, 115, 115, 0.3);
}

/* score helper function via data attr — use JS to apply class */
.score-badge[data-score] { /* populated by app.js */ }

/* ── Tables ───────────────────────────────────────────────── */
table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

th {
    text-align: left;
    padding: 8px 12px;
    color: var(--text-muted);
    font-weight: 600;
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}

td {
    padding: 10px 12px;
    border-bottom: 1px solid rgba(37, 49, 71, 0.5);
    color: var(--text-primary);
}

tr:hover td {
    background: var(--card-hover);
}

tr:last-child td {
    border-bottom: none;
}

/* ── Form Inputs ──────────────────────────────────────────── */
input,
select,
textarea {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary);
    font-size: 13px;
    font-family: inherit;
    padding: 7px 10px;
    outline: none;
    transition: border-color var(--transition);
    width: 100%;
}

input:focus,
select:focus,
textarea:focus {
    border-color: var(--accent);
}

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

select option {
    background: var(--card-bg);
    color: var(--text-primary);
}

label {
    display: block;
    font-size: 12px;
    font-weight: 500;
    color: var(--text-secondary);
    margin-bottom: 4px;
}

.form-group {
    margin-bottom: 14px;
}

/* ── Buttons ──────────────────────────────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 7px 14px;
    border-radius: 6px;
    font-size: 13px;
    font-weight: 500;
    font-family: inherit;
    cursor: pointer;
    border: none;
    transition: background var(--transition), opacity var(--transition);
}

.btn-primary {
    background: var(--accent);
    color: #0a0e17;
}

.btn-primary:hover {
    background: #81d4fa;
}

.btn-secondary {
    background: var(--card-bg);
    color: var(--text-primary);
    border: 1px solid var(--border);
}

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

.btn-danger {
    background: rgba(229, 115, 115, 0.15);
    color: var(--danger);
    border: 1px solid rgba(229, 115, 115, 0.3);
}

.btn-danger:hover {
    background: rgba(229, 115, 115, 0.25);
}

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

/* ── Stats Grid ───────────────────────────────────────────── */
.stats-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
    gap: 12px;
    margin-bottom: 24px;
}

.stat-card {
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 16px;
}

.stat-label {
    font-size: 11px;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
    margin-bottom: 6px;
}

.stat-value {
    font-size: 24px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
}

.stat-sub {
    font-size: 11px;
    color: var(--text-secondary);
    margin-top: 4px;
}

/* ── Alerts / Toasts ──────────────────────────────────────── */
.alert {
    padding: 10px 14px;
    border-radius: 6px;
    font-size: 13px;
    margin-bottom: 12px;
    display: flex;
    align-items: center;
    gap: 8px;
}

.alert-success {
    background: rgba(129, 199, 132, 0.12);
    border: 1px solid rgba(129, 199, 132, 0.3);
    color: var(--success);
}

.alert-warning {
    background: rgba(255, 183, 77, 0.12);
    border: 1px solid rgba(255, 183, 77, 0.3);
    color: var(--warning);
}

.alert-danger {
    background: rgba(229, 115, 115, 0.12);
    border: 1px solid rgba(229, 115, 115, 0.3);
    color: var(--danger);
}

/* ── Empty State ──────────────────────────────────────────── */
.empty-state {
    text-align: center;
    padding: 60px 20px;
    color: var(--text-secondary);
}

.empty-state .empty-icon {
    font-size: 40px;
    margin-bottom: 12px;
    opacity: 0.5;
}

.empty-state p {
    font-size: 13px;
    color: var(--text-muted);
    margin-top: 6px;
}

/* ── Tag Pills ────────────────────────────────────────────── */
.tag {
    display: inline-flex;
    align-items: center;
    padding: 2px 8px;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 500;
    background: var(--card-bg);
    border: 1px solid var(--border);
    color: var(--text-secondary);
}

.tag-accent {
    background: var(--accent-dim);
    border-color: rgba(79, 195, 247, 0.3);
    color: var(--accent);
}

/* ── Dividers ─────────────────────────────────────────────── */
.divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 16px 0;
}

/* ── Spinner ──────────────────────────────────────────────── */
.spinner {
    display: inline-block;
    width: 16px;
    height: 16px;
    border: 2px solid var(--border);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin 0.7s linear infinite;
}

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

/* ── HTMX loading indicator ───────────────────────────────── */
.htmx-indicator {
    display: none;
}

.htmx-request .htmx-indicator {
    display: inline-block;
}

/* Mobile hamburger - hidden on desktop */
.mobile-hamburger {
    display: none;
    align-items: center;
    justify-content: center;
    background: none;
    border: 1px solid var(--border);
    color: var(--text-secondary);
    border-radius: 6px;
    width: 36px;
    height: 36px;
    font-size: 18px;
    cursor: pointer;
    margin-bottom: 12px;
    flex-shrink: 0;
}

.mobile-hamburger:hover {
    background: var(--card-bg);
    color: var(--text-primary);
}

.sidebar-backdrop {
    display: none;
}

/* ── Responsive ───────────────────────────────────────────── */
@media (max-width: 768px) {
    .sidebar {
        position: fixed;
        left: 0; top: 0; bottom: 0;
        width: var(--sidebar-width);
        min-width: var(--sidebar-width);
        transform: translateX(-100%);
        transition: transform 0.22s ease;
        z-index: 100;
    }
    .sidebar.mobile-open {
        transform: translateX(0);
    }
    .sidebar.mobile-open .nav-label,
    .sidebar.mobile-open .sidebar-logo,
    .sidebar.mobile-open .sidebar-models {
        display: block !important;
    }
    .sidebar-backdrop.visible {
        display: block;
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.5);
        z-index: 99;
    }
    .mobile-hamburger {
        display: flex;
    }
    .main-content {
        width: 100%;
        padding: 16px;
    }
    .nav-label, .sidebar-logo, .sidebar-models, .badge {
        display: none !important;
    }
    .sidebar-logo-mini {
        display: block !important;
    }
    .listing-location,
    .listing-mpg {
        display: none;
    }
    /* Bare `.filter-bar` here is the TRENDS bar (a stacked column of labelled
       fields). The Deals bar opts out below — it is a chip row at every
       width, which is the whole point of the chip design: nothing but the
       filters you are using is on screen, so there is nothing to collapse. */
    .filter-bar {
        flex-direction: column;
        align-items: stretch;
        padding: 0;
        gap: 0;
    }
    /* Deals chip bar on mobile: still one wrapping row, search takes the
       first line to itself and the chips wrap beneath it. Specificity 0,2,0
       beats the `flex-direction: column` above at equal source order; the
       padding/gap have a complementary min-width twin further down rather
       than a bare declaration, which would sit LATER in the file and win
       here too. */
    .filter-bar.chip-bar {
        flex-direction: row;
        flex-wrap: wrap;
        padding: 8px 10px;
        gap: 6px;
    }
    .filter-bar.chip-bar .search-input {
        flex: 1 1 100%;
        min-width: 0;
        max-width: none;
    }
    /* (Presets is NOT pinned right here — its `margin-left: auto` lives in
       the min-width:769px twin, so on mobile it just flows after the chips.)

       Popovers anchor to the BAR, not to their trigger, once the chips wrap:
       a 180–200px panel hung off a 61px chip sitting anywhere in a 375px row
       runs off one edge or the other (it ran to x=-96 before this). Making
       the wrappers static hands the containing block to the bar itself
       (position: sticky), so left+right stretch the panel to the bar's width
       and `top: calc(100% + 6px)` drops it just below the whole bar. */
    .filter-bar.chip-bar .chip-pop-wrap,
    .filter-bar.chip-bar .preset-wrap {
        position: static;
    }
    .filter-bar.chip-bar .chip-popover,
    .filter-bar.chip-bar .preset-dropdown {
        left: 10px;
        right: 10px;
        min-width: 0;
    }
    .search-input {
        min-width: 0;
        max-width: none;
    }
    .stats-grid {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (max-width: 480px) {
    .main-content {
        padding: 12px;
    }

    .page-header {
        margin-bottom: 16px;
    }

    .page-header h1 {
        font-size: 18px;
    }

    .stats-grid {
        grid-template-columns: 1fr;
    }

    /* Stack listing rows as mini-cards */
    .listing-row-inner {
        flex-wrap: wrap;
        gap: 8px;
        padding: 10px 12px;
    }

    .listing-title {
        flex: 1 1 calc(100% - 80px);
        white-space: normal;
        order: 1;
    }

    .star-btn {
        order: 0;
    }

    .listing-score-col {
        order: 2;
    }

    .listing-chevron {
        display: none;
    }

    /* Bottom stats row */
    .listing-price-col,
    .listing-mileage,
    .listing-ppm {
        order: 3;
    }

    .listing-price-col {
        text-align: left;
    }

    .listing-mileage {
        min-width: auto;
        text-align: left;
    }

    .listing-ppm {
        min-width: auto;
        text-align: left;
    }

    .listing-location {
        display: none;
    }

    /* Detail panel adjustments */
    .stats-grid[style*="repeat(auto-fit"] {
        grid-template-columns: repeat(2, 1fr) !important;
    }

    .stat-value {
        font-size: 20px;
    }

    /* Trends adjustments */
    .trends-model-select {
        min-width: 0;
        width: 100%;
    }

    .range-pills {
        width: 100%;
        justify-content: flex-start;
    }

    /* ── Trends filter bar (mobile) ─────────────────────────────
       Same idea as the Deals filter panel — collapsible, 2-column grid,
       compact inputs — but scoped to .trends-filter-bar rather than the
       shared .filter-bar, whose mobile rules above belong to Deals' own
       search-row-plus-panel structure and must not be disturbed.

       Trends has no search box to keep visible, so the WHOLE bar collapses
       instead of just an inner groups panel. That is the actual fix: the
       bar is sticky at top:0, so left expanded it stacked ten fields into
       a column that covered the charts. */
    .trends-filters-toggle {
        display: inline-flex;
        align-items: center;
    }
    /* Doubled-up selector (.filter-bar.trends-filter-bar, specificity 0,2,0)
       is load-bearing, not stylistic: the base `.filter-bar { display: flex }`
       is declared LOWER in this file than this media query, so a plain
       `.trends-filter-bar { display: grid }` loses to it at equal specificity
       and the panel silently stays a flex column. */
    .filter-bar.trends-filter-bar {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 6px 8px;
        align-items: end;
        padding: 8px 10px;
    }
    .filter-bar.trends-filter-bar.filters-collapsed {
        display: none;
    }
    .trends-filter-bar .filter-group {
        min-width: 0;
    }
    /* Type spans the row so Apply and Clear land side by side on the last
       row instead of straddling two. */
    .trends-filter-bar .filter-group-wide {
        grid-column: 1 / -1;
    }
    .trends-filter-bar .filter-group label {
        width: 100%;
    }
    .trends-filter-bar .filter-group input,
    .trends-filter-bar .filter-group select {
        width: 100% !important;
        font-size: 12px;
        padding: 5px 6px;
        box-sizing: border-box;
    }
    /* Apply / Clear share the final row. */
    .trends-filter-bar > .btn {
        width: 100%;
    }

    /* Small multiples stack rather than shrinking below a legible width. */
    .small-multiples.is-multi,
    .pinned-panels {
        grid-template-columns: 1fr;
    }

    .panel {
        padding: 14px 14px 16px;
    }

    .chart-frame       { height: 200px; }
    .chart-frame-tall  { height: 300px; }

    .pin-stats {
        gap: 14px;
    }

    .scatter-legend .legend-count {
        margin-left: 0;
    }

    .filter-group input,
    .filter-group select {
        width: 100% !important;
    }

    .filter-group {
        flex: 1;
        min-width: 0;
    }

    /* Settings table horizontal scroll */
    .settings-table {
        display: block;
        overflow-x: auto;
    }
}

/* Price drop badge */
.price-drop-badge {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: 11px;
    font-weight: 600;
    color: var(--success);
    background: rgba(76, 175, 80, 0.12);
    padding: 2px 6px;
    border-radius: 4px;
    white-space: nowrap;
}

/* --- Trends Enhancements --- */

.trends-model-select {
    min-width: 160px;
}

.range-pills {
    display: flex;
    gap: 4px;
    flex-wrap: wrap;
}

/* Trends filter toggle — a mobile affordance only. On desktop the nine
   fields fit in one row and are always visible, so showing a button that
   cannot change anything would just be a dead control (which is exactly
   what it was before: it toggled a `.open` class no rule ever read).
   .filter-active-dot is absolutely positioned, so this anchors it. */
.trends-filters-toggle {
    position: relative;
}

/* The desktop hide is gated on min-width rather than declared bare and
   re-enabled inside the max-width block. A bare `display: none` here would
   sit LATER in the file than the mobile rule at equal specificity and win at
   EVERY width — the toggle would then be unreachable on mobile and the
   filters with it. (Deals used to carry an equivalent .filter-toggle-btn
   with exactly that bug; the chip bar removed the control entirely.)
   Two non-overlapping media queries cannot fight, whatever the order. */
@media (min-width: 769px) {
    .trends-filters-toggle {
        display: none;
    }
}

/* ── Trends panels ─────────────────────────────────────────
   Three panels, one question each. Chrome stays recessive: hairline
   borders one shade off the surface, generous padding, no heavy fills. */

.trends-panels {
    display: flex;
    flex-direction: column;
    gap: 20px;
}
/* Refetch holds the previous render at reduced opacity rather than
   flashing a skeleton — no layout jump. */
.trends-panels.is-loading {
    opacity: 0.55;
    transition: opacity 0.15s ease;
    pointer-events: none;
}

.panel {
    padding: 18px 20px 20px;
}
.panel-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 14px;
}
.panel-title {
    font-size: 15px;
    font-weight: 700;
    margin: 0 0 3px;
    color: var(--text-primary);
}
.panel-sub {
    font-size: 12px;
    line-height: 1.5;
    color: var(--text-secondary);
    margin: 0;
    max-width: 68ch;
}
.panel-sub strong {
    color: var(--text-primary);
    font-weight: 600;
}
.panel-actions {
    display: flex;
    gap: 6px;
    flex-shrink: 0;
}
/* An author `display` beats the UA stylesheet's `[hidden] { display: none }`,
   so the flex above would keep this visible while collapsed. Same trap the
   .reset-zoom-btn[hidden] rule below exists for. */
.panel-actions[hidden] {
    display: none;
}

/* Collapsible panel header (Market direction). The whole title block is the
   toggle, so the hit target is the header rather than a lone chevron. */
.panel-head-collapsible {
    align-items: center;
    margin-bottom: 0;
}
.panel-collapse-btn {
    display: flex;
    align-items: center;
    gap: 10px;
    background: none;
    border: none;
    padding: 0;
    cursor: pointer;
    text-align: left;
    color: inherit;
    font: inherit;
    /* Claim the row rather than shrink-to-fit: as a bare flex item inside
       .panel-head this collapsed below its content width and wrapped the
       title onto three lines. */
    flex: 1 1 auto;
    min-width: 0;
}
.panel-collapse-btn:hover .panel-title { color: var(--accent); }
.panel-collapse-btn .panel-title { margin: 0; }
.panel-chevron {
    color: var(--text-secondary);
    font-size: 13px;
    flex-shrink: 0;
}
.panel-summary {
    display: block;
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 2px;
}
/* The body carries the gap the header gave up, so a collapsed panel is a
   tight strip and an expanded one keeps its original spacing. */
#panel-a-body { margin-top: 14px; }
.panel-empty {
    padding: 28px 16px;
    text-align: center;
}
.panel-empty .muted {
    font-size: 12px;
    margin-top: 4px;
}

/* Chart frames size to include the axis band, so the card never grows a
   tiny nested scrollbar to reach clipped x-axis labels. */
.chart-frame {
    position: relative;
    height: 230px;
}
.chart-frame-tall  { height: 380px; }
.chart-frame-pin   { height: 150px; }

/* Panel A — small multiples, one per model when scope is "all models" */
.small-multiples {
    display: grid;
    grid-template-columns: 1fr;
    gap: 22px;
}
.small-multiples.is-multi {
    grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
}
.multiple {
    margin: 0;
    min-width: 0;
}
.multiple-head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
    margin-bottom: 6px;
}
.multiple-title {
    font-size: 13px;
    font-weight: 700;
    color: var(--text-primary);
}
.multiple-stat {
    font-size: 12px;
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
}
.multiple-stat .delta {
    margin-left: 6px;
    font-weight: 600;
}
/* A rising asking-price market is bad news for a buyer, and vice versa —
   these carry meaning, so they also carry a ▲/▼ glyph, never colour alone. */
.multiple-stat .delta.up   { color: var(--danger); }
.multiple-stat .delta.down { color: var(--success); }

/* Panel B — scatter legend (score ramp + the two ring encodings) */
.scatter-legend {
    display: flex;
    align-items: center;
    gap: 18px;
    flex-wrap: wrap;
    margin-bottom: 10px;
    font-size: 11px;
    color: var(--text-secondary);
}
.scatter-legend .legend-item {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}
.scatter-legend .ramp {
    display: inline-flex;
    border-radius: 3px;
    overflow: hidden;
}
.scatter-legend .ramp-step {
    width: 18px;
    height: 10px;
}
.scatter-legend .legend-ring {
    width: 11px;
    height: 11px;
    border-radius: 50%;
    border: 2px solid var(--warning);
    background: transparent;
}
.scatter-legend .legend-ring-pin {
    border-color: #0d9aec;
}
.scatter-legend .legend-count {
    margin-left: auto;
    color: var(--text-muted);
    font-variant-numeric: tabular-nums;
}

/* Panel C — one small panel per pinned listing */
.pinned-panels {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
    gap: 18px;
}
.pinned-panels:empty {
    display: none;
}
.pin-panel {
    margin: 0;
    min-width: 0;
    padding: 12px 14px 14px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
}
.pin-panel-head {
    display: flex;
    align-items: center;
    gap: 7px;
    margin-bottom: 10px;
}
.pin-swatch {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
}
.pin-title {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-primary);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    flex: 1;
    min-width: 0;
}
.pin-actions {
    display: flex;
    align-items: center;
    gap: 6px;
    flex-shrink: 0;
}
/* Star toggle. Matches the deals-row star: a glyph swap plus colour, so the
   state is never carried by colour alone. */
.pin-star {
    background: none;
    border: none;
    padding: 2px 4px;
    font-size: 16px;
    line-height: 1;
    cursor: pointer;
    color: var(--text-muted);
    transition: color var(--transition);
}
.pin-star:hover {
    color: var(--warning);
}
.pin-star.is-starred {
    color: var(--warning);
}
.pin-star:disabled {
    opacity: 0.5;
    cursor: progress;
}
.pin-stats {
    display: flex;
    gap: 20px;
    margin-bottom: 8px;
}
.pin-stat {
    display: flex;
    flex-direction: column;
    min-width: 0;
}
.pin-stat-label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.pin-stat-value {
    /* Proportional figures: tabular-nums makes a standalone number look loose. */
    font-size: 19px;
    font-weight: 700;
    color: var(--text-primary);
    line-height: 1.2;
}
.pin-stat-detail {
    font-size: 11px;
    color: var(--text-secondary);
}
.pin-nohistory {
    font-size: 12px;
    padding: 16px 0;
    text-align: center;
}

/* Table view — the WCAG-clean twin of each chart */
.table-view {
    margin-top: 16px;
    overflow-x: auto;
}
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 12px;
    font-variant-numeric: tabular-nums;
    margin-bottom: 18px;
}
.data-table caption {
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    padding-bottom: 6px;
}
.data-table th,
.data-table td {
    padding: 5px 10px;
    border-bottom: 1px solid var(--border);
    text-align: right;
    white-space: nowrap;
}
.data-table thead th {
    color: var(--text-muted);
    font-weight: 600;
}
.data-table tbody th[scope="row"] {
    text-align: left;
    font-weight: 500;
    color: var(--text-primary);
    max-width: 320px;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Drill-down list */
.drilldown-area {
    margin-top: 24px;
}
.drill-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    border-bottom: 1px solid var(--border);
}
.drill-main {
    flex: 1;
    min-width: 0;
}
.drill-title {
    font-weight: 600;
    font-size: 14px;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.drill-star { color: var(--warning); margin-left: 4px; }
.drill-meta {
    font-size: 12px;
    color: var(--text-secondary);
    margin-top: 2px;
}
.drill-price { text-align: right; white-space: nowrap; }
.drill-price-value {
    font-size: 15px;
    font-weight: 700;
    color: var(--success);
}
.drill-price-meta { font-size: 11px; color: var(--text-muted); }
.drill-summary {
    font-size: 13px;
    color: var(--text-secondary);
    padding: 8px 14px;
}
.drill-imported { margin-top: 8px; }
.drill-imported > summary {
    font-size: 12px;
    color: var(--text-muted);
    cursor: pointer;
    padding: 8px 14px;
}
.drill-error { padding: 16px; color: var(--danger); }

/* ── Filter bar (shared: Deals chip bar + Trends field bar) ────────
 *
 * Frosted glass. A solid background is declared FIRST as the fallback, then
 * the translucent surface + blur are layered on inside @supports, so a
 * browser without backdrop-filter still gets an opaque, readable sticky bar
 * rather than list rows showing through it.
 *
 * NOTE for anyone adding rules below: the max-width:768px block sits ABOVE
 * this point in the file. Any `display` (or flex-direction, padding, gap…)
 * written bare down here beats its mobile counterpart at equal specificity
 * at EVERY width. This has caused a real bug twice. Gate desktop-only values
 * in @media (min-width: 769px), or raise specificity deliberately as the
 * mobile block's own `.filter-bar.chip-bar` rules do.
 */
.filter-bar {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    align-items: end;
    padding: 12px 16px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    position: sticky;
    top: 0;
    z-index: 50;
    /* Shadow so content reads as sliding UNDER the bar */
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.35);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    .filter-bar {
        background: rgba(26, 34, 51, 0.62); /* var(--card-bg) at 62% */
        border-color: rgba(255, 255, 255, 0.09);
        -webkit-backdrop-filter: blur(14px) saturate(140%);
        backdrop-filter: blur(14px) saturate(140%);
    }
}

/* ── Deals chip bar ────────────────────────────────────────────────
   One slim row. Every ACTIVE filter is a removable chip; everything else
   lives behind "+ Filter". The old always-on grid of ten labelled fields
   (and the mobile toggle that hid it) is gone — there is nothing left to
   collapse, so there is no toggle button to go stale. */
.filter-bar.chip-bar {
    align-items: center;
    border-radius: 12px;
}
/* gap/padding are media-gated, NOT bare: the mobile block above declares its
   own at the same specificity, and a bare value here — being later in the
   file — would beat it at every width. Same trap the deleted mobile filter
   toggle fell into twice. */
@media (min-width: 769px) {
    .filter-bar.chip-bar {
        gap: 8px;
        padding: 10px 14px;
    }
}
.chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border-radius: 999px;
    font-size: 12px;
    line-height: 1.5;
    padding: 4px 11px;
    white-space: nowrap;
    cursor: pointer;
    background: rgba(var(--chip-pink-rgb), 0.14);
    border: 1px solid rgba(var(--chip-pink-rgb), 0.38);
    color: #eec3dd;
    transition: background var(--transition), border-color var(--transition);
}
.chip:hover { background: rgba(var(--chip-pink-rgb), 0.22); }
/* The two controls (sort, add) take the purple half of the accent so they
   read as chrome rather than as another active filter. */
.chip-sort,
.chip-add {
    background: rgba(var(--chip-purple-rgb), 0.14);
    border-color: rgba(var(--chip-purple-rgb), 0.40);
    color: #cdbcf6;
}
.chip-sort:hover,
.chip-add:hover { background: rgba(var(--chip-purple-rgb), 0.22); }
.chip-label { cursor: pointer; }
.chip-x {
    background: none;
    border: none;
    color: inherit;
    opacity: 0.7;
    font-weight: 700;
    font-size: 13px;
    line-height: 1;
    padding: 0 0 0 2px;
    cursor: pointer;
}
.chip-x:hover { opacity: 1; }
.chip-list {
    display: inline-flex;
    gap: 6px;
    flex-wrap: wrap;
    align-items: center;
    min-width: 0;
}
.chip-pop-wrap { position: relative; }
/* Absolute, never fixed: the bar's backdrop-filter makes it a containing
   block, so a fixed popover would anchor to the bar and not the viewport. */
.chip-popover {
    position: absolute;
    top: calc(100% + 6px);
    left: 0;
    min-width: 180px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
    z-index: 100;
    padding: 6px;
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.chip-pop-list {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.chip-pop-item {
    background: none;
    border: none;
    color: var(--text-primary);
    text-align: left;
    font-size: 13px;
    padding: 6px 10px;
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
}
.chip-pop-item:hover { background: var(--card-hover); }
.chip-pop-item.active {
    color: var(--chip-purple);
    font-weight: 600;
}
.chip-pop-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 4px 0;
}
.chip-pop-form {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px;
}
.chip-pop-dash {
    font-size: 12px;
    color: var(--text-secondary);
    white-space: nowrap;
}
.chip-pop-form input,
.chip-pop-form select {
    width: 80px;
    min-width: 0;
    padding: 4px 8px;
    font-size: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
}
.chip-pop-form .chip-pop-wide { width: 130px; }
/* Presets are pinned to the far end of the bar on desktop only — the mobile
   block overrides this back to 0 so a long chip run does not crush them. */
@media (min-width: 769px) {
    .filter-bar.chip-bar .preset-wrap { margin-left: auto; }
}

/* Used by the Trends filters toggle only — the Deals bar's toggle button and
   its dot went away with the chip bar (nothing to collapse). */
.filter-active-dot {
    position: absolute;
    top: 5px;
    right: 5px;
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    pointer-events: none;
}

/* Preset dropdown */
.preset-wrap {
    position: relative;
}
.preset-dropdown {
    position: absolute;
    top: calc(100% + 4px);
    right: 0;
    min-width: 200px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 4px 16px rgba(0,0,0,0.5);
    z-index: 100;
    padding: 6px 0;
}
.preset-dropdown .preset-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 6px 12px;
    gap: 8px;
    cursor: pointer;
    font-size: 13px;
}
.preset-dropdown .preset-item:hover {
    background: var(--card-hover);
}
.preset-dropdown .preset-item .preset-name {
    flex: 1;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.preset-dropdown .preset-del {
    background: none;
    border: none;
    color: var(--text-secondary);
    cursor: pointer;
    padding: 0 2px;
    font-size: 14px;
    line-height: 1;
}
.preset-dropdown .preset-del:hover { color: var(--danger); }
.preset-save-form {
    padding: 8px 12px;
    border-top: 1px solid var(--border);
    display: flex;
    gap: 6px;
    margin-top: 4px;
}
.preset-save-form input {
    flex: 1;
    padding: 4px 8px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    font-size: 12px;
}
.preset-empty {
    padding: 8px 12px;
    color: var(--text-muted);
    font-size: 12px;
    font-style: italic;
}
.search-input {
    min-width: 220px;
    max-width: 320px;
}
.filter-group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}
.filter-group label {
    font-size: 10px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.5px;
}
.filter-group input,
.filter-group select {
    padding: 4px 8px;
    font-size: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    width: 90px;
}
.filter-group select {
    width: 110px;
}

/* Drill-down pin button */
.drill-pin-btn {
    padding: 2px 8px;
    font-size: 11px;
    font-weight: 600;
    border: 1px solid var(--border);
    border-radius: 4px;
    background: var(--card-bg);
    color: var(--text-secondary);
    cursor: pointer;
    white-space: nowrap;
}
.drill-pin-btn:hover {
    border-color: var(--accent);
    color: var(--accent);
}
.drill-pin-btn.pinned {
    border-color: var(--accent);
    color: var(--accent);
    background: rgba(79, 195, 247, 0.1);
}
.drill-pin-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

/* Reset-zoom button. Lives in the panel header next to the table-view
   toggle rather than floating over the plot: zoom is now an explicit
   drag-to-select gesture, so its undo belongs with the other controls
   instead of covering data in the top-right corner. `hidden` does the
   showing/hiding, so it needs no display rule here. */
.reset-zoom-btn[hidden] {
    display: none;
}

/* Sparkline container in detail modal */
.sparkline-container {
    background: var(--bg);
    border-radius: 6px;
    padding: 8px;
}

/* ── Collection Dropdown ─────────────────────────────────── */
.collection-dropdown-wrap {
    position: relative;
    display: inline-flex;
}

.collection-dropdown {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 4px;
    min-width: 220px;
    background: var(--card-bg);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 6px 0;
    z-index: 50;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
    display: none;
}

.collection-dropdown.open {
    display: block;
}

.collection-dropdown-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    font-size: 13px;
    color: var(--text-primary);
    cursor: pointer;
    transition: background var(--transition);
}

.collection-dropdown-item:hover {
    background: var(--card-hover);
}

.collection-dropdown-item input[type="checkbox"] {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    accent-color: var(--accent);
}

.collection-dropdown-divider {
    border: none;
    border-top: 1px solid var(--border);
    margin: 4px 0;
}

.collection-dropdown-create {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
}

.collection-dropdown-create input {
    flex: 1;
    padding: 4px 8px;
    font-size: 12px;
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-primary);
    width: auto;
}

.collection-dropdown-create button {
    padding: 4px 10px;
    font-size: 12px;
    font-weight: 600;
    background: var(--accent);
    color: #0a0e17;
    border: none;
    border-radius: 4px;
    cursor: pointer;
    white-space: nowrap;
}

.collection-dropdown-create button:hover {
    background: #81d4fa;
}

/* ── Settings Tabs ───────────────────────────────────────── */
.settings-tabs {
    display: flex;
    border-bottom: 1px solid var(--border);
    margin-bottom: 20px;
    gap: 0;
}
.settings-tab {
    padding: 12px 20px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-secondary);
    background: none;
    border: none;
    border-bottom: 2px solid transparent;
    cursor: pointer;
    transition: color var(--transition), border-color var(--transition);
}
.settings-tab:hover {
    color: var(--text-primary);
}
.settings-tab.active {
    color: var(--accent);
    border-bottom-color: var(--accent);
}

/* ── Pager (collections list, starred) ──────────────────────── */
.pager {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    padding: 12px 0;
}
.pager-current {
    font-size: 12px;
    color: var(--text-muted);
}
.pager-disabled {
    opacity: 0.4;
    pointer-events: none;
}

/* Toast notifications — global htmx error/success surfacing (app.js) */
#toast-stack {
    position: fixed;
    bottom: 16px;
    right: 16px;
    z-index: 2000;
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-width: 360px;
}
.toast {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 10px 12px;
    border-radius: 6px;
    font-size: 13px;
    color: #1a1a1a;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
    animation: toast-in 0.15s ease-out;
}
.toast-error { background: var(--danger); }
.toast-success { background: var(--success); }
.toast-warning { background: var(--warning); }
.toast-text { flex: 1; }
.toast-close {
    background: none;
    border: none;
    color: inherit;
    cursor: pointer;
    font-size: 12px;
    opacity: 0.7;
    padding: 0 0 0 4px;
}
.toast-close:hover { opacity: 1; }
@keyframes toast-in {
    from { opacity: 0; transform: translateY(6px); }
    to { opacity: 1; transform: none; }
}
@media (max-width: 768px) {
    #toast-stack {
        left: 16px;
        right: 16px;
        max-width: none;
    }
}

/* ── Sidebar model tree (Stage 2 redesign) ─────────────────────────────── */
/* Rendered as a partial that re-renders via OOB swaps, so styling lives in
   classes rather than the inline-style house pattern. */
[x-cloak] { display: none !important; }

.tree-add-btn {
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 13px;
    line-height: 1;
    padding: 1px 7px 3px;
}
.tree-add-btn:hover { color: var(--accent); border-color: var(--accent); }

.sidebar-sublabel { margin-top: 10px; opacity: 0.7; }

.model-row {
    display: flex;
    align-items: center;
    position: relative;
    border-radius: 4px;
}
.model-row:hover { background: var(--bg-hover, rgba(128,128,128,0.08)); }

.model-row-link {
    flex: 1;
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
    padding: 3px 2px 3px 4px;
    text-decoration: none;
    color: inherit;
}
.model-row-name {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.model-row-paused .model-row-name { color: var(--text-muted); }
.model-paused-tag {
    font-size: 9px;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 3px;
    padding: 0 4px;
}
.model-row-orphan .model-row-name { color: var(--text-muted); font-style: italic; }

.model-menu-btn {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 13px;
    padding: 2px 6px;
    min-width: 32px;
    min-height: 28px;
    opacity: 0.45;
}
.model-row:hover .model-menu-btn, .model-menu-btn[aria-expanded="true"] { opacity: 1; }

.model-menu {
    position: absolute;
    right: 4px;
    top: 100%;
    z-index: 300;
    min-width: 190px;
    background: var(--bg-card, var(--bg));
    border: 1px solid var(--border);
    border-radius: 6px;
    box-shadow: 0 6px 18px rgba(0,0,0,0.25);
    padding: 4px;
    display: flex;
    flex-direction: column;
}
.model-menu button {
    background: none;
    border: none;
    color: var(--text-primary, inherit);
    cursor: pointer;
    text-align: left;
    font-size: 12px;
    padding: 7px 10px;
    border-radius: 4px;
}
.model-menu button:hover { background: var(--bg-hover, rgba(128,128,128,0.12)); }
.model-menu .model-menu-danger { color: var(--danger); }

/* Scan progress dot — inert placeholder until the status poller fills it. */
.scan-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    flex-shrink: 0;
    background: transparent;
}
.scan-dot.scanning {
    background: var(--accent);
    animation: scan-pulse 1.2s ease-in-out infinite;
}
.scan-dot.queued { border: 1.5px solid var(--accent); }
@keyframes scan-pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.3; }
}

/* ── Add Search Target modal ───────────────────────────────────────────── */
.modal-overlay {
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(0,0,0,0.55);
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: 8vh 16px 16px;
    overflow-y: auto;
}
.modal-box {
    background: var(--bg-card, var(--bg));
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 20px;
    width: 100%;
    max-width: 560px;
    box-shadow: 0 12px 40px rgba(0,0,0,0.4);
}
.modal-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 14px;
}
.modal-close {
    background: none;
    border: none;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 14px;
    padding: 4px 8px;
}
.modal-close:hover { color: var(--danger); }

/* Also used by the add-target modal, which renders on every page — the
   original definition is page-local to settings.ejs. */
.settings-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 12px;
}

/* Form styling inside the modal (the equivalent rules for the settings page
   are page-local in settings.ejs). */
.modal-box .form-group { display: flex; flex-direction: column; gap: 4px; margin-bottom: 0; }
.modal-box .form-group label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted); }
.modal-box .form-group input {
    background: var(--bg);
    border: 1px solid var(--border);
    border-radius: 6px;
    color: var(--text-primary, inherit);
    padding: 7px 9px;
    font-size: 13px;
}
.modal-box .form-group input:focus { outline: none; border-color: var(--accent); }
.modal-box .form-hint { font-size: 10px; color: var(--text-muted); }

/* ── Scan status footer widget ─────────────────────────────────────────── */
.scan-progress { display: flex; flex-direction: column; gap: 5px; }
.scan-progress-bar {
    height: 5px;
    border-radius: 3px;
    background: var(--border);
    overflow: hidden;
}
.scan-progress-fill {
    height: 100%;
    border-radius: 3px;
    background: var(--accent);
    transition: width 0.6s ease;
}
.scan-progress-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 11px;
    color: var(--text-muted);
}
.scan-progress-model {
    flex: 1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-secondary);
}
.scan-idle-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    font-size: 11px;
    color: var(--text-muted);
}
.scan-now-subtle {
    background: none;
    border: none;
    color: var(--text-muted);
    font-size: 11px;
    cursor: pointer;
    padding: 2px 0;
    white-space: nowrap;
}
.scan-now-subtle:hover { color: var(--accent); }

/* ── Activity tab v2 ───────────────────────────────────────────────────── */
.log-inflight-card { border-left: 3px solid var(--accent); padding: 12px 16px; }
.log-chip-row {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--border);
}
.log-chip {
    font-size: 11px;
    padding: 2px 8px;
    border-radius: 10px;
    background: var(--bg);
    border: 1px solid var(--border);
    color: var(--text-secondary);
}
.log-status-tag {
    font-size: 10px;
    padding: 1px 6px;
    border-radius: 4px;
    margin-left: 6px;
    background: rgba(128,128,128,0.12);
}
.log-problem { margin-top: 6px; font-size: 11px; border-radius: 4px; }
.log-problem summary { cursor: pointer; padding: 4px 8px; }
.log-problem-warn { background: rgba(255,183,77,0.08); color: var(--warning); }
.log-problem-error { background: rgba(229,115,115,0.08); color: var(--danger); }
.log-problem-acked { opacity: 0.45; }
.log-problem-body { padding: 4px 8px 8px; color: var(--text-secondary); }
/* A collapsed run of identical warnings. Same chrome as one .log-problem —
   including the acked fade, which the ack button applies to .log-group too —
   with its members indented so the nesting reads. */
.log-group { margin-top: 6px; font-size: 11px; border-radius: 4px; }
.log-group summary { cursor: pointer; padding: 4px 8px; }
.log-group-body { padding-left: 16px; padding-bottom: 4px; }
/* opacity compounds, so an acked group whose members are each also acked
   would expand to 0.45 x 0.45. The group already carries the fade. */
.log-group.log-problem-acked .log-problem-acked { opacity: 1; }
.log-ack-btn, .log-retry-btn {
    background: none;
    border: 1px solid var(--border);
    border-radius: 4px;
    color: var(--text-muted);
    cursor: pointer;
    font-size: 10px;
    padding: 1px 7px;
    margin-left: 6px;
}
.log-ack-btn:hover, .log-retry-btn:hover { color: var(--accent); border-color: var(--accent); }

/* Login — standalone page, no app chrome. */
.login-shell { max-width: 360px; margin: 12vh auto; padding: 0 20px; }
.login-form { display: flex; flex-direction: column; gap: 10px; margin-top: 20px; }
.login-form input { padding: 10px; font-size: 15px; }
.login-form button { padding: 10px; font-size: 15px; cursor: pointer; }
.login-sent { margin-top: 20px; }
.login-error { margin-top: 12px; color: var(--danger); }
/* Code entry: the second door in, for when the emailed link was opened by a
   browser the user did not want to stay in (issue #26). */
.login-hint { margin-top: 12px; color: var(--text-secondary); font-size: 13px; }
.login-form input#code {
    font-size: 20px;
    letter-spacing: 0.25em;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
.login-resend { margin-top: 20px; border-top: 1px solid var(--border); padding-top: 16px; }
.login-resend button {
    padding: 8px 12px;
    font-size: 13px;
    cursor: pointer;
    background: transparent;
    color: var(--text-secondary);
    border: 1px solid var(--border);
    border-radius: 4px;
}
.login-resend button:hover:not(:disabled) { color: var(--accent); border-color: var(--accent); }
.login-resend button:disabled { cursor: not-allowed; opacity: 0.55; }
