/* ============================================================
   Brand colour
   ============================================================
   site.css derives its whole accent palette from --primary-h/s/l
   ("change --primary-h to retheme the entire UI"). Custom
   properties resolve at use time, so overriding the three source
   values here re-tints everything that references them —
   --brand-primary, the sidebar, focus rings — without editing
   site.css itself.

   The default highlight is a deep charcoal, #26353F. Clients with their
   own theme colours still override it.

   site.css derives several shades with fixed, high saturation
   (hover, light tint, sidebar, disabled buttons, dark-mode info).
   Against a near-neutral charcoal those come out as distinctly
   blue, so each is set explicitly here as a neutral charcoal tint. */

:root {
    --primary-h: 204;
    --primary-s: 25%;
    --primary-l: 20%;
    --brand-primary-hover: hsl(204 25% 28%);
    --brand-primary-light: hsl(204 20% 95%);
    --sidebar-bg: hsl(204 25% 13%);
    --sidebar-text: hsl(204 12% 84%);
    --sidebar-section: hsl(204 10% 55%);
}

.btn-primary.disabled {
    background: hsl(204 14% 68%);
    border-color: hsl(204 14% 68%);
}

/* Dark mode: charcoal would disappear into the slate surfaces, so the
   highlight is lifted to a mid grey that still carries white text. */
[data-theme="dark"] {
    --primary-s: 18%;
    --primary-l: 44%;
    --brand-primary-hover: hsl(204 18% 52%);
    /* Restated: the light-mode values above would otherwise win here */
    --brand-primary-light: hsl(204 18% 44% / 0.15);
    --sidebar-bg: hsl(204 25% 8%);
}

    [data-theme="dark"] .btn-primary.disabled {
        background: hsl(204 14% 28%);
        border-color: hsl(204 14% 28%);
    }

    [data-theme="dark"] .notification-info {
        background: hsl(204 25% 26% / 0.85);
        color: hsl(204 20% 90%);
    }

    [data-theme="dark"] .info-box.info {
        color: hsl(204 20% 85%);
    }

/* Default logo: one image per theme */
.logo-dark {
    display: none;
}

[data-theme="dark"] .logo-light {
    display: none;
}

[data-theme="dark"] .logo-dark {
    display: inline;
}

/* ============================================================
   SosNext migration shim.

   The old NGStyle.css layout vocabulary (propertypair, listtitle,
   listrow, filehead/filesection, vcenterdiv…) is still used by a
   number of Client partials. NGStyle.css is not loaded under the
   new _Layout, so these classes would otherwise render unstyled.

   Everything here is expressed in the framework's own tokens so
   those partials read as part of the new UI, and each rule can be
   deleted as its markup is converted to first-class controls.
   site.css is never modified.
   ============================================================ */

/* ── Label / value rows ─────────────────────────────────── */
.propertypair {
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: var(--space-4);
    padding: var(--space-2) 0;
    border-bottom: 1px solid var(--border);
}

    .propertypair:last-child {
        border-bottom: none;
    }

    .propertypair div:first-child {
        flex-basis: 30%;
        flex-shrink: 0;
        text-align: right;
        font-size: var(--font-size-xs);
        color: var(--text-muted);
    }

    .propertypair div:last-child {
        flex-basis: 70%;
        font-size: var(--font-size-sm);
        color: var(--text-primary);
    }

.kvp {
    margin-top: var(--space-3);
}

    .kvp > div:first-child {
        margin-bottom: var(--space-1);
        font-size: var(--font-size-xs);
        font-weight: 500;
        color: var(--text-secondary);
    }

/* ── Simple flex list rows ──────────────────────────────────
   Scoped to div: "listrow" is also used as a click hook on table
   rows, and display:flex on a <tr> destroys column alignment. */
div.listtitle {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--surface-sunken);
    border-bottom: 1px solid var(--border);
    font-size: var(--font-size-xs);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--text-secondary);
}

div.listrow {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    border-bottom: 1px solid var(--border);
    font-size: var(--font-size-sm);
    color: var(--text-primary);
    transition: background var(--transition-fast);
}

    div.listrow:hover {
        background: var(--surface-hover, var(--surface-sunken));
    }

    div.listrow:last-child {
        border-bottom: none;
    }

