/* Aurora-style visual layer for the Insights section.
   Tokens first, then the shell (drawer + app bar), then the page primitives that
   InsightsPage.razor and the dashboard components use. Everything here is additive:
   MudBlazor keeps doing the layout, this only restyles surfaces. */

:root {
    --ins-navy-900: #12233F;
    --ins-navy-800: #17304F;
    --ins-navy-700: #1E3C63;
    --ins-navy-600: #27508A;
    --ins-blue: #2C6BB0;
    --ins-blue-deep: #1F4E8C;
    --ins-teal: #2FB3A0;
    --ins-green: #1E9E63;
    --ins-red: #D64545;
    --ins-surface: #FFFFFF;
    --ins-canvas: #EEF2F7;
    --ins-line: #E3E8EF;
    --ins-ink: #1B2432;
    --ins-ink-muted: #6B7A90;
    --ins-radius: 14px;
    --ins-shadow: 0 1px 2px rgba(18, 35, 63, .06), 0 6px 18px rgba(18, 35, 63, .06);
}

/* ---------- Shell: navy rail, light canvas ---------- */

.ins-drawer.mud-drawer {
    background: linear-gradient(180deg, var(--ins-navy-900) 0%, var(--ins-navy-800) 100%);
    border-right: none;
    /* MudBlazor colours nav icons from this variable via a rule more specific than
       anything reasonable here, so set the variable rather than fight it. Matches the
       label colour below: icons read as part of the text, not as grey furniture. */
    --mud-palette-drawer-icon: #D5E1F2;
}

.ins-brand {
    padding: 22px 20px 18px;
    display: flex;
    align-items: center;
    gap: 12px;
    color: #FFF;
}

/* A tenant's logo sits ABOVE the wordmark rather than beside it.

   Beside it, the logo had to share a 260px drawer with two lines of text and was capped at
   150px wide -- enough for an icon, not for the lockup most companies actually supply, which
   arrived unreadably small. Stacking gives it the drawer's full width.

   Only when there IS a logo: the built-in truck icon is a 34px square and reads correctly
   next to the text, so the default layout is left alone. */
.ins-brand--stacked {
    flex-direction: column;
    align-items: flex-start;
    gap: 10px;
}

/* With the wordmark hidden the logo is the whole identity, so it gets the height the two
   lines of text were using and then some.

   The number is chosen so that WIDTH becomes the binding constraint rather than height. At
   84px a squarish logo -- 1.41:1 measured on a real one -- rendered only 117px wide in a
   220px drawer and left a third of the space empty, because height ran out first. At 180px
   the same logo fills the width exactly.

   Deliberately not width:100% with a height cap. Forcing the width would letterbox anything
   squarer than the cap allows, leaving the logo small inside a wide white plate. Letting the
   two limits negotiate means a wide logo fills the width, a square one grows until height
   stops it, and neither is ever stretched or boxed. */
.ins-brand--logo-only .ins-brand__logo {
    max-height: 180px;
}

/* contain rather than cover: a customer's logo is usually wider than it is tall, and cover
   would crop it. Letterboxing an unexpected aspect ratio is the failure that still shows the
   whole logo. */
.ins-brand__logo {
    display: block;
    max-height: 48px;
    max-width: 100%;
    object-fit: contain;
    object-position: left center;
    flex: 0 0 auto;

    /* A light plate behind the logo, because the drawer is dark navy and most companies supply
       a logo as dark ink on transparent -- which would be invisible against it. With the plate,
       transparent and white-background logos both read correctly, and the only case still not
       served is a logo drawn in white for dark backgrounds, which is the rarer one and has an
       obvious remedy. */
    background: #FFF;
    padding: 6px 8px;
    border-radius: 6px;
}

.ins-brand__mark {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: linear-gradient(135deg, var(--ins-teal), var(--ins-blue));
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
}

.ins-brand__name {
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: .12em;
    line-height: 1.1;
}

.ins-brand__sub {
    font-size: .68rem;
    letter-spacing: .22em;
    color: #9FB4D4;
}

/* Nav items become navy pills; the active one flips to a white slab like the reference. */
.ins-drawer .mud-navmenu {
    padding: 6px 12px 24px;
}

.ins-drawer .mud-nav-link,
.ins-drawer .mud-nav-link-group > .mud-nav-link {
    color: #D5E1F2;
    border-radius: 8px;
    margin: 3px 0;
    font-weight: 500;
    transition: background-color .15s ease, color .15s ease;
}

/* Icons follow the label to white on hover; the resting colour comes from
   --mud-palette-drawer-icon above. */
