/* Dark is the default (this is a TV dashboard, spec calls for dark/high-
   contrast by default) — light is an explicit opt-in via the toggle in the
   header, persisted in localStorage. See js/app.js's theme init. */
/* Enterprise palette: muted slate/navy ground with restrained, desaturated
   signal colors — deliberately pulled back from an earlier neon
   trading-terminal look (near-black bg, saturated neon gain/loss) toward
   something that reads as a professional ops console rather than a stock
   ticker. --accent-user / --accent-store are a SEPARATE pair from --accent
   (the header's amber flourish) — they exist purely to color-code the Users
   vs. Stores boards (left rail + heading) so which one you're looking at is
   unambiguous regardless of which is currently the 80% main stage vs. the
   20% sidebar; they're never used for gain/loss/severity, which stays on
   --gain/--loss/--neutral throughout. */
:root,
:root[data-theme="dark"] {
    --bg: #0a0e17;
    --panel: #121828;
    --panel-border: #232b3f;
    --text: #e7eaf2;
    --text-dim: #8590a8;
    --gain: #22c55e;
    --loss: #ef4444;
    --neutral: #3b82f6;
    --accent: #e0a030;
    --accent-user: #818cf8;
    --accent-store: #2dd4bf;
}

:root[data-theme="light"] {
    --bg: #f3f5f9;
    --panel: #ffffff;
    --panel-border: #dde3ec;
    --text: #16202f;
    --text-dim: #5b6579;
    /* Darkened vs. the dark theme's signal colors — the same hex on a white
       background loses contrast and looks washed out. */
    --gain: #16a34a;
    --loss: #dc2626;
    --neutral: #2563eb;
    --accent: #a3660a;
    --accent-user: #4f46e5;
    --accent-store: #0d9488;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
    color: var(--text);
    font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
    height: 100%;
    overflow: hidden;
}

.tabular {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum" 1;
    font-family: 'SF Mono', 'Consolas', 'Menlo', monospace;
}

#app {
    display: flex;
    flex-direction: column;
    height: 100vh;
    width: 100vw;
}

/* Wraps the stat strip + stage grid as one unit so js/app.js's applyDomain()
   can show/hide the whole "purchase" scope's content in one line — flex:1 +
   flex-direction:column preserves the same layout the strip/grid had as
   direct #app children before this wrapper existed (fixed-height strip,
   grid filling the rest). Needs its own [hidden] override for the same
   reason as .stage-toggle[hidden] above: this class sets "display: flex",
   which otherwise wins the cascade over the browser's default
   [hidden]{display:none}. */
#purchase-domain {
    display: flex;
    flex-direction: column;
    flex: 1;
    overflow: hidden;
}
#purchase-domain[hidden] {
    display: none;
}

/* "audit" scope's whole view — a placeholder today (store_item_audit_totals
   isn't populated by any trigger yet), shown instead of #purchase-domain
   for audit/admin accounts on that domain. Same [hidden] override reasoning
   as above. */
.audit-domain {
    display: flex;
    flex-direction: column;
    flex: 1;
    padding: 20px 32px;
    gap: 16px;
    overflow-y: auto;
}
.audit-domain[hidden] {
    display: none;
}
.audit-domain h2 {
    margin: 0;
    font-size: 15px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-dim);
}

header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 14px 32px;
    border-bottom: 1px solid var(--panel-border);
    /* A thin accent strip along the very top — the one "ticker" flourish on
       an otherwise plain header, evoking a trading-terminal chrome without
       overdoing it. */
    box-shadow: inset 0 2px 0 0 var(--accent);
}

header h1 {
    font-size: 20px;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin: 0;
    color: var(--text-dim);
}

