/* styles/home.css -- Dashboard page (home.html). Sidebar + top nav + top-right controls + KPI
   row + chart grid + route table, a sibling shell to the Map page (index.html) rather than the
   long-scroll editorial layout this file used to hold. Extends styles/main.css's shared tokens
   and reuses its .control-panel/.panel-section-card/.filter-group/.floating-island/.nav-item/
   .kpi-card/.dashboard-modal-card/.performance-table/.segmented-control/.toggle-switch component
   classes wherever the same visual language applies -- this file only adds the dashboard-specific
   shell/grid/donut/ranking layout on top. */

html, body {
    height: 100%;
    overflow: hidden;
}

body.home-page {
    background: var(--bg-primary);
}

.home-page a {
    color: inherit;
    text-decoration: none;
}

.home-page h1, .home-page h2, .home-page h3, .kpi-value {
    font-family: var(--font-display);
}

/* ==================== CATEGORICAL PALETTE ====================
   A fixed-order, CVD-safe 8-hue set for identity encoding (category/human-factor/avoidability/
   day-type donuts) -- separate from main.css's sequential blue->purple ramp, which stays reserved
   for magnitude encoding (the time-of-day heatmap) per dataviz best practice: sequential and
   categorical are different jobs and shouldn't share one ramp. Colors are assigned in this fixed
   order to whatever labels are present -- never re-sorted by value -- so a given category always
   reads as the same color across renders/filters. */
:root {
    --cat-1: #2a78d6; /* blue */
    --cat-2: #eb6834; /* orange */
    --cat-3: #1baf7a; /* aqua */
    --cat-4: #eda100; /* yellow */
    --cat-5: #e87ba4; /* magenta */
    --cat-6: #008300; /* green */
    --cat-7: #4a3aa7; /* violet */
    --cat-8: #e34948; /* red */
}

[data-theme="dark"], :root:not([data-theme="light"]) {
    --cat-1: #3987e5;
    --cat-2: #d95926;
    --cat-3: #199e70;
    --cat-4: #c98500;
    --cat-5: #d55181;
    --cat-6: #008300;
    --cat-7: #9085e9;
    --cat-8: #e66767;
}

/* ==================== SIDEBAR ====================
   A short floating card, same shape/position as the Map page's .control-panel (top:space-lg,
   left:space-lg, width:300px, height auto to its content) -- not a full-height docked panel. Only
   thing added on top of the base .control-panel rules is a scroll safety net in case the filter
   list ever runs taller than the viewport. */
.dash-page-sidebar .panel-content {
    max-height: calc(100vh - 160px);
    overflow-y: auto;
}

/* ==================== MAIN CONTENT AREA ==================== */
.dashboard-main {
    position: absolute;
    inset: 0 0 0 300px;
    top: 0;
    overflow-y: auto;
    padding: calc(var(--space-lg) * 2 + 40px) var(--space-xl) var(--space-2xl);
    transition: inset var(--transition-normal);
}

/* Sidebar collapsed to its 48px pill -- reclaim the freed width instead of leaving a dead
   300px-wide gutter down the left side. Toggled alongside .control-panel.collapsed in
   js/homeController.js's panel-toggle handler. */
.dashboard-main.sidebar-collapsed {
    inset: 0 0 0 96px;
}

.dash-topbar {
    position: absolute;
    top: var(--space-lg);
    right: var(--space-xl);
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    z-index: var(--z-fixed);
}

.dash-share-btn {
    display: flex;
    align-items: center;
    gap: 8px;
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--space-sm) var(--space-md);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.85rem;
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    box-shadow: var(--shadow-md);
    transition: background var(--transition-fast), border-color var(--transition-fast);
}

.dash-share-btn:hover {
    background: var(--bg-tertiary);
    border-color: var(--accent-primary);
}

.dash-toast {
    position: fixed;
    top: 70px;
    right: var(--space-xl);
    background: var(--bg-secondary);
    border: 1px solid var(--accent-success);
    color: var(--text-primary);
    padding: var(--space-sm) var(--space-md);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-xl);
    font-size: 0.85rem;
    z-index: var(--z-tooltip);
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity var(--transition-fast), transform var(--transition-fast);
}