.ins-drawer .mud-nav-link:hover .mud-icon-root {
    color: #FFF;
}

/* MudBlazor styles hover and active through
   .mud-navmenu.mud-navmenu-default .mud-nav-link...:not(.mud-nav-link-disabled), which
   outranks a plain .ins-drawer .mud-nav-link rule. Left to it, the active row rendered as
   the theme's primary blue on a 6%-black tint -- all but invisible against a navy rail.
   Matching that selector's shape wins on source order instead. */
.ins-drawer .mud-navmenu.mud-navmenu-default .mud-nav-link:hover:not(.mud-nav-link-disabled) {
    background-color: var(--ins-navy-700);
    color: #FFF;
}

.ins-drawer .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) {
    background-color: #FFF;
    color: var(--ins-navy-900);
    font-weight: 600;
}

.ins-drawer .mud-navmenu.mud-navmenu-default .mud-nav-link.active:not(.mud-nav-link-disabled) .mud-icon-root {
    color: var(--ins-blue);
}

/* Hovering the selected row was dropping MudBlazor's 6%-black tint over the white slab,
   leaving navy text on a dark row -- the one state neither the plain hover rule nor the
   plain active rule covers. Stated explicitly so the slab stays light, with just enough
   shift to register as hover. */
.ins-drawer .mud-navmenu.mud-navmenu-default .mud-nav-link.active:hover:not(.mud-nav-link-disabled) {
    background-color: #EDF3FB;
    color: var(--ins-navy-900);
}

.ins-drawer .mud-navmenu.mud-navmenu-default .mud-nav-link.active:hover:not(.mud-nav-link-disabled) .mud-icon-root {
    color: var(--ins-blue-deep);
}

/* Group children sit on a slightly lighter panel so the hierarchy reads at a glance. */
.ins-drawer .mud-nav-group .mud-collapse-container {
    background-color: rgba(255, 255, 255, .04);
    border-radius: 8px;
    margin-bottom: 6px;
}

.ins-appbar.mud-appbar {
    background: var(--ins-surface);
    color: var(--ins-ink);
    border-bottom: 1px solid var(--ins-line);
    box-shadow: none;
}

.ins-canvas {
    background-color: var(--ins-canvas);
}

/* ---------- Page primitives ---------- */

.ins-page {
    padding: 4px 4px 28px;
}

.ins-page__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 24px;
    flex-wrap: wrap;
    margin-bottom: 18px;
}

.ins-page__title {
    margin: 0;
    font-size: 1.9rem;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--ins-navy-900);
    line-height: 1.15;
}

.ins-page__subtitle {
    margin: 6px 0 0;
    font-size: .95rem;
    color: var(--ins-ink-muted);
}

/* Filter/action strip, mirroring the reference's labelled controls row. */
.ins-toolbar {
    display: flex;
    /* Full width so the bar's right edge lines up with the cards below it, rather
       than the card shrinking to its contents and floating mid-page. */
    width: 100%;
    align-items: flex-end;
    gap: 20px;
    flex-wrap: wrap;
    background: var(--ins-surface);
    border: 1px solid var(--ins-line);
    border-radius: var(--ins-radius);
    box-shadow: var(--ins-shadow);
    padding: 14px 18px;
    margin-bottom: 18px;
}

.ins-field {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

.ins-field__label {
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ins-ink-muted);
}

.ins-toolbar__spacer {
    flex: 1 1 auto;
}

/* Now a labelled block like the date field rather than loose text, so the bar has
   three groups sharing one bottom edge. align-self:center was what left the
   timestamp floating 20px above everything else. */
.ins-toolbar__meta {
    align-items: flex-end;
    text-align: right;
    font-size: .8rem;
    color: var(--ins-ink-muted);
    white-space: nowrap;
}

/* Match the control height next to it so both labels start on the same line and
   the timestamp centres against the buttons. */
.ins-toolbar__meta > span:last-child {
    display: flex;
    align-items: center;
    height: 37px;
}

/* The picker sizes itself to two full-width inputs, which drew an underline half
   again as wide as the dates sitting on it. */
.ins-toolbar .mud-picker {
    width: 260px;
}

/* The calendar adornment is taller than the buttons and hung below the field's
   bottom edge, breaking the line the rest of the bar sits on. */
.ins-toolbar .mud-input .mud-icon-button {
    padding: 4px;
}

/* ---------- Cards ---------- */

.ins-card {
    background: var(--ins-surface);
    border: 1px solid var(--ins-line);
    border-radius: var(--ins-radius);
    box-shadow: var(--ins-shadow);
    padding: 18px 20px;
    height: 100%;
}