.header-controls {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* Active-filter indicator — selection itself happens by clicking a tile on
   the Users board (or the same tile again to clear); this is the
   always-visible "who am I filtered to right now, click to go back to
   everyone" chip, since the Users board (and its tiles) isn't on screen
   while viewing Stores. Hidden entirely when no filter is active — the
   [hidden] attribute alone would lose to this button's own "display: flex"
   below (same specificity trap as .panel-overlay[hidden] elsewhere in this
   file), so that needs an explicit override too. */
.user-filter-chip {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 13px;
    padding: 4px 8px 4px 14px;
    border-radius: 999px;
    border: 1px solid var(--accent);
    background: transparent;
    color: var(--accent);
    cursor: pointer;
    max-width: 220px;
}
.user-filter-chip:hover {
    background: var(--accent);
    color: var(--bg);
}
.user-filter-chip[hidden] {
    display: none;
}
#user-filter-chip-label {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Inline search bar, not a modal — deliberately: this stays part of the
   header's normal flow, and results drop down directly beneath it rather
   than taking over the screen. */
.search-bill-form {
    position: relative;
    display: flex;
    align-items: center;
    gap: 6px;
}
/* Now conditionally hidden in the audit domain (js/app.js's applyDomain) —
   same [hidden]-vs-class-display cascade trap as .stage-toggle[hidden]
   above. */
.search-bill-form[hidden] {
    display: none;
}

.search-bill-form input[type="text"] {
    font-size: 13px;
    padding: 5px 12px;
    border-radius: 999px;
    border: 1px solid var(--panel-border);
    background: var(--panel);
    color: var(--text);
    width: 120px;
}
.search-bill-form input[type="text"]:hover,
.search-bill-form input[type="text"]:focus {
    border-color: var(--neutral);
}
.search-bill-form button[type="submit"] {
    font-size: 13px;
    padding: 5px 14px;
    border-radius: 999px;
    border: 1px solid var(--neutral);
    background: transparent;
    color: var(--neutral);
    cursor: pointer;
}
.search-bill-form button[type="submit"]:hover {
    background: var(--neutral);
    color: #fff;
}

/* Results drop straight down from the form, anchored top-right so it
   doesn't run off the edge of the screen — this is the whole reason it's a
   positioned panel off the form rather than a full modal overlay. */
.search-bill-results {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    width: 420px;
    max-height: 60vh;
    overflow-y: auto;
    background: var(--panel);
    border: 1px solid var(--panel-border);
    border-radius: 10px;
    padding: 10px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    z-index: 20;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
}
.search-bill-results[hidden] {
    display: none;
}

.search-bill-results .bill-group {
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 8px 10px;
}
.search-bill-results .bill-group-header {
    display: flex;
    justify-content: space-between;
    font-weight: 600;
    font-size: 13px;
    margin-bottom: 4px;
}

.conn-status-group {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 3px;
}
/* Same [hidden]-vs-class-display cascade trap as .stage-toggle[hidden]
   above — now conditionally hidden in the audit domain. */
.conn-status-group[hidden] {
    display: none;
}

#conn-status {
    font-size: 14px;
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--panel-border);
}
#conn-status.connected { color: var(--gain); border-color: var(--gain); }
#conn-status.disconnected { color: var(--loss); border-color: var(--loss); }

/* "Updated Xs ago" — the connected badge only proves the socket is open,
   not that any data has actually landed recently; this is the thing that
   answers "is this actually live" at a glance. Ticks forward every second
   in js/app.js regardless of whether new data has arrived. */
.last-refreshed {
    font-size: 11px;
    color: var(--text-dim);
    padding-right: 4px;
}

#theme-toggle {
    font-size: 13px;
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--panel-border);
    background: var(--panel);
    color: var(--text-dim);
    cursor: pointer;
}
#theme-toggle:hover {
    border-color: var(--neutral);
    color: var(--text);
}

#logout-button {
    font-size: 13px;
    padding: 4px 12px;
    border-radius: 999px;
    border: 1px solid var(--panel-border);
    background: var(--panel);
    color: var(--text-dim);
    cursor: pointer;
}
#logout-button:hover {
    border-color: var(--loss);
    color: var(--loss);
}

.login-form {
    display: flex;
    flex-direction: column;
    gap: 12px;
}
.login-form label {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 12px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}
.login-form input {
    font-size: 14px;
    padding: 8px 12px;
    border-radius: 8px;
    border: 1px solid var(--panel-border);
    background: var(--bg);
    color: var(--text);
}
.login-form input:focus {
    border-color: var(--neutral);
    outline: none;
}
.login-form button[type="submit"] {
    margin-top: 4px;
    font-size: 14px;
    font-weight: 600;
    padding: 10px 16px;
    border-radius: 8px;
    border: none;
    background: var(--neutral);
    color: #fff;
    cursor: pointer;
}
.login-form button[type="submit"]:hover {
    filter: brightness(1.1);
}
.login-error {
    font-size: 13px;
    color: var(--loss);
    min-height: 16px;
}

/* Which of the three views (Stores / Live Feed / Users) fills the 80%
   main-stage region — a per-viewer preference, same persistence pattern as
   the theme toggle (see js/app.js). Styled as one pill split into segments
   rather than separate buttons, so the active one reads as a single toggle
   state rather than independent controls. */