/* ── File detail section chrome ─────────────────────────── */
.filehead {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-4) var(--space-5);
    margin-top: var(--space-5);
    background: var(--surface);
    border: 1px solid var(--border);
    border-bottom: none;
    border-top-left-radius: var(--border-radius);
    border-top-right-radius: var(--border-radius);
    font-size: var(--font-size-base);
    font-weight: 600;
    color: var(--text-primary);
}

.filestatus {
    text-align: center;
    text-transform: uppercase;
    padding: var(--space-2);
    font-size: var(--font-size-xs);
    font-weight: 600;
    letter-spacing: 0.04em;
    border-left: 1px solid var(--border);
    border-right: 1px solid var(--border);
}

.filesection {
    background: var(--surface);
    border: 1px solid var(--border);
    border-top: none;
    border-bottom-left-radius: var(--border-radius);
    border-bottom-right-radius: var(--border-radius);
    padding: var(--space-5);
}

/* Status tints, semantic rather than per-client themed. Scoped to
   .filestatus so these very generic names cannot leak elsewhere. */
.filestatus.warning { background: var(--color-warning-bg); color: var(--text-primary); }
.filestatus.ok      { background: var(--color-success-bg); color: var(--text-primary); }
.filestatus.holding { background: var(--color-warning-bg); color: var(--text-primary); }
.filestatus.moving  { background: var(--color-info-bg);    color: var(--text-primary); }
.filestatus.bad     { background: var(--color-danger-bg);  color: var(--text-primary); }
.filestatus.none    { background: var(--surface-sunken);   color: var(--text-secondary); }

/* ── Centring helpers ───────────────────────────────────── */
.vcenterdiv {
    display: flex;
    flex-direction: row;
    align-items: center;
}

.hcenterdiv {
    display: flex;
    flex-direction: row;
    justify-content: center;
}

/* ── Inline icons ───────────────────────────────────────────
   Replaces the FontAwesome <i> glyphs used by partials that have
   not yet moved to the framework's own inline SVGs. FontAwesome
   is not loaded by _Layout. */
.icon-inline {
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    flex-shrink: 0;
}

/* ── Tabs ───────────────────────────────────────────────────
   Settings, Account Settings and Client Edit are tabbed pages.
   SosNext has no tab component, so the existing markup keeps its
   class names and is restyled here in framework tokens. Replace
   this block if a first-class tab control is added to site.css. */
.tabrow {
    display: flex;
    flex-direction: row;
    gap: var(--space-1);
    overflow-x: auto;
    border-bottom: 1px solid var(--border);
    margin-bottom: var(--space-5);
}

    .tabrow::-webkit-scrollbar {
        height: 0;
    }

.tablink {
    padding: var(--space-3) var(--space-4);
    white-space: nowrap;
    text-decoration: none;
    font-size: var(--font-size-sm);
    font-weight: 500;
    color: var(--text-secondary);
    border-bottom: 2px solid transparent;
    transition: color var(--transition-fast), border-color var(--transition-fast);
}

    .tablink:hover {
        color: var(--text-primary);
        text-decoration: none;
    }

    .tablink.selected {
        color: var(--brand-primary);
        border-bottom-color: var(--brand-primary);
    }

/* ── 12-column grid ─────────────────────────────────────────
   Bootstrap is not loaded by _Layout, but a number of partials
   still lay out with .row / .col-*. This is the minimum needed
   to keep those columns intact until the markup is converted. */
div.row {
    display: flex;
    flex-wrap: wrap;
    margin-left: calc(var(--space-3) * -0.5);
    margin-right: calc(var(--space-3) * -0.5);
}

    div.row > [class^="col-"],
    div.row > [class*=" col-"],
    div.row > .col {
        padding-left: calc(var(--space-3) * 0.5);
        padding-right: calc(var(--space-3) * 0.5);
        box-sizing: border-box;
    }