.ins-card__title {
    font-size: 1rem;
    font-weight: 700;
    color: var(--ins-ink);
    margin: 0 0 12px;
}

/* KPI tile: blue label, oversized value, optional footnote under a rule. */
.ins-kpi {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.ins-kpi__label {
    font-size: .95rem;
    font-weight: 600;
    color: var(--ins-blue);
}

.ins-kpi__value {
    font-size: 2.1rem;
    font-weight: 700;
    color: var(--ins-blue-deep);
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.ins-kpi__foot {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--ins-line);
    font-size: .8rem;
    color: var(--ins-ink-muted);
}

.ins-kpi--good .ins-kpi__value { color: var(--ins-green); }
.ins-kpi--bad .ins-kpi__value { color: var(--ins-red); }

.ins-pos { color: var(--ins-green); font-weight: 600; }
.ins-neg { color: var(--ins-red); font-weight: 600; }

/* ---------- Australia map ----------
   The SVG carries inline fill/stroke presentation attributes; CSS properties outrank
   those, so restyling here needs no edit to the several-thousand-character path data.
   (The old .state rules live in app.css, which index.html does not load.) */

:root {
    --ins-map-fill: #C7D8EC;
    --ins-map-stroke: #1F4E8C;
    --ins-map-hover: #2C6BB0;
}

.australia-map .state {
    fill: var(--ins-map-fill);
    stroke: var(--ins-map-stroke);
    stroke-width: 1.5;
    cursor: pointer;
    transition: fill .18s ease;
}

.australia-map .state:hover {
    fill: var(--ins-map-hover);
}

.australia-map .state-label {
    fill: var(--ins-navy-900);
    font-size: 20px;
    pointer-events: none;
}

/* ---------- Split layout ----------
   Was 30vw + 50vw, which measures the viewport and so ignored the 260px drawer --
   the pair overflowed the content area. Flex basis plus min-width:0 lets the grid
   shrink to whatever is actually left and scroll inside itself instead. */

.ins-split__aside {
    /* Was a fixed-ish 360px, which left the map dwarfed by the grid next to it.
       Growing at flex-grow:1 against the grid's 2 gives it roughly a third of the row. */
    flex: 1 1 420px;
    min-width: 320px;
    max-width: 640px;
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.australia-map {
    /* Was inline on the SVG, which outranked any class and so could not be capped. */
    display: block;
    width: 100%;
    max-width: 810px;
    height: auto;
    margin: 0 auto;
}

/* Beside a panel rather than alone: the viewBox is 810x610, so capping the width caps
   the height with it -- 300px wide lands at ~226px tall, which keeps the volume charts
   below it on screen. */
.australia-map--compact {
    max-width: 380px;
}

/* font-size on SVG text is in viewBox units, so a compact map shrinks its own labels:
   20 units across 810 renders at ~9px once the map is 380px wide. Scaling the type up
   here keeps the figures readable without giving the map back the width. */
.australia-map--compact .state-label {
    font-size: 30px;
}

.ins-split__main {
    flex: 2 1 560px;
    min-width: 0;
}

/* ---------- Data grids ---------- */

.ins-grid {
    background: var(--ins-surface);
    border: 1px solid var(--ins-line);
    border-radius: var(--ins-radius);
    box-shadow: var(--ins-shadow);
    padding: 8px;
    min-width: 0;
    overflow-x: auto;
}

.ins-grid .mud-table-container {
    overflow-x: auto;
}

/* Column headers read as labels rather than another row of data. */
.ins-grid .mud-table-head .mud-table-cell {
    background: var(--ins-canvas);
    color: var(--ins-navy-900);
    font-weight: 700;
    font-size: .72rem;
    letter-spacing: .06em;
    text-transform: uppercase;
    white-space: nowrap;
    border-bottom: 1px solid var(--ins-line);
}

.ins-grid .mud-table-body .mud-table-cell {
    font-size: .82rem;
    border-bottom: 1px solid #F0F3F8;
}

.ins-grid .mud-table-body .mud-table-row:nth-of-type(even) {
    background-color: #FAFCFE;
}

.ins-grid .mud-table-body .mud-table-row:hover {
    background-color: #EDF3FA;
}

.ins-grid .mud-table-pagination {
    border-top: 1px solid var(--ins-line);
    background: var(--ins-surface);
}

/* ---------- Horizontal overflow ----------
   The app-wide half of this fix lives in StyleSheet.css, next to the flex rules that
   cause it. These are the Insights-specific containers: MudStack and MudGrid are flex
   containers, so their children need the same min-width floor lifted or one wide child
   re-inflates the parent and the page scrolls sideways again. */

.ins-page,
.ins-card,
.ins-grid,
.ins-page .mud-grid > .mud-grid-item {
    min-width: 0;
}

/* The map/grid row. MudStack renders utility classes (d-flex flex-row ...) and no
   .mud-stack class, so it needs a class of its own to be addressable.

   Two things went wrong here without these three declarations. The row defaulted to
   min-width:auto, so it was floored at its content's width; and the column MudStack
   above it uses align-items:flex-start, which sizes children to fit-content rather
   than stretching them, so the row had no width to be floored against in the first
   place. It measured 2503px inside a 1212px parent and .content simply clipped the
   overhang -- the grid was not scrollable, it was cut off. */
.ins-split {
    width: 100%;
    min-width: 0;
    align-self: stretch;
}

.ins-split > * {
    min-width: 0;
}

.ins-page {
    max-width: 100%;
}

/* ---------- Summary table ----------
   The dashboard's overview table. Deliberately not a MudDataGrid: no filtering,
   resizing or column menus, so it has no intrinsic width to fight and fits whatever
   column it is given. */

.ins-card__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 12px;
}

.ins-card__head .ins-card__title {
    margin: 0;
}

.ins-card__link {
    font-size: .8rem;
    font-weight: 600;
    color: var(--ins-blue);
    text-decoration: none;
    white-space: nowrap;
}

.ins-card__link:hover {
    text-decoration: underline;
}

.ins-summary {
    width: 100%;
    border-collapse: collapse;
    font-size: .85rem;
}

.ins-summary th {
    text-align: left;
    padding: 0 10px 8px;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ins-ink-muted);
    border-bottom: 1px solid var(--ins-line);
    white-space: nowrap;
}