.dash-toast.visible {
    opacity: 1;
    transform: translateY(0);
}

/* ==================== KPI ROW ==================== */
.dash-kpi-row {
    display: grid;
    grid-template-columns: repeat(5, 1fr);
    gap: var(--space-md);
    margin-bottom: var(--space-lg);
}

.dash-kpi-card {
    width: 100%;
    min-width: 0;
    text-align: left;
    padding: var(--space-md) var(--space-lg);
    position: relative;
    overflow: hidden;
}

.dash-kpi-card .kpi-value {
    font-size: 1.55rem;
    margin-top: 4px;
}

.dash-kpi-card .kpi-trend {
    display: inline-block;
    margin-top: 4px;
    font-weight: var(--font-weight-semibold);
    font-variant-numeric: tabular-nums;
}

.dash-kpi-card .kpi-trend.up { color: var(--accent-error); }
.dash-kpi-card .kpi-trend.down { color: var(--accent-success); }
.dash-kpi-card .kpi-trend.flat { color: var(--text-muted); }


/* ==================== ROW 2 ====================
   grid-template-rows is a fixed px value, not auto/min-height -- Chart.js's canvases are
   responsive:true/maintainAspectRatio:false, which measure their container on every render. A
   container sized by content (min-height inside an auto grid row) creates a measure/layout
   feedback loop: each re-render (theme toggle, filter change) reads a container that grew very
   slightly from the last one and grows again, so the cards visibly expand a little more on every
   interaction. Pinning the row to one explicit height breaks the loop -- the container size is
   fixed input, never an output of the chart's own render. */
/* Row A: Incidents Over Time + Incidents by Category. Row B: Incidents by Time of Day + Top
   Routes. Both use the same fixed-row-height approach for the same Chart.js-in-a-grid reason, but
   sized separately -- Row A is taller so Incidents by Category's rotated in-bar/above-bar labels
   get real room instead of squeezing the actual bars down to make space. */
.dash-row2, .dash-row2b {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-lg);
    margin-bottom: var(--space-lg);
}

.dash-row2 {
    grid-template-rows: 500px;
    grid-auto-rows: 500px;
}

.dash-row2b {
    grid-template-rows: 460px;
    grid-auto-rows: 460px;
}

.dash-trend-card, .dash-heatmap-card, .dash-routes-card, .dash-category-card {
    height: 100%;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    position: relative;
}

/* Frequency/Time control pinned to a card's top-right corner, same absolute-positioning approach
   as the Top Routes card's metric control -- immune to the title's width, never wraps. Reused on
   "Incidents Over Time" and "Incidents by Time of Day". */
.dash-metric-header {
    position: relative;
    padding-right: 150px;
}

.dash-metric-header h3 {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.dash-metric-header h3.dash-dimension-title, h3.dash-dimension-title {
    display: flex;
    align-items: center;
    gap: 6px;
    overflow: visible;
    text-overflow: clip;
}

.dash-dimension-select {
    margin-bottom: 0;
    width: auto;
    min-width: 0;
}

.dash-dimension-select .view-select {
    padding: 3px 24px 3px 8px;
    font-family: var(--font-display);
    font-size: 1rem;
    font-weight: 600;
    border: none;
    background: var(--bg-tertiary);
}

.dash-dimension-select .select-wrap-chevron {
    right: 8px;
    font-size: 0.6rem;
}

.dash-card-metric {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-md);
    width: auto;
    margin-bottom: 0;
    z-index: 2;
}

.dash-card-metric .segmented-btn {
    padding: 4px 8px;
    font-size: 0.7rem;
}

.dash-card-pertrip-row {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding: 6px var(--space-md) 0;
    flex-shrink: 0;
}

.dash-card-pertrip-row-split {
    justify-content: space-between;
}

.dash-card-pertrip {
    margin: 0;
}

.dash-trend-monthly-wrap {
    display: flex;
    align-items: center;
    gap: 4px;
}