.col   { flex: 1 0 0%; }
.col-1  { flex: 0 0 8.3333%;  max-width: 8.3333%; }
.col-2  { flex: 0 0 16.6667%; max-width: 16.6667%; }
.col-3  { flex: 0 0 25%;      max-width: 25%; }
.col-4  { flex: 0 0 33.3333%; max-width: 33.3333%; }
.col-5  { flex: 0 0 41.6667%; max-width: 41.6667%; }
.col-6  { flex: 0 0 50%;      max-width: 50%; }
.col-7  { flex: 0 0 58.3333%; max-width: 58.3333%; }
.col-8  { flex: 0 0 66.6667%; max-width: 66.6667%; }
.col-9  { flex: 0 0 75%;      max-width: 75%; }
.col-10 { flex: 0 0 83.3333%; max-width: 83.3333%; }
.col-11 { flex: 0 0 91.6667%; max-width: 91.6667%; }
.col-12 { flex: 0 0 100%;     max-width: 100%; }

/* The md/lg variants only ever widen at the breakpoint. */
@media (max-width: 767px) {
    div.row > [class*="col-md-"],
    div.row > [class*="col-lg-"] {
        flex: 0 0 100%;
        max-width: 100%;
    }
}

@media (min-width: 768px) {
    .col-md-1  { flex: 0 0 8.3333%;  max-width: 8.3333%; }
    .col-md-2  { flex: 0 0 16.6667%; max-width: 16.6667%; }
    .col-md-3  { flex: 0 0 25%;      max-width: 25%; }
    .col-md-4  { flex: 0 0 33.3333%; max-width: 33.3333%; }
    .col-md-5  { flex: 0 0 41.6667%; max-width: 41.6667%; }
    .col-md-6  { flex: 0 0 50%;      max-width: 50%; }
    .col-md-8  { flex: 0 0 66.6667%; max-width: 66.6667%; }
    .col-md-9  { flex: 0 0 75%;      max-width: 75%; }
    .col-md-12 { flex: 0 0 100%;     max-width: 100%; }
}

/* Utility classes the old markup relies on. */
.d-none { display: none !important; }
.d-block { display: block !important; }
.text-danger { color: var(--color-danger); }
.text-muted { color: var(--text-muted); }
.mb-0 { margin-bottom: 0 !important; }

@media (min-width: 768px) {
    .d-md-none { display: none !important; }
    .d-md-block { display: block !important; }
    .d-md-flex { display: flex !important; }
}

/* ── Adjacent card merging across ajax slots ─────────────────
   site.css merges directly adjacent .card siblings into one
   continuous stack. On the file-detail page each card sits in
   its own .detail-slot — the target an ajax refresh replaces —
   so the cards are not DOM siblings and that rule cannot see
   them. This applies the same merge one level up.

   The :has(> .card) guard keeps a slot that is still waiting on
   its ajax content from flattening the card above it. Note that
   :has() may not be nested inside another :has(), so each guard
   sits on its own compound selector.

   Values mirror the "Adjacent card merging" block in site.css;
   keep them in step if that block changes. */

/* Lower card: flatten the top and pull it onto the shared border. */
.detail-slot:has(> .card) + .detail-slot > .card {
    margin-top: -1px; /* collapse shared border */
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    box-shadow: none;
}

/* Upper card: flatten the bottom when a card follows it. */
.detail-slot:has(+ .detail-slot > .card) > .card {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    box-shadow: none;
}

/* Opt-out — add .card-separated to the lower card, as in site.css */
.detail-slot + .detail-slot > .card.card-separated {
    margin-top: var(--space-6);
    border-top-left-radius: var(--border-radius-lg);
    border-top-right-radius: var(--border-radius-lg);
    box-shadow: var(--shadow-sm);
}

.detail-slot:has(+ .detail-slot > .card.card-separated) > .card {
    border-bottom-left-radius: var(--border-radius-lg);
    border-bottom-right-radius: var(--border-radius-lg);
    box-shadow: var(--shadow-sm);
}


/* ── Search box width in the list toolbar ────────────────────
   .list-toolbar-left is a flex row and .search-filter-container
   has no flex basis, so the search box shrank to its content
   width instead of filling the toolbar. */
.list-toolbar-left > .search-filter-container {
    flex: 1;
    min-width: 0;
}