.ins-summary td {
    padding: 9px 10px;
    border-bottom: 1px solid #F0F3F8;
    color: var(--ins-ink);
}

.ins-summary tbody tr:last-child td {
    border-bottom: none;
}

.ins-summary tbody tr:hover {
    background-color: #F5F8FC;
}

/* Name column absorbs the slack and ellipsises; max-width:0 with width:100% is the
   trick that makes a table cell shrinkable enough for text-overflow to apply. */
.ins-summary__label {
    width: 100%;
    max-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 500;
}

.ins-summary .num {
    text-align: right;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ins-summary__foot {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--ins-line);
    font-size: .78rem;
    color: var(--ins-ink-muted);
}

.ins-empty {
    margin: 18px 4px;
    color: var(--ins-ink-muted);
    font-size: .88rem;
}

/* .ins-card sets height:100% so KPI tiles in a MudGrid row match heights. On the
   split row that backfires: a definite cross size opts the item out of the row's
   align-items:stretch, so the card sat short next to the taller map. Letting it be
   auto hands sizing back to stretch. */
.ins-split__main.ins-card {
    height: auto;
}

/* ---------- KPI row ----------
   Seven tiles across the top. auto-fit keeps them on one line while there is room
   for a 140px minimum and reflows to fewer columns rather than overflowing. */

.ins-kpi-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    gap: 12px;
    width: 100%;
    min-width: 0;
}

/* Tighter than a standalone card: seven abreast needs the numbers to come down. */
.ins-kpi-row .ins-card {
    padding: 12px 14px;
}

.ins-kpi-row .ins-kpi__label {
    font-size: .76rem;
    line-height: 1.25;
}

.ins-kpi-row .ins-kpi__value {
    font-size: 1.5rem;
}

.ins-kpi-row .ins-kpi__foot {
    margin-top: 8px;
    padding-top: 8px;
    font-size: .7rem;
}

/* ---------- Map selection ---------- */

.australia-map .state.selected {
    fill: var(--ins-blue-deep);
    stroke: var(--ins-navy-900);
}

/* A map with no click handler is a picture, so it should not invite a click. */
.australia-map--static .state {
    cursor: default;
}

.australia-map--static .state:hover {
    fill: var(--ins-map-fill);
}

.ins-hint {
    display: flex;
    align-items: center;
    gap: 6px;
    margin: -4px 0 10px;
    font-size: .78rem;
    color: var(--ins-ink-muted);
}

.ins-hint .mud-icon-root {
    color: var(--ins-blue);
}

.ins-hint strong {
    color: var(--ins-ink);
}

/* Summary table acting as a selector, like the map on the dashboard. */
.ins-summary--clickable tbody tr {
    cursor: pointer;
}

.ins-summary--clickable tbody tr.is-selected {
    background-color: #E4EDF8;
}

.ins-summary--clickable tbody tr.is-selected .ins-summary__label {
    font-weight: 700;
    color: var(--ins-blue-deep);
    box-shadow: inset 3px 0 0 var(--ins-blue-deep);
}