.stage-toggle {
    display: flex;
    border: 1px solid var(--panel-border);
    border-radius: 999px;
    overflow: hidden;
}
/* Both #domain-toggle and #stage-toggle-group reuse this class and can now
   carry the `hidden` attribute (js/app.js's applyDomain()) — without this,
   the class's own "display: flex" above wins the cascade over the browser's
   default [hidden]{display:none} (author CSS beats the UA stylesheet
   regardless of selector specificity), so the element would stay visible
   despite being hidden. Same trap already noted on .panel-overlay[hidden]
   below. */
.stage-toggle[hidden] {
    display: none;
}
.stage-toggle button {
    font-size: 13px;
    padding: 4px 14px;
    border: none;
    background: var(--panel);
    color: var(--text-dim);
    cursor: pointer;
}
.stage-toggle button:hover {
    color: var(--text);
}
.stage-toggle button.active {
    background: var(--neutral);
    color: #fff;
}

/* Trading-terminal layout: whichever view is picked as the "main stage"
   (header toggle — currently Users/Stores; Live Feed is parked, see
   index.html's #panel-feed comment) fills 80% of the width, full height,
   and the rest share the remaining 20% column stacked on top of each other.
   Same shape as a BSE/NSE terminal's watchlist + news-tape split.
   js/app.js's applyStage() sets each panel's grid-column/grid-row (and this
   grid's own row count) directly at runtime — simpler than fighting CSS
   grid-template-areas for a mapping that changes with how many views are
   active — so grid-template-rows here is just a starting value, overwritten
   as soon as applyStage() runs. #stage-grid is `main` (renamed from a bare
   `main` selector so it reads clearly here). */
#stage-grid {
    flex: 1;
    display: grid;
    grid-template-columns: 20% 80%;
    grid-template-rows: 1fr;
    gap: 1px;
    background: var(--panel-border);
    overflow: hidden;
}

.stage-panel {
    background: var(--panel);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    padding: 16px 18px;
    gap: 12px;
}
/* The main-stage panel gets the more prominent treatment (app background,
   roomier padding) — same visual weight the old fixed center-panel always
   had, now following whichever content is actually dominant instead of
   being tied to Stores specifically. */
.stage-panel.panel-main {
    background: var(--bg);
    padding: 20px 28px;
    gap: 16px;
}

.stage-panel h2 {
    margin: 0;
    font-size: 15px;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-dim);
}

/* Bifurcation: Users and Stores each get their own accent color (a left
   rail + a matching heading tint) so which board is which reads instantly
   regardless of whether it's currently the 80% main stage or squeezed into
   the 20% sidebar. Deliberately separate from --gain/--loss/--neutral —
   this is purely a "which section is this" cue, not a value judgement, so
   it never touches the heat-cell severity styling underneath. */
.board-users {
    box-shadow: inset 3px 0 0 0 var(--accent-user);
}
.board-users h2 {
    color: var(--accent-user);
}
.board-stores {
    box-shadow: inset 3px 0 0 0 var(--accent-store);
}
.board-stores h2 {
    color: var(--accent-store);
}

/* Fixed KPI strip, full width, between the header and the stage grid — see
   index.html's comment on why this moved out of #panel-users. flex-shrink: 0
   keeps it a constant height regardless of what #stage-grid below does with
   the rest of the viewport; the cards themselves are deliberately compact
   (smaller padding/font than the old in-panel version) so this reads as a
   slim KPI ribbon, not a second hero section competing with the boards
   underneath. */
.stat-strip {
    display: flex;
    flex-shrink: 0;
    gap: 12px;
    padding: 12px 32px;
    background: var(--panel);
    border-bottom: 1px solid var(--panel-border);
}

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

.stat-card .label {
    font-size: 11px;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.06em;
}

.stat-card .value {
    font-size: 24px;
    font-weight: 600;
    margin-top: 4px;
    white-space: nowrap;
}

/* The three supporting counts (bills/stores/users) — context for the
   headline net-impact figure, not competing with it, so they get less
   width and a smaller value size rather than four equally-weighted cards. */
.stat-card-secondary {
    flex: 0.6;
}
.stat-card-secondary .value {
    font-size: 18px;
    color: var(--text);
}

.value.gain { color: var(--gain); }
.value.loss { color: var(--loss); }

/* Quote board (Stores and Users views both use this) — fills whatever
   vertical space is left in its panel and scrolls internally. Wider tiles
   than before, sized like a market-watch board rather than a compact list. */
.heat-grid {
    flex: 1;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 10px;
    align-content: start;
    overflow-y: auto;
}