.dash-card-pertrip .toggle-row-label {
    font-size: 0.7rem;
}

.dash-trend-daypart-check {
    font-size: 0.78rem;
    color: var(--text-secondary);
}

/* Replaces the plain "Top Routes" title -- left side is scope (direction + View), Frequency/Time
   is pinned to the card's actual top-right corner via absolute positioning (not flex order/
   margin-left:auto) so it can never get squeezed into wrapping onto its own line regardless of
   how much room the left side needs, and stays "Frequency"/"Time" as full words. Per Trip Rate is
   its own thin row underneath the header, right-aligned. */
.dash-routes-card {
    position: relative;
}

.dash-routes-header {
    align-items: center;
    padding-right: 150px; /* clears the absolutely-positioned metric control */
}

.dash-routes-header-left {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.dash-routes-view-select {
    margin-bottom: 0;
    min-width: 0;
    width: 88px;
    margin-left: 4px;
}

.dash-routes-view-select .view-select {
    padding: 5px 24px 5px 10px;
    font-size: 0.76rem;
}

.dash-routes-metric {
    position: absolute;
    top: var(--space-sm);
    right: var(--space-md);
    width: auto;
    margin-bottom: 0;
    z-index: 2;
}

.dash-routes-metric .segmented-btn {
    padding: 4px 8px;
    font-size: 0.7rem;
}

.dash-routes-pertrip-row {
    display: flex;
    justify-content: flex-end;
    padding: 6px var(--space-md) 0;
}

.dash-routes-pertrip {
    margin: 0;
}

.dash-routes-pertrip .toggle-row-label {
    font-size: 0.7rem;
}

/* Best/Worst ranking direction -- an icon-only button (just the loop/rotate glyph, not a bordered
   pill wrapping the word) sitting beside plain, unboxed text that flips between "Worst" and
   "Best". Each click loops to the other end of the same ranking. */
.dash-direction-loop-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    background: none;
    border: none;
    padding: 0;
    color: var(--text-muted);
    cursor: pointer;
    flex-shrink: 0;
    border-radius: var(--radius-sm);
    transition: background var(--transition-fast), color var(--transition-fast);
}

.dash-direction-loop-btn:hover {
    background: var(--bg-tertiary);
    color: var(--accent-primary);
}

.dash-direction-loop-btn i {
    font-size: 0.78rem;
}

.dash-direction-label {
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--text-primary);
    white-space: nowrap;
}

.dash-routes-ranking {
    list-style: none;
    margin: 0;
    padding: var(--space-sm) var(--space-md) var(--space-md);
    display: flex;
    flex-direction: column;
    justify-content: space-evenly;
    gap: 10px;
    flex: 1;
}

.dash-route-row {
    display: grid;
    grid-template-columns: 22px 1fr auto;
    align-items: center;
    gap: var(--space-sm);
    font-size: 0.85rem;
}

.dash-route-rank {
    font-family: var(--font-display);
    font-weight: 700;
    color: var(--text-muted);
    font-size: 0.8rem;
    text-align: center;
}

.dash-route-info {
    grid-column: 2 / 4;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
}

.dash-route-name {
    color: var(--text-primary);
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.dash-route-value {
    color: var(--text-secondary);
    font-variant-numeric: tabular-nums;
    font-size: 0.8rem;
    white-space: nowrap;
}

.dash-route-bar-track {
    grid-column: 2 / 4;
    height: 11px;
    background: var(--bg-tertiary);
    border-radius: 999px;
    overflow: hidden;
    margin-top: 4px;
}

.dash-route-bar-fill {
    height: 100%;
    border-radius: 999px;
}

/* ==================== ROW 4 (donuts: Human Factor / Avoidability / Day Type) ==================== */
.dash-row3 {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: var(--space-lg);
    margin-bottom: var(--space-lg);
}

.dash-donut-card { min-height: 300px; display: flex; flex-direction: column; }

.dash-donut-body {
    flex: 1;
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-sm) var(--space-md) var(--space-md);
    min-height: 0;
}