.ins-summary--clickable tbody tr.is-selected:hover {
    background-color: #D9E6F5;
}

/* Chip filter bar. Chips wrap onto several lines, so unlike the date toolbar this
   one aligns its groups to the top rather than to a shared bottom edge. */
.ins-toolbar--filters {
    /* Inherits align-items:flex-end from .ins-toolbar. The dropdowns are all the same
       height so it reads the same for them, but it lines the date picker and the two
       buttons up with the inputs rather than floating them at the top of the row. */
    row-gap: 14px;
}

.ins-toolbar--filters .mud-chipset {
    margin: 0;
}

/* MudChart draws unclassed <text> at 12px. Axis labels are dense on a half-width
   chart, but 10px was too small to read comfortably. 12px with fewer labels reads better
   than 10px with more.
   Note MudBlazor marks bar charts .mud-chart-line as well, so that one selector
   covers both -- and scoping to the chart classes keeps the map's own labels out. */
.ins-card svg.mud-chart-line text,
.ins-card svg.mud-chart-donut text {
    font-size: 12px;
    fill: var(--ins-ink-muted);
}

/* Filter dropdowns: fixed width so the three sit in a predictable row rather than
   each sizing to its longest customer name. Narrowed from 240px when the date range and
   refresh controls joined this bar -- at 240 the row wrapped, which cost more height than
   the merge saved. */
.ins-filter-select {
    width: 190px;
}

/* Only selected values get a chip, so this row is usually empty and costs nothing. */
.ins-active-filters {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    padding: 0 4px;
}

.ins-active-filters .ins-field__label {
    margin-right: 4px;
}

.ins-active-filters .mud-chip {
    margin: 0;
}

/* ---------- Overview sections ---------- */

.ins-section {
    margin: 18px 4px 2px;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--ins-ink-muted);
}

.ins-section:first-of-type {
    margin-top: 4px;
}

/* Charts side by side while there is room for a readable one, wrapping rather than
   squeezing -- the same reflow the KPI row uses. */
.ins-chart-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 12px;
    width: 100%;
    min-width: 0;
}

/* The figure half of a swap card, standing in for the chart. */
.ins-figure {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 220px;
    font-size: 3rem;
    font-weight: 700;
    color: var(--ins-blue-deep);
    font-variant-numeric: tabular-nums;
}

.ins-card__total {
    font-size: 1.05rem;
    font-weight: 700;
    color: var(--ins-blue-deep);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.ins-card__foot {
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--ins-line);
    font-size: .75rem;
    color: var(--ins-ink-muted);
}