/* ── Status bar help button ──────────────────────────────────
   .card-help-btn is display:flex, which is right inside
   .card-header-actions but makes it a block on its own line
   inside .card-status. Lay the status row out as flex so the
   marker sits beside the status text. */
.card-status {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

/* ── Action rows ─────────────────────────────────────────────
   site.css has no general-purpose button row: .form-row is a
   grid (auto-fit, 300px minimum), so a lone button placed in it
   stretches rather than aligning. .modal-footer has the right
   behaviour but is modal chrome. This is that behaviour without
   the border or padding, for use inside cards and forms. */
.form-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: var(--space-3);
}

    .form-actions.form-actions-center {
        justify-content: center;
    }

    .form-actions.form-actions-between {
        justify-content: space-between;
    }

    .form-actions.form-actions-start {
        justify-content: flex-start;
    }


/* ── Editable field rows ─────────────────────────────────────
   .field-row is designed for read-only label/value pairs. When the value
   holds a control, centre the row on the control and let it fill the cell. */
.field-row:has(.form-control, .form-check, .btn) {
    align-items: center;
}

.field-row-value > .form-control,
.field-row-value > select.form-control {
    width: 100%;
}

.field-row-value > .form-hint {
    margin-top: var(--space-1);
}

label.field-row-label {
    margin: 0;
}

/* ── Content width ───────────────────────────────────────────
   site.css caps the content column at 1280px, which leaves dead space to
   the right on wide windows. Let it fill the available width instead. */
.app-content-inner {
    max-width: none;
}

/* ── Charts ──────────────────────────────────────────────────
   Styling for the SVG chart partials in Pages/Shared/Charts. Series
   colours are set in code; everything structural follows the theme. */
.chart {
    width: 100%;
}

.chart-title {
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--text-primary);
    margin-bottom: var(--space-3);
}

.chart-svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

/* Two-layer plot: the geometry stretches to the container width at a fixed height,
   while the overlay (labels, markers, hover targets) keeps its natural proportions. */
.chart-plot {
    position: relative;
    width: 100%;
}

.chart-geometry,
.chart-overlay {
    position: absolute;
    overflow: visible;
}

.chart-grid {
    stroke: var(--border-default);
    stroke-width: 1;
    shape-rendering: crispEdges;
}

.chart-axis {
    stroke: var(--border-strong, var(--border-default));
    stroke-width: 1;
    shape-rendering: crispEdges;
}

.chart-axis-label {
    fill: var(--text-muted);
    font-family: var(--font-sans);
    font-size: 11px;
}

.chart-line {
    fill: none;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.chart-point {
    stroke: var(--surface-card);
    stroke-width: 1.5;
}

.chart-bar,
.chart-slice {
    transition: opacity var(--transition-fast, 0.15s);
}

    .chart-bar:hover,
    .chart-slice:hover {
        opacity: 0.85;
    }

.chart-slice {
    stroke: var(--surface-card);
    stroke-width: 2;
}

.chart-donut-total {
    fill: var(--text-primary);
    font-family: var(--font-sans);
    font-size: 24px;
    font-weight: 700;
}

.chart-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-5);
    margin-top: var(--space-3);
    font-size: var(--font-size-sm);
    color: var(--text-secondary, var(--text-muted));
}

.chart-legend-item {
    display: flex;
    align-items: center;
    gap: var(--space-2);
}

.chart-swatch {
    width: 10px;
    height: 10px;
    border-radius: 2px;
    flex-shrink: 0;
}

.chart-pie-layout {
    display: flex;
    align-items: flex-start;          /* pie stays at the top as the card grows */
    gap: var(--space-6);
    flex-wrap: wrap;
}

/* The pie takes the space left over; the legend shrinks to its content and sits
   against the right edge. */
.chart-pie-svg {
    flex: 1 1 240px;
    min-width: 0;
    max-width: 100%;
}

.chart-pie-legend {
    flex: 0 1 auto;
    margin-left: auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    font-size: var(--font-size-sm);
}

    .chart-pie-legend .chart-legend-label {
        color: var(--text-primary);
    }

    .chart-pie-legend .chart-legend-value {
        margin-left: auto;
        padding-left: var(--space-6);
        color: var(--text-muted);
        white-space: nowrap;
    }