.dash-donut-canvas-wrap {
    position: relative;
    width: 150px;
    height: 150px;
    flex-shrink: 0;
}

.dash-donut-center {
    position: absolute;
    /* Inset in from the ring itself (not flush with the canvas edge) -- the doughnut's cutout
       hole is smaller than the canvas box, so the center label needs real margin to stay clear
       of the colored ring, not just centered in the full canvas square. */
    inset: 30px;
    border-radius: 50%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    overflow: hidden;
}

.dash-donut-center .v {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 1.05rem;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    line-height: 1.1;
}

.dash-donut-center .l {
    font-size: 0.58rem;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.dash-donut-legend {
    list-style: none;
    margin: 0;
    padding: 0;
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.dash-donut-legend li {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.76rem;
    color: var(--text-secondary);
}

.dash-donut-legend .swatch {
    width: 9px;
    height: 9px;
    border-radius: 2px;
    flex-shrink: 0;
}

.dash-donut-legend .label {
    /* Not flex:1 -- growing the label box (rather than sizing to its text) is what was pushing
       .pct all the way to the legend's far right edge, reading as a huge gap between a short
       label and its percentage. Natural width + ellipsis only kicks in on a genuinely long name. */
    flex: 0 1 auto;
    max-width: 140px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    color: var(--text-primary);
}

.dash-donut-legend .pct {
    font-variant-numeric: tabular-nums;
    color: var(--text-muted);
    flex-shrink: 0;
    margin-left: 4px;
}

/* Route-number pill -- referenced from js/homeController.js (Top Routes ranking + this table's
   Route column) but never actually had a CSS definition anywhere in the project, so it rendered
   as plain inline text with no background, picking up whatever color the surrounding cell/row
   happened to set instead of its own. */
.route-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--accent-primary);
    color: #fff;
    font-weight: 700;
    font-size: 0.78rem;
    line-height: 1.4;
    padding: 1px 7px;
    border-radius: 4px;
    margin-right: 4px;
    white-space: nowrap;
}

/* ==================== ROUTE PERFORMANCE TABLE ==================== */
.dash-table-card {
    display: flex;
    flex-direction: column;
    max-height: 640px;
}

/* Overrides main.css's .performance-table td:first-child, which colors the ENTIRE first cell
   (badge + route long name together) in accent red -- here only the badge itself should be red
   (via .route-badge's own background above), the long name should read as normal bold text. */
.dash-table-card .performance-table td:first-child {
    color: var(--text-primary);
    font-weight: var(--font-weight-semibold);
}

.dash-sortable-table th {
    cursor: pointer;
    -webkit-user-select: none;
    user-select: none;
    white-space: nowrap;
}

.dash-sortable-table th:hover {
    color: var(--accent-primary);
}

.dash-sort-icon {
    display: inline-block;
    width: 0.7em;
    font-size: 0.7rem;
    color: var(--accent-primary);
}

.dash-table-controls {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-sm) var(--space-md);
    border-bottom: 1px solid var(--border-color);
}

.dash-table-count {
    font-size: 0.8rem;
    color: var(--text-muted);
}

.dash-export-btn {
    display: flex;
    align-items: center;
    gap: 6px;
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: 6px var(--space-sm);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.8rem;
    cursor: pointer;
}

.dash-export-btn:hover { background: var(--bg-surface); }

.dash-table-card .performance-table-container {
    flex: 1;
    margin: var(--space-md);
    margin-top: 0;
}

.dash-delta {
    font-size: 0.76rem;
    font-variant-numeric: tabular-nums;
    margin-left: 5px;
}

.dash-delta.up { color: var(--accent-error); }
.dash-delta.down { color: var(--accent-success); }
.dash-delta.flat { color: var(--text-muted); }