.ins-card__tools {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* A measure and its trend side by side: the chart takes the room, the figure sits beside
   it. Collapses to stacked before the chart gets too narrow to read. */
.ins-measure-row {
    display: grid;
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    gap: 12px;
    width: 100%;
    min-width: 0;
}

@media (max-width: 1000px) {
    .ins-measure-row {
        grid-template-columns: 1fr;
    }
}

/* Centres the figure against the height of the chart next to it. */
.ins-measure {
    display: flex;
    flex-direction: column;
}

.ins-measure .ins-figure {
    flex: 1 1 auto;
}

/* State codes need far less room than customer names. */
.ins-filter-select--narrow {
    width: 150px;
}

/* The carrier cards are a third the height of a full chart, so their stand-in figure
   should not reserve a full chart's worth of space. */
.ins-figure--small {
    min-height: 140px;
    font-size: 2rem;
}

/* A bar carrying only a control, so it should not claim a full toolbar's padding. */
.ins-toolbar--inline {
    padding: 10px 18px;
}

/* Filter toggles. MudButtonGroup fights this on two fronts: it sets Variant on the group,
   which outranks any variant a child button asks for, and it paints its children through
   .mud-button-group-text.mud-button-group-override-styles.mud-button-group-text-primary
   .mud-button-root -- four classes deep. So the state is carried by a class, and these
   selectors go a class deeper again rather than trying to out-argue it. */
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button.ins-toggle {
    background-color: var(--ins-surface);
    color: var(--ins-blue-deep);
}

.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button.ins-toggle:hover {
    background-color: #EDF3FB;
}

.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button.ins-toggle--on,
.mud-button-group-root.mud-button-group-override-styles .mud-button-root.mud-button.ins-toggle--on:hover {
    background-color: var(--ins-blue-deep);
    color: #FFF;
    font-weight: 600;
}

/* Key for the consignment grid's row shading. */
.ins-legend {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 18px;
    padding: 0 6px 4px;
    font-size: .78rem;
    color: var(--ins-ink-muted);
}

.ins-legend__item {
    display: inline-flex;
    align-items: center;
    gap: 7px;
}

.ins-legend__swatch {
    width: 22px;
    height: 12px;
    border-radius: 3px;
    border: 1px solid rgba(18, 35, 63, .18);
    flex: 0 0 auto;
}

.ins-legend__item--muted {
    font-style: italic;
}

/* ---------- Consignment row shading ----------
   Amber for a problem still unfolding, red for one that has already happened, both as
   pale tints so the row text stays black-on-light. Derived from the palette's red rather
   than the mustard and pink that were here before, which belonged to no scheme at all.
   The legend swatches wear these same classes. */

:root {
    --ins-amber: #C98A1B;
    --ins-row-overdue: #FAEBCD;
    --ins-row-late: #F7DBDB;
}

.ins-row--overdue,
.ins-grid .mud-table-body .mud-table-row.ins-row--overdue {
    background-color: var(--ins-row-overdue);
}

.ins-row--late,
.ins-grid .mud-table-body .mud-table-row.ins-row--late {
    background-color: var(--ins-row-late);
}

/* The hover tint would otherwise wipe the shading off whichever row you are pointing at. */
.ins-grid .mud-table-body .mud-table-row.ins-row--overdue:hover {
    background-color: #F5DFB4;
}

.ins-grid .mud-table-body .mud-table-row.ins-row--late:hover {
    background-color: #F2C9C9;
}

/* MudChart scales a fixed 650x350 viewBox to the container, so a font-size set here is
   scaled with it: the same 12px rendered at 14px on a 300px-tall chart and 9px on a
   180px one. These compensate per height band so every chart lands near 14px on screen.
   Sizes are pre-scaling; check the rendered height, not this number. The selectors match
   the depth of the base rule above, which would otherwise outrank a bare modifier. */
.ins-card .ins-chart--xs svg.mud-chart-line text,
.ins-card .ins-chart--xs svg.mud-chart-donut text {
    font-size: 22px;
}

.ins-card .ins-chart--sm svg.mud-chart-line text,
.ins-card .ins-chart--sm svg.mud-chart-donut text {
    font-size: 17px;
}

.ins-card .ins-chart--md svg.mud-chart-line text,
.ins-card .ins-chart--md svg.mud-chart-donut text {
    font-size: 15px;
}


/* ---------- Disruptions page ----------
   Three panels on one row: map, warnings, incidents. They are siblings rather than the map
   plus a stacked column, because stacking put the incident list below the fold -- and since
   clicking an incident zooms the map, that meant scrolling up to see the result of every
   click and back down to make the next one.

   All three are given the same explicit height rather than being stretched to the tallest.
   Stretching cannot work here: the incident list can hold 150 rows, so its natural height
   would set the row and the map would be dragged to match it. One height variable drives
   every panel, and each panel scrolls inside itself. */

.ins-disruptions {
    /* Sized against the viewport rather than a flat pixel cap, because the fixed 560px left
       roughly 140px of dead space below the panels on a 1025px-tall window.

       The 340px subtracted is the chrome above and below: app bar, page header, the
       conditions strip and its margin, plus the canvas padding. Measured, not guessed. The
       clamp keeps it sane at both extremes -- never so short the map is useless, never so
       tall that a big monitor gets one enormous panel. */
    --ins-disruptions-h: clamp(360px, calc(100vh - 340px), 960px);

    display: grid;
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr) minmax(0, 1fr);
    gap: 16px;
    width: 100%;
    min-width: 0;
}

.ins-disruptions > * {
    min-width: 0;
}

/* Column layout so the head and foot keep their natural size and the scroll region takes
   whatever is left -- which is what makes three panels of identical height line up. */
.ins-disruptions > .ins-card {
    height: var(--ins-disruptions-h);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}

/* min-height:0 is load-bearing, not decoration. A flex child defaults to min-height:auto,
   which refuses to shrink below its content -- so without this the list grows past the card
   instead of scrolling inside it, and the panels go back to being different heights. */