.chart-empty {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 120px;
    color: var(--text-muted);
    font-size: var(--font-size-sm);
}

/* Compact form control, for selects that sit in a card header or toolbar
   where a full-width .form-control would stretch the row. */
.form-control-sm {
    width: auto;
    min-width: 150px;
    height: auto;
    padding: 0.3rem 0.55rem;
    font-size: var(--font-size-sm);
    line-height: 1.4;
}

/* ── Chart tooltips ──────────────────────────────────────────
   Driven by wwwroot/js/charts.js; the partials tag hoverable
   elements with data-tip. */
.chart-hit {
    fill: transparent;
    pointer-events: all;
}

.chart-tooltip {
    position: fixed;
    z-index: var(--z-tooltip, 1080);
    pointer-events: none;
    max-width: 260px;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--border-default);
    border-radius: var(--border-radius, 6px);
    background: var(--surface-card);
    box-shadow: var(--shadow-lg, 0 8px 24px rgba(0, 0, 0, 0.18));
    font-size: var(--font-size-sm);
    color: var(--text-primary);
    line-height: 1.35;
}

.chart-tooltip-title {
    font-weight: 600;
    margin-bottom: 2px;
}

.chart-tooltip-row {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    white-space: nowrap;
}

.chart-tooltip-dot {
    width: 8px;
    height: 8px;
    border-radius: 2px;
    flex-shrink: 0;
}

.chart-tooltip-label {
    color: var(--text-muted);
}

.chart-tooltip-value {
    margin-left: auto;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* ── Multi-select dropdown (Pages/Shared/_MultiSelect) ───────
   Reuses the filter-panel look; the button sits in a card header. */
.multiselect {
    position: relative;
}

.multiselect-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    max-width: 260px;
}

    /* Card headers pair this button with a .form-control-sm select; .btn-sm is smaller in
       both padding and type, so match the select's metrics to keep the two the same height. */
    .multiselect-btn.btn-sm {
        padding: 0.3rem 0.55rem;
        font-size: var(--font-size-sm);
        line-height: 1.4;
    }

    .multiselect-btn .multiselect-label {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .multiselect-btn svg {
        width: 14px;
        height: 14px;
        flex-shrink: 0;
    }

.multiselect-panel {
    left: auto;
    right: 0;
    min-width: 260px;
    max-height: none;                 /* the option list scrolls, not the whole panel */
    padding: var(--space-2) var(--space-3);
}

/* site.js puts the collapse chevron in .card-header-actions alongside any filters, so hide
   everything but the chevron while the card is closed. */
.card.collapsed .card-header-actions > :not(.card-collapse-btn) {
    display: none;
}

/* .card clips its content, which cuts the flyout off at the card edge. Lift that while a
   picker is open so the list can hang below the card. */
.card:has(.multiselect-panel.open),
.card-header:has(.multiselect-panel.open) {
    overflow: visible;
}

.multiselect-search {
    padding-bottom: var(--space-2);
}

    .multiselect-search .form-control-sm {
        width: 100%;
        min-width: 0;
    }

.multiselect-all {
    border-bottom: 1px solid var(--border-default);
    padding-bottom: var(--space-2);
    margin-bottom: var(--space-1);
}

/* Roughly twenty rows, and never more than half the viewport. */
.multiselect-options {
    max-height: min(560px, 50vh);
    overflow-y: auto;
}

    /* .filter-option sets display:flex, which beats the browser's [hidden] rule — without
       this, filtered-out rows stay on screen. */
    .multiselect-options .filter-option[hidden] {
        display: none;
    }

    .multiselect-panel.open {
        display: block;
    }

    .multiselect-panel .filter-option {
        padding: var(--space-1) 0;
    }

/* ── Legend colour overrides (wwwroot/js/charts.js) ──────────
   Clicking a legend entry opens a colour picker; right-click clears it. */
.chart-legend-editable {
    cursor: pointer;
    border-radius: var(--border-radius, 6px);
    padding: 2px 4px;
    margin: -2px -4px;
}

    .chart-legend-editable:hover {
        background: var(--surface-sunken);
    }

/* The picker is only a handle for the browser's colour dialog. */
.chart-colour-picker {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
}