.dash-show-more-btn {
    display: block;
    margin: 0 auto var(--space-md);
    background: var(--bg-tertiary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    padding: var(--space-sm) var(--space-lg);
    color: var(--text-primary);
    font-family: inherit;
    font-size: 0.82rem;
    cursor: pointer;
}

.dash-show-more-btn:hover { background: var(--bg-surface); }
.dash-show-more-btn:empty { display: none; }

/* ==================== FOOTER ==================== */
.dash-footer {
    margin-top: var(--space-xl);
    padding-top: var(--space-md);
    border-top: 1px solid var(--border-color);
    color: var(--text-muted);
    font-size: 0.78rem;
    text-align: center;
}

/* ==================== LOADING / EMPTY ==================== */
.home-loading, .home-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 100%;
    color: var(--text-muted);
    font-size: 0.85rem;
}

/* ==================== RESPONSIVE ==================== */
@media (max-width: 1400px) {
    .dash-row3 { grid-template-columns: repeat(2, 1fr); }
}

@media (max-width: 1000px) {
    .dash-kpi-row { grid-template-columns: repeat(2, 1fr); }
    .dash-row2, .dash-row2b {
        grid-template-columns: 1fr;
        grid-template-rows: none;
        grid-auto-rows: 460px;
    }
}

@media (max-width: 720px) {
    .dash-page-sidebar { display: none; }
    /* The sidebar's back-to-map arrow disappears with it -- the nav pill would otherwise collide
       with the top-right Share control at this width, so it's replaced by a plain inline back
       link rather than kept and fought over layout space. */
    .floating-island#primaryNav { display: none; }
    .dashboard-main { inset: 0; padding: calc(var(--space-lg) * 2 + 76px) var(--space-md) var(--space-xl); }
    .dash-mobile-back {
        display: flex;
        align-items: center;
        gap: 6px;
        position: absolute;
        top: var(--space-lg);
        left: var(--space-md);
        color: var(--text-primary);
        font-weight: 700;
        font-size: 0.85rem;
        z-index: var(--z-fixed);
    }
    .dash-topbar { top: calc(var(--space-lg) + 40px); flex-wrap: wrap; justify-content: flex-end; }
    .dash-kpi-row { grid-template-columns: 1fr 1fr; }
    .dash-row3 { grid-template-columns: 1fr; }
}

@media (min-width: 721px) {
    .dash-mobile-back { display: none; }
}

/* ==================== ROUTE SEARCH (multi-select autocomplete) ==================== */
.route-search-combo {
    position: relative;
}

.route-search-suggestions {
    position: absolute;
    top: calc(100% + 2px);
    left: 0;
    right: 0;
    z-index: var(--z-dropdown);
    background: var(--bg-secondary);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    max-height: 220px;
    overflow-y: auto;
    box-shadow: var(--shadow-lg);
    display: none;
}

.route-search-suggestions.open {
    display: block;
}

.route-search-suggestion {
    display: flex;
    align-items: baseline;
    gap: 8px;
    padding: var(--space-sm) var(--space-md);
    cursor: pointer;
    transition: background var(--transition-fast);
}

.route-search-suggestion:hover {
    background: var(--bg-tertiary);
}

.route-search-suggestion .rs-route {
    font-weight: 700;
    color: var(--accent-primary);
    flex-shrink: 0;
}

.route-search-suggestion .rs-name {
    color: var(--text-muted);
    font-size: 0.8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.route-search-empty {
    padding: var(--space-sm) var(--space-md);
    color: var(--text-muted);
    font-size: 0.8rem;
}

.route-search-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 8px;
}

.route-search-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    background: var(--accent-primary);
    color: #fff;
    border-radius: 999px;
    padding: 2px 6px 2px 10px;
    font-size: 0.75rem;
    font-weight: 600;
}

.route-search-chip button {
    background: none;
    border: none;
    color: #fff;
    cursor: pointer;
    padding: 2px;
    font-size: 0.85rem;
    line-height: 1;
    opacity: 0.8;
}

.route-search-chip button:hover {
    opacity: 1;
}

/* Ward/District Performance Summary rows have no transit mode -- see renderPerformanceTable's
   colCount comment. */
.dash-sortable-table.hide-transit-col th:nth-child(2),
.dash-sortable-table.hide-transit-col td:nth-child(2) {
    display: none;
}