.ins-disruptions__scroll {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* The map fills whatever the head and foot leave. Leaflet measures its container on
   creation, and the card's explicit height means that resolves to a real pixel value. */
.ins-disruptions__canvas {
    flex: 1 1 auto;
    width: 100%;
    border-radius: 8px;
    overflow: hidden;
}

/* Below this the three-across row makes each list too narrow to read, so the map takes the
   full width and the two lists sit side by side beneath it -- still side by side, which is
   the part that keeps the click-to-zoom loop short. */
@media (max-width: 1400px) {
    .ins-disruptions {
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    }

    .ins-disruptions__map {
        grid-column: 1 / -1;
    }
}

@media (max-width: 900px) {
    .ins-disruptions {
        grid-template-columns: minmax(0, 1fr);
    }
}


/* ---------- Conditions strip (disruptions page) ----------
   Current conditions and the week ahead, across the top of the page. The data already
   arrives with the warnings, so this draws what was previously being fetched and thrown
   away -- it costs no extra API calls.

   A row rather than a card in the grid below, because a forecast is context for the whole
   page rather than a fourth thing to compare against the other three. */

.ins-conditions {
    /* height:auto is load-bearing. .ins-card sets height:100%, and the page wrapper this sits
       in (.content.ins-canvas) is a flex container whose .ins-page child stretches to the full
       viewport -- so that 100% resolved against a definite ~826px and the strip took nearly
       two thirds of the screen. grid-auto-rows:1fr below then expanded the tiles to fill it,
       turning a 140px strip into an 800px one. Content height, stated explicitly. */
    height: auto;
    flex: 0 0 auto;

    display: flex;
    align-items: stretch;
    gap: 20px;
    flex-wrap: wrap;
    margin-bottom: 16px;
}

.ins-conditions__now {
    flex: 0 0 auto;
    min-width: 210px;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-right: 20px;
    border-right: 1px solid var(--ins-line);
}

/* The divider only makes sense while the two sit on one line. */
@media (max-width: 820px) {
    .ins-conditions__now {
        border-right: none;
        padding-right: 0;
    }
}

.ins-conditions__temp {
    font-size: 2.4rem;
    font-weight: 600;
    line-height: 1.1;
    color: var(--ins-ink);
    font-variant-numeric: tabular-nums;
}

.ins-conditions__where {
    font-size: .95rem;
    font-weight: 600;
    color: var(--ins-ink);
}

.ins-conditions__detail {
    font-size: .78rem;
    color: var(--ins-ink-muted);
}

/* auto-fit rather than a fixed count: seven days fit on a wide screen and reflow to fewer
   columns instead of overflowing, which is how the other rows on this page behave. */
.ins-conditions__days {
    flex: 1 1 420px;
    min-width: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(92px, 1fr));

    /* Equal rows, not content-sized ones. Once the tiles wrap onto a second line each grid
       row would otherwise size to its own tallest tile, so the row holding a wordy forecast
       stood ~30px taller than the one below it and the strip looked ragged. */
    grid-auto-rows: 1fr;

    /* Rows pack to the top rather than sharing out spare height. With grid-auto-rows:1fr a
       container that is ever taller than its content would stretch the tiles to fill it. */
    align-content: start;
    gap: 8px;
}

.ins-conditions__day {
    text-align: center;
    padding: 10px 6px;
    border: 1px solid var(--ins-line);
    border-radius: 10px;
    background: var(--ins-canvas);
    min-width: 0;
}

.ins-conditions__day--today {
    border-color: var(--ins-blue);
    background: var(--ins-surface);
}

.ins-conditions__dayname {
    font-size: .74rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--ins-ink-muted);
}

.ins-conditions__range {
    font-size: .95rem;
    font-weight: 600;
    color: var(--ins-ink);
    font-variant-numeric: tabular-nums;
}

.ins-conditions__precis {
    font-size: .72rem;
    color: var(--ins-ink-muted);
    /* Two lines then clip: "Shower or two developing" must not make one tile taller than
       its neighbours and ripple the whole row. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.ins-conditions__rain {
    font-size: .72rem;
    font-weight: 600;
    color: var(--ins-blue);
}

/* ---------- Freight at risk ----------
   A page of stacked incident panels, each holding a short table of consignments. Its shape
   differs from the dashboards in two ways that need saying rather than fighting. */

/* Content height, stated explicitly -- the same trap .ins-conditions documents above.
   .ins-card sets height:100%, and .ins-page sits inside a flex container (.content.ins-canvas)
   that stretches to the viewport, so that 100% resolves against a definite height rather than
   collapsing to auto. Without this every incident panel is a full screen tall, however few rows
   it holds, and a page of six incidents becomes six screens of mostly whitespace. */
.ins-card--fit {
    height: auto;
    flex: 0 0 auto;
}

/* Two equal stat tiles. .ins-measure-row is 2fr/1fr because it pairs a chart with a figure
   beside it; here both children are figures and the lopsided split just makes one number
   look more important than the other. */
.ins-stat-row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
    width: 100%;
    min-width: 0;
    margin-bottom: 16px;
}