.heat-cell {
    background: var(--panel);
    border: 1px solid var(--panel-border);
    border-left: 3px solid var(--loss);
    border-radius: 8px;
    padding: 12px 14px;
    cursor: pointer;
    transition: border-color 0.15s ease, transform 0.1s ease;
}
.heat-cell:hover {
    border-color: var(--neutral);
    border-left-color: var(--neutral);
    transform: translateY(-1px);
}
/* Users view only — marks whichever person the header's user-filter
   dropdown is currently scoped to, since clicking a tile there also sets
   that global filter (see renderUserHeatGrid in js/app.js). Clicking an
   already-selected tile again clears it — the same one-click-back idea as
   the header's clear button, just from inside the board itself. */
.heat-cell.selected {
    border-color: var(--accent);
    border-left-color: var(--accent);
}

.heat-cell-top {
    display: flex;
    align-items: baseline;
    gap: 6px;
    margin: 2px 0 8px;
}

/* Rank badge — "who's #1 worst" should be readable without doing the
   sorted-list math yourself, especially useful once Users/Stores boards
   shrink to the 20% sidebar where the list itself is harder to scan. */
.heat-cell .rank {
    font-size: 11px;
    font-weight: 700;
    color: var(--text-dim);
    flex-shrink: 0;
}

.heat-cell .store {
    font-size: 12px;
    letter-spacing: 0.02em;
    color: var(--text-dim);
    text-transform: uppercase;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.heat-cell .impact {
    font-size: 19px;
    font-weight: 600;
    white-space: nowrap;
}

/* Relative-severity bar — how this entry's loss compares to the worst one
   currently shown, at a glance, without reading every number on the board. */
.heat-cell .severity-bar {
    margin-top: 8px;
    height: 3px;
    border-radius: 2px;
    background: var(--panel-border);
    overflow: hidden;
}
.heat-cell .severity-fill {
    height: 100%;
    background: var(--loss);
}

/* Live tape — dense, monospace rows so numbers line up like a ticker, with
   a brief color flash on arrival rather than just a fade — the closest a
   CSS-only feed gets to a real exchange tape's blink-on-print. */
.feed {
    flex: 1;
    overflow-y: auto;
    display: flex;
    flex-direction: column-reverse;
    gap: 6px;
}

.feed-row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 8px;
    background: var(--panel);
    border: 1px solid var(--panel-border);
    border-radius: 6px;
    padding: 8px 12px;
    font-size: 13px;
    animation: tape-in 1.1s ease-out;
}

.feed-row .meta {
    color: var(--text-dim);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.feed-row .tabular {
    flex-shrink: 0;
}

@keyframes tape-in {
    0% { opacity: 0; transform: translateY(-6px); background: color-mix(in srgb, var(--loss) 25%, var(--panel)); }
    40% { opacity: 1; transform: translateY(0); }
    100% { background: var(--panel); }
}

.empty-note {
    color: var(--text-dim);
    font-size: 13px;
    padding: 8px 0;
}

.panel-overlay {
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, 0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
}
.panel-overlay[hidden] {
    display: none; /* the [hidden] attribute alone loses to the class's "display: flex" above */
}

.panel-card {
    background: var(--bg);
    border: 1px solid var(--panel-border);
    border-radius: 12px;
    width: min(520px, 90vw);
    max-height: 80vh;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

.panel-card-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 16px 20px;
    border-bottom: 1px solid var(--panel-border);
}

.panel-card-header h3 {
    margin: 0;
    font-size: 16px;
}

.panel-card-header button {
    background: none;
    border: none;
    color: var(--text-dim);
    font-size: 22px;
    line-height: 1;
    cursor: pointer;
    padding: 0 4px;
}
.panel-card-header button:hover {
    color: var(--text);
}

.panel-card-body {
    padding: 12px 20px 20px;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

.supplier-group {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.panel-row {
    display: flex;
    justify-content: space-between;
    background: var(--panel);
    border: 1px solid var(--panel-border);
    border-radius: 8px;
    padding: 8px 14px;
    font-size: 14px;
}

.panel-row-supplier {
    font-weight: 600;
    border-color: var(--neutral);
}

.panel-row-item {
    margin-left: 16px;
    background: transparent;
    font-size: 13px;
    color: var(--text-dim);
}

/* Cost vs. best-cost detail — shown on every line item, no click needed. A
   snapshot from the most recent event, not a full price history — same
   caveat as the bill label. */
.panel-row-cost {
    margin-top: 3px;
    font-size: 12px;
    color: var(--accent);
}
.panel-row-item .tabular {
    color: inherit;
}
.panel-row-item .gain { color: var(--gain); }
.panel-row-item .loss { color: var(--loss); }

.panel-row .qty {
    color: var(--text-dim);
    font-size: 12px;
}