@media (max-width: 700px) {
    .ins-stat-row {
        grid-template-columns: 1fr;
    }
}

/* .ins-figure reserves 220px because it stands in for a missing chart and has to hold that
   space open. These tiles never stand in for anything -- they are a number and a caption at
   the top of a page whose real content is below them -- so the reserved height is pure cost,
   pushing the first incident under the fold. Overrides the flex-grow .ins-measure applies for
   the same reason. */
.ins-figure--compact {
    min-height: 0;
    flex: 0 0 auto;
    font-size: 2.1rem;
    justify-content: flex-start;
    padding: 0;
    line-height: 1.15;
}

/* The card primitives space themselves for a card with a chart in it. In a tile that is three
   short lines, those gaps are most of the height -- so the head margin, the rule above the
   footnote and the footnote's own padding are all pulled in. Scoped to the row rather than
   applied to the primitives, which the dashboards still want at full size. */
.ins-stat-row .ins-card {
    padding: 14px 16px;
}

.ins-stat-row .ins-card__head {
    margin-bottom: 6px;
}

.ins-stat-row .ins-card__title {
    margin-bottom: 0;
}

.ins-stat-row .ins-card__foot {
    margin-top: 8px;
    padding-top: 8px;
}

/* The incident header is the expand/collapse control, so it has to look like one. */
.ins-incident__head {
    cursor: pointer;
    user-select: none;
}

.ins-incident__head:hover .ins-card__title {
    color: var(--ins-blue);
}

.ins-incident__chevron {
    color: var(--ins-ink-muted);
}

/* An expanded incident is capped rather than allowed to run to its natural height. Collapsing is
   what stops a busy incident hiding the others; this is what stops the one that IS open doing the
   same. Roughly eight rows, which is enough to see the shape of the freight and judge whether to
   scroll -- and the inner scrollbar is itself the signal that there is more. */
.ins-incident__rows {
    max-height: 320px;
    overflow-y: auto;
}

/* Pinned, because the cap above means these rows scroll. Six columns of consignment data are
   unreadable once "Due" and "Why flagged" have scrolled off, and an operator halfway down a
   24-row list should not have to scroll back up to remember which column is which. Needs its
   own background: sticky leaves the cell transparent and the rows run underneath it. */
.ins-incident__rows thead th {
    position: sticky;
    top: 0;
    z-index: 1;
    background: var(--ins-surface);
}

/* ---------- Issues ---------- */

/* The search box in a filter toolbar. Everything else in the bar is sized to its content, but a
   search field with room for one word invites one-word searches -- so this one takes the slack and
   still collapses to a usable width when the bar wraps. */
.ins-field--grow {
    flex: 1 1 260px;
    min-width: 220px;
}

/* An issue form is long enough that unlabelled blocks of inputs stop reading as groups. */
.ins-form-section {
    margin: 22px 0 10px;
    font-size: .78rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--ins-blue);
}

.ins-form-section:first-child {
    margin-top: 4px;
}

/* The linked-consignment chips on an issue, and the linked-issue chips on a consignment. */
.ins-link-row {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    align-items: center;
}

/* Status tiles across the top of the issues insights page. Auto-fit rather than a fixed column
   count, so adding a sixth status re-flows instead of overflowing the row. */
.ins-status-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 12px;
    width: 100%;
}

.ins-status {
    border-left: 4px solid var(--ins-line);
    cursor: pointer;
    padding: 14px 16px;
}

.ins-status:hover {
    box-shadow: 0 2px 4px rgba(18, 35, 63, .10), 0 10px 24px rgba(18, 35, 63, .10);
}

.ins-status__figure {
    font-size: 1.9rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.ins-status__label {
    font-size: .74rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ins-ink-muted);
    margin-top: 2px;
}

.ins-status__share {
    font-size: .72rem;
    color: var(--ins-ink-muted);
    margin-top: 6px;
}

/* Ranked bar lists. A list rather than a MudChart because the labels are long sentences -- a bar
   chart would either truncate them or spend most of its width on the axis. */
.ins-bars {
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.ins-bar__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin-bottom: 4px;
}

.ins-bar__label {
    font-size: .82rem;
    color: var(--ins-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.ins-bar__value {
    font-size: .78rem;
    font-weight: 700;
    color: var(--ins-blue-deep);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.ins-bar__pct {
    font-weight: 400;
    color: var(--ins-ink-muted);
    margin-left: 6px;
}

.ins-bar__track {
    height: 6px;
    border-radius: 3px;
    background: var(--ins-line);
    overflow: hidden;
}

.ins-bar__fill {
    height: 100%;
    border-radius: 3px;
    background: var(--ins-blue);
}
