/* ─── TABLE OF CONTENTS ──────────────────────────────────
    1. Global / Reset
    2. Layout             (container, main-content)
    3. Login Page
    4. Sidebar
    5. Cards              (dashboard-card, machine-card, idle-card)
    6. OEE Summary Banner
    7. Progress Bars
    8. Animations & Floating Button
    9. Toasts
   10. DataTables
   11. Gauges
   12. Responsive Columns (Dashboard)
   13. Under Development Page
   14. Navbar
   15. Alarms             (alarm-card, alarms-summary-banner)
   16. Electricity Cards
   17. Buttons            (global pill .btn system + .btn-gas)
   18. Accordion
   19. CloEE Advisor Panel
   20. Chat Messages
   21. Table Scroll & Modal
   22. Scroll-to-Bottom
   23. Table Card Wrapper (production flow dashboard style)
   24. Unit drag-and-drop (admin)
   25. Machine Card (shared: dashboard + chat) — themed states, warning labels, gauge wrapper
─────────────────────────────────────────────────────────── */

/* === 0. Theme Tokens =====================================
   Semantic colour tokens. Light is the default (look unchanged).
   Dark mode is activated by data-bs-theme="dark" on <html>
   (Bootstrap 5.3 native color mode — see theme_scripts.html).
   Rule: new UI colours must reference a token, never a raw hex.
─────────────────────────────────────────────────────────── */
:root {
    --surface:        #ffffff;          /* card bodies, panels        */
    --surface-2:      #f8f9fa;          /* card headers, sidebar, head */
    --surface-sunken: #e9ecef;          /* wells, track backgrounds    */
    --text:           #212529;          /* primary text                */
    --text-muted:     #6c757d;          /* secondary text              */
    --border:         #dee2e6;          /* borders, dividers           */
    --link:           #0d6efd;          /* links / primary accent      */
    --navbar-bg:      rgb(139, 139, 139);
    --gauge-track-opacity: 0.18;        /* tune inactive gauge arc     */
    --gauge-track:    #000000;          /* inactive gauge arc base     */
    --gauge-text:     #212529;          /* gauge centre number         */
    --chart-paper:    #ffffff;          /* Plotly paper/plot bg        */
    --chart-grid:     rgba(0, 0, 0, 0.08);
    /* Status hues are identical in both modes (green/amber/red). */
    /* Text colour for dark-on-tint chips/headers (flips to a light variant on dark). */
    --danger-text:    #842029;
    --warning-text:   #664d03;
    /* Severity scale. The *hue* tokens are for borders, tints and icons sitting on a
       tint — they are the app's existing status hexes, named so a component never has
       to repeat them. As foreground text none of them clears WCAG AA against --surface,
       so a label uses the matching *-text token below, which does. */
    --sev-critical:   #dc3545;
    --sev-warning:    #d89100;          /* the app's canonical amber (report KPI, energy) */
    --sev-setup:      var(--link);
    --sev-ok:         #198754;
    --setup-text:     #084298;
    --ok-text:        #0a3622;
}

html[data-bs-theme="dark"] {
    --surface:        #1f2630;          /* cards/panels — elevated, clearly above the body */
    --surface-2:      #12161d;          /* body / sidebar / table-head base                */
    --surface-sunken: #0c0f15;          /* wells, tracks                                    */
    --text:           #e6e8eb;
    --text-muted:     #9aa3ad;
    --border:         #2c333d;
    --link:           #5aa6ff;
    --navbar-bg:      #11161d;
    --gauge-track-opacity: 0.34;
    --gauge-track:    #000000;
    --gauge-text:     #e6e8eb;
    --chart-paper:    #1f2630;
    --chart-grid:     rgba(255, 255, 255, 0.10);
    --danger-text:    #f1aeb5;
    --warning-text:   #ffe69c;
    /* Hues hold, per the rule above; only the readable text variants flip. */
    --sev-critical:   #dc3545;
    --sev-warning:    #d89100;
    --sev-setup:      var(--link);
    --sev-ok:         #198754;
    --setup-text:     #9ec5fe;
    --ok-text:        #a3cfbb;
    color-scheme: dark;
}

/* Page background follows the theme on dark; light is left to Bootstrap. */
html[data-bs-theme="dark"] body {
    background-color: var(--surface-2);
    color: var(--text);
}

/* === 1. Global / Reset === */
body {
    font-family: Arial, sans-serif;
    margin: 0;
    padding: 0;
    overflow-x: hidden;
}

h1 {
    color: var(--text);
}

ul {
    list-style-type: none;
    padding: 0;
}

li {
    margin: 10px 0;
}

/* Anchors inherit their context's size. This used to force `font-size: 18px` on every
   anchor in the app, which is why ~300 rules downstream re-declare a font-size just to
   claw a link back to the size of the text around it.

   Hover shifts the colour instead of underlining. The blanket `a:hover { text-decoration:
   underline }` out-specified every single-class `text-decoration: none`, so ~31 components
   carried a defensive override and the ones that forgot (nav rows, KPI values, chips)
   underlined on hover for no reason. Prose links keep the underline — see .prose below. */
a {
    text-decoration: none;
    color: var(--link);
}

a:hover {
    color: color-mix(in srgb, var(--link) 78%, var(--text));
}

/* Inline links inside running text still need the underline to be findable. Opt in by
   marking the container, not by underlining every anchor in the application. */
.prose a,
.content-body a {
    text-decoration: underline;
}

/* === 2. Layout === */
.container {
    width: 100%;
    max-width: 1600px; /* Optional max width */
    margin: 0 auto;
    padding: 20px 40px; /* Consistent spacing left and right */
}

.main-content {
    /* Sidebar floats with a 12px margin, so content clears 220px + 12px gap.
       Bottom padding reserves room for the docked Ask CloEE bar so page
       content is never hidden behind it. The navbar offset (was 60px top) is
       gone now that the top navbar has been removed. */
    margin-left: 244px;
    transition: margin-left 0.3s ease;
    padding: 24px 24px 104px 24px;
}

/* Flicker-free sidebar collapse: use .sidebar-collapsed on html/body */
.sidebar-collapsed .main-content {
    margin-left: 84px;
}

/* === 3. Login Page === */
/* Applied via class="login-page" on <body> in login.html */
html:has(body.login-page) {
    height: 100%;
}
.login-page {
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-top: 40px;
    padding-bottom: 40px;
    background-color: #f5f5f5;
}

/* === 4. Sidebar === */
/* Detached "floating" sidebar: inset from the viewport edges with a rounded
   card look so the app reads as more spacious (navbar removed). */
#sidebar {
    display: flex;
    flex-direction: column;
    top: 12px;
    left: 12px;
    height: calc(100vh - 24px);
    background-color: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 8px 28px rgba(0, 0, 0, 0.12);
    transition: width 0.3s ease;
    overflow: hidden;
    white-space: nowrap;
    padding-top: 0;
    position: fixed;
    width: 220px;
    /* position:fixed makes #sidebar a stacking context, which *traps* the
       collapsed-sidebar hover flyout (.sidebar-group:hover > .collapse, z-index
       1100) at this element's root-level layer no matter how high its own
       z-index is. Keep this above the Ask CloEE bar (1045) and its notice (1046)
       so the flyout is never painted under them, but below Bootstrap modal
       backdrops (1050) and toasts (1055) so real modals still cover the sidebar.
       Dropped back below the chat overlay while it's open — see body.agentic-open
       rule below. */
    z-index: 1048;
}

/* While the centred Ask CloEE conversation overlay (agentic-overlay, z-index
   1035) is open, its dialog is centred at 50vw and can extend near the sidebar
   on narrow viewports. Drop the sidebar back under the overlay so the dialog
   cleanly covers it; the backdrop hides the sidebar anyway, so the flyout can't
   be triggered in this state (which is the only reason the sidebar sits above
   the Ask bar in the first place). */
body.agentic-open #sidebar {
    z-index: 100;
}

/* Lock the page underneath while the overlay is open. The dialog is deliberately
   chrome-free (no fill on the rail gaps or the backdrop itself), so without this a wheel
   event that lands there has no scrollable ancestor to consume it and falls through to the
   page behind, which visibly shifts under the blur. */
body.agentic-open {
    overflow: hidden;
}

/* Sidebar header: CloEE wordmark + collapse control */
.sidebar-header {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.4rem;
    padding: 14px 14px 12px;
    border-bottom: 1px solid var(--border);
}

.sidebar-logo-link {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
    text-decoration: none;
}

.sidebar-logo-img {
    height: 26px;
    width: auto;
}

.sidebar-collapsed #sidebar .sidebar-header {
    justify-content: center;
    padding: 14px 0 12px;
}
.sidebar-collapsed #sidebar .sidebar-logo-link {
    display: none;
}

.sidebar-collapsed #sidebar {
    width: 60px;
}

/* Sidebar collapse / expand button (lives in the header) */
#sidebar-toggle {
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    background: var(--surface);
    color: var(--text-muted);
    border: 1px solid var(--border);
    border-radius: 8px;
    font-size: 14px;
    cursor: pointer;
    transition: background-color 0.2s ease, color 0.2s ease;
}

#sidebar-toggle:hover {
    background: var(--surface-sunken);
    color: var(--text);
}

/* Sidebar links */
.sidebar-link {
    padding: 12px 16px;
    display: flex;
    align-items: center;
    color: var(--text);
    text-decoration: none;
    transition: all 0.2s ease;
    border-left: 4px solid transparent;
}

.sidebar-link:hover,
.sidebar-link:focus {
    background-color: var(--surface-sunken);
    color: var(--text);
}

.sidebar-link.active {
    font-weight: bold;
    color: var(--link);
    background: color-mix(in srgb, var(--link) 12%, color-mix(in srgb, var(--surface) 78%, transparent));
    border-left: 4px solid color-mix(in srgb, var(--link) 70%, var(--border));
    border-radius: 6px;
    margin: 0;
    padding-left: 12px;
}

.sidebar-link.active:hover {
    background: color-mix(in srgb, var(--link) 16%, var(--surface));
}

.sidebar-link i {
    margin-right: 12px;
    width: 20px;
    text-align: center;
}

.sidebar-collapsed #sidebar .sidebar-link span {
    display: none;
}

.sidebar-collapsed #sidebar .sidebar-link i {
    margin-right: 0;
}

/* Icon-only rail rows. Scoped away from .sidebar-link-sub: those live in the
   hover flyout, which is a normal labelled menu — centring them (and dropping
   their accent border) would misalign the active item against its siblings. */
.sidebar-collapsed #sidebar .sidebar-link:not(.sidebar-link-sub).active {
    background: color-mix(in srgb, var(--link) 12%, color-mix(in srgb, var(--surface) 78%, transparent));
    border-left: none;
    border-radius: 8px;
    margin: 0;
    justify-content: center;
}

.sidebar-collapsed #sidebar .sidebar-link:not(.sidebar-link-sub).active i {
    color: var(--link);
}

/* Collapsible sidebar group (e.g., Configuration > Jobs / System / Users / Factories) */
.sidebar-group-header {
    cursor: pointer;
}

/* Collapsed rail: a group whose section is the current page marks its own icon.
   Otherwise the rail shows no active state at all for grouped pages (Energy,
   Manage) — the marked sub-link only exists inside the hover flyout. Styled at
   the same tint as .sidebar-link.active but without its left accent, so the
   icon stays optically centred on the 60px rail (nothing shifts on activation).
   Expanded, the open group already marks the sub-link, so this stays scoped. */
.sidebar-collapsed #sidebar .sidebar-group-header.active-group {
    background: color-mix(in srgb, var(--link) 12%, color-mix(in srgb, var(--surface) 78%, transparent));
    border-radius: 8px;
}

.sidebar-collapsed #sidebar .sidebar-group-header.active-group:hover,
.sidebar-collapsed #sidebar .sidebar-group-header.active-group:focus {
    background: color-mix(in srgb, var(--link) 16%, var(--surface));
}

.sidebar-collapsed #sidebar .sidebar-group-header.active-group i {
    color: var(--link);
}

.sidebar-group-header .bi-chevron-down {
    margin-left: auto;
    font-size: 0.85em;
    transition: transform 0.2s ease;
}

.sidebar-group-header[aria-expanded="false"] .bi-chevron-down {
    transform: rotate(-90deg);
}

.sidebar-link-sub {
    padding-left: 44px;
    font-size: 0.95em;
    color: var(--text-muted);
}

.sidebar-link-sub.active {
    background: color-mix(in srgb, var(--link) 12%, color-mix(in srgb, var(--surface) 78%, transparent));
    color: var(--link);
    border-left: 4px solid color-mix(in srgb, var(--link) 70%, var(--border));
    border-radius: 6px;
    margin: 0;
    padding-left: 40px;
}

.sidebar-collapsed #sidebar .sidebar-link-sub {
    display: none;
}

.sidebar-collapsed #sidebar .sidebar-group-header .bi-chevron-down {
    display: none;
}

/* Collapsed sidebar: reveal a group's sub-links as a hover flyout so they can be
   clicked without expanding the whole sidebar. The flyout is position:fixed so it
   escapes the sidebar's clipping (#sidebar overflow:hidden, .sidebar-links
   overflow-y:auto) without disabling the sidebar's own scrolling. Its vertical
   position (`top`) is set by positionSidebarFlyout() in cloeecore.html, which
   clamps it to the viewport so it opens upward near the bottom of the screen. */
.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse {
    display: block !important; /* override Bootstrap's collapse-hidden state */
    position: fixed;
    left: 72px; /* fallback (12px sidebar inset + 60px collapsed width); overwritten by JS on hover */
    top: 0; /* fallback; overwritten by JS on hover */
    min-width: 200px;
    padding: 6px;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 .55rem 1.2rem color-mix(in srgb, var(--text) 18%, transparent);
    z-index: 1100;
}

/* Every flyout row reserves the same 3px accent gutter and border-radius, so the
   active row reads as an inset pill rather than an edge-to-edge block, and
   labels never shift horizontally as the active item changes. */
.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub {
    display: flex !important;
    padding: 9px 12px;
    border-left: 3px solid transparent;
    border-radius: 8px;
    font-weight: 500;
}

.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub:hover {
    background: var(--surface-sunken);
    color: var(--text);
}

.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub span {
    display: inline !important;
}

.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub i {
    margin-right: 12px;
}

/* Active flyout item: an inset pill with a left accent, matching how the
   expanded sidebar marks its active row. Theme tokens only, so it stays
   readable in both light and dark. */
.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub.active {
    background: color-mix(in srgb, var(--link) 14%, transparent);
    color: var(--link);
    border-left-color: var(--link);
    font-weight: 600;
}

.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub.active:hover {
    background: color-mix(in srgb, var(--link) 20%, transparent);
    color: var(--link);
}

.sidebar-collapsed #sidebar .sidebar-group:hover > .collapse .sidebar-link-sub.active i {
    color: var(--link);
}

.sidebar-links {
    flex: 1 1 auto;
    overflow-y: auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* Flips the scrollbar to the left edge: collapsed-rail icons use right-placed
       Bootstrap tooltips/flyouts, and a right-edge scrollbar sits on top of that
       hover target, dropping the hover and closing the tooltip before it can be
       read. Direction only affects the inline axis, not this column's stacking
       order, so rows still list top-to-bottom in source order. */
    direction: rtl;
}

.sidebar-links > * {
    direction: ltr;
}

.sidebar-user-info {
    flex-shrink: 0;
    /* Remove absolute positioning and related properties */
    position: static;
    left: unset;
    bottom: unset;
    width: 100%;
    padding: 8px 12px;
    text-align: left;
    /* No block-level opacity here: it would bleed into the fixed account-card
       flyout (opacity groups the whole subtree and a child cannot opt out),
       washing it out over page content. Rows mute themselves via tokens. */
    font-size: 0.95em;
    pointer-events: auto;
    transition: visibility 0.2s;
    z-index: 200;
    background: var(--surface-2);
    border-top: 1px solid var(--border);
}

.sidebar-user-info * {
    pointer-events: auto;
}
.sidebar-user-info .sidebar-logout-btn,
.sidebar-user-info .sidebar-user-email-text {
    display: inline-flex;
}
/* Collapsed rail: hide the inline email/logout rows. Scoped to the trigger
   (.sidebar-user-email) and the action row so the hover card below — which
   carries the same data for the collapsed state — keeps its own sizing. */
.sidebar-collapsed #sidebar .sidebar-user-actions .sidebar-logout-btn,
.sidebar-collapsed #sidebar .sidebar-user-email .sidebar-user-email-text {
    display: none !important;
}
.sidebar-collapsed #sidebar .sidebar-user-email .bi-person-circle {
    display: inline-block;
    font-size: 20px !important;
    margin-right: 0 !important;
}
.sidebar-collapsed #sidebar .sidebar-user-info {
    text-align: center;
    padding-left: 0 !important;
    padding-right: 0 !important;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 8px;
}
.sidebar-collapsed #sidebar .sidebar-user-block {
    align-items: center;
    width: 100%;
}

.sidebar-logout-btn {
    display: flex;
    align-items: center;
    font-size: 0.93em;
    color: var(--text-muted) !important;
    margin-left: 0;
    padding: 0;
    background: none;
    border: none;
    text-decoration: none;
    gap: 3px;
    opacity: 0.7;
    transition: opacity 0.2s, color 0.2s;
    cursor: pointer;
}
.sidebar-logout-btn i {
    color: var(--text-muted) !important;
    font-size: 1em;
    transition: color 0.2s;
}
.sidebar-logout-btn:hover {
    opacity: 1;
    color: var(--link) !important;
    text-decoration: underline;
}
.sidebar-logout-btn:hover i {
    color: var(--link) !important;
}

/* === 5. Cards === */
.dashboard-card {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    overflow: hidden;
    transition: 0.3s ease-in-out;
    text-decoration: none;
    color: inherit;
    background-color: var(--surface);
    border: 1px solid var(--border);
}

.dashboard-card:hover {
    transform: scale(1.05);
    box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
}

.dashboard-card.machine-card {
    --machine-card-accent: var(--text);
    height: 100%;
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 0;
    position: relative;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.08);
}

.machine-card-main-link {
    min-width: 0;
    display: flex;
    flex: 1 0 auto;
    flex-direction: column;
    color: inherit;
    text-decoration: none;
}

.machine-card-main-link:hover,
.machine-card-main-link:focus {
    color: inherit;
}

/* Flex, not grid: a grid's minmax(0,1fr) middle column spans the FULL leftover
   width even for a short name, and text-align:center then centers the name
   within that whole span — which pushes the icons out to the true edges with a
   big empty gap on each side of the name. Flex + justify-content:center instead
   packs [icon][gap][name][gap][icon] as one cluster and centers the cluster, so
   any leftover width lands outside the icons (toward the true edge) rather than
   between an icon and the name. Icon *chrome* (padding, margins, borders) stays
   roomy by default — see fitMachineCardTitles() in dashboard.html, which only
   adds .name-tight, and the CSS below only compacts under it, for the specific
   cards whose name doesn't fit even once shrunk to the font floor. */
.dashboard-card.machine-card .card-header {
    font-size: 24px;
    font-weight: 700;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.25rem 0.5rem 0.2rem;
    background-color: transparent;
    color: var(--machine-card-accent);
    border-bottom: 0;
}

/* Still meaningfully tighter than the roomy 0.5rem+0.5rem (16px) horizontal
   clearance, but never below ~half the card's 16px border-radius: any less and an
   icon's own box starts overlapping the rounded-corner arc rather than sitting
   inside the flat part of the corner. That overlap reads as "badge glued to the
   corner" — sharper icons (an octagon) show it more than round ones (a circle),
   so it looked like only some icons were positioned badly when in fact every icon
   sat at the identical, too-tight offset. */
.machine-card.name-tight .card-header {
    padding: 0.25rem 0.35rem 0.2rem;
}

.dashboard-card.machine-card .card-body {
    flex: 1 0 auto;
    padding: 0.25rem 0.75rem 0.8rem;
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    font-size: 0.9rem;
}

/* Classic dashboard machine-card details: muted labels establish hierarchy while
   bold values remain scannable on the factory floor. */
.dashboard-card.machine-card .gauge-wrapper {
    width: min(100%, 150px);
    max-width: 150px;
}

.machine-card-detail {
    min-width: 0;
    margin: 0;
    color: var(--text);
    line-height: 1.25;
}

.machine-card-job,
.machine-card-idle {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: center;
    column-gap: 0.3rem;
}

.machine-card-timing {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.4rem;
}

.machine-card-timing-item {
    display: flex;
    flex-direction: column;
    gap: 0.14rem;
    text-align: center;
}

/* A formatted start timestamp is one value, not a date plus a separate time.
   Keep it on one line within its timing column. */
.machine-card-timing-item .machine-card-detail-value {
    white-space: nowrap;
}

.machine-card-detail-label {
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 600;
    opacity: 0.5;
}

.machine-card-detail-value {
    min-width: 0;
    color: var(--text);
    font-weight: 700;
    overflow-wrap: anywhere;
}

/* No job reported: said quietly, so it doesn't read as a job named "No program". */
.machine-card-detail-value.is-empty { color: var(--text-muted); font-weight: 600; }

/* The name owns the header. The live lamp sits alone on the left, while warning
   and machine-state icons share the right tray; neither side shifts the name. */
#dashboard-cards-row .dashboard-card.machine-card .card-header {
    min-width: 0;
}

/* Single line is the default. fitMachineCardTitles() (dashboard.html) sets
   --machine-card-title-size once on the row — one size for every card, so the board
   reads as one system — and adds .machine-card-title--wrap (below) per card to the
   handful of names that need a second line at that size. flex-shrink lets the name
   give up width to the fixed-size icon trays before either happens. */
#dashboard-cards-row .machine-card-title {
    display: block;
    flex: 0 1 auto;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: var(--machine-card-title-size, inherit);
    text-align: center;
}

/* For names too long for one line at the grid's shared size: wrap to two instead of
   shrinking the whole board a step further. Only offered at or below label size
   (TITLE_WRAP_MAX_SIZE in dashboard.html) — two lines at a display size read as a
   headline and swamp the gauge. overflow-wrap stays `normal`: breaking inside a word turns
   CARBURIZE BAY 07 into "CARBURI / ZE BAY 07", which reads as a broken name rather
   than a wrapped one. A word too wide for the column therefore overflows instead,
   which is exactly what titleOverflowsWrapped() (dashboard.html) tests for before
   accepting the size. */
#dashboard-cards-row .machine-card-title.machine-card-title--wrap {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: normal;
    /* Two lines of a name are one thing, not two — the body's 1.5 leading is generous
       enough that the second line would cost a card ~18px of height for whitespace the
       name doesn't need. --machine-card-title-wrap-leading is what the header below
       reserves; keep the two in step. */
    line-height: var(--machine-card-title-wrap-leading, 1.05);
}

/* A wrapped header is a line taller than a single-line one, which would stagger the
   gauges across the row. Once any name in the grid wraps, every header reserves both
   lines (the trays and the name stay vertically centred in it) — the tight leading
   above keeps that reservation to roughly one extra line of text, not one and a half.
   The padding term matches .card-header's own 0.25rem + 0.2rem. */
#dashboard-cards-row.machine-titles-wrapped .dashboard-card.machine-card .card-header {
    min-height: calc(
        var(--machine-card-title-size, 24px) * var(--machine-card-title-wrap-leading, 1.05) * 2
        + 0.45rem
    );
}

/* Default: the live lamp keeps its own inset from the card's true edge and a
   comfortable gap to the title. flex: 0 0 auto keeps the tray at its natural
   (icon + padding) size — it never grows or shrinks. */
.machine-card-live-icons {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    min-width: 0;
    padding-left: 0.5rem;
    margin-right: 0.4rem;
    line-height: 1;
}

.machine-card-status-icons {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    gap: 0.35rem;
    padding-right: 0.5rem;
    margin-left: 0.4rem;
    line-height: 1;
}

/* Only on a card whose name still doesn't fit at the smallest font (see
   fitMachineCardTitles()) do the trays give most of their inset up — tighter, but
   not flush: see the corner-clearance note on .name-tight .card-header above,
   which this pairs with. */
.machine-card.name-tight .machine-card-live-icons {
    padding-left: 0.15rem;
    margin-left: 0;
    margin-right: 0.15rem;
}

.machine-card.name-tight .machine-card-status-icons {
    padding-right: 0.15rem;
    margin-left: 0.15rem;
    gap: 0.2rem;
}

/* Missing ideal time is actionable without competing with the live runtime in
   the footer. It belongs with the other warning/status icons on the right, and
   keeps a light bordered chip by default — like the original outline button,
   just built with plain CSS instead of Bootstrap's .btn so the tight variant
   below can strip it cleanly for the handful of cards that need the room. */
.machine-card-ideal-time-action {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    min-width: 1.55rem;
    min-height: 1.55rem;
    padding: 0.15rem;
    border: 1px solid color-mix(in srgb, #fd7e14 45%, var(--border));
    border-radius: 0.35rem;
    background: color-mix(in srgb, #fd7e14 8%, transparent);
    color: #fd7e14;
    line-height: 1;
    text-decoration: none;
}

.machine-card-ideal-time-action:hover,
.machine-card-ideal-time-action:focus {
    color: #c25e08;
    background: color-mix(in srgb, #fd7e14 16%, transparent);
}

/* Its label is visually-hidden, so the focus ring is the only keyboard affordance. */
.machine-card-ideal-time-action:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: 2px;
}

.machine-card-ideal-time-action[hidden] {
    display: none;
}

.machine-card-ideal-time-action .bi {
    font-size: 0.82rem;
}

.machine-card.name-tight .machine-card-ideal-time-action {
    min-width: 0;
    min-height: 0;
    padding: 0;
    border: none;
    background: transparent;
}

.machine-card.name-tight .machine-card-ideal-time-action .bi {
    font-size: 0.95rem;
}

.machine-card-downtime-indicator {
    display: inline-flex;
    flex: 0 1 auto;
    align-items: center;
    gap: 0;
    min-width: 0;
    color: var(--machine-card-accent);
    font-size: 0.78rem;
    font-weight: 700;
    line-height: 1;
}

.machine-card-downtime-indicator .bi {
    flex: 0 0 auto;
    font-size: 0.95rem;
}

/* Idle/no-program state uses the same compact header affordance as downtime. */
.machine-card-idle-indicator {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    color: #fd7e14;
    font-size: 0.95rem;
    line-height: 1;
}

/* A live batch uses a compact, gently pulsing status lamp in the same header
   tray as the idle and downtime indicators. The accessible label and tooltip
   provide the state for users who cannot rely on the colour or motion alone. */
.machine-card-running-indicator {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    color: #198754;
    font-size: 0.58rem;
    line-height: 1;
    animation: machine-card-live-pulse 2.4s ease-in-out infinite;
}

@keyframes machine-card-live-pulse {
    0%, 100% { opacity: 0.38; transform: scale(0.88); }
    50% { opacity: 1; transform: scale(1); }
}

html[data-bs-theme="dark"] .machine-card-running-indicator {
    color: #75b798;
}

@media (prefers-reduced-motion: reduce) {
    .machine-card-running-indicator,
    .integration-live-dot {
        animation: none;
    }
}

/* "Ignition Connected" (per-factory flag): a faded caption above the unit
   name and a small, slow-breathing lamp in the top-right corner — present but
   quieter than the header's own state icons. Absolutely positioned so the
   flex header and fitMachineCardTitles() are unaffected; the extra header
   top padding keeps the caption clear of the name. */
.machine-card.has-integration-badge .card-header {
    padding-top: 1.1rem;
}
.machine-card-integration {
    position: absolute;
    inset: 0.3rem 0.6rem auto;
    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;
    z-index: 1;
}
.machine-card-integration-label {
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1;
    letter-spacing: 0.02em;
    color: var(--text-muted);
    opacity: 0.5;
    white-space: nowrap;
}
.integration-live-dot {
    position: absolute;
    top: 0;
    right: 0;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--sev-ok);
    box-shadow: 0 0 0 2px color-mix(in srgb, var(--sev-ok) 22%, transparent);
    animation: machine-card-live-pulse 3.2s ease-in-out infinite;
}
.machine-card-integration .integration-live-dot {
    top: 50%;
    margin-top: -3.5px;
}
.dense-machine-card.has-integration-badge {
    position: relative;
}
.dense-machine-card .integration-live-dot {
    top: 0.3rem;
    right: 0.3rem;
    width: 6px;
    height: 6px;
}

/* Batch overruns use the same compact header affordance as downtime context;
   the detailed percentage is available on hover so warning cards stay aligned. */
.machine-card-overrun-indicator {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  line-height: 1;
  font-size: 0.95rem;
}
.machine-card-overrun-indicator.is-warning { color: #fd7e14; }
.machine-card-overrun-indicator.is-critical { color: #dc3545; }

/* Live-job progress is a card footer rather than another detail row: it stays
   flush to the lower edge while the card body above can keep a stable height. */
.machine-card-progress {
    --machine-card-progress-color: #198754;
    position: relative;
    z-index: 0;
    flex: 0 0 auto;
    min-height: 1.35rem;
    overflow: hidden;
    background: color-mix(in srgb, var(--machine-card-progress-color) 8%, var(--surface));
    border-top: 1px solid color-mix(in srgb, var(--machine-card-progress-color) 28%, var(--border));
    color: var(--text);
}

.machine-card-progress[hidden] {
    display: none;
}

.machine-card-progress.is-warning {
    --machine-card-progress-color: #fd7e14;
}

.machine-card-progress.is-critical {
    --machine-card-progress-color: #dc3545;
}

.machine-card-progress-track,
.machine-card-progress-fill {
    position: absolute;
    inset: 0;
}

.machine-card-progress-track {
    background: color-mix(in srgb, var(--border) 30%, var(--surface-2));
}

.machine-card-progress-fill {
    right: auto;
    width: 0;
    /* 72%, not 82%: the runtime label (var(--text)) sits directly on this fill
       once the bar reaches full width, and the critical/red state at 82% only
       measured ~4.3:1 in light mode (below WCAG AA's 4.5:1). 72% clears both
       themes with margin without materially changing the fill's colour. */
    background: color-mix(in srgb, var(--machine-card-progress-color) 72%, var(--surface));
    transition: width 0.35s ease, background-color 0.2s ease;
}

/* Match the machine-card timing value above: 0.9rem, bold, compact. */
.machine-card-progress-runtime {
    position: relative;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 1.35rem;
    color: var(--text);
    font-size: 0.9rem;
    font-weight: 700;
    line-height: 1;
    text-shadow: 0 1px 2px color-mix(in srgb, var(--surface) 65%, transparent);
}

/* No ideal time configured is a warning state, so it wears the same amber as the
   idle and overrun indicators. The stripe bands stay low-alpha mixes against
   --surface so var(--text) keeps its AA margin in both themes (see the contrast
   note on the progress fill above) rather than sitting on saturated #fd7e14. */
.machine-card-progress--unconfigured {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 1.35rem;
    padding: 0.2rem 0.5rem;
    background: repeating-linear-gradient(
        -45deg,
        color-mix(in srgb, #fd7e14 18%, var(--surface)),
        color-mix(in srgb, #fd7e14 18%, var(--surface)) 8px,
        color-mix(in srgb, #fd7e14 6%, var(--surface)) 8px,
        color-mix(in srgb, #fd7e14 6%, var(--surface)) 16px
    );
    border-top-color: color-mix(in srgb, #fd7e14 55%, var(--border));
    color: var(--text);
}

.machine-card-progress--unconfigured .machine-card-progress-runtime {
    min-height: 0;
}

/* Card state for idle machines (no active program) — amber/orange warning */
.idle-card {
    background-color: var(--surface);
    border: 2px solid #fd7e14;
}

/* Card state: idle on registered downtime — amber/yellow warning */
.downtime-card {
    background-color: #fffdf0;
    border: 2px solid #ffc107 !important;
}


/* Pill label for actively running machines */
.running-label {
    background-color: rgba(25, 135, 84, 0.1);
    border: 1px solid #198754;
    border-radius: 6px;
    padding: 4px 10px;
    color: #0a3622;
    font-size: 0.88rem;
    display: inline-block;
}

/* Pill label for idle machines (no downtime) — matches idle-card colors */
.idle-label {
    background-color: transparent;
    border: 1px solid #fd7e14;
    border-radius: 6px;
    padding: 4px 10px;
    color: #984c0c;
    font-size: 0.88rem;
    display: inline-block;
}

/* Downtime label shown inside idle-on-downtime cards */
.downtime-label {
    background-color: rgba(255, 193, 7, 0.15);
    border: 1px solid #ffc107;
    border-radius: 6px;
    padding: 4px 10px;
    color: #856404;
    font-size: 0.88rem;
    margin-top: 4px;
    margin-bottom: 8px;
    display: inline-block;
}

/* Warning label shown inside running-on-downtime cards */
.downtime-running-label {
    background-color: rgba(253, 126, 20, 0.12);
    border: 1px solid #fd7e14;
    border-radius: 6px;
    padding: 4px 10px;
    color: #7d3a00;
    font-size: 0.82rem;
    margin-top: 4px;
    margin-bottom: 8px;
    display: inline-block;
}

/* Alert for running-on-downtime state on unit details page */
.alert-downtime-running {
    background-color: rgba(253, 126, 20, 0.12);
    border: 1px solid #fd7e14;
    color: #7d3a00;
}

/* Alert for idle state on unit details page */
.alert-idle {
    background-color: #fffdf0;
    border: 1px solid #ffc107;
    color: #664d03;
}

/* Info button inside downtime-running alert */
.btn-downtime-info {
    background-color: rgba(253, 126, 20, 0.15);
    border: 1px solid #fd7e14;
    color: #7d3a00;
    font-size: 0.8rem;
    padding: 2px 8px;
    border-radius: 4px;
    line-height: 1.5;
}
.btn-downtime-info:hover {
    background-color: rgba(253, 126, 20, 0.25);
    color: #5a2900;
}

/* === 6. OEE Summary Banner === */
.oee-summary-banner {
    background-color: #ffc107;
    padding: 5px 10px; /* Less vertical space */
    color: #212529;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    border-radius: 6px;

    display: flex;
    justify-content: center;
    align-items: baseline;
    gap: 20px;
    flex-wrap: nowrap;
    text-align: center;
    overflow: hidden;
}
.alarms-summary-text,
.oee-summary-text {
    font-size: clamp(1.2rem, 3.5vw, 3rem);
    text-transform: uppercase;
    font-weight: 700;
    letter-spacing: 1px;
    margin: 0;
    white-space: nowrap;
}

.alarms-summary-value,
.oee-summary-value {
    font-size: clamp(1.2rem, 3.5vw, 3rem);
    font-weight: 800;
    margin: 0;
    white-space: nowrap;
}

/* === 7. Progress Bars === */
.progress {
    background-color: #e9ecef;
    border-radius: 10px;
    height: 16px;
    overflow: hidden;
}

.progress-bar {
    font-size: 0.8rem;
    line-height: 16px;
    border-radius: 10px;
}

/* === 8. Animations & Floating Button === */
.fade-in {
    animation: fadeIn 0.7s ease-in;
}

@keyframes fadeIn {
    from { opacity: 0; }
    to   { opacity: 1; }
}

/* Floating CloEE logo (display: none — kept for structural reference) */
.floating-logo-btn {
    position: fixed;
    bottom: 24px;
    right: 24px;
    width: 240px;
    height: 240px;
    z-index: 9999;
    transition: transform 0.3s ease;
    display: none !important;
}

.floating-logo-btn img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.floating-logo-btn:hover {
    transform: scale(1.2);
}

.custom-bg {
    background: linear-gradient(to right, #e2e8f0, #e5e7eb);
}

@media (prefers-color-scheme: dark) {
    .custom-bg {
        background: linear-gradient(to right, #1f2937, #111827);
        color: white !important;
    }
}

/* Disable card hover effect for jobs configuration page */
.dashboard-detail-card
.dashboard-detail-card:hover
.jobs-configuration-card,
.jobs-configuration-card:hover {
    transform: none !important;
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
}

/* === 9. Toasts === */
/* Toasts carry failures, so they must arrive promptly — the slide-in used to run for half a second
   from off-screen, which read as the app lagging behind the click. Entry is fast; the 5s hold is
   unchanged, because an error still has to survive the operator looking away. */
  .toast-container {
    position: fixed;
    bottom: 1rem;
    right: -350px;
    z-index: 1055;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    transition: right 0.18s ease-out, opacity 0.18s ease-out;
  }

  .toast-container.show {
    right: 1rem;
  }

  .toast-message {
    min-width: 250px;
    max-width: 350px;
    opacity: 0;
    animation: fadeSlideIn 0.18s forwards, fadeOut 0.5s 4.5s forwards;
  }

  @keyframes fadeSlideIn {
    from { opacity: 0; transform: translateX(100%); }
    to { opacity: 1; transform: translateX(0); }
  }

  @keyframes fadeOut {
    to { opacity: 0; transform: translateX(100%); }
  }

  @media (prefers-reduced-motion: reduce) {
    .toast-container {
      transition-duration: 0.01ms;
    }

    .toast-message {
      opacity: 1;
      animation: none;
    }
  }

/* Card overrides (disable hover except on machine-card) */
.card {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border-radius: 0.5rem;
    border: none;
    padding: 20px;
    margin-bottom: 10px;
  }

.dashboard-card {
  transition: none !important;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
}
.dashboard-card:hover {
  transform: none !important;
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1) !important;
}

.dashboard-card.machine-card {
  transition: transform 0.2s ease-in-out;
}
.dashboard-card.machine-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 12px 24px rgba(0, 0, 0, 0.2);
}

/* === 10. DataTables === */

.dataTables_wrapper {
  padding: 0.75rem;
  background-color: var(--surface-2);
  border-radius: 0 0 0.75rem 0.75rem;
  margin-top: 0;
  width: 100%;
}

.dataTables_wrapper .row { margin: 0; }

.dataTables_wrapper .dataTables_length,
.dataTables_wrapper .dataTables_filter {
  display: block !important;
  visibility: visible !important;
  margin-bottom: 0.75rem;
  padding: 0.5rem 0;
}

.dataTables_wrapper .dataTables_length label,
.dataTables_wrapper .dataTables_filter label {
  font-size: 0.875rem;
  font-weight: 500;
  color: #495057;
  margin-bottom: 0;
}

.dataTables_wrapper .dataTables_length select,
.dataTables_wrapper .dataTables_filter input {
  border: 1px solid #ced4da;
  border-radius: 0.375rem;
  padding: 0.375rem 0.75rem;
  font-size: 0.875rem;
}

.dataTables_wrapper .dataTables_length select:focus,
.dataTables_wrapper .dataTables_filter input:focus {
  border-color: #86b7fe;
  outline: 0;
  box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}

.dataTables_wrapper .dataTables_info {
  font-size: 0.875rem;
  color: #6c757d;
  padding-top: 0.75rem;
}

.dataTables_wrapper .dataTables_paginate { padding-top: 0.75rem; }

/* DataTables ships `.paginate_button { color:#333 !important }` AND paints the
   `.current`/`:hover` states with a white→grey `background:` gradient image, so
   every colour here needs !important and the `background` *shorthand* (not the
   longhand) to clear that gradient — in both light and dark modes. */
.dataTables_wrapper .dataTables_paginate .paginate_button {
  padding: 0.375rem 0.75rem;
  margin: 0 0.125rem;
  border: 1px solid var(--border) !important;
  background: var(--surface) !important;
  color: var(--link) !important;
  border-radius: 0.375rem;
  transition: all 0.15s ease-in-out;
  font-size: 0.875rem;
}

.dataTables_wrapper .dataTables_paginate .paginate_button:hover,
.dataTables_wrapper .dataTables_paginate .paginate_button.current,
.dataTables_wrapper .dataTables_paginate .paginate_button.current:hover {
  background: var(--link) !important;
  color: #ffffff !important;
  border-color: var(--link) !important;
}

.dataTables_wrapper .dataTables_paginate .paginate_button.disabled,
.dataTables_wrapper .dataTables_paginate .paginate_button.disabled:hover {
  opacity: 0.5;
  cursor: not-allowed;
  background: var(--surface) !important;
  color: var(--text-muted) !important;
  border-color: var(--border) !important;
}

h1, h5 {
  font-weight: 600;
}

/* === 11. Gauges === */
.gauge-container {
    max-width: 100%;
    width: 100%;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 10px 0;
    position: relative;
}

/* Constrain gauge size on larger screens */
@media (min-width: 768px) {
    .gauge-container {
        max-width: 200px;
    }
}

/* Smaller sizing for electricity and dashboard cards to prevent overlap */
@media (min-width: 768px) {
    .electricity-card .gauge-container,
    .dashboard-card .gauge-container {
        max-width: 160px;
    }
}

/* Allow gauges to shrink on smaller screens */
@media (max-width: 767px) {
    .gauge-container {
        max-width: 150px;
    }
}

/* Extra responsive breakpoints for tighter layouts */
@media (max-width: 1400px) {
    .electricity-card .gauge-container,
    .dashboard-card .gauge-container {
        max-width: 140px;
    }
}

@media (max-width: 1200px) {
    .electricity-card .gauge-container,
    .dashboard-card .gauge-container {
        max-width: 130px;
    }
}

/* When chat panel is open, allow flexible sizing */
.cloee-assistant-open .gauge-container {
    max-width: 100%;
}

/* Ensure canvas elements resize properly */
.gauge-container canvas {
    max-width: 100% !important;
    height: auto !important;
    display: block;
}

/* Minimum readable size for all gauge types */
.gauge-card .gauge-container,
.electricity-card .gauge-container,
.dashboard-card .gauge-container {
    min-width: 120px;
}

/* Progressive sizing when chat panel is open */
.cloee-assistant-open .gauge-card .gauge-container,
.cloee-assistant-open .electricity-card .gauge-container,
.cloee-assistant-open .dashboard-card .gauge-container {
    max-width: 160px;
}

@media (max-width: 1400px) {
    .cloee-assistant-open .gauge-container {
        max-width: 140px;
    }
}

@media (max-width: 1200px) {
    .cloee-assistant-open .gauge-container {
        max-width: 120px;
    }
}

@media (max-width: 992px) {
    .cloee-assistant-open .gauge-container {
        max-width: 100px;
    }
}

/* Gauge wrapper */
.gauge-wrapper {
    width: 100%;
    max-width: 210px;
    margin: 0 auto;
    aspect-ratio: 2.2 / 1;
    overflow: hidden;
}

/* Inside a flex-column card-body (dashboard unit cards), align-self: center ensures
   the wrapper is truly centred regardless of margin:auto flex-column edge cases,
   and flex-shrink: 0 prevents it from compressing when other content is present. */
.machine-card .card-body .gauge-wrapper {
    align-self: center;
    flex-shrink: 0;
}

/* Make gauges readable even with many columns */
@media (min-width: 1400px) {
    .electricity-card .gauge-wrapper,
    .dashboard-card .gauge-wrapper {
        max-width: 180px;
    }
}

@media (max-width: 1399px) {
    .electricity-card .gauge-wrapper,
    .dashboard-card .gauge-wrapper {
        max-width: 160px;
    }
}

@media (max-width: 1200px) {
    .electricity-card .gauge-wrapper,
    .dashboard-card .gauge-wrapper {
        max-width: 140px;
    }
}

/* When chat panel is open, ensure gauges remain readable */
.cloee-assistant-open .electricity-card .gauge-wrapper,
.cloee-assistant-open .dashboard-card .gauge-wrapper {
    max-width: 180px;
}

@media (max-width: 1400px) {
    .cloee-assistant-open .electricity-card .gauge-wrapper,
    .cloee-assistant-open .dashboard-card .gauge-wrapper {
        max-width: 160px;
    }
}

@media (max-width: 1200px) {
    .cloee-assistant-open .electricity-card .gauge-wrapper,
    .cloee-assistant-open .dashboard-card .gauge-wrapper {
        max-width: 140px;
    }
}

@media (max-width: 992px) {
    .cloee-assistant-open .electricity-card .gauge-wrapper,
    .cloee-assistant-open .dashboard-card .gauge-wrapper {
        max-width: 120px;
    }
}

.gauge-wrapper canvas {
    max-width: 100% !important;
    height: 100% !important;
    display: block;
}

/* Screen-saver idle mode: after prolonged no-input periods, clear chrome so
   dashboards fit more operational data. Factory selectors and warning actions
   remain visible; pointer/keyboard/touch activity restores the full interface. */
html:is(.cloee-idle-display, .cloee-display-view) #sidebar,
html:is(.cloee-idle-display, .cloee-display-view) .ask-cloee-bar,
html:is(.cloee-idle-display, .cloee-display-view) .ask-cloee-notice,
html:is(.cloee-idle-display, .cloee-display-view) .agentic-overlay,
html:is(.cloee-idle-display, .cloee-display-view) .facility-overview,
html:is(.cloee-idle-display, .cloee-display-view) .facility-overview-tooltip,
html:is(.cloee-idle-display, .cloee-display-view) .floating-logo-btn {
    opacity: 0;
    pointer-events: none;
    visibility: hidden;
}

html:is(.cloee-idle-display, .cloee-display-view) .agentic-overlay.open {
    display: none !important;
}

html:is(.cloee-idle-display, .cloee-display-view) .main-content {
    margin-left: 0;
    padding: 12px 12px 32px;
}

html:is(.cloee-idle-display, .cloee-display-view) .tp-center,
html:is(.cloee-idle-display, .cloee-display-view) .tp-below-filters,
html:is(.cloee-idle-display, .cloee-display-view) .dashboard-view-toggle,
html:is(.cloee-idle-display, .cloee-display-view) #dashboard-display-view,
html:is(.cloee-idle-display, .cloee-display-view) .cards-sort-controls,
html:is(.cloee-idle-display, .cloee-display-view) .dense-sort-controls {
    display: none !important;
}

/* The map's own status summary remains visible in manual Display view, so the
   toolbar Attention action steps away instead of competing for its top-right lane. */
html.cloee-display-view .shared-attention-indicator {
    display: none !important;
}

html:is(.cloee-idle-display, .cloee-display-view) .tp-toolbar-shell,
html:is(.cloee-idle-display, .cloee-display-view) .dashboard-toolbar-cq {
    position: fixed !important;
    top: 12px !important;
    left: 12px;
    right: 12px;
    z-index: 1042;
    padding-bottom: 0 !important;
}

/* The fixed factory picker and Exit button occupy the first row in Display view. */
html:is(.cloee-idle-display, .cloee-display-view) #oee-summary-row {
    margin-top: 3.25rem;
}

html:is(.cloee-idle-display, .cloee-display-view) .dashboard-toolbar-cq .tp-toolbar-shell {
    position: static !important;
    inset: auto !important;
}

html:is(.cloee-idle-display, .cloee-display-view) .tp-toolbar--with-actions {
    justify-content: space-between;
}

/* Core dashboard's explicit Display view has an intentional return path. It is
   present only for the manual state; automatic idle display still returns on input. */
.dashboard-display-view-exit {
    position: fixed;
    top: 12px;
    right: 12px;
    z-index: 1043;
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    color: var(--text);
    box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.12);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
}

.dashboard-display-view-exit:hover,
.dashboard-display-view-exit:focus-visible {
    border-color: color-mix(in srgb, var(--link) 45%, var(--border));
    background: color-mix(in srgb, var(--link) 10%, var(--surface));
    color: var(--text);
}

.dashboard-display-view-exit kbd {
    border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
    border-radius: 0.25rem;
    background: var(--surface-2);
    color: var(--text-muted);
    font-size: 0.7rem;
    line-height: 1;
    padding: 0.15rem 0.28rem;
}

/* === 12. Adaptive Unit Card Grids ===
   Configuration stores ordered unit groups separated by __break__. Each group
   renders as one wrapping layout: cards stay readable, incomplete lines stay centred, and
   the number of cards follows the space left by the navigation/chat panels. */
.unit-card-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: stretch;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}

.unit-card-grid-item {
    display: flex;
    flex: 0 1 100%;
    min-width: 0;
}

.unit-card-grid-item > .dashboard-card,
.unit-card-grid-item > .electricity-card {
    width: 100%;
}

/* Electricity/gas cards historically supplied their own vertical margin. The
   shared grid owns spacing now, so row gaps stay consistent with machine cards. */
.unit-card-grid .electricity-card {
    margin-bottom: 0;
}

.unit-card-grid-banner {
    flex: 0 0 100%;
    margin: 0;
}

@media (min-width: 576px) {
    .unit-card-grid-item {
        flex-basis: 192px;
    }
}

/* === 13. Under Development Page === */


    .under-dev-page {
        background: linear-gradient(135deg, #f8f9fa, #ffffff);
        min-height: 100vh;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;
        text-align: center;
        padding: 2rem;
        animation: fadeIn 0.8s ease-in;
    }

    @keyframes fadeIn {
        from { opacity: 0; transform: translateY(20px); }
        to { opacity: 1; transform: translateY(0); }
    }

    .dev-icon {
        font-size: 4rem;
        margin-bottom: 1rem;
    }

    .dev-title {
        font-size: 3rem;
        font-weight: 700;
        color: #212529;
    }

    .dev-subtext {
        font-size: 1.2rem;
        color: #495057;
        margin-bottom: 2rem;
    }

/* === 14. Sidebar footer (customer brand + theme switcher + user) ===
   Re-homed from the removed top navbar. See components/sidebars/base.html.
   The CloEE wordmark lives in the header (§4); the customer logo + theme
   switcher sit on one row above the signed-in user. */
/* Customer brand sits on its own line above the signed-in user block. */
.sidebar-customer-row {
    display: flex;
    align-items: center;
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border);
    min-width: 0;
}

.sidebar-customer-wrap {
    display: inline-flex;
    align-items: center;
    min-width: 0;
    overflow: hidden;
}

.sidebar-customer-logo {
    height: 24px;
    width: auto;
    max-width: 100%;
    object-fit: contain;
}
.sidebar-customer-wrap--custom .sidebar-customer-logo {
    /* The value is validated and frozen on the assigned brand version. */
    height: var(--demo-brand-logo-height, 24px);
}

/* Brand-profile previews depict what the *demo user* will see in each theme,
   so every colour below is deliberately pinned instead of reading a §0 token.
   A token follows the reviewing operator's own console theme, which made the
   "Day" preview render dark the moment the operator switched to night — the
   one thing these previews exist to answer. The light values mirror §0's light
   palette; the dark values mirror the real dark sidebar. */
.demo-brand-preview {
    --preview-surface: #ffffff;
    --preview-surface-2: #f8f9fa;
    --preview-text: #212529;
    --preview-muted: #6c757d;
    --preview-border: #dee2e6;
    color: var(--preview-text);
}
.demo-brand-preview--dark {
    --preview-surface: #1d232d;
    --preview-surface-2: #171c24;
    --preview-text: #f4f5f7;
    --preview-muted: #aab3bf;
    --preview-border: #47505a;
}
.demo-brand-preview__muted { color: var(--preview-muted); }

/* The flat logo card above each sidebar replica. Bootstrap's .bg-light is
   remapped to the dark surface in §26, so it cannot be used here either. */
.demo-brand-logo-card {
    border: 1px solid var(--preview-border);
    border-radius: .4rem;
    background: var(--preview-surface-2);
}

/* A compact, deliberately structural replica of the real demo sidebar, used
   when choosing a logo version.  It shows both theme and final CSS height. */
.demo-brand-sidebar-preview {
    position: relative;
    min-height: 178px;
    overflow: hidden;
    border: 1px solid var(--preview-border);
    border-radius: .4rem;
    background: var(--preview-surface);
}
.demo-brand-sidebar-preview__header,
.demo-brand-sidebar-preview__logo-row,
.demo-brand-sidebar-preview__user {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .4rem;
    padding: .45rem .55rem;
}
.demo-brand-sidebar-preview__header { border-bottom: 1px solid var(--preview-border); font-size: .72rem; }
.demo-brand-sidebar-preview__content { display: grid; gap: .35rem; padding: .6rem .55rem; }
.demo-brand-sidebar-preview__content span { display: block; width: 58%; height: .28rem; border-radius: 99px; background: currentColor; opacity: .16; }
.demo-brand-sidebar-preview__content span:nth-child(2) { width: 77%; }
.demo-brand-sidebar-preview__footer { position: absolute; right: 0; bottom: 0; left: 0; }
.demo-brand-sidebar-preview__logo-row { min-height: 42px; justify-content: flex-start; border-top: 1px solid var(--preview-border); }
.demo-brand-sidebar-preview__logo-row img { width: auto; max-width: 100%; object-fit: contain; }
.demo-brand-sidebar-preview__user { justify-content: flex-start; border-top: 1px solid var(--preview-border); font-size: .64rem; white-space: nowrap; }
.demo-brand-version-thumb {
    width: 84px;
    height: 36px;
    padding: .2rem;
    border: 1px solid var(--preview-border);
    border-radius: .2rem;
    background: var(--preview-surface-2);
    object-fit: contain;
}

/* Full-scale, 220px expanded-sidebar replica used while editing a version.
   Keep this synchronized with the footer rules above: it is a decision aid,
   not a generic image thumbnail. */
.demo-brand-actual-sidebar {
    position: relative;
    display: flex;
    flex-direction: column;
    width: 220px;
    min-height: calc(var(--preview-logo-height, 24px) + 160px);
    overflow: hidden;
    border: 1px solid var(--preview-border);
    border-radius: 14px;
    background: var(--preview-surface-2);
    box-shadow: 0 8px 28px rgba(0, 0, 0, .12);
}
/* The expanded sidebar sits on the darker of the two dark surfaces, so it
   carries its own slightly darker divider than the compact replica. */
.demo-brand-actual-sidebar.demo-brand-preview--dark { --preview-border: #37414e; }
.demo-brand-actual-sidebar__header {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: 14px;
    border-bottom: 1px solid var(--preview-border);
    font-size: 1.05rem;
}
.demo-brand-actual-sidebar__header > :first-child { font-size: 1.3rem; }
.demo-brand-actual-sidebar__footer { margin-top: auto; padding: 8px 12px; }
.demo-brand-actual-sidebar__logo-row {
    display: flex;
    align-items: center;
    min-height: 42px;
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--preview-border);
    overflow: hidden;
}
.demo-brand-actual-sidebar__logo-row img { width: auto; max-width: 100%; object-fit: contain; }
.demo-brand-actual-sidebar__email {
    display: flex;
    align-items: center;
    gap: 5px;
    padding-bottom: 4px;
    font-size: .9rem;
    font-weight: 600;
    white-space: nowrap;
}
.demo-brand-actual-sidebar__email i { font-size: 1.05rem; }
.demo-brand-actual-sidebar__actions {
    display: flex;
    align-items: center;
    color: var(--preview-muted);
    font-size: .93rem;
    opacity: .82;
}
.demo-brand-actual-sidebar__actions span { display: inline-flex; align-items: center; gap: 3px; }
.demo-brand-actual-sidebar__actions button {
    display: inline-flex;
    width: 32px;
    height: 32px;
    align-items: center;
    justify-content: center;
    margin-left: auto;
    border: 1px solid var(--preview-border);
    border-radius: 8px;
    background: var(--preview-surface);
    color: inherit;
}
.demo-brand-actual-sidebar.demo-brand-preview--dark .demo-brand-actual-sidebar__actions button { background: #242c37; }

/* Bodycote / Geberit theme swap: original in light mode, reversed white
   in dark mode. The white variant sits straight on the surface (no pill,
   transparent). */
.sidebar-customer-logo--dark {
    display: none;
}
html[data-bs-theme="dark"] .sidebar-customer-logo--light {
    display: none;
}
html[data-bs-theme="dark"] .sidebar-customer-logo--dark {
    display: inline-block;
    background-color: transparent;
    padding: 0;
}

/* The email has its own row; logout and the theme switcher share the action row
   below so a long address can never crowd the toggle out of view. */
.sidebar-user-top {
    display: flex;
    align-items: center;
    min-width: 0;
    margin-bottom: 4px;
}
.sidebar-user-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    min-width: 0;
    width: 100%;
}
.sidebar-user-actions .sidebar-theme-toggle {
    margin-left: auto;
}

.sidebar-theme-toggle {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--border);
    border-radius: 8px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    transition: background-color 0.2s ease;
}

.sidebar-theme-toggle:hover {
    background: var(--surface-sunken);
}

.sidebar-user-block {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    min-width: 0;
}

.sidebar-user-email {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    gap: 5px;
    min-width: 0;
    max-width: 100%;
    font-size: 0.9em;
    color: var(--text);
}

.sidebar-user-email .bi-person-circle {
    flex-shrink: 0;
}

.sidebar-user-email-text {
    display: -webkit-box;
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: normal;
    overflow-wrap: anywhere;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-height: 1.25;
}

/* Collapsed sidebar: drop the customer logo, stack person + theme switcher. */
.sidebar-collapsed #sidebar .sidebar-customer-row {
    display: none;
}

/* "Connected to Ignition" (per-factory flag): full logo above the customer
   brand when expanded; only the orange mark above the person icon when
   collapsed. The logo's navy wordmark swaps to a white variant in dark mode. */
.sidebar-integration-row {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    margin-bottom: 10px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border);
    min-width: 0;
}
/* The caption sits in the logo's own blank top-left band (above the wordmark,
   left of the tall "!"), so it costs no height and the logo can run wider. */
.sidebar-integration-caption {
    position: absolute;
    top: 3px;
    left: 0;
    font-size: 0.62rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--text-muted);
    line-height: 1;
}
/* Sized by width: the tall orange mark would otherwise dictate the height and
   shrink the wordmark to illegibility. */
.sidebar-integration-logo {
    width: 164px;
    height: auto;
    max-width: 100%;
}
.sidebar-integration-logo--dark,
.sidebar-integration-mark,
html[data-bs-theme="dark"] .sidebar-integration-logo--light {
    display: none;
}
html[data-bs-theme="dark"] .sidebar-integration-logo--dark {
    display: block;
}
.sidebar-collapsed #sidebar .sidebar-integration-row {
    position: static;
    align-items: center;
    margin-bottom: 0;
    padding-bottom: 8px;
    width: 100%;
}
.sidebar-collapsed #sidebar .sidebar-integration-caption,
.sidebar-collapsed #sidebar .sidebar-integration-logo {
    display: none;
}
.sidebar-collapsed #sidebar .sidebar-integration-mark {
    display: block;
    width: 22px;
    height: 22px;
}
.sidebar-collapsed #sidebar .sidebar-user-top {
    flex-direction: column;
    align-items: center;
    gap: 8px;
    margin-bottom: 0;
}
.sidebar-collapsed #sidebar .sidebar-user-actions {
    flex-direction: column;
    justify-content: center;
    gap: 8px;
}
.sidebar-collapsed #sidebar .sidebar-user-actions .sidebar-theme-toggle {
    margin-left: 0;
}

/* Collapsed-rail account card: the rail hides the email text and the logout
   row, so hovering (or keyboard-focusing) the person icon opens them as a
   flyout. Like the group flyout it is position:fixed to escape #sidebar's
   overflow:hidden, flush against the rail's right edge — any breathing room
   comes from its own padding, never from an offset that would drop :hover
   while the cursor crosses the gap. JS (sidebars/base.html) sets left/bottom. */
.sidebar-user-menu {
    display: flex;
    min-width: 0;
    max-width: 100%;
}

.sidebar-user-card {
    display: none;
}

/* The hover target must span the whole rail, not just the icon: the card opens
   flush against the rail's right edge, so anything narrower means the cursor
   leaves :hover — closing the card — before it can reach it. Same reason the
   group flyout hangs off the full-width .sidebar-group. */
.sidebar-collapsed #sidebar .sidebar-user-top,
.sidebar-collapsed #sidebar .sidebar-user-menu {
    width: 100%;
    justify-content: center;
}

/* Keep the icon (and its hover pill) centred and icon-sized inside that row. */
.sidebar-collapsed #sidebar .sidebar-user-email {
    flex: 0 0 auto;
    cursor: pointer;
    padding: 6px;
    border-radius: 8px;
    transition: background-color 0.2s ease;
}

.sidebar-collapsed #sidebar .sidebar-user-menu:hover .sidebar-user-email,
.sidebar-collapsed #sidebar .sidebar-user-menu:focus-within .sidebar-user-email {
    background: var(--surface-sunken);
}

.sidebar-user-email:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: 2px;
}

.sidebar-collapsed #sidebar .sidebar-user-menu:hover > .sidebar-user-card,
.sidebar-collapsed #sidebar .sidebar-user-menu:focus-within > .sidebar-user-card {
    display: block;
    position: fixed;
    left: 72px; /* fallback (12px sidebar inset + 60px collapsed width) */
    bottom: 12px; /* fallback; both overwritten by JS on hover */
    top: auto;
    width: max-content;
    min-width: 200px;
    max-width: 260px;
    padding: 10px;
    text-align: left;
    white-space: normal;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 .55rem 1.2rem color-mix(in srgb, var(--text) 18%, transparent);
    z-index: 1100;
}

.sidebar-user-card-identity {
    display: flex;
    align-items: center;
    gap: 8px;
    min-width: 0;
    padding: 2px 4px 9px;
    border-bottom: 1px solid var(--border);
}

.sidebar-user-card-avatar {
    flex-shrink: 0;
    font-size: 22px;
    color: var(--text-muted);
}

.sidebar-user-card-text {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.sidebar-user-card-label {
    font-size: 0.72rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-muted);
}

.sidebar-user-card-email {
    font-size: 0.9rem;
    line-height: 1.3;
    color: var(--text);
    overflow-wrap: anywhere;
}

.sidebar-user-card-action {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding: 8px 10px;
    border-radius: 8px;
    font-size: 0.9rem;
    color: var(--text);
    text-decoration: none;
}

.sidebar-user-card-action i {
    color: var(--text-muted);
}

.sidebar-user-card-action:hover,
.sidebar-user-card-action:focus-visible {
    background: var(--surface-sunken);
    color: var(--link);
}

.sidebar-user-card-action:hover i,
.sidebar-user-card-action:focus-visible i {
    color: var(--link);
}


  .gauge-container {
    padding-top: 0 !important;
    margin-top: 0 !important;
  }

  .gauge-card {
    padding-top: 10px !important;
  }

/* === 15. Alarms === */


/* Alarms Summary Banner */
.alarms-summary-banner {
    background-color: #dc3545;
    padding: 5px 10px;
    color: #fff;
    box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
    border-radius: 6px;

    display: flex;
    justify-content: center;
    align-items: baseline;
    gap: 20px;
    flex-wrap: nowrap;
    text-align: center;
    overflow: hidden;
    transition: transform 0.3s ease-in-out;
}

.alarms-summary-banner:hover {
    transform: scale(1.01);
}

/* Alarm Card Colors */
.alarm-card-warning {
    background-color: #fff3cd;
    border: 1px solid #ffeeba;
}

.alarm-card-error {
    background-color: #f8d7da;
    border: 1px solid #f5c6cb;
}

/* Alarm unit cards: same base look as the OEE machine card (.dashboard-card),
   but with their own header/body sizing rather than the OEE card's icon-tray
   grid header, which alarm cards don't use. */
.alarm-unit-card {
    height: 100%;
    display: flex;
    flex-direction: column;
}

.alarm-unit-card .card-header {
    background-color: transparent;
    border-bottom: 0;
    padding: 0.6rem 0.75rem 0.35rem;
}

.alarm-unit-card-title {
    display: block;
    font-size: 1.1rem;
    font-weight: 700;
    color: var(--text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.alarm-unit-card .card-body {
    flex: 1 0 auto;
    padding: 0.25rem 0.9rem 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    font-size: 0.9rem;
}

.alarm-unit-card .alarm-count-value {
    font-size: 1.2rem;
}

/* === 16. Electricity Cards === */
.electricity-card {
    box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    overflow: hidden;
    transition: 0.3s ease-in-out;
    text-decoration: none;
    color: inherit;
    background: #fff;
    margin-bottom: 2rem;
}




.electricity-card .card-header {
    font-size: 1rem;
    font-weight: 600;
    padding: 10px 16px;
    background-color: transparent;
    color: var(--text);
    border-bottom: 1px solid color-mix(in srgb, var(--border) 55%, transparent);
    text-align: center;
}

.electricity-card .card-body {
    padding: 16px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    font-size: 0.95rem;
}

/* Compact report energy summaries. Accent tints mix with semantic surfaces so the cards
   retain their hierarchy in either Bootstrap colour mode. */
.energy-summary-card {
    --energy-summary-accent: #0d6efd;
    min-height: 10.5rem;
    padding: 1rem;
    border: 1px solid color-mix(in srgb, var(--energy-summary-accent) 28%, var(--border));
    border-radius: 1rem;
    background: linear-gradient(
        135deg,
        color-mix(in srgb, var(--energy-summary-accent) 14%, var(--surface)),
        var(--surface) 68%
    );
    box-shadow: 0 0.5rem 1.25rem color-mix(in srgb, var(--energy-summary-accent) 10%, transparent);
    color: var(--text);
}

.energy-summary-card--power { --energy-summary-accent: #d89100; }
.energy-summary-card--gas { --energy-summary-accent: #0d6efd; }
.energy-summary-card--ammonia { --energy-summary-accent: #fd7e14; }
/* The two ammonia exposure metrics are different kinds of measurement (a slow 8h dose vs a
   discrete 15-min burst), so they never share an accent — the colour is half of what tells the
   two sections apart at a glance. See AmmoniaGuide.md "What the dashboard shows". */
.energy-summary-card--ammonia-twa { --energy-summary-accent: #d89100; }
.energy-summary-card--ammonia-stel { --energy-summary-accent: #dc3545; }
.batch-flow-card { --energy-summary-accent: #198754; }

.energy-summary-stack {
    display: flex;
    flex-direction: column;
    gap: 1rem;
}

.energy-summary-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
}

.energy-summary-card__stat {
    min-width: 0;
    flex: 1 1 0;
}

.energy-summary-card__stat--end { text-align: right; }

.energy-summary-card__label {
    display: block;
    color: var(--text-muted);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.energy-summary-card__value {
    display: block;
    color: var(--text);
    font-size: clamp(1rem, 2vw, 1.3rem);
    line-height: 1.2;
    overflow-wrap: anywhere;
}

.energy-summary-card__value small {
    color: var(--text-muted);
    font-size: 0.72em;
    font-weight: 600;
}

.machine-pareto-card__stat-row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.energy-summary-card__title {
    display: flex;
    flex: 0 1 auto;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    margin: 0.15rem 0 0;
    color: var(--text);
    font-size: 0.95rem;
    text-align: center;
    white-space: nowrap;
}

.energy-summary-card__title i,
.energy-summary-card__empty i { color: var(--energy-summary-accent); }

.energy-summary-card__trend {
    position: relative;
    margin: 0.75rem 0;
}

.energy-summary-card__delta {
    display: inline-block;
    margin-bottom: 0.3rem;
    color: var(--text-muted);
    font-size: 0.92rem;
    font-weight: 700;
    white-space: nowrap;
}

/* Shown instead of a delta when the two windows cover different meters, so their ratio would
   measure the data gap rather than consumption. Deliberately quieter than a real delta. */
.energy-summary-card__delta--muted {
    font-weight: 600;
    font-style: italic;
    opacity: 0.75;
}

.energy-summary-card__bars {
    display: block;
    width: 100%;
    height: 3rem;
    overflow: visible;
    border-bottom: 1px solid color-mix(in srgb, var(--text-muted) 35%, var(--border));
}

.energy-mini-bar { fill: var(--text-muted); opacity: 0.42; }
.energy-mini-bar--peak { fill: var(--energy-summary-accent); opacity: 1; }
/* Baseline "shadow" bars for a chosen comparison period — drawn behind the main bars, kept
   recessive so the solid series still reads as primary (theme-safe: mixes against --surface). */
.energy-mini-bar--compare { fill: var(--text-muted); opacity: 0.16; }

.energy-mini-bar--interactive { cursor: help; outline: none; }

.energy-mini-bar--interactive:hover,
.energy-mini-bar--interactive:focus {
    fill: var(--energy-summary-accent);
    opacity: 1;
    stroke: var(--energy-summary-accent);
    stroke-width: 1.5;
}

.energy-summary-card__chart-tooltip {
    position: absolute;
    bottom: 3.45rem;
    z-index: 2;
    min-width: max-content;
    max-width: min(15rem, 92%);
    padding: 0.32rem 0.45rem;
    border: 1px solid color-mix(in srgb, var(--energy-summary-accent) 38%, var(--border));
    border-radius: 0.4rem;
    background: var(--surface);
    box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.14);
    color: var(--text);
    font-size: 0.68rem;
    line-height: 1.2;
    pointer-events: none;
    text-align: center;
    transform: translateX(-50%);
}

.energy-summary-card__chart-tooltip[hidden] { display: none; }

.energy-summary-card__chart-tooltip span,
.energy-summary-card__chart-tooltip strong { display: block; }

.energy-summary-card__chart-tooltip span { color: var(--text-muted); }
.energy-summary-card__chart-tooltip strong { color: var(--text); font-weight: 800; }

.energy-summary-card__empty {
    display: grid;
    min-height: 8.5rem;
    place-content: center;
    gap: 0.35rem;
    color: var(--text-muted);
    text-align: center;
}

.energy-summary-card__empty i { font-size: 1.4rem; }
.energy-summary-card__empty strong { color: var(--text); }

.batch-flow-card__comparison,
.energy-summary-card__legacy-note {
    display: inline-block;
    margin-bottom: 0.3rem;
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 700;
    white-space: nowrap;
}

.batch-flow-card__comparison strong { color: var(--text); }

.batch-flow-card--legacy {
    display: flex;
    flex-direction: column;
}

.batch-flow-card__legacy-note {
    margin-top: auto;
}

/* Keep the established report KPI cards at their original scale; the radar complements them
   without replacing their values, deltas, or period sparklines. */
.report-kpi-overview {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    align-items: stretch;
    gap: 1rem;
}

.report-kpi-grid {
    display: grid;
    grid-column: span 2;
    grid-template-columns: minmax(0, 1fr);
    gap: 0.4rem;
}

/* States the two things the KPI numbers depend on but can't show: which units they average over,
   and which window the deltas are measured against. */
.report-kpi-grid__basis {
    grid-column: span 2;
    margin: 0.15rem 0 0;
    color: var(--text-muted);
    font-size: 0.78rem;
    line-height: 1.3;
}

.report-kpi-profile-stack {
    display: grid;
    grid-column: span 4;
    /* KPI profile is auto-height (its radar is width-bound, so extra stretch just leaves a
       dead gap under the title) — Rework/Scrap sit right under it at their own natural size,
       and Batch Flow gets the trailing 1fr to absorb whatever stretch is left, centering its
       content instead of leaving it pinned to the top with blank space below. */
    grid-template-rows: auto auto minmax(0, 1fr);
    gap: 0.4rem;
    min-width: 0;
}

.report-kpi-profile-stack .batch-flow-card {
    display: flex;
    flex-direction: column;
    justify-content: center;
}

.report-downtime-quality-cards {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.4rem;
}

/* .downtime-analysis-card already carries flex:1 1 auto expecting a flex parent — without
   display:flex here it just sits at its natural content height and leaves the rest of the
   stretched grid cell blank underneath it instead of actually growing to fill it. */
.report-kpi-downtime {
    display: flex;
    flex-direction: column;
    grid-column: span 6;
    min-width: 0;
}

.report-kpi-card {
    --report-kpi-accent: #198754;
    display: flex;
    flex-direction: column;
    min-height: 6.5rem;
    padding: 0.55rem 0.65rem;
    border: 1px solid color-mix(in srgb, var(--report-kpi-accent) 30%, var(--border));
    border-radius: 0.8rem;
    background: linear-gradient(
        135deg,
        color-mix(in srgb, var(--report-kpi-accent) 11%, var(--surface)),
        var(--surface) 68%
    );
    box-shadow: 0 0.35rem 0.85rem color-mix(in srgb, var(--report-kpi-accent) 8%, transparent);
    color: var(--text);
}

.report-kpi-card--danger { --report-kpi-accent: #dc3545; }
.report-kpi-card--warning { --report-kpi-accent: #d89100; }
.report-kpi-card--success { --report-kpi-accent: #198754; }
.report-kpi-card--neutral { --report-kpi-accent: var(--text-muted); }

.report-kpi-card__header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    row-gap: 0.15rem;
    gap: 0.5rem;
}

.report-kpi-card__header h5 {
    margin: 0;
    color: var(--text);
    font-size: 0.78rem;
    font-weight: 800;
    letter-spacing: -0.015em;
}

.report-kpi-card__value {
    display: block;
    margin-top: 0.1rem;
    color: var(--report-kpi-accent);
    font-size: clamp(1.45rem, 2.2vw, 1.9rem);
    font-weight: 800;
    letter-spacing: -0.075em;
    line-height: 1;
}

.report-kpi-card__delta {
    display: inline-flex;
    align-items: center;
    gap: 0.26rem;
    padding: 0.22rem 0.44rem;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 800;
    line-height: 1;
    white-space: nowrap;
}

.report-kpi-card__delta--improved {
    background: color-mix(in srgb, #198754 13%, var(--surface));
    color: #198754;
}

.report-kpi-card__delta--declined {
    background: color-mix(in srgb, #dc3545 13%, var(--surface));
    color: #dc3545;
}

.report-kpi-card__delta--neutral {
    background: color-mix(in srgb, var(--text-muted) 10%, var(--surface));
    color: var(--text-muted);
}

.report-kpi-card__trend {
    display: flex;
    align-items: flex-end;
    flex: 1 1 auto;
    min-height: 1.4rem;
    margin: 0.25rem 0 0.05rem;
}

.report-kpi-card__sparkline-wrap {
    position: relative;
    width: 100%;
}

.report-kpi-card__sparkline {
    display: block;
    width: 100%;
    height: 1.4rem;
    overflow: visible;
}

.report-kpi-card__sparkline polyline {
    fill: none;
    stroke: var(--report-kpi-accent);
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-width: 2.25;
}

/* Comparison-period "shadow" line: muted + dashed, sits behind the solid accent line. The
   element+class selector out-specifies the accent-stroke rule above so the muted stroke wins. */
.report-kpi-card__sparkline polyline.report-kpi-card__sparkline-compare {
    stroke: var(--text-muted);
    stroke-width: 1.75;
    stroke-dasharray: 3 2.5;
    opacity: 0.6;
}

.report-kpi-card__sparkline-point {
    fill: var(--report-kpi-accent);
    stroke: var(--surface);
    stroke-width: 1;
    opacity: 0;
    cursor: pointer;
    outline: none;
    -webkit-tap-highlight-color: transparent;
    transition: opacity 0.12s ease;
}

.report-kpi-card__sparkline-point:hover,
.report-kpi-card__sparkline-point:focus-visible {
    opacity: 1;
}

.report-kpi-card__sparkline-tooltip {
    background: var(--surface);
    border: 1px solid color-mix(in srgb, var(--report-kpi-accent) 38%, var(--border));
    border-radius: 0.3rem;
    box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.14);
    color: var(--text);
    font-size: 0.68rem;
    line-height: 1.2;
    min-width: max-content;
    padding: 0.2rem 0.32rem;
    pointer-events: none;
    position: absolute;
    text-align: center;
    transform: translate(-50%, calc(-100% - 0.35rem));
    z-index: 3;
}

.report-kpi-card__sparkline-tooltip[hidden] { display: none; }
.report-kpi-card__sparkline-tooltip span,
.report-kpi-card__sparkline-tooltip strong { display: block; }
.report-kpi-card__sparkline-tooltip span { color: var(--text-muted); }
.report-kpi-card__sparkline-tooltip strong { color: var(--text); font-weight: 800; }

.report-kpi-card__sparkline-empty {
    width: 100%;
    border-bottom: 1px solid color-mix(in srgb, var(--text-muted) 32%, var(--border));
}

.report-kpi-radar-card {
    --energy-summary-accent: #0d6efd;
    /* Overrides .energy-summary-card's 10.5rem min-height: the radar itself is width-bound
       (see .report-kpi-overview__radar-wrap's aspect-ratio below), so a taller floor here just
       stretches the wrap past square and letterboxes the SVG with dead space top/bottom. */
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    padding: 0.85rem;
}

.report-kpi-radar-card__header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.75rem;
    margin-bottom: 0.2rem;
}

.report-kpi-radar-card__eyebrow,
.report-kpi-radar-card__scale {
    color: var(--text-muted);
    font-size: 0.66rem;
    font-weight: 800;
    letter-spacing: 0.055em;
    text-transform: uppercase;
}

.report-kpi-radar-card__header h5 {
    display: flex;
    align-items: center;
    gap: 0.3rem;
    margin: 0.04rem 0 0;
    color: var(--text);
    font-size: 0.95rem;
    font-weight: 800;
}

.report-kpi-radar-card__header h5 i { color: var(--energy-summary-accent); }

.report-kpi-radar-card__scale {
    flex: 0 0 auto;
    padding: 0.2rem 0.42rem;
    border: 1px solid color-mix(in srgb, var(--energy-summary-accent) 26%, var(--border));
    border-radius: 999px;
    background: color-mix(in srgb, var(--energy-summary-accent) 8%, var(--surface));
}

.report-kpi-overview__radar-wrap {
    position: relative;
    min-width: 0;
    min-height: 0;
    flex: 0 1 auto;
    width: 100%;
    /* Must match report_render.js's RADAR_VB_WIDTH / RADAR_VB_HEIGHT exactly — the radar's
       label bounding box is wider than tall, not square; a mismatched ratio here letterboxes
       the SVG (preserveAspectRatio defaults to xMidYMid meet) and brings back the dead margin. */
    aspect-ratio: 260 / 158;
    margin: 0 auto;
}

.report-kpi-radar {
    display: block;
    width: 100%;
    height: 100%;
    overflow: visible;
}

.report-kpi-radar__ring {
    fill: color-mix(in srgb, var(--energy-summary-accent) 3%, transparent);
    stroke: color-mix(in srgb, var(--energy-summary-accent) 20%, var(--border));
    stroke-width: 1;
}

.report-kpi-radar__axis {
    stroke: color-mix(in srgb, var(--energy-summary-accent) 22%, var(--border));
    stroke-width: 1;
}

.report-kpi-radar__profile {
    fill: color-mix(in srgb, var(--energy-summary-accent) 20%, transparent);
    stroke: var(--energy-summary-accent);
    stroke-linejoin: round;
    stroke-width: 2;
}

/* Comparison-period "shadow" profile: neutral, mostly-transparent fill + dashed muted outline,
   drawn behind the solid profile. Rule follows the base so its overrides win at equal specificity. */
.report-kpi-radar__profile--compare {
    fill: color-mix(in srgb, var(--text-muted) 14%, transparent);
    stroke: var(--text-muted);
    stroke-width: 1.5;
    stroke-dasharray: 3 2.5;
    opacity: 0.75;
}

.report-kpi-radar__point {
    fill: var(--surface);
    stroke: var(--energy-summary-accent);
    stroke-width: 2.25;
    cursor: pointer;
    outline: none;
}

.report-kpi-radar__point:hover,
.report-kpi-radar__point:focus,
.report-kpi-radar__point[aria-pressed="true"] {
    fill: var(--energy-summary-accent);
    stroke: var(--surface);
    stroke-width: 3;
}

.report-kpi-radar__label {
    fill: var(--text);
    font-size: 7px;
    font-weight: 800;
}

.report-kpi-radar__empty {
    fill: var(--text-muted);
    font-size: 9px;
    font-weight: 700;
}

.report-kpi-radar__tooltip {
    position: absolute;
    z-index: 2;
    min-width: max-content;
    padding: 0.32rem 0.45rem;
    border: 1px solid color-mix(in srgb, var(--energy-summary-accent) 38%, var(--border));
    border-radius: 0.4rem;
    background: var(--surface);
    box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.14);
    color: var(--text);
    font-size: 0.68rem;
    line-height: 1.2;
    pointer-events: none;
    text-align: center;
    transform: translate(-50%, calc(-100% - 0.35rem));
}

.report-kpi-radar__tooltip[hidden] { display: none; }
.report-kpi-radar__tooltip strong { display: block; color: var(--text); font-weight: 800; }

.report-quality-card {
    justify-content: space-between;
}

.report-quality-card--rework { --report-kpi-accent: #d89100; }
.report-quality-card--scrap { --report-kpi-accent: #dc3545; }

.report-quality-card__rate {
    padding: 0.26rem 0.5rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--report-kpi-accent) 13%, var(--surface));
    color: var(--report-kpi-accent);
    font-size: 0.92rem;
    font-weight: 800;
    line-height: 1;
    white-space: nowrap;
}

.report-quality-card__caption {
    color: var(--text-muted);
    font-size: 0.72rem;
    font-weight: 600;
}

.report-insights {
    padding-top: 0.1rem;
}

.report-insights__utilities {
    min-width: 0;
}

/* Power, Ammonia, and Gas Flow share one row — each card takes 4 of 12 grid columns. */
.report-insights--utilities .energy-summary-stack {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

.report-insights--utilities .energy-summary-card {
    height: 100%;
    min-width: 0;
}

/* Three utility cards fit only when the report panel has generous room. Switch before their
   title/value groups begin to wrap (sidebar, chat panel, or browser zoom can narrow it well before
   the viewport reaches a conventional tablet breakpoint). */
@media (max-width: 1400px) {
    .report-insights--utilities .energy-summary-stack { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1200px) {
    .report-insights--utilities .report-insights__utilities {
        width: 100%;
    }

    .col-xl-6 .report-kpi-overview {
        grid-template-columns: repeat(12, minmax(0, 1fr));
    }

    /* A comparison panel is half-width, so keep its KPI cards as a compact group
       instead of turning them into five full-width rows. */
    .col-xl-6 .report-kpi-grid {
        grid-column: span 12;
        grid-template-columns: repeat(4, minmax(0, 1fr));
        gap: 0.35rem;
    }

    .col-xl-6 .report-kpi-card {
        min-height: 5.5rem;
        padding: 0.5rem 0.55rem;
    }

    .col-xl-6 .report-kpi-profile-stack {
        grid-column: span 12;
    }

    .col-xl-6 .report-kpi-downtime {
        grid-column: span 12;
    }

    .col-xl-6 .report-insights--utilities .energy-summary-stack {
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.5rem;
    }
}

@media (max-width: 991.98px) {
    .report-kpi-overview { grid-template-columns: minmax(0, 1fr); }
    .report-kpi-grid { grid-column: auto; grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .report-kpi-profile-stack { grid-column: auto; }
    .report-kpi-downtime { grid-column: auto; }
    .report-insights--utilities .energy-summary-stack { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 575.98px) {
  .report-insights--utilities .energy-summary-stack { grid-template-columns: minmax(0, 1fr); }
}

/* Route-backed Manage center */
.manage-page {
  --manage-accent: #81bc48;
  max-width: 1500px;
  margin-inline: auto;
  padding-block: clamp(1rem, 2vw, 2rem);
}

.manage-page-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1.25rem;
}

.manage-page-header__eyebrow {
  color: var(--manage-accent);
  font-size: .72rem;
  font-weight: 750;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.manage-scope-badge {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, var(--manage-accent) 35%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--manage-accent) 8%, var(--surface));
  color: var(--text);
  padding: .42rem .72rem;
  font-size: .78rem;
  font-weight: 650;
}

.manage-search-card {
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--surface);
  box-shadow: 0 .25rem .6rem color-mix(in srgb, var(--text) 8%, transparent);
  padding: clamp(1rem, 2vw, 1.4rem);
}

.manage-destination-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 290px), 1fr));
  gap: .9rem;
}

.manage-destination-card {
  position: relative;
  display: grid;
  grid-template-columns: 2.5rem 1fr auto;
  align-items: center;
  gap: .85rem;
  min-height: 6rem;
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--surface);
  color: var(--text);
  padding: 1rem;
  text-decoration: none;
  transition: border-color .16s ease, box-shadow .16s ease, transform .16s ease;
}

.manage-destination-card:hover,
.manage-destination-card:focus-visible {
  border-color: color-mix(in srgb, var(--manage-accent) 55%, var(--border));
  box-shadow: 0 .55rem 1rem color-mix(in srgb, var(--text) 16%, transparent);
  color: var(--text);
  /* The whole card is the affordance — Bootstrap's link underline on hover would
     otherwise strike through the title/description inside it. */
  transform: translateY(-1px);
}

.manage-destination-card__icon {
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: .75rem;
  background: color-mix(in srgb, var(--manage-accent) 10%, var(--surface-2));
  color: var(--manage-accent);
  font-size: 1.1rem;
}

.manage-destination-card__copy {
  display: grid;
  gap: .2rem;
}

.manage-destination-card__copy small {
  color: var(--text-muted);
  line-height: 1.35;
}

.manage-destination-card__meta {
  align-self: start;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-muted);
  padding: .2rem .5rem;
  font-size: .7rem;
}

.manage-destination-card--top {
  order: -1;
  border-color: color-mix(in srgb, var(--manage-accent) 55%, var(--border));
}

/* A single settings card inside a section, surfaced only while the search query matches it.
   Quieter than a section card so a result list reads as "section, then the cards within it";
   the distinction is carried by the "In <Section>" line, never by colour alone. */
.manage-destination-card--nested {
  min-height: 0;
  padding: .75rem .9rem;
  background: color-mix(in srgb, var(--surface-2) 45%, var(--surface));
}

.manage-destination-card--nested .manage-destination-card__icon {
  width: 2rem;
  height: 2rem;
  border-radius: .6rem;
  font-size: .95rem;
}

.manage-settings-layout {
  --manage-settings-primary-nav-height: 2.5rem;
  --manage-settings-jump-nav-height: 0px;
  min-width: 0;
}

.manage-settings-navigation {
  position: sticky;
  top: .75rem;
  z-index: 20;
  padding: .45rem;
  border: 1px solid var(--border);
  /* Concentric with the .7rem tabs inside: .7rem + .45rem padding. */
  border-radius: 1.15rem;
  background: var(--surface);
  box-shadow: 0 .2rem .6rem color-mix(in srgb, var(--text) 7%, transparent);
}

.manage-settings-tabs {
  min-width: 0;
}

.manage-settings-tablist {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: .4rem;
}

.manage-settings-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-height: 2.5rem;
  border: 1px solid var(--border);
  border-radius: .7rem;
  color: var(--text);
  padding: .55rem .85rem;
  font-size: .9rem;
  font-weight: 600;
  line-height: 1.15;
  text-decoration: none;
  white-space: nowrap;
  background: var(--surface);
  transition: background-color .15s ease, border-color .15s ease, box-shadow .15s ease;
}

.manage-settings-tab:hover {
  background: var(--surface-2);
  color: var(--text);
}

.manage-settings-tab:focus-visible {
  z-index: 1;
  color: var(--text);
  outline: 3px solid color-mix(in srgb, var(--manage-accent) 38%, transparent);
  outline-offset: -3px;
}

.manage-settings-tab.active {
  border-color: var(--manage-accent);
  background: color-mix(in srgb, var(--manage-accent) 12%, var(--surface));
  color: var(--text);
  font-weight: 750;
  box-shadow: 0 .15rem .5rem color-mix(in srgb, var(--text) 6%, transparent);
}

.manage-card-scope {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-muted);
  padding: .18rem .55rem;
  font-size: .68rem;
  font-weight: 650;
  white-space: nowrap;
}

.manage-card-factory {
  width: auto;
  min-width: 9rem;
  max-width: 14rem;
  border-color: var(--border);
  background-color: var(--surface);
  color: var(--text);
}

.layout-unit-order {
  display: flex;
  flex-direction: column;
  gap: .55rem;
}

.layout-unit-row {
  display: flex;
  flex-wrap: wrap;
  gap: .65rem;
  min-height: 3.1rem;
  padding: .55rem;
  border: 1px dashed var(--border);
  border-radius: .5rem;
  background: var(--surface-2);
}

.layout-unit-card {
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  min-width: 7.5rem;
  padding: .55rem .75rem;
  border: 1px solid var(--border);
  border-radius: .45rem;
  background: var(--surface);
  color: var(--text);
  cursor: grab;
  font-weight: 600;
  line-height: 1.2;
  box-shadow: 0 .25rem .6rem color-mix(in srgb, var(--text) 8%, transparent);
}

.layout-unit-card.sortable-chosen {
  cursor: grabbing;
  box-shadow: 0 .55rem 1rem color-mix(in srgb, var(--text) 16%, transparent);
}

.layout-unit-card.sortable-ghost {
  opacity: .45;
}

.layout-row-break {
  display: flex;
  align-items: center;
  gap: .5rem;
  padding: .2rem .5rem;
}

.layout-row-break hr {
  flex: 1;
  margin: 0;
  border-style: dashed;
  opacity: .35;
}

.settings-field-group {
  margin: 0 0 1rem;
  padding: 0;
  border: 0;
}

.settings-field-group__legend {
  float: none;
  width: auto;
  margin-bottom: .5rem;
  color: var(--text-muted);
  font-size: .7rem;
  font-weight: 650;
  letter-spacing: .05em;
  text-transform: uppercase;
}

.settings-field-group__rule {
  margin: 0 0 1rem;
  opacity: .35;
}

.manage-settings-content {
  display: grid;
  /* minmax(0, 1fr), not the default auto track: an auto track sizes to its items'
     min-content, so one wide table pushes the whole settings column past the viewport
     instead of scrolling inside its own card. */
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
  min-width: 0;
  transition: opacity .15s ease;
}

.manage-settings-jump-navigation {
  position: sticky;
  top: calc(.75rem + var(--manage-settings-primary-nav-height) + .5rem);
  z-index: 19;
  display: flex;
  align-items: center;
  gap: .65rem;
  min-width: 0;
  padding: .5rem .65rem;
  border: 1px solid color-mix(in srgb, var(--manage-accent) 22%, var(--border));
  border-radius: .85rem;
  background: color-mix(in srgb, var(--manage-accent) 4%, var(--surface));
  box-shadow: 0 .2rem .6rem color-mix(in srgb, var(--text) 7%, transparent);
}

.manage-settings-jump-navigation__label {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 750;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.manage-settings-jump-navigation__links {
  display: flex;
  flex: 1 1 auto;
  flex-wrap: wrap;
  gap: .3rem;
  min-width: 0;
}

.manage-settings-jump-link {
  display: inline-flex;
  align-items: center;
  min-height: 1.9rem;
  padding: .3rem .55rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 600;
  line-height: 1.15;
  text-decoration: none;
  transition: background-color .15s ease, border-color .15s ease, color .15s ease;
}

.manage-settings-jump-link:hover {
  background: var(--surface-2);
  color: var(--text);
}

.manage-settings-jump-link:focus-visible {
  color: var(--text);
  outline: 3px solid color-mix(in srgb, var(--manage-accent) 38%, transparent);
  outline-offset: 1px;
}

.manage-settings-jump-link.active {
  border-color: color-mix(in srgb, var(--manage-accent) 65%, var(--border));
  background: color-mix(in srgb, var(--manage-accent) 12%, var(--surface));
  color: var(--text);
  font-weight: 750;
}

.manage-settings-content > :target {
  scroll-margin-top:
    calc(2rem + var(--manage-settings-primary-nav-height) + var(--manage-settings-jump-nav-height));
}

.manage-settings-content.is-loading {
  opacity: .55;
  pointer-events: none;
}

/* Dark mode: management labels read on --text, never on link blue.
   Bootstrap keeps its light-mode blue for .btn-link / .btn-outline-primary /
   .text-primary and bare <a>s inherit --link, all of which sit near 3:1 against
   the dark card surface. Inside a .manage-page the hue moves to the border,
   tint and fill instead — the same rule the .btn-outline-secondary selected
   state already follows (§17). Scoped to .manage-page, which is the shared
   wrapper on Manage overview, Settings, Users & Activity and Platform Admin,
   so link colour on dashboards and in the sidebar is untouched.

   Why a component's own `color` is not enough here: §25 nests `a { color:
   var(--link) }` inside html[data-bs-theme="dark"], which resolves to (0,1,1)
   and so outranks every single-class rule like .manage-settings-tab (0,1,0).
   In dark mode that turned tabs, destination cards and jump links blue even
   though each already declares --text. These rules clear that bar. */
html[data-bs-theme="dark"] .manage-page a:not(.btn):not(.manage-settings-jump-link),
html[data-bs-theme="dark"] .manage-page a:not(.btn):not(.manage-settings-jump-link):hover,
html[data-bs-theme="dark"] .manage-page .btn-link,
html[data-bs-theme="dark"] .manage-page .btn-link:hover,
html[data-bs-theme="dark"] .manage-page .btn-link:focus-visible {
  color: var(--text);
}

/* The jump nav keeps its designed two-tier read — muted at rest, --text once
   hovered or marked .active — which is the light-mode behaviour the §25 anchor
   rule was overriding. It is handled separately from the blanket rule above so
   the resting state stays muted rather than being flattened to --text. */
html[data-bs-theme="dark"] .manage-page .manage-settings-jump-link {
  color: var(--text-muted);
}

html[data-bs-theme="dark"] .manage-page .manage-settings-jump-link:hover,
html[data-bs-theme="dark"] .manage-page .manage-settings-jump-link:focus-visible,
html[data-bs-theme="dark"] .manage-page .manage-settings-jump-link.active {
  color: var(--text);
}

html[data-bs-theme="dark"] .manage-page .btn-outline-primary {
  border-color: color-mix(in srgb, var(--link) 55%, var(--border));
  color: var(--text);
}

html[data-bs-theme="dark"] .manage-page .btn-outline-primary:hover,
html[data-bs-theme="dark"] .manage-page .btn-outline-primary:focus-visible,
html[data-bs-theme="dark"] .manage-page .btn-outline-primary:active {
  background: color-mix(in srgb, var(--link) 22%, var(--surface));
  border-color: color-mix(in srgb, var(--link) 65%, var(--border));
  color: var(--text);
}

/* Bootstrap's .text-primary utility is !important, so the decorative blue on
   modal titles and icons needs the same weight to resolve to --text. */
html[data-bs-theme="dark"] .manage-page .text-primary {
  color: var(--text) !important;
}

/* DataTables paints .paginate_button with its own !important colours (§10), so
   the resting page numbers need matching weight. The .current/:hover state is
   left alone — its label is white on a solid --link fill, which already reads. */
html[data-bs-theme="dark"] .manage-page .dataTables_wrapper .dataTables_paginate
  .paginate_button:not(.current):not(.disabled):not(:hover) {
  color: var(--text) !important;
}

/* Preserve the original OEE threshold control after moving the unchanged card to a route-backed page. */
.threshold-bar {
  width: 100%;
  height: 8px;
  border-radius: 4px;
}

.dual-range-wrap {
  position: relative;
  height: 28px;
}

.dual-range-wrap input[type="range"] {
  position: absolute;
  left: 0;
  width: 100%;
  height: 28px;
  margin: 0;
  padding: 0;
  appearance: none;
  background: transparent;
  pointer-events: none;
}

.dual-range-wrap input[type="range"]::-webkit-slider-thumb {
  width: 18px;
  height: 18px;
  appearance: none;
  border: 2px solid #495057;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
  cursor: grab;
  pointer-events: all;
}

.dual-range-wrap input[type="range"]:active::-webkit-slider-thumb {
  cursor: grabbing;
}

.dual-range-wrap input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border: 2px solid #495057;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 1px 4px rgba(0, 0, 0, .3);
  cursor: grab;
  pointer-events: all;
}

.dual-range-wrap input[type="range"]::-webkit-slider-runnable-track,
.dual-range-wrap input[type="range"]::-moz-range-track {
  background: transparent;
}

@media (max-width: 991.98px) {
  .manage-settings-navigation {
    position: static;
  }

  .manage-settings-jump-navigation {
    position: static;
  }

  .manage-settings-content > :target {
    scroll-margin-top: 1rem;
  }
}

/* ── Unit activity timeline ─────────────────────────────────────────────── */
.unit-timeline {
  min-width: 0;
  color: var(--text);
}

.unit-timeline__toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  min-height: 2.25rem;
  margin-bottom: .35rem;
  padding: .75rem 1rem 0;
}

/* Right-aligned, after the tools in source order but before them visually — the key
   reads next to the plot it describes, and the controls stay pinned to the corner. */
.unit-timeline__legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: .35rem .8rem;
  min-width: 0;
  margin-left: auto;
  color: var(--text-muted);
  font-size: .76rem;
}

.unit-timeline__legend-more {
  padding: .05rem .4rem;
  user-select: none;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-size: .72rem;
  line-height: 1.4;
}

.unit-timeline__legend-more:hover,
.unit-timeline__legend-more[aria-expanded="true"] {
  border-color: color-mix(in srgb, var(--text) 32%, transparent);
  color: var(--text);
}

/* `contents` so each revealed reason wraps as its own chip alongside the core four,
   instead of the whole group jumping to a line of its own as one flex item. */
.unit-timeline__legend-reasons {
  display: contents;
}

.unit-timeline__legend-reasons[hidden] {
  display: none;
}

.unit-timeline__legend-item {
  display: inline-flex;
  align-items: center;
  gap: .34rem;
  white-space: nowrap;
}

.unit-timeline__swatch {
  width: .62rem;
  height: .62rem;
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, var(--timeline-swatch) 74%, var(--text));
  border-radius: .22rem;
  background: var(--timeline-swatch);
}

.unit-timeline__tools {
  flex: 0 0 auto;
}

.unit-timeline__viewport {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.unit-timeline__svg {
  display: block;
  width: 100%;
  height: auto;
  min-height: 250px;
  touch-action: none;
  user-select: none;
}

.unit-timeline__svg:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--link) 45%, transparent);
  outline-offset: -3px;
}

/* A click on the chart focuses it (tabindex="0"), and the UA then paints its own ring
   round the whole plot — noise the mouse user never asked for. Keyboard focus still
   gets the ring above, so this costs nothing in a11y terms. */
.unit-timeline__svg:focus:not(:focus-visible),
.unit-timeline__segment:focus:not(:focus-visible) {
  outline: none;
}

.unit-timeline__pan-surface {
  fill: transparent;
  cursor: crosshair;
}

/* The band swept out by a drag-zoom, before the release commits it. */
.unit-timeline__zoom-band {
  fill: color-mix(in srgb, var(--link) 16%, transparent);
  stroke: var(--link);
  stroke-width: 1;
  pointer-events: none;
}

.unit-timeline__grid {
  stroke: var(--chart-grid);
  stroke-width: 1;
  stroke-dasharray: 2 5;
}

.unit-timeline__axis-label,
.unit-timeline__navigator-label {
  fill: var(--text-muted);
  font-size: 10px;
  font-weight: 600;
}

.unit-timeline__navigator-label {
  font-size: 9px;
  letter-spacing: .06em;
  text-transform: uppercase;
}

.unit-timeline__segment {
  cursor: default;
}

.unit-timeline__segment--idle,
.unit-timeline__segment--downtime {
  cursor: pointer;
}

.unit-timeline__segment:focus-visible .unit-timeline__ribbon,
.unit-timeline__segment:focus-visible .unit-timeline__rail {
  stroke: var(--text);
  stroke-width: 2.5;
}

.unit-timeline__ribbon {
  fill-opacity: .26;
  stroke-width: 1.2;
  transition: fill-opacity .15s ease;
}

/* A dark ground carries a translucent fill much further than a white one, so the
   light theme needs the extra weight to keep the ribbon from washing out. */
html[data-bs-theme="dark"] .unit-timeline__ribbon {
  fill-opacity: .18;
}

.unit-timeline__segment:hover .unit-timeline__ribbon,
.unit-timeline__segment:focus .unit-timeline__ribbon {
  fill-opacity: .3;
}

.unit-timeline__segment--rework .unit-timeline__ribbon {
  stroke-dasharray: 5 3;
}

.unit-timeline__ribbon-edge {
  stroke-width: 2.25;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.unit-timeline__inferred-end-marker {
  pointer-events: none;
  stroke: var(--text);
  stroke-width: 1.5;
  stroke-dasharray: 3 2;
}

.unit-timeline__tooltip-disclosure {
  color: var(--text-muted);
}

.unit-timeline__transition {
  stroke-width: 1;
  opacity: .45;
}

.unit-timeline__rail {
  opacity: 1;
  stroke: color-mix(in srgb, currentColor 55%, var(--text));
  stroke-width: .8;
}

.unit-timeline__rail--planned {
  opacity: .82;
}

.unit-timeline__planned-overlay {
  pointer-events: none;
  stroke-linecap: square;
  stroke: var(--surface);
  opacity: .5;
}

.unit-timeline__segment:hover .unit-timeline__rail,
.unit-timeline__segment:focus .unit-timeline__rail {
  opacity: 1;
  filter: drop-shadow(0 0 3px color-mix(in srgb, var(--text) 24%, transparent));
}

.unit-timeline__label-chip {
  fill: var(--surface);
  stroke: var(--border);
  stroke-width: .7;
}

.unit-timeline__duration {
  fill: var(--text);
  font-size: 10px;
  font-weight: 700;
  pointer-events: none;
}

.unit-timeline__highlight {
  fill: color-mix(in srgb, var(--bs-warning) 17%, transparent);
  stroke: var(--bs-warning);
  stroke-width: 1.5;
  stroke-dasharray: 5 4;
}

.unit-timeline__highlight--rail {
  fill: color-mix(in srgb, var(--bs-warning) 25%, transparent);
  stroke-width: 1.25;
}

.unit-timeline__empty {
  fill: var(--text-muted);
  font-size: 13px;
}

.unit-timeline__navigator-track {
  fill: var(--surface-sunken);
  stroke: var(--border);
  stroke-width: 1;
}

.unit-timeline__navigator-segment {
  opacity: .52;
}

.unit-timeline__navigator-window {
  fill: color-mix(in srgb, var(--link) 12%, transparent);
  stroke: var(--link);
  stroke-width: 1.5;
  cursor: grab;
}

.unit-timeline__navigator-handle {
  fill: var(--surface);
  stroke: var(--link);
  stroke-width: 1.4;
  cursor: ew-resize;
}

.unit-timeline__tooltip {
  position: absolute;
  z-index: 5;
  display: grid;
  gap: .16rem;
  width: min(15rem, calc(100% - 1rem));
  padding: .55rem .65rem;
  border: 1px solid var(--border);
  border-radius: .65rem;
  background: var(--surface);
  box-shadow: 0 .5rem 1.5rem rgba(0, 0, 0, .18);
  color: var(--text);
  font-size: .76rem;
  line-height: 1.35;
  pointer-events: none;
}

.unit-timeline__tooltip[hidden] {
  display: none;
}

.unit-timeline__tooltip span {
  color: var(--text-muted);
}

/* The compact variant keeps its toolbar: the legend still has to explain the colours,
   and dropping the zoom/reset buttons would leave the modal with no way back from a
   zoomed view now that a plain wheel scrolls the page. */
.unit-timeline--compact .unit-timeline__toolbar {
  padding: 0 0 .15rem;
  min-height: 1.9rem;
}

.unit-timeline--compact .unit-timeline__viewport {
  overflow: visible;
  border: 0;
  border-radius: 0;
  background: transparent;
}

.unit-timeline--compact .unit-timeline__svg {
  min-height: 255px;
}

.unit-timeline--compact .unit-timeline__ribbon {
  fill-opacity: .2;
  stroke-width: .7;
}

html[data-bs-theme="dark"] .unit-timeline--compact .unit-timeline__ribbon {
  fill-opacity: .12;
}

.unit-timeline--compact .unit-timeline__segment:hover .unit-timeline__ribbon,
.unit-timeline--compact .unit-timeline__segment:focus .unit-timeline__ribbon {
  fill-opacity: .3;
}

.unit-timeline--compact .unit-timeline__ribbon-edge {
  stroke-width: 2.2;
}

.unit-timeline--compact .unit-timeline__axis-label {
  font-size: 9px;
}

.unit-timeline--compact .unit-timeline__duration--rail {
  font-size: 11px;
  font-weight: 800;
}

@media (max-width: 575.98px) {
  .unit-timeline__toolbar {
    align-items: flex-start;
    flex-direction: column;
  }
  .unit-timeline__tools {
    align-self: flex-end;
  }
  .unit-timeline__svg {
    min-height: 235px;
  }
}

@media (max-width: 575.98px) {
  .manage-page-header {
    display: grid;
  }

  .manage-scope-badge {
    justify-self: start;
  }

  .manage-destination-card {
    grid-template-columns: 2.5rem 1fr;
  }

  .manage-destination-card__arrow,
  .manage-destination-card__meta {
    display: none;
  }

  .manage-settings-navigation {
    margin-inline: -.25rem;
  }

  .manage-settings-tab {
    min-height: 2.55rem;
    padding: .55rem .7rem;
    font-size: .82rem;
  }

  .manage-settings-jump-navigation {
    align-items: flex-start;
    padding: .55rem;
  }

  .manage-settings-jump-navigation__label {
    padding-top: .4rem;
  }

  .manage-settings-jump-link {
    font-size: .74rem;
  }

}

@media (max-width: 420px) {
  .energy-summary-card__header { gap: 0.4rem; }
  .energy-summary-card__title { font-size: 0.8rem; }
  .report-kpi-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .report-kpi-card { min-height: 5.75rem; padding: 0.5rem; }
    .report-kpi-card__header h5 { font-size: 0.72rem; }
    .report-kpi-card__delta { font-size: 0.6rem; padding: 0.2rem 0.35rem; }
}

/* === 17. Buttons === */
/* === Shared selector dropdowns ===
   Factory and report-period pickers use a compact raised toggle with a menu that
   follows the collapsed-sidebar flyout language: an elevated surface, inset
   rounded rows, and a subtle accent for the selected value. The selected state
   is communicated by tint and border; labels remain primary text rather than
   link blue in either theme. */
.selector-toggle {
    border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--surface) 78%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    color: var(--text);
    box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.08);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    line-height: 1.2;
    max-width: 100%;
    padding: 0.5rem 1rem;
    transition: border-color 0.15s, box-shadow 0.15s, color 0.15s, background-color 0.15s;
    white-space: nowrap;
}

.selector-toggle:hover,
.selector-toggle:focus-visible,
.selector-toggle.show {
    border-color: color-mix(in srgb, var(--link) 35%, var(--border));
    color: var(--text);
    box-shadow: 0 0.45rem 1rem rgba(0, 0, 0, 0.12);
}

.selector-menu {
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: 0 0.55rem 1.2rem color-mix(in srgb, var(--text) 18%, transparent);
    padding: 6px;
}

.selector-menu > li { margin: 0; }

.selector-menu .dropdown-item {
    align-items: center;
    border-left: 3px solid transparent;
    border-radius: 8px;
    color: var(--text);
    display: flex;
    font-size: 0.8rem;
    font-weight: 500;
    gap: 0.4rem;
    padding: 0.55rem 0.7rem;
    text-decoration: none;
}

.selector-menu .dropdown-item:hover,
.selector-menu .dropdown-item:focus-visible {
    background: var(--surface-sunken);
    color: var(--text);
}

.selector-menu .dropdown-item.active,
.selector-menu .dropdown-item:active {
    background: color-mix(in srgb, var(--link) 12%, var(--surface));
    border-left-color: color-mix(in srgb, var(--link) 70%, var(--border));
    color: var(--text);
    font-weight: 600;
}

.selector-menu .dropdown-item.active:hover,
.selector-menu .dropdown-item.active:focus-visible,
.selector-menu .dropdown-item:active:hover {
    background: color-mix(in srgb, var(--link) 16%, var(--surface));
    color: var(--text);
}

.selector-menu .dropdown-item i { color: inherit; }

/* Report period pickers are intentionally denser than the toolbar factory
   picker, while still using the same shared control and menu language. */
.dropdown-select .selector-toggle {
    background-color: color-mix(in srgb, var(--surface) 88%, transparent);
    font-size: 0.8rem;
    font-weight: 600;
    gap: 0.35rem;
    padding: 0.375rem 0.75rem;
}

.dropdown-select .selector-toggle span {
    overflow: hidden;
    text-overflow: ellipsis;
}

.dropdown-select .selector-menu,
.factory-picker .selector-menu {
    max-height: 40vh;
    overflow-y: auto;
}

/* The dark-mode global anchor rule is more specific than Bootstrap's plain
   .dropdown-item selector. Restate the selector contract at higher specificity
   so neither idle nor selected picker options inherit link blue. */
html[data-bs-theme="dark"] .selector-toggle,
html[data-bs-theme="dark"] .selector-menu .dropdown-item,
html[data-bs-theme="dark"] .selector-menu .dropdown-item:hover,
html[data-bs-theme="dark"] .selector-menu .dropdown-item:focus-visible,
html[data-bs-theme="dark"] .selector-menu .dropdown-item.active,
html[data-bs-theme="dark"] .selector-menu .dropdown-item:active {
    color: var(--text);
}

/* Global button language — unifies every Bootstrap .btn across the app with the
   time-period bar's pill look (macros/time_period_bar.html §.tp-btn). styles.css loads
   AFTER Bootstrap, so these plain-`.btn` rules win at equal specificity without
   !important, while Bootstrap's higher-specificity rules for grouped buttons
   (.btn-group > .btn:not(:first-child)) and the icon-only .btn-close keep their own
   styling untouched. Semantic colours (primary/danger/success/warning/info) are left
   to Bootstrap — only shape, shadow and transition are unified here. */
.btn {
    border-radius: 999px;            /* full pill, matches the tp-bar */
    font-weight: 500;
    box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.08);
    transition: border-color 0.15s, box-shadow 0.15s, color 0.15s, background-color 0.15s, transform 0.15s;
}
.btn:hover,
.btn:focus-visible {
    box-shadow: 0 0.45rem 1rem rgba(0, 0, 0, 0.12);
}

/* Neutral / toolbar buttons → the exact tp-bar pill (surface fill, token border,
   link-tinted hover + selected). This is the app's dominant button and also restyles
   every bespoke class built on btn-outline-secondary (.quick-period, .btn-window,
   .rework-selection-btn, .unit-filter-btn, .reveal-conn-btn, .toggle-password-btn, …)
   with no per-class edits, and makes them dark-mode-correct via tokens. */
.btn-outline-secondary,
.btn-secondary {
    background: var(--surface);
    border-color: color-mix(in srgb, var(--border) 70%, transparent);
    color: var(--text-muted);
}
.btn-outline-secondary:hover,
.btn-outline-secondary:focus,
.btn-secondary:hover,
.btn-secondary:focus {
    background: var(--surface);
    border-color: color-mix(in srgb, var(--link) 35%, var(--border));
    color: var(--text);
}
.btn-check:checked + .btn-outline-secondary,
.btn-outline-secondary.active,
.btn-secondary.active {
    background: color-mix(in srgb, var(--link) 8%, var(--surface));
    border-color: color-mix(in srgb, var(--link) 50%, var(--border));
    /* Blue is the selected-state cue, not the label colour. This also covers
       local segmented controls such as the OEE Layout / OEE sort buttons. */
    color: var(--text);
}

/* Text buttons stay inline — no raised pill shadow. */
.btn-link,
.btn-link:hover,
.btn-link:focus {
    box-shadow: none;
}

/* Date / time pickers — match the unified pill control language (mirrors the
   time-period bar's .tp-field) so standalone timepickers (form-control datetime
   inputs on reports/downtimes/hydra pages) sit consistently beside the pill buttons.
   Only radius + a soft resting shadow are added; Bootstrap's form-control background,
   border and blue :focus ring are left intact (the focus ring replaces the resting
   shadow on focus, so accessibility is preserved). */
input[type="date"],
input[type="datetime-local"],
input[type="time"] {
    border-radius: 999px;
    box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.08);
    transition: border-color 0.15s, box-shadow 0.15s;
}

/* Gas action buttons; also used on the Downtimes page */
.btn-gas {
    background-color: #16ceda;
    color: #fff;
    border: none;
    cursor: pointer;
    transition: transform 0.2s, box-shadow 0.2s;
}
.btn-gas:hover, .btn-gas:focus {
    background-color: #139eaa;
    color: #fff;
    transform: scale(1.05);
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3) !important;
}
.btn-gas[data-selected="true"] {
    box-shadow: 0 0 0 3px rgba(255, 255, 255, 0.5), 0 4px 12px rgba(0, 0, 0, 0.3) !important;
    transform: scale(1.05);
}

/* === 17a. Read-only mode ===
   Applied by components/read_only_mode.html to every write control on a read-only (demo) session.
   Deliberately NOT the `disabled` property on buttons: Chrome/Firefox swallow pointer events on a
   disabled element, so the tooltip explaining why the control is inert could never fire. The
   control stays hoverable and focusable; a capture-phase handler stops activation. */
.is-read-only {
    opacity: 0.55;
    cursor: not-allowed;
}
.is-read-only:focus-visible {
    outline: 2px solid var(--border);
    outline-offset: 2px;
}

/* === 18. Accordion === */
.accordion-item {
    border-radius: 0.5rem;
    overflow: hidden;
    margin-bottom: 1rem;
}

.accordion-button:not(.collapsed) {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
    box-shadow: none;
    background-color: #f8f9fa !important;
    color: #212529;
}

.accordion-collapse {
    border-bottom-left-radius: 0.5rem;
    border-bottom-right-radius: 0.5rem;
    overflow: hidden;
}

.accordion-button:focus {
    box-shadow: none;
}

/* Accordion inside a table-card-wrapper: flat, no per-item rounding or gaps */
.table-card-wrapper .accordion {
    border-radius: 0;
}
.table-card-wrapper .accordion-item {
    border-radius: 0;
    margin-bottom: 0;
    border-left: none;
    border-right: none;
}
.table-card-wrapper .accordion-item:first-child {
    border-top: none;
}
.table-card-wrapper .accordion-collapse {
    border-radius: 0;
}

/* === 19. CloEE Advisor Panel === */
.cloee-assistant-panel {
  position: fixed;
  top: 60px;
  right: -32px;
  width: 32px;
  min-width: 0;
  max-width: 32px;
  height: calc(100vh - 60px);
  background: transparent;
  border-left: none;
  box-shadow: none;
  z-index: 1040;
  transition: right 0.3s cubic-bezier(.4,0,.2,1), width 0.3s cubic-bezier(.4,0,.2,1), min-width 0.3s, max-width 0.3s;
  pointer-events: none;
}
.cloee-assistant-panel .cloee-assistant-header,
.cloee-assistant-panel .cloee-assistant-body {
  display: none !important;
}
.cloee-assistant-panel.open {
  right: 0 !important;
  width: 33.33%;
  min-width: 320px;
  max-width: 33.33vw;
  background: #fff;
  border-left: 1px solid #dee2e6;
  box-shadow: -4px 0 16px rgba(0, 0, 0, 0.1);
  transition: right 0.3s cubic-bezier(.4,0,.2,1), width 0.3s cubic-bezier(.4,0,.2,1), min-width 0.3s, max-width 0.3s;
  pointer-events: auto;
}
.cloee-assistant-panel.open .cloee-assistant-header,
.cloee-assistant-panel.open .cloee-assistant-body {
  display: block !important;
}

.cloee-assistant-header {
    position: relative; /* Use positioning instead of flexbox */
    padding: 0.5rem 1.5rem;
    padding-right: 4rem; /* Make room for close button */
    border-bottom: 1px solid #dee2e6;
    background: #f8f9fa;
    min-height: 45px;
    box-sizing: border-box;
}

.cloee-assistant-header h5 {
    color: #212529;
    font-weight: 600;
    margin: 0;
    line-height: 1.5;
    font-size: 1.1rem;
    padding-top: 0.2rem; /* Adjust vertical centering */
}

.cloee-assistant-header .btn-close {
    position: absolute;
    top: 50%;
    right: 1.5rem;
    transform: translateY(-50%); /* Perfect vertical centering */
    margin: 0;
}

.cloee-assistant-body {
    height: calc(100vh - 60px - 45px); /* Total height minus navbar minus smaller header */
    padding: 0.5rem 1.5rem 0.5rem 1.5rem;
    overflow-y: auto;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    width: 100%;
}

/* Main content adjustment when panel is open */
.main-content.cloee-assistant-open {
    margin-right: 33.33%;
    max-width: calc(66.67vw - 200px); /* Account for sidebar */
}

.sidebar-collapsed .main-content.cloee-assistant-open {
    max-width: calc(66.67vw - 60px); /* Account for collapsed sidebar */
}

/* Responsive adjustments */
@media (max-width: 768px) {
    .cloee-assistant-panel {
        width: 100%;
        min-width: 100%;
        max-width: 100vw;
        right: -100%;
    }

    .main-content.cloee-assistant-open {
        margin-right: 100%;
        max-width: 0;
    }

    .sidebar-collapsed .main-content.cloee-assistant-open {
        max-width: 0;
    }
}

@media (min-width: 769px) and (max-width: 1200px) {
    .cloee-assistant-panel {
        min-width: 320px;
        max-width: 400px;
        width: 400px;
    }

    .main-content.cloee-assistant-open {
        margin-right: 400px;
        max-width: calc(100vw - 400px - 200px);
    }

    .sidebar-collapsed .main-content.cloee-assistant-open {
        max-width: calc(100vw - 400px - 60px);
    }
}

/* === 20. Chat Messages === */
.assistant-panel-body {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  width: 100%;
}

.assistant-workspace {
  flex: 1 1 auto;
  min-height: 0;
  min-width: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
}

.chat-conversation-column {
  min-width: 0;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.chat-history-rail,
.chat-outline-rail,
.desktop-active-chat-title {
  display: none;
}

.chat-icon-button,
.session-row-actions-toggle,
.chat-rail-new {
  border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.chat-icon-button,
.session-row-actions-toggle {
  width: 2.25rem;
  height: 2.25rem;
}

.chat-icon-button:hover,
.chat-icon-button:focus,
.session-row-actions-toggle:hover,
.session-row-actions-toggle:focus,
.chat-rail-new:hover,
.chat-rail-new:focus {
  border-color: color-mix(in srgb, var(--link) 35%, var(--border));
  background: var(--surface-sunken);
  color: var(--text);
}

.chat-icon-button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.chat-rail-heading {
  min-height: 2.75rem;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

.chat-rail-new {
  gap: 0.3rem;
  min-height: 2.25rem;
  padding: 0.35rem 0.7rem;
  font-size: 0.78rem;
  font-weight: 600;
}

.desktop-session-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  /* Same gutter fix as .assistant-attention-list directly above it in the rail: reserve
     room for the thumb instead of letting an overlay-style scrollbar sit on the rows. */
  padding: 0.25rem 0.4rem 0.5rem 0;
  scrollbar-color: color-mix(in srgb, var(--text-muted) 55%, transparent) transparent;
  scrollbar-width: thin;
}

.desktop-session-list::-webkit-scrollbar { width: 0.5rem; }
.desktop-session-list::-webkit-scrollbar-track { background: transparent; }
.desktop-session-list::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 55%, transparent);
}
.desktop-session-list::-webkit-scrollbar-corner { background: transparent; }

/* The desktop history rail is navigation, not a second content card. Keep recent chats dense
   and let the active chat earn the only persistent status accent. */
.chat-history-section .desktop-session-list {
  gap: 0.1rem;
  padding-top: 0.1rem;
}

.chat-history-section .desktop-session-row {
  border-left: 2px solid transparent;
  border-radius: 0.4rem;
}

/* A hairline between rows so title+timestamp pairs read as separate list items now that the
   rail has no card fill behind it — same list language as .assistant-attention-row above it. */
.chat-history-section .desktop-session-row + .desktop-session-row {
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}

.chat-history-section .desktop-session-row.active {
  border-left-color: var(--sev-ok);
  background: color-mix(in srgb, var(--sev-ok) 10%, var(--surface));
}

/* Advisor work in the chat rail. A running chat shows a small spinner beside its elapsed time; a
   chat whose answer finished off screen gets an accent dot and a semibold title until it is
   opened. The dot has an aria-label and the row keeps its text, so the cue is never colour alone. */
.session-picker-row.is-run-running .session-picker-row-time,
.session-picker-row.is-run-queued .session-picker-row-time {
  color: var(--text);
}
.session-picker-row-time {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-variant-numeric: tabular-nums;
}
.session-run-spinner {
  flex: 0 0 auto;
  width: 0.625rem;
  height: 0.625rem;
  border: 1.5px solid color-mix(in srgb, var(--link) 25%, transparent);
  border-top-color: var(--link);
  border-radius: 50%;
  animation: session-run-spin 0.9s linear infinite;
}
@keyframes session-run-spin {
  to { transform: rotate(360deg); }
}

.session-unread-dot {
  flex: 0 0 auto;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--link);
  animation: session-unread-in 0.24s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@keyframes session-unread-in {
  from { transform: scale(0); }
  to   { transform: scale(1); }
}
.session-picker-row.has-unread-answer .session-picker-row-title {
  font-weight: 600;
  color: var(--text);
}
.session-picker-row.is-unread-error .session-unread-dot { background: var(--sev-critical); }

@media (prefers-reduced-motion: reduce) {
  .session-run-spinner {
    animation: none;
    border-color: var(--link);
  }
  .session-unread-dot { animation: none; }
}

.chat-history-section .desktop-session-row .session-picker-select {
  padding: 0.42rem 0.38rem;
}

.chat-history-section .desktop-session-row .session-picker-row-title {
  font-size: 0.78rem;
}

.chat-history-section .desktop-session-row .session-picker-row-time {
  font-size: 0.68rem;
}

.chat-history-section #desktop-load-more-sessions {
  flex: 0 0 auto;
  width: auto;
  align-self: stretch;
  margin-top: 0.3rem;
  border: 1px dashed color-mix(in srgb, var(--border) 90%, transparent);
  border-radius: 0.45rem;
  background: var(--surface);
  color: var(--text-muted);
  padding: 0.38rem 0.45rem;
  font-size: 0.72rem;
}

.chat-history-section #desktop-load-more-sessions:hover,
.chat-history-section #desktop-load-more-sessions:focus-visible {
  border-color: color-mix(in srgb, var(--link) 55%, var(--border));
  background: var(--surface-sunken);
  color: var(--text);
}

.chat-history-section,
.assistant-attention-rail {
  box-sizing: border-box;
  min-width: 0;
  min-height: 0;
}

.assistant-attention-rail {
  display: flex;
  flex-direction: column;
}

.assistant-attention-heading {
  gap: 0.5rem;
}

/* Worst severity across every listed factory, so the heading still reports status
   once the first rows have scrolled out of the rail. */
.assistant-attention-count {
  flex: 0 0 auto;
  border-radius: 999px;
  color: var(--text-muted);
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 0.125rem 0.5rem;
  white-space: nowrap;
}

.assistant-attention-count.is-danger {
  background: color-mix(in srgb, var(--sev-critical) 14%, var(--surface));
  color: var(--danger-text);
}

.assistant-attention-list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0;
  /* A real right-hand gutter, not just the rail's own outer padding: an overlay-style
     OS scrollbar draws over this list's own content box, and with no gutter reserved
     here its thumb sat on top of each row, eating the click before it reached the row. */
  padding: 0.125rem 0.4rem 0.25rem 0;
  scrollbar-color: color-mix(in srgb, var(--text-muted) 55%, transparent) transparent;
  scrollbar-width: thin;
}

.assistant-attention-list::-webkit-scrollbar { width: 0.5rem; }
.assistant-attention-list::-webkit-scrollbar-track { background: transparent; }
.assistant-attention-list::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 55%, transparent);
}
.assistant-attention-list::-webkit-scrollbar-corner { background: transparent; }

.assistant-attention-status {
  color: var(--text-muted);
  font-size: 0.8125rem;
  line-height: 1.35;
  padding: 0.375rem 0.25rem;
}

.assistant-attention-status.is-success,
.assistant-attention-status.is-danger {
  color: var(--text);
}

/* Rows read as the same list language as .desktop-session-row directly below them —
   same padding, same hover surface — rather than a denser second idiom. */
.assistant-attention-row {
  --attention-accent: var(--text-muted);
  width: 100%;
  min-width: 0;
  display: grid;
  grid-template-columns: 1rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem;
  border: 0;
  border-radius: 0.4rem;
  background: transparent;
  color: var(--text);
  padding: 0.5rem 0.375rem;
  text-align: left;
}

.assistant-attention-row + .assistant-attention-row {
  border-top: 1px solid color-mix(in srgb, var(--border) 72%, transparent);
}

.assistant-attention-row.is-danger {
  --attention-accent: var(--danger-text);
}

.assistant-attention-row > i:first-child {
  color: var(--attention-accent);
  font-size: 0.8125rem;
}

.assistant-attention-row:hover {
  background: var(--surface-sunken);
  color: var(--text);
}

.assistant-attention-row:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: -2px;
}

.assistant-attention-row__copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.0625rem;
}

.assistant-attention-row__copy strong {
  overflow: hidden;
  color: var(--text);
  font-size: 0.875rem;
  font-weight: 600;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assistant-attention-row__copy > span {
  overflow: hidden;
  color: var(--text-muted);
  font-size: 0.75rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.assistant-attention-row__arrow {
  color: var(--text-muted);
  font-size: 0.75rem;
}

.desktop-older-sessions-marker {
  color: var(--text-muted);
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  margin: 0.42rem 0 0.18rem;
  padding-top: 0.34rem;
  border-top: 1px solid var(--border);
  text-transform: uppercase;
}


.desktop-session-row {
  grid-template-columns: minmax(0, 1fr) auto;
}

.desktop-session-row .session-picker-select {
  padding: 0.55rem 0.45rem;
}

.session-row-actions {
  align-self: center;
}

/* Positioning only — the visual treatment is shared with the toolbar menu via .chat-actions-menu. */
.session-actions-popover {
  position: fixed;
  z-index: 1050;
}

.session-actions-popover[hidden] {
  display: none !important;
}

.session-row-actions-toggle {
  width: 1.9rem;
  height: 1.9rem;
  border-color: transparent;
  background: transparent;
}

/* Shared look for both chat action menus: the toolbar "..." dropdown and the body-level popover
   the history rail opens. Compact rows, icon gutter, and a soft elevated card. */
.chat-actions-menu {
  min-width: 12.5rem;
  padding: 0.3rem;
  border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
  border-radius: 0.75rem;
  background: var(--surface);
  box-shadow: 0 0.75rem 1.75rem rgba(0, 0, 0, 0.16), 0 0.15rem 0.4rem rgba(0, 0, 0, 0.08);
  animation: chatActionsMenuIn 0.12s ease-out both;
}

@keyframes chatActionsMenuIn {
  from { opacity: 0; transform: translateY(-0.25rem); }
  to   { opacity: 1; transform: translateY(0); }
}

.chat-actions-menu .dropdown-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  width: 100%;
  border: 0;
  border-radius: 0.5rem;
  background: transparent;
  color: var(--text);
  padding: 0.45rem 0.6rem;
  font-size: 0.83rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: left;
}

.chat-actions-menu .dropdown-item .bi {
  flex: 0 0 1rem;
  color: var(--text-muted);
  font-size: 0.9rem;
  text-align: center;
}

.chat-actions-menu .dropdown-item:hover,
.chat-actions-menu .dropdown-item:focus-visible {
  background: var(--surface-sunken);
  color: var(--text);
}

.chat-actions-menu .dropdown-item:hover .bi,
.chat-actions-menu .dropdown-item:focus-visible .bi {
  color: var(--text);
}

.chat-actions-menu .dropdown-item.is-danger,
.chat-actions-menu .dropdown-item.is-danger .bi {
  color: #dc3545;
}

.chat-actions-menu .dropdown-item.is-danger:hover,
.chat-actions-menu .dropdown-item.is-danger:focus-visible {
  background: color-mix(in srgb, #dc3545 12%, var(--surface));
  color: #dc3545;
}

.chat-actions-menu .dropdown-item[hidden] {
  display: none;
}

.chat-actions-menu .dropdown-divider {
  margin: 0.3rem 0.4rem;
  border-top-color: color-mix(in srgb, var(--border) 70%, transparent);
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .chat-actions-menu { animation: none; }
}

/* Renaming happens where the title is shown — toolbar, history row, or picker toggle — so the
   editor has to sit in whichever slot it replaced. */
.inline-rename-input {
  flex: 1 1 auto;
  min-width: 0;
  width: 100%;
  border: 1px solid color-mix(in srgb, var(--link) 55%, var(--border));
  border-radius: 0.45rem;
  background: var(--surface);
  color: var(--text);
  padding: 0.3rem 0.5rem;
  font-size: 0.85rem;
  font-weight: 600;
  line-height: 1.3;
  box-shadow: 0 0 0 0.15rem color-mix(in srgb, var(--link) 18%, transparent);
}

.inline-rename-input:focus {
  outline: none;
  border-color: var(--link);
  box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--link) 25%, transparent);
}

.inline-rename-input:disabled {
  opacity: 0.7;
  cursor: progress;
}

.session-picker-row .inline-rename-input {
  margin: 0.25rem 0.35rem;
}

/* Narrow layouts hide the toolbar title, so the editor stands in for the picker toggle — which
   is sized by its content and would otherwise collapse around an empty input. */
.session-picker:has(.inline-rename-input) {
  flex: 1 1 12rem;
}

/* Transient chat confirmations ("Share link copied"). Floats centred over the top of the chat
   viewport itself (anchored to .chat-outer-wrapper, which is position: relative) rather than the
   screen corner, so it reads as feedback on the chat, not a generic page-level flash toast. */
.chat-toast-host {
  position: absolute;
  top: 0.75rem;
  left: 50%;
  transform: translateX(-50%);
  z-index: 1090;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  width: max-content;
  max-width: min(26rem, calc(100% - 1.5rem));
  pointer-events: none;
}

.chat-toast {
  pointer-events: auto;
  cursor: pointer;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.5rem;
  border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  padding: 0.5rem 1rem;
  font-size: 0.82rem;
  font-weight: 500;
  line-height: 1.3;
  box-shadow: 0 0.75rem 1.75rem rgba(0, 0, 0, 0.18);
  animation: chatToastIn 0.18s cubic-bezier(0.16, 1, 0.3, 1) both;
}

.chat-toast.is-leaving {
  animation: chatToastOut 0.18s ease-in both;
}

.chat-toast .bi {
  font-size: 0.9rem;
}

.chat-toast--success .bi { color: #198754; }
.chat-toast--info .bi { color: var(--link); }
.chat-toast--danger .bi { color: #dc3545; }

.chat-toast--info,
.chat-toast--danger {
  border-radius: 0.75rem;
}

.chat-toast-detail {
  flex: 1 1 100%;
  overflow-wrap: anywhere;
  user-select: all;
  color: var(--text-muted);
  font-size: 0.76rem;
}

@keyframes chatToastIn {
  from { opacity: 0; transform: translateY(-0.6rem) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}

@keyframes chatToastOut {
  from { opacity: 1; transform: translateY(0); }
  to   { opacity: 0; transform: translateY(-0.4rem); }
}

@media (prefers-reduced-motion: reduce) {
  .chat-toast,
  .chat-toast.is-leaving { animation: none; }
}

.session-picker-title-line {
  width: 100%;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.35rem;
}

.session-shared-indicator {
  flex: 0 0 auto;
  color: var(--text-muted);
  font-size: 0.78rem;
}

.conversation-outline {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  /* Hug content and centre it in the rail instead of stretching the list edge-to-edge —
     a short conversation used to pin "Start" to the top and "Latest" to the bottom with a
     large empty gap between them. */
  justify-content: center;
  align-items: center;
  gap: 0.5rem;
  padding-right: 0.15rem;
}

.conversation-outline-list {
  flex: 0 1 auto;
  width: 100%;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 0.18rem;
  /* A dedicated gutter plus a thin, always-inset thumb: without this the native
     scrollbar drew flush against the item edge and its thumb sat directly on top
     of the dash/text click target, so a scroll drag was read as an item click. */
  padding-right: 0.4rem;
  scrollbar-color: color-mix(in srgb, var(--text-muted) 55%, transparent) transparent;
  scrollbar-width: thin;
}

.conversation-outline-list::-webkit-scrollbar { width: 0.5rem; }
.conversation-outline-list::-webkit-scrollbar-track { background: transparent; }
.conversation-outline-list::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-muted) 55%, transparent);
}
.conversation-outline-list::-webkit-scrollbar-corner { background: transparent; }

.conversation-outline-jump {
  flex: 0 0 auto;
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  border: 1px solid color-mix(in srgb, var(--border) 75%, transparent);
  background: var(--surface);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.85rem;
}

.conversation-outline-jump:hover,
.conversation-outline-jump:focus-visible {
  border-color: color-mix(in srgb, var(--link) 35%, var(--border));
  background: var(--surface-sunken);
  color: var(--text);
}

/* An index, not a control strip: a dash and the question text, with the dash carrying the
   active state. No rail, pill or fill — the outline sits directly on the blurred backdrop. */
.conversation-outline-item {
  width: 100%;
  min-width: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--text-muted);
  display: grid;
  grid-template-columns: 0.75rem minmax(0, 1fr);
  align-items: start;
  gap: 0.4rem;
  padding: 0.3rem 0.1rem;
  font-size: 0.74rem;
  line-height: 1.25;
  text-align: left;
}

.conversation-outline-dash {
  color: var(--border);
  line-height: 1.25;
}

.conversation-outline-item span:last-child {
  overflow: hidden;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
}

.conversation-outline-item:hover,
.conversation-outline-item:focus-visible,
.conversation-outline-item.active {
  color: var(--text);
}

.conversation-outline-item:hover .conversation-outline-dash,
.conversation-outline-item:focus-visible .conversation-outline-dash,
.conversation-outline-item.active .conversation-outline-dash {
  color: var(--text);
}

.conversation-outline-item.active {
  font-weight: 500;
}

.shared-chat-page {
  max-width: 980px;
  margin: 0 auto;
  padding-top: 2rem;
  padding-bottom: 2rem;
}

.shared-chat-header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  margin-bottom: 1rem;
}

.shared-chat-eyebrow {
  color: var(--text-muted);
  font-size: 0.82rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.shared-chat-card {
  min-width: 0;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 1rem;
  background: var(--surface);
  box-shadow: 0 0.6rem 1.5rem rgba(0, 0, 0, 0.08);
}

.shared-chat-scroll {
  min-height: 18rem;
  max-height: calc(100vh - 14rem);
  padding: 1.25rem !important;
}

.shared-chat-empty {
  width: 100%;
  margin: auto;
  color: var(--text-muted);
  text-align: center;
}

@media (max-width: 575.98px) {
  .shared-chat-page {
    padding-top: 1rem;
    padding-bottom: 1rem;
  }

  .shared-chat-scroll {
    max-height: calc(100vh - 11rem);
    padding: 0.8rem !important;
  }
}

@media (min-width: 1200px) {
  /* The history rail is wider than the outline rail because it carries the attention
     index: factory names plus a counts line need the room to stay at body size. */
  .assistant-workspace {
    grid-template-columns: 16rem minmax(0, 1fr) 14rem;
    gap: 1rem;
  }

  .chat-history-rail,
  .chat-outline-rail {
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  /* No divider lines anywhere in the overlay — the rails are separated from the conversation
     by the grid gap alone, so the blurred page reads through uninterrupted. */
  .chat-history-rail {
    padding-right: 0.85rem;
  }

  /* Attention sits at the top of the rail and takes only the room its rows need
     (four factories at most, so it cannot run away); chat history takes the rest and
     scrolls. The previous contract was the other way round — history grew without
     limit and attention was the squeezed remainder at the bottom of the rail, which
     is what forced its type down to an unreadable size. */
  .assistant-attention-rail {
    flex: 0 0 auto;
    min-height: 0;
    max-height: 40%;
    padding-bottom: 0.5rem;
  }

  .chat-history-section {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
  }

  .chat-history-rail:has(.assistant-attention-rail) .chat-history-section {
    padding-top: 0.25rem;
  }

  /* The rail carries no heading, so it reserves the close button's gutter itself. */
  .chat-outline-rail {
    padding-left: 0.85rem;
    padding-top: 3.25rem;
  }

  .agentic-overlay .session-picker,
  .agentic-overlay .active-chat-actions {
    display: none;
  }

  .desktop-active-chat-title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-width: 0;
    border: 0;
    background: transparent;
    padding: 0.15rem 0.35rem;
    border-radius: 0.4rem;
    color: var(--text);
    font-size: 0.92rem;
  }

  .desktop-active-chat-title span {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }

  .desktop-active-chat-title .bi-pencil {
    flex: 0 0 auto;
    font-size: 0.76rem;
    color: var(--text-muted);
    opacity: 0;
    transition: opacity 0.15s ease;
  }

  .desktop-active-chat-title:not(:disabled):hover,
  .desktop-active-chat-title:not(:disabled):focus-visible {
    background: var(--surface-sunken);
  }

  .desktop-active-chat-title:not(:disabled):hover .bi-pencil,
  .desktop-active-chat-title:not(:disabled):focus-visible .bi-pencil {
    opacity: 1;
  }

  .desktop-active-chat-title:disabled {
    cursor: default;
  }

  .agentic-overlay .session-toolbar {
    margin-right: 0 !important;
  }

  /* Line the bar up with the conversation column: the 16rem/14rem rail asymmetry puts that
     column's centre 1rem right of the viewport centre. */
  body.agentic-open .ask-cloee-bar {
    left: calc(50vw + 1rem);
    width: min(720px, calc(100vw - 28rem - 64px));
  }

  body.agentic-open .ask-cloee-notice {
    left: calc(50vw + 1rem);
    max-width: min(720px, calc(100vw - 28rem - 64px));
  }
}

.session-toolbar {
  flex: 0 0 auto;
  border-bottom: 1px solid var(--border);
  padding-bottom: 0 !important;
  margin-bottom: 10px !important;
  margin-top: 10px !important;
  /* Flex so the prompt-quota chip can sit opposite the session picker. Wraps rather than
     overflowing in the narrow docked panel. */
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

/* Remaining advisor prompts, shown only for metered (read-only demo) accounts. Exhausted state is
   never colour-only — the label itself changes to "No questions left · resets in …". */
.chat-quota-chip {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
  border-radius: 999px;
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 500;
  line-height: 1.2;
  padding: 0.3rem 0.7rem;
  white-space: nowrap;
}

.chat-quota-chip.is-exhausted {
  border-color: color-mix(in srgb, var(--bs-warning) 45%, var(--border));
  background: color-mix(in srgb, var(--bs-warning) 12%, var(--surface));
  color: color-mix(in srgb, var(--bs-warning) 65%, var(--text));
}

.session-picker {
  max-width: 100%;
}

.session-picker-toggle {
  border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-muted);
  box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.08);
  font-size: 0.8rem;
  font-weight: 500;
  line-height: 1.2;
  padding: 0.5rem 0.9rem;
  cursor: pointer;
  white-space: nowrap;
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  gap: 0.35rem;
  transition: border-color 0.15s, box-shadow 0.15s, color 0.15s, background-color 0.15s;
}

.session-picker-toggle:hover,
.session-picker-toggle:focus,
.session-picker-toggle.show {
  border-color: color-mix(in srgb, var(--link) 35%, var(--border));
  color: var(--text);
  box-shadow: 0 0.45rem 1rem rgba(0, 0, 0, 0.12);
}

#session-picker-title {
  display: inline-block;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: min(17rem, 65vw);
}

.session-picker-menu {
  background: var(--surface);
  border-color: var(--border);
  border-radius: 8px;
  min-width: min(22rem, calc(100vw - 2rem));
  max-width: min(24rem, calc(100vw - 2rem));
  max-height: 42vh;
  overflow-y: auto;
  padding: 0.35rem;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.10), 0 1px 4px rgba(0, 0, 0, 0.06);
}

.session-picker-new {
  width: 100%;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--link);
  display: flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.55rem 0.65rem;
  font-size: 0.85rem;
  font-weight: 600;
  text-align: left;
}

.session-picker-new:hover,
.session-picker-new:focus {
  background: var(--surface-sunken);
  color: var(--link);
}

.session-picker-more {
  width: 100%;
  border: 0;
  border-radius: 6px;
  background: transparent;
  color: var(--text-muted);
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  padding: 0.55rem 0.65rem;
  font-size: 0.8rem;
  font-weight: 600;
}

.session-picker-more:hover,
.session-picker-more:focus {
  background: var(--surface-sunken);
  color: var(--text);
}

.session-picker-more:disabled {
  opacity: 0.65;
  cursor: wait;
}

.session-picker-list {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.session-picker-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  border-radius: 6px;
  color: var(--text);
}

.session-picker-row.active {
  background: color-mix(in srgb, #198754 14%, var(--surface));
}

.session-picker-select {
  width: 100%;
  min-width: 0;
  border: 0;
  background: transparent;
  color: inherit;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.1rem;
  padding: 0.55rem 0.65rem;
  text-align: left;
}

.session-picker-row:hover,
.session-picker-row:focus-within {
  background: var(--surface-sunken);
}

.session-picker-row.active:hover,
.session-picker-row.active:focus-within {
  background: color-mix(in srgb, #198754 20%, var(--surface));
}

.session-picker-row-title {
  width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.85rem;
  font-weight: 600;
}

.session-picker-row-time {
  color: var(--text-muted);
  font-size: 0.72rem;
}

.session-picker-delete {
  width: 2rem;
  height: 2rem;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-right: 0.25rem;
}

.session-picker-delete:hover,
.session-picker-delete:focus {
  background: color-mix(in srgb, #dc3545 14%, var(--surface));
  color: #dc3545;
}

.session-picker-empty {
  color: var(--text-muted);
  font-size: 0.8rem;
  padding: 0.55rem 0.65rem;
}

.chat-outer-wrapper {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  width: 100%;
  position: relative;
  background: transparent !important;
  overflow: hidden;
  padding: 0;
  margin: 0;
}

.chat-inner-scroll {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 1.1rem;
  /* The queued chip above the Ask CloEE bar adds its height here, so it never covers the last row. */
  padding: 0.7rem 0.7rem var(--queued-chip-space, 0px) 0.7rem;
  /* A queued prompt flying in from the chip starts partly outside the column; never scroll sideways. */
  overflow-x: clip;
  transition: padding-bottom 0.22s cubic-bezier(0.2, 0.8, 0.2, 1);
  box-sizing: border-box;
  background: transparent;
  border-radius: 0;
  box-shadow: none;
  border: none;
  transition: background 0.2s;
  align-items: flex-start;
  justify-content: flex-start;
  padding-bottom: 0 !important;
  margin-bottom: 0 !important;
  scroll-padding-bottom: 0 !important;
  padding-left: 0 !important;
}

.chat-bottom-bar-fixed {
  flex: 0 0 auto;
  width: 100%;
  position: static;
  background: #fff;
  border-top: 1px solid #ececec;
  box-shadow: 0 -2px 8px 0 rgba(31,38,135,0.03);
  padding: 0;
  margin: 0;
  z-index: 10;
}

.chat-bottom-bar-fixed,
#chat-bottom-bar {
  border-top: none !important;
}

.chat-form {
  width: 100%;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  margin: 0;
  padding: 0.75rem 0.75rem 0 0.75rem;
  box-sizing: border-box;
  padding-bottom: 0 !important;
  margin-bottom: 0 !important;
}

.chat-input-animated {
  flex: 1 1 auto;
  border-radius: 12px;
  border: 1px solid #e0e0e0;
  font-size: 1.08rem;
  padding: 0.65rem 1rem;
  transition: border 0.2s, box-shadow 0.2s, background 0.2s;
  background: rgba(255,255,255,0.7);
  box-shadow: 0 1px 2px 0 rgba(0,0,0,0.04);
  backdrop-filter: saturate(180%) blur(10px);
  padding-bottom: 0 !important;
  margin-bottom: 0 !important;
  resize: none;
  min-height: 40px;
  max-height: 90px;
  overflow-y: auto;
  font-family: inherit;
  line-height: 1.5;
}

.chat-input-animated:focus {
  border: 1px solid #28a745;
  box-shadow: 0 2px 8px 0 rgba(40, 167, 69, 0.15);
  outline: none;
}

.chat-form .chat-send-btn {
  border-radius: 50%;
  width: 2.5rem;
  height: 2.5rem;
  flex: 0 0 2.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.25rem;
  background: #28a745;
  border-color: #28a745;
  color: white;
  box-shadow: 0 1px 2px 0 rgba(40, 167, 69, 0.15);
  transition: background 0.2s, box-shadow 0.2s;
}

.chat-form .chat-send-btn:hover {
  background: #218838;
  border-color: #218838;
  box-shadow: 0 2px 8px 0 rgba(40, 167, 69, 0.25);
}

.chat-form .chat-send-btn:active {
  background: #1e7e34;
  border-color: #1e7e34;
  box-shadow: 0 2px 8px 0 rgba(40, 167, 69, 0.35);
}

/* Rows that join the transcript while it is open (an answer landing, the user's own prompt) ease
   in rather than popping; a full history load renders without this class. */
.chat-message.chat-message-enter {
  animation: chat-message-enter 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
}
@keyframes chat-message-enter {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .chat-message.chat-message-enter { animation: none; }
}

.chat-message {
  padding: 0.85rem 1.2rem;
  border-radius: 1.2rem;
  max-width: 90%;
  box-sizing: border-box;
  word-wrap: break-word;
  transition: background 0.2s, color 0.2s;
  opacity: 0;
  animation: fadeIn 0.35s forwards;
  font-size: 1rem;
  line-height: 1.6;
}

.chat-message.welcome-message {
  font-size: 1rem;
  padding: 0.7rem 1rem;
  max-width: 100%;
  width: 100%;
  text-align: left;
}

.chat-message.welcome-message ul {
  margin-top: 0.3em;
  margin-bottom: 0.3em;
  padding-left: 1.1em;
  text-align: left;
}

.chat-message.welcome-message li {
  font-size: 0.98em;
  margin-bottom: 0.12em;
  margin-top: 0;
  line-height: 1.2;
  font-weight: 600;
  position: relative;
  display: block;
  margin-right: 0;
  text-align: left;
}

.chat-message.welcome-message li::before {
  content: '\2022';
  color: #0d6efd;
  font-size: 1.1em;
  margin-right: 0.5em;
  vertical-align: middle;
  display: inline-block;
}

.chat-message .cloee-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: #e3f7e7;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
  color: #2e7d32;
  flex-shrink: 0;
  border: none;
}

.user-message {
  align-self: flex-end;
  background: #e8e8e8;
  color: #333;
  margin-right: 0;
  font-weight: 500;
}


.assistant-message {
  align-self: stretch;
  background: transparent;
  border: none;
  display: flex;
  gap: 0.75rem;
  padding: 0.75rem 1rem;
  width: 100%;
  max-width: 100%;
}

.assistant-message .cloee-avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  background: #e3f7e7;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  font-size: 1rem;
  color: #2e7d32;
  flex-shrink: 0;
  border: none;
}

.assistant-content {
  flex: 1 1 auto;
  padding: 0;
  margin: 0;
  min-width: 0;
  max-width: 100%;
  overflow-wrap: anywhere;
  text-align: left;
}

.assistant-content > p,
.assistant-content > ul,
.assistant-content > ol,
.assistant-content > blockquote {
  max-width: 74ch;
}

.assistant-content > :first-child {
  margin-top: 0;
}

.assistant-content > :last-child {
  margin-bottom: 0;
}

.assistant-content table {
  border-collapse: separate;
  border-spacing: 0;
  width: 100%;
  margin: 0;
  font-size: 0.86rem;
  color: var(--text);
}

.assistant-content table th,
.assistant-content table td {
  border-right: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  padding: 0.55rem 0.65rem;
  text-align: left;
  vertical-align: middle;
}

.assistant-content table th {
  background: var(--surface-2);
  color: var(--text);
  font-weight: 700;
  position: sticky;
  top: 0;
  z-index: 1;
}

.assistant-content table tbody tr:nth-child(even) {
  background: color-mix(in srgb, var(--surface-2) 62%, transparent);
}

/* === 21. Table Scroll & Modal === */
.table-scroll-wrapper {
  display: block;
  width: 100%;
  max-width: 100%;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  margin: 0.75rem 0 0.45rem;
  border: 1px solid var(--border);
  border-radius: 0.7rem;
  box-sizing: border-box;
  position: relative;
  background: var(--surface);
}

.table-scroll-wrapper table {
  width: auto;
  min-width: 100%;
}

.table-actions {
  display: flex;
  gap: 0.55rem;
  margin-top: 0.55rem;
  font-size: 0.86rem;
  align-items: center;
  flex-wrap: wrap;
  /* A single child (just Export table) stays start-aligned; a joined-in
     .dashboard-links-group (see enhanceDashboardLinks) is pushed to the right. */
  justify-content: space-between;
}

.table-action-btn {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 999px;
  cursor: pointer;
  font-weight: 600;
  padding: 0.35rem 0.7rem;
  transition: all 0.2s;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
}

.table-action-btn:active {
  transform: scale(0.98);
}

.table-download-btn {
  color: var(--link);
  text-decoration: none;
}

.table-download-btn:hover {
  background: color-mix(in srgb, var(--link) 10%, var(--surface));
  color: var(--link);
}

/* Trailing "View X on dashboard" links every raw get_* AI tool answer ends with (see
   enhanceDashboardLinks) — same pill language as .table-action-btn/.table-download-btn above,
   kept as its own class only so "download" doesn't misname a plain navigation link. */
.dashboard-links-row {
  display: flex;
  gap: 0.55rem;
  margin-top: 0.55rem;
  font-size: 0.86rem;
  align-items: center;
  flex-wrap: wrap;
}

/* When the link(s) directly follow a table, enhanceDashboardLinks joins them onto the
   Export table row instead (this group sits inside .table-actions, pushed right by its
   justify-content: space-between) rather than using .dashboard-links-row above. */
.dashboard-links-group {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  flex-wrap: wrap;
}

/* Scoped under .assistant-content on both rules: its own `.assistant-content a { color:
   #0d6efd }` / `.assistant-content a:hover { text-decoration: underline }` outrank a bare
   `.dashboard-link-btn` on specificity (they'd win back the hardcoded light-mode blue in dark
   theme, and the underline on hover, without this prefix). */
.assistant-content .dashboard-link-btn {
  color: var(--link);
  text-decoration: none;
}

.assistant-content .dashboard-link-btn:hover {
  background: color-mix(in srgb, var(--link) 10%, var(--surface));
  color: var(--link);
  text-decoration: none;
}

/* Report download file card — rendered in the assistant chat in place of a raw
   download link, so it feels like the assistant dropped a file you can download. */
/* Centred, not left-hugged — same reasoning as .cloee-domain-card in the chat-cards section. */
/* Left-hugged, not centred: it's a compact attachment chip inline with the rest of the
   assistant's content (prose is text-align:left, hugs the avatar), so it stays put regardless
   of how wide the row gets — the docked chat panel is narrow enough this never showed, but the
   agentic overlay's 1152px conversation column (.chat-outer-wrapper) turned centring into a
   396px-gutter floating island. */
.report-file-card {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin: 0.5rem 0;
  padding: 0.7rem 0.85rem;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  max-width: 360px;
}
.report-file-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  min-width: 0;
}
.report-file-icon {
  font-size: 1.6rem;
  line-height: 1;
  flex-shrink: 0;
}
.report-file-meta {
  flex: 1 1 auto;
  min-width: 0;
}
.report-file-name {
  font-weight: 600;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.report-file-sub {
  font-size: 0.78rem;
  color: var(--text-muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.report-file-btn {
  width: 100%;
  border: none;
  border-radius: 8px;
  padding: 0.45rem 0.8rem;
  font-weight: 600;
  font-size: 0.85rem;
  color: #fff;
  background: #28a745;
  cursor: pointer;
  transition: background 0.2s, transform 0.1s;
}
.report-file-btn:hover { background: #218838; }
.report-file-btn:active { transform: scale(0.97); }
.report-file-btn:disabled { opacity: 0.7; cursor: default; }

.assistant-content h1, .assistant-content h2, .assistant-content h3, .assistant-content h4, .assistant-content h5, .assistant-content h6 {
  color: var(--text);
  margin: 0.75rem 0 0.5rem 0;
  font-weight: 600;
  letter-spacing: 0;
  line-height: 1.4;
}

.assistant-content h1 { font-size: 1.4em; }
.assistant-content h2 { font-size: 1.3em; }
.assistant-content h3 { font-size: 1.2em; }
.assistant-content h4 { font-size: 1.1em; }
.assistant-content h5 { font-size: 1em; }
.assistant-content h6 { font-size: 0.95em; }

.assistant-content code {
  background: #f3f6fa;
  padding: 0.2rem 0.4rem;
  border-radius: 0.25rem;
  font-family: 'Courier New', monospace;
  font-size: 0.9em;
}

.assistant-content pre {
  background: #1e1e1e;
  color: #d4d4d4;
  padding: 1rem;
  border-radius: 0.5rem;
  overflow-x: auto;
  margin: 0.5rem 0;
}

.assistant-content pre code {
  background: none;
  padding: 0;
  color: inherit;
}

.assistant-content p {
  margin: 0 0 0.6rem;
}

/* An advisor answer opens with a headline line and follows it with at most three bullets, so the
   list hugs the sentence it belongs to rather than floating a full Bootstrap paragraph gap below. */
.assistant-content ul, .assistant-content ol {
  margin: 0.35rem 0 0.6rem;
  padding-left: 1.5rem;
}
/* Restore list markers: the global `ul { list-style-type: none }` reset (top of file) strips
   bullets app-wide, which would render chat bullet lists as unmarked indented lines. */
.assistant-content ul { list-style-type: disc; }
.assistant-content ol { list-style-type: decimal; }

.assistant-content li {
  margin: 0.25rem 0;
  line-height: 1.6;
}

/* The marker is structure, not a value: muting it keeps the bolded figure the brightest thing
   on the line. */
.assistant-content li::marker {
  color: var(--text-muted);
}

.assistant-content blockquote {
  border-left: 3px solid #0d6efd;
  padding-left: 1rem;
  margin: 0.5rem 0;
  color: #555;
}

.assistant-content strong { font-weight: 700; color: var(--text); }
.assistant-content em { font-style: italic; }
.assistant-content a {
  color: #0d6efd;
  text-decoration: none;
  overflow-wrap: anywhere;
  word-break: break-word;
}

.assistant-content a:hover {
  text-decoration: underline;
}

.typing-dot-group {
  display: flex;
  align-items: center;
  gap: 0.3rem;
  height: 20px;
  overflow: hidden;
}

.typing-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  background: #0d6efd;
  border-radius: 50%;
  opacity: 0.6;
  animation: typing-bounce 1.2s infinite;
  flex-shrink: 0;
}

.typing-dot:nth-child(2) {
  animation-delay: 0.2s;
}

.typing-dot:nth-child(3) {
  animation-delay: 0.4s;
}

@keyframes typing-bounce {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-6px); opacity: 1; }
}

/* === 22. Scroll-to-Bottom === */
.scroll-to-bottom-btn {
  position: absolute;
  bottom: 70px;
  right: 15px;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: #28a745;
  color: white;
  border: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.2rem;
  box-shadow: 0 2px 8px rgba(40, 167, 69, 0.3);
  transition: all 0.2s ease;
  z-index: 20;
}

.scroll-to-bottom-btn:hover {
  background: #218838;
  box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4);
  transform: translateY(-2px);
}

.scroll-to-bottom-btn:active {
  background: #1e7e34;
  transform: translateY(0);
}

/* === 23. Table Card Wrapper (production flow dashboard style) === */

.table-card-wrapper {
  background: white;
  overflow: hidden;
  border: 1px solid rgba(0,0,0,0.125);
  display: flex;
  flex-direction: column;
}

.table-card-header {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid rgba(0,0,0,0.125);
  border-radius: 0.75rem 0.75rem 0 0;
  flex-shrink: 0;
}

.table-card-body {
  padding: 0;
  background: white;
  flex: 1;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-height: 0;
  /* Without this the flex item's automatic min-width keeps the body at the table's
     min-content width, so a wide table overflows the card instead of scrolling. */
  min-width: 0;
}

.table-card-body .table-responsive {
  flex: 1;
  overflow: auto;
  min-height: 0;
}

.table-card-body .table {
  margin-bottom: 0;
  border-radius: 0;
}

.table-card-body .table thead th {
  border-top: none;
  font-weight: 600;
  font-size: 0.8125rem;
  text-transform: uppercase;
  letter-spacing: 0.5px;
  color: #495057;
  padding: 0.75rem 1rem;
}

.table-card-body .table tbody td {
  padding: 0.75rem 1rem;
  vertical-align: middle;
  font-size: 0.9rem;
}

.table-card-wrapper.table-card-collapsed {
  border-radius: 0.75rem !important;
}

/* === 23a. Collapsible report tables ===
   Saved Reports and Job Performance intentionally share one visual component.
   The latter renders in standalone exports too, so this recipe belongs in the
   shared stylesheet rather than only in reports.html. */
.report-table-card {
  --report-table-accent: var(--link);
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 1.25rem;
  background: var(--surface);
  box-shadow: 0 .75rem 2rem rgba(0, 0, 0, .07);
}

.report-table-toggle {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(120deg, color-mix(in srgb, var(--report-table-accent) 7%, var(--surface)), var(--surface));
  color: var(--text);
  text-align: left;
}

.report-table-toggle:focus-visible {
  outline: 3px solid color-mix(in srgb, var(--report-table-accent) 40%, transparent);
  outline-offset: -3px;
}

.report-table-heading { display: flex; align-items: center; gap: .8rem; min-width: 0; }

.report-table-heading-icon {
  display: inline-flex;
  width: 2.5rem;
  height: 2.5rem;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: .85rem;
  background: color-mix(in srgb, var(--report-table-accent) 13%, var(--surface));
  color: var(--report-table-accent);
  font-size: 1.1rem;
}

.report-table-eyebrow {
  display: block;
  margin-bottom: .1rem;
  color: var(--text-muted);
  font-size: .67rem;
  font-weight: 700;
  letter-spacing: .12em;
  line-height: 1;
}

.report-table-title { display: block; margin: 0; font-size: 1rem; font-weight: 700; color: var(--text); }
.report-table-subtitle { display: block; margin: .18rem 0 0; color: var(--text-muted); font-size: .8rem; }

.report-table-toggle-meta { display: flex; align-items: center; gap: .75rem; flex: 0 0 auto; }

.report-table-count {
  padding: .28rem .55rem;
  border: 1px solid color-mix(in srgb, var(--report-table-accent) 20%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--report-table-accent) 9%, var(--surface));
  color: var(--text);
  font-size: .75rem;
  font-weight: 700;
  white-space: nowrap;
}

.report-table-chevron { color: var(--text-muted); transition: transform .2s ease; }
.report-table-toggle[aria-expanded="true"] .report-table-chevron { transform: rotate(180deg); }

.report-table-card .dataTables_wrapper {
  min-width: 0;
  padding: .9rem 1.25rem 1.2rem;
  background: transparent;
}

.report-table-card .report-table-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.9rem;
  padding: .75rem 0 0;
  border-top: 1px solid var(--border);
  background: transparent;
}

.report-table-card table.report-table {
  border-collapse: separate;
  border-spacing: 0 .45rem;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: transparent;
}

.report-table-card table.report-table thead th {
  position: relative;
  padding: 0 .75rem .25rem;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.report-table-card table.report-table thead th.sorting,
.report-table-card table.report-table thead th.sorting_asc,
.report-table-card table.report-table thead th.sorting_desc,
.report-table-card table.report-table thead th.sorting_asc_disabled,
.report-table-card table.report-table thead th.sorting_desc_disabled {
  padding-right: 1.65rem;
  background-image: none !important;
}

.report-table-card table.report-table thead th.sorting::after,
.report-table-card table.report-table thead th.sorting_asc::after,
.report-table-card table.report-table thead th.sorting_desc::after {
  position: absolute;
  right: .55rem;
  bottom: .3rem;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 800;
  line-height: 1;
}

.report-table-card table.report-table thead th.sorting::after { content: '↕'; }
.report-table-card table.report-table thead th.sorting_asc::after { content: '↑'; color: var(--report-table-accent); }
.report-table-card table.report-table thead th.sorting_desc::after { content: '↓'; color: var(--report-table-accent); }

.report-table-card table.report-table tbody td {
  padding: .7rem .75rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  color: var(--text);
  vertical-align: middle;
}

.report-table-card table.report-table tbody td:first-child {
  border-left: 1px solid var(--border);
  border-radius: .8rem 0 0 .8rem;
}

.report-table-card table.report-table tbody td:last-child {
  border-right: 1px solid var(--border);
  border-radius: 0 .8rem .8rem 0;
}

.report-table-card table.report-table tbody tr:hover td {
  background: color-mix(in srgb, var(--report-table-accent) 7%, var(--surface));
}

@media (max-width: 575.98px) {
  .report-table-toggle { padding: .85rem 1rem; }
  .report-table-subtitle, .report-table-count { display: none; }
  .report-table-card .dataTables_wrapper { padding: .75rem; }
  .report-table-card table.report-table tbody td { padding: .6rem .5rem; }
}

/* === 23b. Operations data card ===
   The visual companion to the Reports Machines KPI card for workflow-heavy DataTables. The card
   owns hierarchy and scrolling; the table keeps its existing columns and interaction contract. */
.operations-data-card {
  /* CloEE logo green; reports retain their own report-specific accent palette. */
  --operations-data-card-accent: #81bc48;
  --operations-data-card-accent-strong: color-mix(in srgb, var(--operations-data-card-accent) 65%, var(--text));
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--operations-data-card-accent) 22%, var(--border));
  border-radius: 1.25rem;
  background: var(--surface);
  box-shadow: 0 .75rem 2rem color-mix(in srgb, var(--text) 7%, transparent);
}

.operations-data-card__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: linear-gradient(120deg, color-mix(in srgb, var(--operations-data-card-accent) 9%, var(--surface)), var(--surface));
}

.operations-data-card__heading { display: flex; align-items: center; gap: .8rem; min-width: 0; }

.operations-data-card__icon {
  display: inline-flex;
  width: 2.5rem;
  height: 2.5rem;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  border-radius: .85rem;
  background: color-mix(in srgb, var(--operations-data-card-accent) 14%, var(--surface));
  color: var(--operations-data-card-accent-strong);
  font-size: 1.1rem;
}

.operations-data-card__eyebrow {
  display: block;
  margin-bottom: .12rem;
  color: var(--text-muted);
  font-size: .67rem;
  font-weight: 700;
  letter-spacing: .12em;
  line-height: 1;
  text-transform: uppercase;
}

.operations-data-card__title { margin: 0; color: var(--text); font-size: 1rem; font-weight: 700; }
.operations-data-card__subtitle { margin: .18rem 0 0; color: var(--text-muted); font-size: .8rem; }

.operations-data-card__count {
  flex: 0 0 auto;
  padding: .28rem .55rem;
  border: 1px solid color-mix(in srgb, var(--operations-data-card-accent) 20%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--operations-data-card-accent) 9%, var(--surface));
  color: var(--text);
  font-size: .75rem;
  font-weight: 700;
  white-space: nowrap;
}

/* Neutral in-cell provenance/metadata pill — the quieter sibling of __count, for a label that
   annotates a row rather than reporting status. Tokenized rather than Bootstrap's `text-bg-light`,
   which paints a fixed light neutral that survives into dark mode. */
.operations-data-card__tag {
  display: inline-flex;
  align-items: center;
  padding: .1rem .45rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-2) 60%, var(--surface));
  color: var(--text-muted);
  font-size: .7rem;
  font-weight: 500;
  white-space: nowrap;
}

.operations-data-card__controls {
  padding: .75rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 55%, var(--surface));
}

.operations-data-card__toolbar,
.operations-data-card__filter-group,
.operations-data-card__toolbar-actions,
.operations-data-card__datatable-controls,
.operations-data-card__datatable-controls .cycles-data-table-controls {
  display: flex;
  align-items: center;
}

.operations-data-card__toolbar { gap: .75rem; min-width: 0; }
.operations-data-card__filter-group { gap: .5rem; flex: 0 0 auto; }
.operations-data-card__toolbar-actions { gap: .35rem; flex: 0 0 auto; }

.batch-details-operations-card .operations-data-card__header { flex-wrap: wrap; }
.batch-details-operations-card__header-actions { margin-left: auto; }

.unit-details-table-card .operations-data-card__header,
.unit-details-batches-card .operations-data-card__header,
.downtimes-operations-card .operations-data-card__header { flex-wrap: wrap; }

.unit-details-table-card__header-actions,
.unit-details-batches-card__header-actions,
.downtimes-operations-card__header-actions {
  flex-wrap: wrap;
  justify-content: flex-end;
  margin-left: auto;
}

.operations-data-card__header-data-controls {
  display: flex;
  align-items: center;
  min-width: 0;
}

.operations-data-card__datatable-controls {
  min-width: 0;
  margin-left: auto;
  padding-left: .85rem;
  border-left: 1px solid var(--border);
}

.operations-data-card__datatable-controls .cycles-data-table-controls { gap: 1rem; }

.operations-data-card__datatable-controls .dataTables_filter {
  display: flex !important;
  align-items: center;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.operations-data-card__datatable-controls .dataTables_filter label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.operations-data-card__datatable-controls .dataTables_filter input {
  margin-left: .35rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
  line-height: 1.5;
  padding: .25rem .65rem;
  outline: 0;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.operations-data-card__datatable-controls .dataTables_filter input { width: 8rem; }

.operations-data-card__datatable-controls .dataTables_filter input:focus {
  border-color: color-mix(in srgb, var(--operations-data-card-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--operations-data-card-accent) 16%, transparent);
}

/* Compact generated controls for operational cards that keep their own DataTables layout. */
.operations-data-card .unit-data-table-controls,
.operations-data-card .batches-data-table-controls {
  display: flex;
  justify-content: flex-end;
  min-height: 2rem;
}

.operations-data-card .unit-data-table-controls .dataTables_filter,
.operations-data-card .batches-data-table-controls .dataTables_filter {
  display: flex !important;
  align-items: center;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.operations-data-card .unit-data-table-controls .dataTables_filter label,
.operations-data-card .batches-data-table-controls .dataTables_filter label,
.operations-data-card .unit-table-footer .dataTables_length label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.operations-data-card .unit-data-table-controls .dataTables_filter input,
.operations-data-card .batches-data-table-controls .dataTables_filter input,
.operations-data-card .unit-table-footer .dataTables_length select {
  margin-left: .35rem;
  padding: .25rem .65rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
  line-height: 1.5;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.operations-data-card .unit-data-table-controls .dataTables_filter input,
.operations-data-card .batches-data-table-controls .dataTables_filter input { width: 8rem; }

.operations-data-card .unit-data-table-controls .dataTables_filter input:focus,
.operations-data-card .batches-data-table-controls .dataTables_filter input:focus,
.operations-data-card .unit-table-footer .dataTables_length select:focus {
  outline: 0;
  border-color: color-mix(in srgb, var(--operations-data-card-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--operations-data-card-accent) 16%, transparent);
}

.operations-data-card__body { position: relative; overflow: hidden; }

.operations-data-card .dataTables_wrapper {
  min-width: 0;
  padding: .35rem 1.25rem 1.2rem;
  background: transparent;
}

.operations-data-card .cycles-table-footer {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding-top: .85rem;
}

.operations-data-card .cycles-table-footer .dataTables_length,
.operations-data-card .cycles-table-footer .dataTables_info,
.operations-data-card .cycles-table-footer .dataTables_paginate {
  margin: 0;
  padding: 0;
}

.operations-data-card .cycles-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

.operations-data-card .cycles-table-footer .dataTables_length label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.operations-data-card .cycles-table-footer .dataTables_length select {
  min-width: 5.4rem;
  margin-left: .35rem;
  padding: .25rem .65rem;
  border-color: var(--border);
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
}

.operations-data-card .cycles-table-footer .dataTables_info {
  color: var(--text-muted);
  font-size: .82rem;
}

.operations-data-card .cycles-table-footer .dataTables_paginate { margin-left: auto; }

.operations-data-card .unit-table-footer {
  display: flex;
  align-items: center;
  gap: .85rem;
  padding-top: .85rem;
}

.operations-data-card .unit-table-footer .dataTables_length,
.operations-data-card .unit-table-footer .dataTables_info,
.operations-data-card .unit-table-footer .dataTables_paginate {
  float: none;
  margin: 0;
  padding: 0;
}

.operations-data-card .unit-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  white-space: nowrap;
}

.operations-data-card .unit-table-footer .dataTables_info {
  color: var(--text-muted);
  font-size: .82rem;
}

.operations-data-card .unit-table-footer .dataTables_paginate { margin-left: auto; }

/* Keep every operational input in the same rounded control family as the rework batch picker. */
.operations-data-card .form-select,
.operations-data-card .form-control,
#reworkModal .form-select,
.rework-combo-search {
  border-color: color-mix(in srgb, var(--border) 70%, transparent);
  border-radius: .65rem;
  background-color: var(--surface);
  color: var(--text);
  box-shadow: 0 .25rem .65rem color-mix(in srgb, var(--text) 8%, transparent);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}

.operations-data-card .form-select:focus,
.operations-data-card .form-control:focus,
#reworkModal .form-select:focus,
.rework-combo-search:focus {
  border-color: color-mix(in srgb, var(--operations-data-card-accent) 65%, var(--border));
  box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--operations-data-card-accent) 20%, transparent);
}

.operations-data-card .form-select:disabled,
.operations-data-card .form-control:disabled {
  background-color: color-mix(in srgb, var(--surface-2) 70%, var(--surface));
  box-shadow: none;
}

/* The batch picker is rendered above the card, so opt it into the same control family explicitly. */
.operations-data-control {
  border-color: color-mix(in srgb, var(--border) 70%, transparent);
  border-radius: .65rem;
  background-color: var(--surface);
  color: var(--text);
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}

.operations-data-control:focus {
  border-color: color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 65%, var(--border));
  box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 20%, transparent);
}

.operations-data-combobox-panel {
  position: fixed;
  z-index: 9999;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: .65rem;
  background: var(--surface);
  box-shadow: 0 .5rem 1rem color-mix(in srgb, var(--text) 15%, transparent);
}

.operations-data-card__scroll {
  max-height: min(62vh, 40rem);
  overflow: auto;
  scrollbar-color: color-mix(in srgb, var(--operations-data-card-accent) 45%, var(--text-muted)) transparent;
  scrollbar-width: thin;
}

/* Keep a DataTable hidden while a collapsed parent becomes measurable. */
.operations-data-card__scroll--sizing { visibility: hidden; }

.operations-data-card__scroll::-webkit-scrollbar { width: .55rem; height: .55rem; }
.operations-data-card__scroll::-webkit-scrollbar-track { background: transparent; }
.operations-data-card__scroll::-webkit-scrollbar-thumb {
  border-radius: 999px;
  background: color-mix(in srgb, var(--operations-data-card-accent) 45%, var(--text-muted));
}
.operations-data-card__scroll::-webkit-scrollbar-corner { background: transparent; }

.operations-data-card table.operations-data-table {
  border-collapse: separate;
  border-spacing: 0 .4rem;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: transparent;
}

.operations-data-card table.operations-data-table > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: 2;
  overflow: hidden;
  padding: 0 1.65rem .3rem .75rem;
  border: 0;
  background: var(--surface);
  box-shadow: none;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

/* DataTables 1.11 uses bitmap sort backgrounds (with `!important` for active states). They bleed
   across sticky columns, so replace them with one token-safe, contained direction marker per header. */
.operations-data-card table.operations-data-table > thead > tr > th.sorting,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_asc,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_desc,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_asc_disabled,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_desc_disabled {
  background-image: none !important;
}

.operations-data-card table.operations-data-table > thead > tr > th.sorting::after,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_asc::after,
.operations-data-card table.operations-data-table > thead > tr > th.sorting_desc::after {
  position: absolute;
  right: .55rem;
  bottom: .3rem;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 800;
  line-height: 1;
}

.operations-data-card table.operations-data-table > thead > tr > th.sorting::after { content: '↕'; }
.operations-data-card table.operations-data-table > thead > tr > th.sorting_asc::after { content: '↑'; color: var(--operations-data-card-accent-strong); }
.operations-data-card table.operations-data-table > thead > tr > th.sorting_desc::after { content: '↓'; color: var(--operations-data-card-accent-strong); }

.operations-data-card table.operations-data-table > tbody > tr:not(.child) {
  --operations-data-row-surface: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
}

.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td {
  padding: .7rem .75rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--operations-data-row-surface);
  color: var(--text);
  vertical-align: middle;
}

.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:first-child {
  border-left: 1px solid var(--border);
  border-radius: .8rem 0 0 .8rem;
  background-clip: padding-box;
}

.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:last-child {
  border-right: 1px solid var(--border);
  border-radius: 0 .8rem .8rem 0;
  background-clip: padding-box;
}

.operations-data-card table.operations-data-table > tbody > tr:not(.child):hover {
  --operations-data-row-surface: color-mix(in srgb, var(--operations-data-card-accent) 7%, var(--surface));
}

.operations-data-card table.operations-data-table > tbody > tr:not(.child):hover > td {
  background: var(--operations-data-row-surface);
  box-shadow: none;
}

.operations-data-card table.operations-data-table > tbody > tr.operations-data-table__row--attention:not(.child) {
  --operations-data-row-surface: color-mix(in srgb, var(--bs-danger) 7%, var(--surface));
}

/* Keep the expand affordance and the unit identity in view while a wide operational table scrolls. */
.operations-data-card table.operations-data-table > thead > tr > th:nth-child(1),
.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:nth-child(1) {
  position: sticky;
  left: 0;
  z-index: 3;
  min-width: 2.5rem;
}

.operations-data-card table.operations-data-table > thead > tr > th:nth-child(2),
.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:nth-child(2) {
  position: sticky;
  left: 2.5rem;
  z-index: 3;
}

.operations-data-card table.operations-data-table > thead > tr > th:nth-child(1),
.operations-data-card table.operations-data-table > thead > tr > th:nth-child(2) { z-index: 4; }

.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:nth-child(1),
.operations-data-card table.operations-data-table > tbody > tr:not(.child) > td:nth-child(2) {
  background: var(--operations-data-row-surface);
}

/* Wide annual matrices have one identity column rather than an expand affordance plus
   identity. Keep just that asset context pinned; the monthly values remain scrollable. */
.operations-data-card table.operations-data-table--single-context > thead > tr > th:nth-child(1),
.operations-data-card table.operations-data-table--single-context > tbody > tr:not(.child) > td:nth-child(1) {
  left: 0;
  min-width: 8rem;
}

.operations-data-card table.operations-data-table--single-context > thead > tr > th:nth-child(2),
.operations-data-card table.operations-data-table--single-context > tbody > tr:not(.child) > td:nth-child(2) {
  position: static;
  left: auto;
  z-index: auto;
  min-width: 0;
}

.operations-data-card table.operations-data-table--single-context > tbody > tr:not(.child) > td:last-child {
  font-weight: 700;
}

/* Unit accordions retain their workflow but share the operations-card hierarchy. */
.operations-data-card__accordion {
  --bs-accordion-bg: transparent;
  --bs-accordion-border-color: var(--border);
  --bs-accordion-btn-bg: var(--surface);
  --bs-accordion-btn-color: var(--text);
  --bs-accordion-active-bg: color-mix(in srgb, var(--operations-data-card-accent) 7%, var(--surface));
  --bs-accordion-active-color: var(--text);
  --bs-accordion-btn-focus-box-shadow: 0 0 0 .22rem color-mix(in srgb, var(--operations-data-card-accent) 20%, transparent);
}

.operations-data-card__accordion-item {
  border: 0;
  border-bottom: 1px solid var(--border);
  background: transparent;
}

.operations-data-card__accordion-item:last-child { border-bottom: 0; }

.operations-data-card__accordion-button {
  gap: .35rem;
  padding: .82rem 1.25rem;
  background: var(--surface);
}

.operations-data-card__accordion-button:not(.collapsed) { box-shadow: none; }

.operations-data-card__accordion-button::after {
  width: 1rem;
  height: 1rem;
  margin-left: auto;
  background-image: none;
  color: var(--operations-data-card-accent-strong);
  content: '⌄';
  font-size: 1.1rem;
  font-weight: 700;
  line-height: .72;
  text-align: center;
  transform: rotate(-90deg);
}

.operations-data-card__accordion-button:not(.collapsed)::after {
  background-image: none;
  transform: rotate(0deg);
}

.operations-data-card__accordion-button .unit-runs-badge {
  border: 1px solid color-mix(in srgb, var(--operations-data-card-accent) 22%, var(--border));
  background: color-mix(in srgb, var(--operations-data-card-accent) 9%, var(--surface));
  color: var(--text);
}

.operations-data-card__toolbar-actions .btn-primary {
  border-color: var(--operations-data-card-accent);
  background: var(--operations-data-card-accent);
  color: var(--gauge-track);
}

.operations-data-card__toolbar-actions .btn-primary:hover,
.operations-data-card__toolbar-actions .btn-primary:focus {
  border-color: var(--operations-data-card-accent-strong);
  background: var(--operations-data-card-accent-strong);
  color: var(--surface);
}

.operations-data-card__toolbar-actions .badge.bg-primary {
  background-color: var(--operations-data-card-accent) !important;
  color: var(--gauge-track);
}

.batch-details-table { min-width: 50rem; }
.batch-details-table-scroll { max-height: min(54vh, 34rem); }
.unit-details-table { min-width: 42rem; }
.unit-details-batches-table { min-width: 66rem; }
.unit-details-batches-card .operations-data-card__scroll { max-height: min(62vh, 40rem); }
.downtimes-table { min-width: 52rem; }
.downtimes-planned-table { min-width: 42rem; }
.activity-log-table { min-width: 60rem; }

.activity-log-filter-card {
  --activity-log-accent: #81bc48;
  border: 1px solid color-mix(in srgb, var(--activity-log-accent) 18%, var(--border));
  background: var(--surface);
  box-shadow: 0 .5rem 1.25rem color-mix(in srgb, var(--text) 6%, transparent);
}

.activity-log-filter-label {
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}

.activity-log-filter-control {
  min-height: 2.25rem;
  border-color: color-mix(in srgb, var(--border) 66%, var(--surface));
  border-radius: .65rem;
  background-color: var(--surface);
  color: var(--text);
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.activity-log-filter-control:focus {
  border-color: color-mix(in srgb, var(--activity-log-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--activity-log-accent) 16%, transparent);
}

.activity-log-reset-filters { min-height: 2.25rem; border-radius: .65rem; }

.activity-log-details-btn {
  display: inline-grid;
  width: 2rem;
  height: 2rem;
  place-items: center;
  padding: 0;
  border: 1px solid color-mix(in srgb, var(--border) 70%, var(--surface));
  border-radius: 50%;
  background: var(--surface);
  color: var(--text-muted);
}

.activity-log-details-btn:hover,
.activity-log-details-btn:focus-visible {
  border-color: color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 48%, var(--border));
  background: color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 9%, var(--surface));
  color: var(--text);
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 16%, transparent);
}

.activity-log-modal {
  --activity-log-modal-status: #81bc48;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--activity-log-modal-status) 20%, var(--border));
  border-radius: 1rem;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1.25rem 3rem color-mix(in srgb, var(--text) 18%, transparent);
}

.activity-log-modal-dialog { --bs-modal-width: 44rem; }

.activity-log-modal[data-activity-action="created"] { --activity-log-modal-status: var(--bs-success); }
.activity-log-modal[data-activity-action="updated"] { --activity-log-modal-status: var(--bs-primary); }
.activity-log-modal[data-activity-action="deleted"] { --activity-log-modal-status: var(--bs-danger); }
.activity-log-modal[data-activity-action="assigned"] { --activity-log-modal-status: var(--bs-warning); }
.activity-log-modal[data-activity-action="unsubscribed"] { --activity-log-modal-status: var(--bs-info); }

.activity-log-modal__header {
  align-items: center;
  gap: 1rem;
  padding: .9rem 1rem;
  border-bottom: 1px solid color-mix(in srgb, var(--activity-log-modal-status) 18%, var(--border));
  background: linear-gradient(
    120deg,
    color-mix(in srgb, var(--activity-log-modal-status) 9%, var(--surface)),
    var(--surface)
  );
}

.activity-log-modal__heading,
.activity-log-modal__title-row,
.activity-log-modal__meta,
.activity-log-modal__meta > span {
  display: flex;
  align-items: center;
}

.activity-log-modal__heading { gap: .75rem; min-width: 0; }
.activity-log-modal__title-group { min-width: 0; }
.activity-log-modal__title-row { gap: .6rem; min-width: 0; flex-wrap: wrap; }

.activity-log-modal__icon {
  display: inline-grid;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  place-items: center;
  border: 1px solid color-mix(in srgb, var(--activity-log-modal-status) 25%, var(--border));
  border-radius: .7rem;
  background: color-mix(in srgb, var(--activity-log-modal-status) 13%, var(--surface));
  color: color-mix(in srgb, var(--activity-log-modal-status) 72%, var(--text));
}

.activity-log-modal__action-badge {
  border: 1px solid color-mix(in srgb, var(--activity-log-modal-status) 30%, var(--border));
  background: color-mix(in srgb, var(--activity-log-modal-status) 14%, var(--surface)) !important;
  color: var(--text) !important;
}

.activity-log-modal .modal-title {
  min-width: 0;
  color: var(--text);
  font-weight: 700;
  overflow-wrap: anywhere;
}

.activity-log-modal .btn-close { flex: 0 0 auto; }

.activity-log-modal__body {
  padding: 1rem;
  background: var(--surface);
  color: var(--text);
}

.activity-log-modal__subject {
  margin: .2rem 0 0;
  color: var(--text-muted);
  font-size: .82rem;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.activity-log-modal__subject:empty { display: none; }

.activity-log-modal__meta {
  gap: .45rem 1rem;
  margin-bottom: .75rem;
  color: var(--text-muted);
  font-size: .75rem;
  flex-wrap: wrap;
}

.activity-log-modal__meta > span { gap: .35rem; }

.activity-log-modal__table-wrap {
  overflow-x: auto;
  padding: .35rem .45rem;
  border: 1px solid var(--border);
  border-radius: .8rem;
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
}

.activity-log-detail-table {
  --operations-data-card-accent: var(--activity-log-modal-status);
  table-layout: fixed;
  font-size: .875rem;
}

.activity-log-detail-table--updated { min-width: 34rem; }
.activity-log-detail-table > thead > tr,
.activity-log-detail-table > thead > tr > th {
  --bs-table-bg: transparent;
  background: transparent !important;
  background-image: none !important;
  box-shadow: none;
}

.activity-log-detail-table > thead > tr > th:first-child { width: 42%; }
.activity-log-detail-table--updated > thead > tr > th:first-child { width: 46%; }
.activity-log-detail-table--updated > thead > tr > th:not(:first-child) { width: 27%; }

.activity-log-detail-table > tbody > tr > td {
  padding: .45rem .5rem;
  overflow-wrap: anywhere;
  white-space: pre-wrap;
}

.activity-log-color-swatch {
  display: inline-block;
  width: 3rem;
  height: 1.25rem;
  border: 1px solid color-mix(in srgb, var(--text) 24%, var(--border));
  border-radius: .35rem;
  background: var(--activity-log-value-color);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--surface) 28%, transparent);
  vertical-align: middle;
}

.activity-log-detail-table--created > tbody > tr > td:first-child,
.activity-log-detail-table--deleted > tbody > tr > td:first-child {
  border-left-color: color-mix(in srgb, var(--activity-log-modal-status) 42%, var(--border));
}

.activity-log-detail-row--unchanged > td { color: var(--text-muted) !important; }

.activity-log-modal__empty {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .9rem 1rem;
  border: 1px dashed var(--border);
  border-radius: .8rem;
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  color: var(--text-muted);
}

.activity-log-modal__empty > i { color: var(--activity-log-modal-status); font-size: 1.1rem; }
.activity-log-modal__empty strong { display: block; color: var(--text); font-size: .85rem; }
.activity-log-modal__empty span { display: block; margin-top: .12rem; font-size: .78rem; }

.activity-log-modal__empty--error {
  border-color: color-mix(in srgb, var(--bs-danger) 38%, var(--border));
  background: color-mix(in srgb, var(--bs-danger) 7%, var(--surface));
  color: var(--bs-danger-text-emphasis);
}

.operations-data-card .activity-log-table-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem 1.25rem 1.15rem;
}

.operations-data-card .activity-log-table-footer .dataTables_length { display: flex; align-items: center; }
.operations-data-card .activity-log-table-footer .dataTables_length label,
.operations-data-card .activity-log-table-footer .dataTables_info { color: var(--text-muted); font-size: .82rem; }
.operations-data-card .activity-log-table-footer .dataTables_paginate { margin-left: auto; }

/* Configuration still has several settings panels that predate operations-data-card.
   Scope the shared hierarchy to that page so the existing fields and controls retain
   their contracts while the page no longer falls back to fixed-light card/table chrome. */
.configuration-page .table-card-wrapper {
  --configuration-card-accent: #81bc48;
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--configuration-card-accent) 22%, var(--border));
  border-radius: 1.25rem !important;
  background: var(--surface);
  box-shadow: 0 .75rem 2rem color-mix(in srgb, var(--text) 7%, transparent) !important;
}

.configuration-page .table-card-header {
  padding: .95rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--configuration-card-accent) 6%, var(--surface)) !important;
  color: var(--text);
}

.configuration-page .table-card-header h5 { color: var(--text); font-weight: 700; }
.configuration-page .table-card-body { background: var(--surface); }

.configuration-page #systemSubtabs {
  flex-wrap: nowrap;
  overflow-x: auto;
  overflow-y: hidden;
  scrollbar-width: thin;
}

.configuration-page #systemSubtabs .nav-item { flex: 0 0 auto; }
.configuration-page #systemSubtabs .nav-link { white-space: nowrap; }

.configuration-page #automatic-downtime-rules,
.configuration-page #downtime-display-colors,
.configuration-page #downtime-reasons {
  scroll-margin-top: 1rem;
}

.configuration-page .downtime-settings-handoff {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .75rem .9rem;
  border: 1px solid color-mix(in srgb, var(--configuration-card-accent) 20%, var(--border));
  border-radius: .85rem;
  background: color-mix(in srgb, var(--configuration-card-accent) 6%, var(--surface));
}

.configuration-page .downtime-settings-handoff__swatch,
.configuration-page .downtime-color-setting__swatch {
  display: inline-block;
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  border-radius: .25rem;
}

.configuration-page .downtime-settings-handoff__icon {
  display: inline-grid;
  width: 2rem;
  height: 2rem;
  flex: 0 0 auto;
  place-items: center;
  border-radius: 50%;
  background: color-mix(in srgb, var(--configuration-card-accent) 13%, var(--surface));
  color: var(--text);
}

.configuration-page .downtime-settings-handoff__copy,
.configuration-page .downtime-color-setting__copy {
  display: flex;
  flex: 1 1 14rem;
  flex-direction: column;
  min-width: 0;
}

.configuration-page .downtime-rule-flow {
  display: flex;
  align-items: center;
  gap: .45rem;
  overflow-x: auto;
  padding: .7rem .8rem;
  border: 1px solid var(--border);
  border-radius: .85rem;
  background: color-mix(in srgb, var(--surface-2) 62%, var(--surface));
  color: var(--text);
  scrollbar-width: thin;
}

.configuration-page .downtime-rule-flow__event,
.configuration-page .downtime-rule-flow__stage,
.configuration-page .downtime-rule-flow__gap {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  flex: 0 0 auto;
  padding: .3rem .65rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  font-size: .78rem;
  font-weight: 600;
  white-space: nowrap;
}

.configuration-page .downtime-rule-flow__stage {
  border-color: color-mix(in srgb, var(--configuration-card-accent) 35%, var(--border));
  background: color-mix(in srgb, var(--configuration-card-accent) 10%, var(--surface));
}

.configuration-page .downtime-rule-flow__gap {
  color: var(--text-muted);
  font-weight: 500;
}

.configuration-page .downtime-rule-flow__arrow {
  flex: 0 0 auto;
  color: var(--text-muted);
}

/* The bordered shell a single settings field sits in. `.configuration-setting-field` is the
   name new cards use; the `.downtime-*` aliases are the original callers in downtimes.html. */
.configuration-page .configuration-setting-field,
.configuration-page .downtime-setting-field,
.configuration-page .downtime-color-setting {
  border: 1px solid var(--border);
  border-radius: .85rem;
  background: color-mix(in srgb, var(--surface-2) 45%, var(--surface));
}

.configuration-page .configuration-setting-field,
.configuration-page .downtime-setting-field { padding: .85rem; }

.configuration-page .configuration-setting-field__input,
.configuration-page .downtime-setting-field__input { width: min(11rem, 100%); }

.configuration-page .downtime-color-setting {
  display: flex;
  align-items: center;
  gap: .75rem;
  padding: .85rem;
}

.configuration-page .settings-actions {
  min-height: 2rem;
}

/* Inline save feedback. This — not the corner toast — is the primary signal that a save landed:
   it appears next to the button the operator just pressed, so nothing has to be looked for. The
   reserved min-width keeps the row from reflowing as the text cycles through its states. */
.configuration-page .settings-save-status,
.configuration-page .downtime-reason-status {
  min-width: 4.75rem;
  color: var(--text-muted);
  font-size: .72rem;
  font-weight: 650;
  line-height: 1.2;
  text-align: right;
}

.configuration-page .settings-actions.has-unsaved-changes .settings-save-status,
.configuration-page .settings-save-status[data-state="dirty"],
.configuration-page .downtime-reason-status[data-state="dirty"] {
  color: var(--text);
}

.configuration-page .settings-save-status[data-state="saved"] {
  color: var(--text);
}

/* Icon as well as colour — a green tick alone is not a status cue. */
.configuration-page .settings-save-status[data-state="saved"]::before {
  content: "\2713";
  margin-right: .25rem;
}


.configuration-page #reasonsTable {
  min-width: 760px;
}

#jobsConfigurationTable_wrapper { min-width: 0; }

.configuration-data-card .dataTables_wrapper {
  min-width: 0;
  padding: .35rem 1.25rem 1.2rem;
  background: transparent;
}

.configuration-data-card__header-controls,
.configuration-data-card .configuration-data-table-controls {
  display: flex;
  align-items: center;
  min-width: 0;
}

.configuration-data-card .configuration-data-table-controls .dataTables_filter {
  display: flex !important;
  align-items: center;
  margin: 0;
  white-space: nowrap;
}

.configuration-data-card .configuration-data-table-controls .dataTables_filter label,
.configuration-data-card .configuration-table-footer .dataTables_length label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.configuration-data-card .configuration-data-table-controls .dataTables_filter input,
.configuration-data-card .configuration-table-footer .dataTables_length select {
  margin-left: .35rem;
  padding: .25rem .65rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
  line-height: 1.5;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.configuration-data-card .configuration-data-table-controls .dataTables_filter input {
  width: min(13rem, 35vw);
}

.configuration-data-card .configuration-data-table-controls .dataTables_filter input:focus,
.configuration-data-card .configuration-table-footer .dataTables_length select:focus {
  border-color: color-mix(in srgb, var(--configuration-card-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--configuration-card-accent) 16%, transparent);
  outline: 0;
}

.configuration-data-card__scroll {
  overflow: auto;
  width: 100%;
}

.configuration-data-card .configuration-table-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.9rem;
  padding: .75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: transparent;
}

.configuration-data-card .configuration-table-footer .dataTables_length,
.configuration-data-card .configuration-table-footer .dataTables_info,
.configuration-data-card .configuration-table-footer .dataTables_paginate {
  float: none;
  margin: 0;
  padding: 0;
}

.configuration-data-card .configuration-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  white-space: nowrap;
}

.configuration-data-card .configuration-table-footer .dataTables_info {
  margin-left: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-variant-numeric: tabular-nums;
  text-align: left;
  white-space: nowrap;
}

.configuration-data-card .configuration-table-footer .dataTables_paginate {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
}

/* Keep generated DataTables metadata predictable across the operational cards:
   page length and range summary remain together, while pagination owns the far edge. */
.operations-data-card .cycles-table-footer,
.operations-data-card .unit-table-footer,
.operations-data-card .activity-log-table-footer {
  min-height: 3.9rem;
  padding: .75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: transparent;
}

.operations-data-card .cycles-table-footer .dataTables_length,
.operations-data-card .cycles-table-footer .dataTables_info,
.operations-data-card .cycles-table-footer .dataTables_paginate,
.operations-data-card .unit-table-footer .dataTables_length,
.operations-data-card .unit-table-footer .dataTables_info,
.operations-data-card .unit-table-footer .dataTables_paginate,
.operations-data-card .activity-log-table-footer .dataTables_length,
.operations-data-card .activity-log-table-footer .dataTables_info,
.operations-data-card .activity-log-table-footer .dataTables_paginate {
  float: none;
  margin-top: 0;
  margin-bottom: 0;
  padding: 0;
}

.operations-data-card .cycles-table-footer .dataTables_info,
.operations-data-card .unit-table-footer .dataTables_info,
.operations-data-card .activity-log-table-footer .dataTables_info {
  margin-left: 0;
  font-variant-numeric: tabular-nums;
  text-align: left;
  white-space: nowrap;
}

.operations-data-card .cycles-table-footer .dataTables_paginate,
.operations-data-card .unit-table-footer .dataTables_paginate,
.operations-data-card .activity-log-table-footer .dataTables_paginate {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
}

.configuration-page .configuration-data-table {
  border-collapse: separate;
  border-spacing: 0 .4rem;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: transparent;
}

.configuration-page .configuration-data-table > thead > tr > th {
  position: relative;
  padding: 0 1.65rem .3rem .75rem;
  border: 0;
  background: var(--surface);
  box-shadow: none;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.configuration-page .configuration-data-table > tbody > tr > td {
  padding: .7rem .75rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  vertical-align: middle;
}

.configuration-page .configuration-data-table > tbody > tr > td:first-child {
  border-left: 1px solid var(--border);
  border-radius: .8rem 0 0 .8rem;
  background-clip: padding-box;
}

.configuration-page .configuration-data-table > tbody > tr > td:last-child {
  border-right: 1px solid var(--border);
  border-radius: 0 .8rem .8rem 0;
  background-clip: padding-box;
}

.configuration-page .configuration-data-table > tbody > tr:hover > td {
  background: color-mix(in srgb, var(--configuration-card-accent) 7%, var(--surface));
}

.configuration-page .configuration-data-table > tbody > tr.has-unsaved-changes > td,
.configuration-page .reason-locked-row.has-unsaved-changes {
  background: color-mix(in srgb, #ffc107 9%, var(--surface));
}

.configuration-page .configuration-data-table > tbody > tr.is-busy > td,
.configuration-page .reason-locked-row[aria-busy="true"] {
  background: color-mix(in srgb, var(--configuration-card-accent) 9%, var(--surface));
}

.configuration-page .configuration-data-table > tbody > tr.is-busy input,
.configuration-page .configuration-data-table > tbody > tr.is-busy select,
.configuration-page .reason-locked-row[aria-busy="true"] input {
  opacity: .72;
}

.configuration-page .downtime-reason-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: .4rem;
  min-width: 13rem;
}

.configuration-page .downtime-reason-actions .btn,
.configuration-page .reason-locked-row__editor .btn {
  min-width: 5.6rem;
}

/* Reserve the line rather than collapsing it, so cycling through the save states never reflows
   the row the operator is reading. */
.configuration-page .downtime-reason-status:empty,
.configuration-page .settings-save-status:empty {
  visibility: hidden;
}

.configuration-page .downtime-reason-status[data-state="saved"] {
  color: var(--text);
}

.configuration-page .downtime-reason-status[data-state="saved"]::before {
  content: "\2713";
  margin-right: .25rem;
}

.configuration-page .downtime-reason-status[data-state="error"],
.configuration-page .settings-save-status[data-state="error"] {
  color: var(--danger-text);
  font-weight: 700;
}

.configuration-page .configuration-data-table > thead > tr > th.sorting,
.configuration-page .configuration-data-table > thead > tr > th.sorting_asc,
.configuration-page .configuration-data-table > thead > tr > th.sorting_desc,
.configuration-page .configuration-data-table > thead > tr > th.sorting_asc_disabled,
.configuration-page .configuration-data-table > thead > tr > th.sorting_desc_disabled {
  background-image: none !important;
}

.configuration-page .configuration-data-table > thead > tr > th.sorting::after,
.configuration-page .configuration-data-table > thead > tr > th.sorting_asc::after,
.configuration-page .configuration-data-table > thead > tr > th.sorting_desc::after {
  position: absolute;
  right: .55rem;
  bottom: .3rem;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 800;
  line-height: 1;
}

.configuration-page .configuration-data-table > thead > tr > th.sorting::after { content: '↕'; }
.configuration-page .configuration-data-table > thead > tr > th.sorting_asc::after { content: '↑'; color: var(--configuration-card-accent); }
.configuration-page .configuration-data-table > thead > tr > th.sorting_desc::after { content: '↓'; color: var(--configuration-card-accent); }

/* Downtime Reasons inline editors (color swatch, label, category) — rounded, tokenized
   controls matching the rest of .configuration-data-card rather than bare Bootstrap defaults. */
.configuration-page .reason-color-input {
  width: 2.4rem;
  height: 1.95rem;
  padding: 1px 2px;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .5rem;
  background-color: var(--surface);
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
  cursor: pointer;
}

.configuration-page .reason-label-input,
.configuration-page .reason-category-input {
  border-radius: .65rem;
  border-color: color-mix(in srgb, var(--border) 58%, var(--surface));
  background-color: var(--surface);
  color: var(--text) !important;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.configuration-page .reason-category-input option {
  color: var(--text);
  background-color: var(--surface);
}

.configuration-page .reason-label-input:focus,
.configuration-page .reason-category-input:focus,
.configuration-page .reason-color-input:focus {
  border-color: color-mix(in srgb, var(--configuration-card-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--configuration-card-accent) 16%, transparent);
}

/* Automatically-managed auto-idle reasons share one contract — color is the only
   editable property — so they read as a labelled group of locked rows. */
.configuration-page .reasons-locked-group {
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: .85rem;
  background: var(--surface);
}

.configuration-page .reasons-locked-group__head {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .15rem .75rem;
  padding: .55rem .9rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
}

.configuration-page .reasons-locked-group__title {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.configuration-page .reasons-locked-group__hint {
  color: var(--text-muted);
  font-size: .78rem;
}

.configuration-page .reason-locked-row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .5rem .75rem;
  padding: .6rem .9rem;
}

.configuration-page .reason-locked-row + .reason-locked-row,
.configuration-page #reasonsPinnedList:not(:empty) + .reason-locked-row {
  border-top: 1px solid var(--border);
}

.configuration-page .reason-locked-row__dot {
  display: inline-block;
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  border: 1px solid color-mix(in srgb, var(--text) 18%, transparent);
  border-radius: 3px;
}

.configuration-page .reason-locked-row__text {
  display: flex;
  flex: 1 1 12rem;
  flex-direction: column;
  gap: .05rem;
  min-width: 0;
}

.configuration-page .reason-locked-row__label {
  margin: 0;
  color: var(--text);
  font-size: .875rem;
  font-weight: 600;
}

.configuration-page .reason-locked-row__meta {
  color: var(--text-muted);
  font-size: .76rem;
}

.configuration-page .reason-locked-row__flags {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .35rem;
}

.configuration-page .reason-locked-row__editor {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin-left: auto;
}

/* Reserves the Save-color button's footprint so every row's picker lands on the
   same vertical line, including the row that has no per-row save. */
.configuration-page .reason-locked-row__action {
  display: flex;
  flex: 0 0 auto;
  justify-content: flex-end;
  min-width: 7.25rem;
}

/* Status chips carry an icon and a word, never colour alone. */
.configuration-page .reason-flag {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  padding: .1rem .5rem;
  border: 1px solid color-mix(in srgb, var(--configuration-card-accent) 38%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--configuration-card-accent) 12%, var(--surface));
  color: var(--text);
  font-size: .72rem;
  font-weight: 600;
  white-space: nowrap;
}

.configuration-page .reason-flag--muted {
  border-color: var(--border);
  background: color-mix(in srgb, var(--surface-2) 60%, var(--surface));
  color: var(--text-muted);
}

@media (max-width: 575.98px) {
  .configuration-page .downtime-settings-handoff {
    align-items: flex-start;
    flex-wrap: wrap;
  }

  .configuration-page .downtime-settings-handoff .btn {
    width: 100%;
  }

  .configuration-page .downtime-color-setting {
    align-items: flex-start;
    flex-wrap: wrap;
  }

  .configuration-page .downtime-color-setting .reason-color-input {
    margin-left: 1.75rem;
  }

  .configuration-page .settings-actions {
    align-items: flex-start !important;
  }

  .configuration-page .settings-save-status {
    min-width: 0;
  }

  .configuration-page .reason-locked-row__editor {
    width: 100%;
    margin-left: 0;
  }
}

/* Users and admin screens share an older table-card shell, including tables created
   dynamically by the device and factory editors. Scope the operations treatment to
   those screens so every table follows the same token-safe workflow language without
   changing its existing IDs, controls, or render contracts. */
.users-page,
.admin-page { --admin-table-accent: #81bc48; }

.users-page .table-card-wrapper,
.admin-page .table-card-wrapper {
  overflow: hidden;
  border: 1px solid color-mix(in srgb, var(--admin-table-accent) 22%, var(--border));
  border-radius: 1.25rem !important;
  background: var(--surface);
  box-shadow: 0 .75rem 2rem color-mix(in srgb, var(--text) 7%, transparent) !important;
}

.users-page .table-card-header,
.admin-page .table-card-header {
  padding: .95rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--admin-table-accent) 6%, var(--surface)) !important;
  color: var(--text);
}

.users-page .table-card-header h5,
.admin-page .table-card-header h5 { color: var(--text); font-weight: 700; }

.users-page .table-card-body,
.admin-page .table-card-body { background: var(--surface); }

.users-page .table,
.admin-page .table {
  border-collapse: separate;
  border-spacing: 0 .4rem;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: transparent;
}

.users-page .table > thead > tr > th,
.admin-page .table > thead > tr > th {
  position: relative;
  padding: 0 .75rem .3rem;
  border: 0;
  background: var(--surface);
  box-shadow: none;
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.users-page .table > tbody > tr:not(.child) > td,
.admin-page .table > tbody > tr:not(.child) > td {
  padding: .7rem .75rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  vertical-align: middle;
}

.users-page .table > tbody > tr:not(.child) > td:first-child,
.admin-page .table > tbody > tr:not(.child) > td:first-child {
  border-left: 1px solid var(--border);
  border-radius: .8rem 0 0 .8rem;
  background-clip: padding-box;
}

.users-page .table > tbody > tr:not(.child) > td:last-child,
.admin-page .table > tbody > tr:not(.child) > td:last-child {
  border-right: 1px solid var(--border);
  border-radius: 0 .8rem .8rem 0;
  background-clip: padding-box;
}

.users-page .table > tbody > tr:not(.child):hover > td,
.admin-page .table > tbody > tr:not(.child):hover > td {
  background: color-mix(in srgb, var(--admin-table-accent) 7%, var(--surface));
}

.users-page .table > thead > tr > th.sorting,
.users-page .table > thead > tr > th.sorting_asc,
.users-page .table > thead > tr > th.sorting_desc,
.users-page .table > thead > tr > th.sorting_asc_disabled,
.users-page .table > thead > tr > th.sorting_desc_disabled,
.admin-page .table > thead > tr > th.sorting,
.admin-page .table > thead > tr > th.sorting_asc,
.admin-page .table > thead > tr > th.sorting_desc,
.admin-page .table > thead > tr > th.sorting_asc_disabled,
.admin-page .table > thead > tr > th.sorting_desc_disabled {
  padding-right: 1.65rem;
  background-image: none !important;
}

.users-page .table > thead > tr > th.sorting::after,
.users-page .table > thead > tr > th.sorting_asc::after,
.users-page .table > thead > tr > th.sorting_desc::after,
.admin-page .table > thead > tr > th.sorting::after,
.admin-page .table > thead > tr > th.sorting_asc::after,
.admin-page .table > thead > tr > th.sorting_desc::after {
  position: absolute;
  right: .55rem;
  bottom: .3rem;
  color: var(--text-muted);
  font-size: .78rem;
  font-weight: 800;
  line-height: 1;
}

.users-page .table > thead > tr > th.sorting::after,
.admin-page .table > thead > tr > th.sorting::after { content: '↕'; }
.users-page .table > thead > tr > th.sorting_asc::after,
.admin-page .table > thead > tr > th.sorting_asc::after { content: '↑'; color: var(--admin-table-accent); }
.users-page .table > thead > tr > th.sorting_desc::after,
.admin-page .table > thead > tr > th.sorting_desc::after { content: '↓'; color: var(--admin-table-accent); }

#usersTable_wrapper { min-width: 0; }

.users-operations-card .dataTables_wrapper {
  min-width: 0;
  padding: .35rem 1.25rem 1.2rem;
  background: transparent;
}

.users-data-card__header-controls,
.users-operations-card .users-data-table-controls {
  display: flex;
  align-items: center;
  min-width: 0;
}

.users-operations-card .users-data-table-controls .dataTables_filter {
  display: flex !important;
  align-items: center;
  margin: 0;
  white-space: nowrap;
}

.users-operations-card .users-data-table-controls .dataTables_filter label,
.users-operations-card .users-table-footer .dataTables_length label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.users-operations-card .users-data-table-controls .dataTables_filter input,
.users-operations-card .users-table-footer .dataTables_length select {
  margin-left: .35rem;
  padding: .25rem .65rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
  line-height: 1.5;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.users-operations-card .users-data-table-controls .dataTables_filter input { width: min(13rem, 35vw); }

.users-operations-card .users-data-table-controls .dataTables_filter input:focus,
.users-operations-card .users-table-footer .dataTables_length select:focus {
  border-color: color-mix(in srgb, var(--admin-table-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--admin-table-accent) 16%, transparent);
  outline: 0;
}

.users-data-card__scroll { overflow: auto; width: 100%; }
.users-data-table { min-width: 62rem; }

.users-operations-card .users-table-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.9rem;
  padding: .75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: transparent;
}

.users-operations-card .users-table-footer .dataTables_length,
.users-operations-card .users-table-footer .dataTables_info,
.users-operations-card .users-table-footer .dataTables_paginate {
  float: none;
  margin: 0;
  padding: 0;
}

.users-operations-card .users-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  white-space: nowrap;
}

.users-operations-card .users-table-footer .dataTables_info {
  color: var(--text-muted);
  font-size: .82rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.users-operations-card .users-table-footer .dataTables_paginate {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
}

.admin-page .admin-data-card .dataTables_wrapper {
  min-width: 0;
  padding: .35rem 1.25rem 1.2rem;
  background: transparent;
}

.admin-page .admin-data-card__header-controls,
.admin-page .admin-data-card .admin-data-table-controls {
  display: flex;
  align-items: center;
  min-width: 0;
}

.admin-page .admin-data-card .admin-data-table-controls .dataTables_filter {
  display: flex !important;
  align-items: center;
  margin: 0;
  white-space: nowrap;
}

.admin-page .admin-data-card .admin-data-table-controls .dataTables_filter label,
.admin-page .admin-data-card .admin-table-footer .dataTables_length label {
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.admin-page .admin-data-card .admin-data-table-controls .dataTables_filter input,
.admin-page .admin-data-card .admin-table-footer .dataTables_length select {
  margin-left: .35rem;
  padding: .25rem .65rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .65rem;
  background: var(--surface);
  color: var(--text);
  font-size: .875rem;
  line-height: 1.5;
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.admin-page .admin-data-card .admin-data-table-controls .dataTables_filter input { width: min(13rem, 35vw); }

.admin-page .admin-data-card .admin-data-table-controls .dataTables_filter input:focus,
.admin-page .admin-data-card .admin-table-footer .dataTables_length select:focus {
  border-color: color-mix(in srgb, var(--admin-table-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--admin-table-accent) 16%, transparent);
  outline: 0;
}

.admin-page .admin-data-card__scroll { overflow: auto; width: 100%; }
.admin-page .chat-users-table { min-width: 46rem; }
.admin-page .chat-sessions-table { min-width: 54rem; }

/* Inline device/shift editors are plain tables, but their controls still belong to the
   same compact native-control family as a DataTable toolbar. */
.admin-page .table .form-control,
.admin-page .table .form-select {
  border-color: color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .55rem;
  background: var(--surface);
  color: var(--text);
}

.admin-page .table .form-control:focus,
.admin-page .table .form-select:focus {
  border-color: color-mix(in srgb, var(--admin-table-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--admin-table-accent) 16%, transparent);
}

.admin-page .admin-data-card .admin-table-footer {
  display: flex;
  align-items: center;
  gap: .75rem;
  min-height: 3.9rem;
  padding: .75rem 1.25rem;
  border-top: 1px solid var(--border);
  background: transparent;
}

/* Every data-card footer wraps on demand rather than only under a breakpoint: the cards
   clip (overflow: hidden), so a footer that cannot wrap puts pagination out of reach at
   any width where the card is narrower than its controls. Wrapping is a no-op when the
   row fits, so desktop keeps its single line. */
.report-table-card .report-table-footer,
.operations-data-card .cycles-table-footer,
.operations-data-card .unit-table-footer,
.operations-data-card .activity-log-table-footer,
.configuration-data-card .configuration-table-footer,
.users-operations-card .users-table-footer,
.admin-page .admin-data-card .admin-table-footer {
  flex-wrap: wrap;
}

.admin-page .admin-data-card .admin-table-footer .dataTables_length,
.admin-page .admin-data-card .admin-table-footer .dataTables_info,
.admin-page .admin-data-card .admin-table-footer .dataTables_paginate {
  float: none;
  margin: 0;
  padding: 0;
}

.admin-page .admin-data-card .admin-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  white-space: nowrap;
}

.admin-page .admin-data-card .admin-table-footer .dataTables_info {
  color: var(--text-muted);
  font-size: .82rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.admin-page .admin-data-card .admin-table-footer .dataTables_paginate {
  flex: 0 0 auto;
  margin-left: auto;
  white-space: nowrap;
}

/* DataTables ships light, loosely spaced controls by default. All CloEE card footers share
   one compact native select, and the length selector is always the first footer item. */
.operations-data-card .cycles-table-footer .dataTables_length,
.operations-data-card .unit-table-footer .dataTables_length,
.operations-data-card .activity-log-table-footer .dataTables_length,
.configuration-data-card .configuration-table-footer .dataTables_length,
.users-operations-card .users-table-footer .dataTables_length,
.admin-page .admin-data-card .admin-table-footer .dataTables_length,
.report-table-card .report-table-footer .dataTables_length {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  float: none;
  margin: 0;
  padding: 0;
  white-space: nowrap;
}

.operations-data-card .cycles-table-footer .dataTables_length label,
.operations-data-card .unit-table-footer .dataTables_length label,
.operations-data-card .activity-log-table-footer .dataTables_length label,
.configuration-data-card .configuration-table-footer .dataTables_length label,
.users-operations-card .users-table-footer .dataTables_length label,
.admin-page .admin-data-card .admin-table-footer .dataTables_length label,
.report-table-card .report-table-footer .dataTables_length label {
  display: inline-flex;
  align-items: center;
  gap: .4rem;
  margin: 0;
  color: var(--text-muted);
  font-size: .82rem;
  font-weight: 600;
}

.operations-data-card .cycles-table-footer .dataTables_length select,
.operations-data-card .unit-table-footer .dataTables_length select,
.operations-data-card .activity-log-table-footer .dataTables_length select,
.configuration-data-card .configuration-table-footer .dataTables_length select,
.users-operations-card .users-table-footer .dataTables_length select,
.admin-page .admin-data-card .admin-table-footer .dataTables_length select,
.report-table-card .report-table-footer .dataTables_length select {
  min-width: 4.6rem;
  min-height: 2.15rem;
  margin: 0;
  padding: .25rem .65rem;
  border: 1px solid color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .6rem;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
  font-size: .875rem;
  line-height: 1.5;
}

.operations-data-card .cycles-table-footer .dataTables_length select:focus,
.operations-data-card .unit-table-footer .dataTables_length select:focus,
.operations-data-card .activity-log-table-footer .dataTables_length select:focus,
.configuration-data-card .configuration-table-footer .dataTables_length select:focus,
.users-operations-card .users-table-footer .dataTables_length select:focus,
.admin-page .admin-data-card .admin-table-footer .dataTables_length select:focus,
.report-table-card .report-table-footer .dataTables_length select:focus {
  border-color: color-mix(in srgb, var(--link) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--link) 16%, transparent);
  outline: 0;
}

.report-table-card .report-table-footer .dataTables_info,
.report-table-card .report-table-footer .dataTables_paginate {
  float: none;
  margin: 0;
  padding: 0;
}

.report-table-card .report-table-footer .dataTables_info {
  color: var(--text-muted);
  font-size: .82rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.report-table-card .report-table-footer .dataTables_paginate {
  margin-left: auto;
  white-space: nowrap;
}

/* DataTables owns the split header/body for scrollX, so do not apply CSS sticky columns there. */
.operations-data-card table.operations-data-table--managed-scroll > thead > tr > th,
.operations-data-card table.operations-data-table--managed-scroll > tbody > tr:not(.child) > td:nth-child(1),
.operations-data-card table.operations-data-table--managed-scroll > tbody > tr:not(.child) > td:nth-child(2) {
  position: static;
  z-index: auto;
}

.operations-data-card table.operations-data-table--managed-scroll > tbody > tr:not(.child) > td:nth-child(1),
.operations-data-card table.operations-data-table--managed-scroll > tbody > tr:not(.child) > td:nth-child(2) {
  background: var(--operations-data-row-surface);
}

/* DataTables child rows own nested detail tables; never apply main-grid framing or sticky cells to them. */
.operations-data-card table.operations-data-table > tbody > tr.child > td {
  padding: 0;
  border: 0;
  background: transparent;
}

/* Expanded rework, alarm, and segment detail tables use the same contained surface without
   inheriting the main grid's sticky context or sort controls. */
.operations-detail-panel {
  margin: .75rem 1rem 1rem;
  padding: .75rem;
  border: 1px solid var(--border);
  border-radius: .9rem;
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
}

.operations-detail-panel--danger {
  border-color: color-mix(in srgb, var(--bs-danger) 28%, var(--border));
  background: color-mix(in srgb, var(--bs-danger) 6%, var(--surface));
}

/* Detail tables also appear in offcanvas and modal workflows. Keep those compact surfaces
   token-safe without requiring an enclosing operations card to provide an accent. */
.operations-detail-panel--compact { margin: 0; }
.operations-modal-table { --operations-data-card-accent: #81bc48; }

.operations-modal-table .form-control,
.operations-modal-table .form-select {
  min-height: 2rem;
  border-color: color-mix(in srgb, var(--border) 58%, var(--surface));
  border-radius: .55rem;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 .1rem .25rem color-mix(in srgb, var(--text) 5%, transparent);
}

.operations-modal-table .form-control:focus,
.operations-modal-table .form-select:focus {
  border-color: color-mix(in srgb, var(--operations-data-card-accent) 48%, var(--border));
  box-shadow: 0 0 0 .16rem color-mix(in srgb, var(--operations-data-card-accent) 16%, transparent);
}

.operations-detail-heading,
.operations-detail-toggle {
  display: flex;
  align-items: center;
  gap: .45rem;
  margin: 0 0 .55rem;
  color: var(--text-muted);
  font-size: .7rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}

.operations-detail-panel--danger .operations-detail-heading { color: var(--bs-danger); }

.operations-detail-stack { display: flow-root; }
.batch-details-segment-timeline { padding-bottom: .6rem; }

.operations-detail-toggle {
  margin-top: 0;
  padding: .2rem .25rem;
  border-radius: .45rem;
  cursor: pointer;
  user-select: none;
}

.operations-detail-toggle:hover { background: color-mix(in srgb, var(--operations-data-card-accent) 7%, var(--surface)); }

.operations-detail-panel > .collapse { overflow-x: auto; }

.operations-detail-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0 .3rem;
  --bs-table-bg: transparent;
  --bs-table-hover-bg: transparent;
}

/* DataTables' own row-background rule (vendor CSS default, plus our dark-mode
   remap in §25) targets `table.dataTable tbody tr` with a plain descendant
   combinator, which ignores table boundaries: it also paints the <tr> of a
   detail table nested inside a DataTables child row (this table lives inside
   #batchesTable's <tbody>). The <th> below is already transparent, so that
   leaked row fill shows straight through as a hard-edged band instead of the
   panel's own background — override the row itself, not just its cells. */
.operations-detail-table > thead > tr {
  background: transparent !important;
}

.operations-detail-table > thead > tr > th {
  padding: 0 .55rem .2rem;
  border: 0;
  background: transparent;
  box-shadow: none;
  color: var(--text-muted);
  font-size: .65rem;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
  white-space: nowrap;
}

.operations-detail-table > tbody > tr { --operations-detail-row-surface: var(--surface); }

.operations-detail-table > tbody > tr > td {
  padding: .52rem .55rem;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
  background: var(--operations-detail-row-surface);
  box-shadow: none;
  color: var(--text);
  vertical-align: middle;
}

.operations-detail-table > tbody > tr > td:first-child {
  border-left: 1px solid var(--border);
  border-radius: .65rem 0 0 .65rem;
  background-clip: padding-box;
}

.operations-detail-table > tbody > tr > td:last-child {
  border-right: 1px solid var(--border);
  border-radius: 0 .65rem .65rem 0;
  background-clip: padding-box;
}

.operations-detail-table > tbody > tr:hover {
  --operations-detail-row-surface: color-mix(in srgb, var(--operations-data-card-accent, #81bc48) 7%, var(--surface));
}

.operations-detail-table > tbody > tr:hover > td {
  background: var(--operations-detail-row-surface);
  box-shadow: none;
}

/* Segment expanders are generated after page load, so give them an explicit
   opt-in surface contract instead of allowing Bootstrap's `.table` cell paint
   to leak through. This keeps the label row panel-led and every segment row
   visibly rounded through the final row in either colour mode. */
.operations-segments-detail-table {
  --bs-table-bg: transparent !important;
  --bs-table-hover-bg: transparent !important;
  border-spacing: 0 .35rem;
}

.operations-segments-detail-table > thead > tr > th {
  background: transparent !important;
  background-image: none !important;
  box-shadow: none !important;
}

.operations-segments-detail-table > tbody > tr > td {
  background: var(--surface) !important;
  box-shadow: none !important;
}

.operations-segments-detail-table > tbody > tr:last-child > td:first-child {
  border-bottom-left-radius: .65rem !important;
}

.operations-segments-detail-table > tbody > tr:last-child > td:last-child {
  border-bottom-right-radius: .65rem !important;
}

@media (max-width: 991.98px) {
  .operations-data-card__toolbar { flex-wrap: wrap; }
}

@media (max-width: 575.98px) {
  .activity-log-modal-dialog { margin: .5rem; }
  .activity-log-modal__header { align-items: flex-start; padding: .75rem; }
  .activity-log-modal__icon { width: 2rem; height: 2rem; }
  .activity-log-modal__body { padding: .75rem; }
  .activity-log-modal__table-wrap { padding: .35rem; }

  .operations-data-card__header { padding: .85rem 1rem; }
  .operations-data-card__subtitle { display: none; }
  .operations-data-card__controls, .operations-data-card .dataTables_wrapper { padding-left: .75rem; padding-right: .75rem; }
  .operations-data-card__toolbar { align-items: stretch; flex-wrap: wrap; }
  .operations-data-card__toolbar-actions { order: 3; }
  .batch-details-operations-card__header-actions {
    width: 100%;
    margin-left: 0;
    justify-content: flex-end;
  }
  .unit-details-table-card__header-actions,
  .unit-details-batches-card__header-actions,
  .downtimes-operations-card__header-actions {
    width: 100%;
    margin-left: 0;
    justify-content: flex-end;
  }
  .operations-data-card__header-data-controls {
    margin-left: auto;
  }
  .operations-data-card__datatable-controls { width: 100%; margin-left: 0; padding-left: 0; border-left: 0; }
  .operations-data-card__datatable-controls .cycles-data-table-controls { justify-content: space-between; width: 100%; }
  .operations-data-card__datatable-controls .dataTables_filter input { width: min(8rem, 35vw); }
  .operations-data-card .unit-data-table-controls .dataTables_filter input,
  .operations-data-card .batches-data-table-controls .dataTables_filter input { width: min(8rem, 35vw); }
  .operations-data-card .cycles-table-footer { flex-wrap: wrap; }
  .operations-data-card .unit-table-footer { flex-wrap: wrap; }
  .operations-data-card .activity-log-table-footer,
  .configuration-data-card .configuration-table-footer,
  .users-operations-card .users-table-footer,
  .admin-page .admin-data-card .admin-table-footer { flex-wrap: wrap; }
  .operations-data-card .cycles-table-footer .dataTables_paginate,
  .operations-data-card .unit-table-footer .dataTables_paginate,
  .operations-data-card .activity-log-table-footer .dataTables_paginate,
  .configuration-data-card .configuration-table-footer .dataTables_paginate,
  .users-operations-card .users-table-footer .dataTables_paginate,
  .admin-page .admin-data-card .admin-table-footer .dataTables_paginate { margin-left: auto; }
  .operations-data-card table.operations-data-table > tbody > tr:not(.child) > td { padding: .6rem .5rem; }
  .operations-detail-panel { margin-left: .5rem; margin-right: .5rem; padding: .6rem; }
  .operations-detail-table > tbody > tr > td { padding: .48rem .45rem; }
}

/* === 24. Reports downtime Pareto === */

/* Mirror the Power/Gas Flow summary-card hierarchy while retaining a
   loss-focused accent for Pareto-specific content. */
.downtime-analysis-card {
  --downtime-accent: #f34062;
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--downtime-accent) 10%, var(--surface)),
    var(--surface) 62%
  );
  border: 1px solid color-mix(in srgb, var(--downtime-accent) 26%, var(--border));
  border-radius: 1rem;
  box-shadow: 0 0.5rem 1.25rem color-mix(in srgb, var(--downtime-accent) 10%, transparent);
  color: var(--text);
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  width: 100%;
}

.downtime-analysis-card__header {
  align-items: center;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 0.75rem;
  padding: 1rem;
}

.downtime-analysis-card__header h5 {
  align-items: center;
  color: var(--text);
  display: flex;
  font-size: 1.2rem;
  font-weight: 700;
  gap: 0.35rem;
  justify-content: center;
  grid-column: 2;
  margin: 0.15rem 0 0;
  text-align: center;
  white-space: nowrap;
}

.downtime-analysis-card__total {
  grid-column: 3;
  justify-self: end;
  flex: 0 0 auto;
  text-align: right;
}

.downtime-analysis-card__total span {
  color: var(--text-muted);
  display: block;
  font-size: 0.68rem;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.downtime-analysis-card__total strong {
  color: var(--downtime-accent);
  display: block;
  font-size: 1.35rem;
  line-height: 1.1;
}

.downtime-analysis-card__header h5 i {
  color: var(--downtime-accent);
}

/* Flex column so the reason list below can claim the card's leftover height. The card is
   stretched by .report-kpi-downtime to match the taller KPI stack beside it; with a fixed-height
   list that surplus used to sit blank under the table while rows scrolled out of sight. */
.downtime-pareto-content {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  padding: 0.7rem 1rem 0.85rem;
}

.downtime-reference-metrics {
  display: grid;
  flex: 0 0 auto;
  gap: 0.4rem;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  margin-bottom: 0.7rem;
}

.downtime-reference-metric {
  background: color-mix(in srgb, var(--downtime-accent) 6%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--downtime-accent) 16%, var(--border));
  border-radius: 0.5rem;
  min-width: 0;
  padding: 0.28rem 0.35rem 0.3rem;
}

.downtime-reference-metric__label {
  color: var(--text-muted);
  display: block;
  font-size: 0.68rem;
  font-weight: 700;
  line-height: 1;
  margin-bottom: 0.18rem;
  text-transform: uppercase;
}

.downtime-reference-metric strong {
  color: var(--text);
  display: block;
  font-size: 1.1rem;
  line-height: 1.15;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.downtime-reference-metric strong .text-success,
.downtime-reference-metric strong .text-danger {
  font-size: 0.62rem !important;
  margin-left: 0.15rem;
}

.downtime-reference-metric__reason {
  align-items: center;
  display: flex;
  gap: 0.22rem;
  color: var(--text);
}

.downtime-reference-metric__reason i {
  border-radius: 50%;
  display: inline-block;
  flex: 0 0 auto;
  height: 0.38rem;
  width: 0.38rem;
}

.downtime-pareto-chart {
  display: grid;
  flex: 0 0 auto;
  grid-template-columns: 2.25rem minmax(0, 1fr);
  gap: 0.2rem;
  max-height: 15.5rem;
  overflow: auto;
}

.downtime-pareto-left-axis {
  align-self: start;
  color: var(--text-muted);
  display: flex;
  flex-direction: column;
  font-size: 0.78rem;
  height: 145px;
  justify-content: space-between;
  line-height: 1;
  padding: 0.05rem 0;
}

.downtime-pareto-left-axis { text-align: right; }

.downtime-pareto-plot {
  min-width: 360px;
  position: relative;
}

.downtime-pareto-grid {
  height: 145px;
  inset: 0;
  position: absolute;
  width: 100%;
}

.downtime-pareto-grid {
  display: grid;
  grid-template-rows: repeat(5, 1fr);
  pointer-events: none;
  z-index: 0;
}

.downtime-pareto-grid span { border-top: 1px dashed color-mix(in srgb, var(--text-muted) 26%, var(--border)); }
.downtime-pareto-grid span:last-child { border-bottom: 1px solid var(--border); }

.downtime-pareto-bars {
  display: grid;
  position: relative;
  z-index: 2;
}

.downtime-pareto-bar-column {
  display: grid;
  grid-template-rows: 145px auto;
  min-width: 0;
  text-align: center;
}

.downtime-pareto-bar-column--interactive {
  cursor: pointer;
  outline: none;
}

.downtime-pareto-bar-column--interactive:hover .downtime-pareto-bar-fill,
.downtime-pareto-bar-column--interactive:focus .downtime-pareto-bar-fill,
.downtime-pareto-bar-column--interactive[aria-pressed="true"] .downtime-pareto-bar-fill {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--surface) 85%, var(--downtime-accent));
  filter: brightness(1.08);
}

.downtime-pareto-bar-column--interactive:hover .downtime-pareto-bar-label,
.downtime-pareto-bar-column--interactive:focus .downtime-pareto-bar-label,
.downtime-pareto-bar-column--interactive[aria-pressed="true"] .downtime-pareto-bar-label {
  color: var(--text);
  font-weight: 800;
}

.downtime-pareto-bar-area { min-width: 0; position: relative; }

.downtime-pareto-bar-fill {
  bottom: 0;
  border-radius: 0.45rem 0.45rem 0 0;
  height: var(--pareto-bar-height);
  left: 16%;
  min-height: 3px;
  position: absolute;
  right: 16%;
}

/* Baseline marker for the chosen comparison period: a thin dashed tick across the bar at that
   period's hours, so the solid bar reads as movement vs the baseline (theme-safe muted colour). */
.downtime-pareto-bar-baseline {
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: var(--pareto-baseline-height);
  height: 0;
  border-top: 2px dashed color-mix(in srgb, var(--text-muted) 72%, transparent);
  pointer-events: none;
}

.downtime-pareto-bar-label {
  color: var(--text-muted);
  font-size: 0.8rem;
  line-height: 1.2;
  margin: 0.35rem 0.08rem 0;
  overflow-wrap: anywhere;
}

.downtime-pareto-chart-tooltip {
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--downtime-accent) 38%, var(--border));
  border-radius: 0.3rem;
  box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.14);
  color: var(--text);
  font-size: 0.72rem;
  line-height: 1.2;
  min-width: max-content;
  padding: 0.2rem 0.32rem;
  pointer-events: none;
  position: absolute;
  text-align: center;
  top: 0.35rem;
  transform: translateX(-50%);
  z-index: 3;
}

.downtime-pareto-chart-tooltip[hidden] { display: none; }
.downtime-pareto-chart-tooltip strong { display: block; color: var(--text); font-weight: 800; }

/* The reason list takes every pixel the chart above it did not, so a short list needs no scroll
   at all and a long one scrolls inside the card rather than stretching it. min-height keeps ~3
   rows legible when the card is short; the wrapper is the positioning context for the fade. */
.downtime-pareto-detail {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  margin-top: 0.55rem;
  min-height: 5rem;
  position: relative;
}

/* Same persistent-scrollbar recipe as .machine-pareto-card__scroll — the OS default auto-hides,
   which is precisely why a scrollable list reads as a complete one. */
.downtime-pareto-detail__scroll {
  flex: 1 1 auto;
  min-height: 0;
  overflow-x: auto;
  overflow-y: auto;
  scrollbar-color: color-mix(in srgb, var(--downtime-accent) 45%, var(--text-muted)) transparent;
  scrollbar-width: thin;
}

.downtime-pareto-detail__scroll::-webkit-scrollbar { height: 0.55rem; width: 0.55rem; }
.downtime-pareto-detail__scroll::-webkit-scrollbar-track { background: transparent; }
.downtime-pareto-detail__scroll::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--downtime-accent) 45%, var(--text-muted));
  border-radius: 999px;
}
.downtime-pareto-detail__scroll::-webkit-scrollbar-corner { background: transparent; }

/* Fade + hint, shown by bindDowntimeDetailScroll only while rows remain below the fold. The card
   background is a gradient, but it has resolved to var(--surface) well above this row, so a
   surface-coloured fade blends cleanly in both themes. */
.downtime-pareto-detail::after {
  background: linear-gradient(transparent, var(--surface));
  bottom: 0;
  content: "";
  height: 2rem;
  left: 0;
  opacity: 0;
  pointer-events: none;
  position: absolute;
  right: 0;
  transition: opacity 0.15s ease;
}

/* Parked at the right edge, clear of the scrollbar, so it never lands on a reason label. */
.downtime-pareto-detail__more {
  align-items: center;
  background: var(--surface);
  border: 1px solid color-mix(in srgb, var(--downtime-accent) 26%, var(--border));
  border-radius: 999px;
  bottom: 0.15rem;
  color: var(--text-muted);
  display: inline-flex;
  font-size: 0.6rem;
  font-weight: 700;
  gap: 0.2rem;
  letter-spacing: 0.04em;
  opacity: 0;
  padding: 0.05rem 0.4rem;
  pointer-events: none;
  position: absolute;
  right: 0.75rem;
  text-transform: uppercase;
  transition: opacity 0.15s ease;
}

.downtime-pareto-detail[data-overflow="more"]::after,
.downtime-pareto-detail[data-overflow="more"] .downtime-pareto-detail__more { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
  .downtime-pareto-detail::after,
  .downtime-pareto-detail__more { transition: none; }
}

.downtime-pareto-table {
  border-collapse: collapse;
  font-size: 0.88rem;
  min-width: 100%;
  width: 100%;
}

/* Sticky so the column meanings survive scrolling — and so the rows visibly slide under a fixed
   header, which is the clearest "there is more here" cue the list has. Needs an opaque fill of
   its own: the card's gradient sits on an ancestor, not on the cells. */
.downtime-pareto-table thead th {
  background: var(--surface);
  /* inset shadow, not border-bottom: a collapsed-border table drops the border on a sticky cell. */
  box-shadow: inset 0 -1px 0 var(--border);
  color: var(--text-muted);
  cursor: help;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 0.1rem 0.08rem 0.3rem;
  position: sticky;
  text-transform: uppercase;
  top: 0;
  white-space: nowrap;
  z-index: 1;
}

.downtime-pareto-table thead th:first-child { padding-left: 0; text-align: left; }
.downtime-pareto-table thead th:not(:first-child) { text-align: right; }

.downtime-pareto-table td {
  border-top: 1px solid color-mix(in srgb, var(--text-muted) 20%, var(--border));
  padding: 0.32rem 0.08rem;
  vertical-align: middle;
}

.downtime-pareto-table td:first-child {
  color: var(--text-muted);
  padding-left: 0;
  width: 52%;
}

.downtime-pareto-table td:not(:first-child) {
  color: var(--text);
  text-align: right;
  white-space: nowrap;
}

.downtime-pareto-table td:nth-child(2) { color: var(--text); font-size: 0.95rem; font-weight: 800; }

.downtime-pareto-swatch {
  border-radius: 50%;
  display: inline-block;
  height: 0.42rem;
  margin-right: 0.35rem;
  width: 0.42rem;
}

.downtime-reference-empty {
  color: var(--text-muted);
  font-size: 0.68rem;
  padding: 2rem 0;
  text-align: center;
}

@media (max-width: 575.98px) {
  .downtime-analysis-card { max-width: none; }
  .downtime-analysis-card__header { padding: 0.75rem; }
  .downtime-analysis-card__header h5 { font-size: 0.9rem; }
  .downtime-analysis-card__total strong { font-size: 0.9rem; }
  .downtime-pareto-content { padding: 0.7rem; }
  .downtime-reference-metrics { gap: 0.25rem; }
  .downtime-reference-metric { padding-inline: 0.25rem; }
  .downtime-pareto-plot { min-width: 320px; }
  .downtime-pareto-bar-fill { left: 10%; right: 10%; }
}

/* === Reports Machine Pareto Heatmap ("Machines KPI" card) ===
   Shares .energy-summary-card as its base class (same as .batch-flow-card /
   .energy-summary-card--power) — the stat/title/stat header, big bold values, accent gradient
   + border + shadow, and dark-mode behaviour all come from that shared recipe via one custom
   property override. Only the scrollable metric×machine matrix below is Pareto-specific. Cell
   colour/intensity is set inline per-cell (data-driven, not a fixed accent) via
   color-mix(... var(--surface)) so it re-tints for dark mode automatically. */
.machine-pareto-card {
  --energy-summary-accent: #6f42c1;
  margin-bottom: 1rem;
}

/* Same card/table family as .machine-pareto-card (see comment above) — only the accent differs.
   Cell severity/tint logic lives in report_render.js's ammoniaCellStyle/ammoniaParetoCell. */
.ammonia-pareto-card {
  --energy-summary-accent: #fd7e14;
}

/* How the figures above the table were derived. Deliberately quiet but always present, never a
   tooltip: a safety-compliance table that reads as TWA/STEL while actually showing period averages
   and instantaneous peaks must carry that caveat where a reader cannot miss it. */
.ammonia-pareto-card__method {
  margin: 0 0 .6rem;
  padding: .5rem .7rem;
  border-left: 2px solid color-mix(in srgb, var(--energy-summary-accent) 45%, var(--border));
  border-radius: .25rem;
  background: color-mix(in srgb, var(--energy-summary-accent) 6%, var(--surface));
  color: var(--text-muted);
  font-size: .72rem;
  line-height: 1.45;
}

.ammonia-pareto-card__severity { gap: 0.45rem; }

.ammonia-pareto-card__severity-item {
  align-items: center;
  background: color-mix(in srgb, var(--ammonia-severity-color) 12%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--ammonia-severity-color) 28%, var(--border));
  border-radius: 999px;
  color: var(--text-muted);
  display: inline-flex;
  font-size: 0.72rem;
  font-weight: 600;
  gap: 0.3rem;
  padding: 0.18rem 0.45rem;
}

.ammonia-pareto-card__severity-item > i {
  background: var(--ammonia-severity-color);
  border-radius: 50%;
  display: inline-block;
  height: 0.42rem;
  width: 0.42rem;
}

.ammonia-pareto-card__severity-item strong { color: var(--text); }

.ammonia-pareto-card__alarm-value {
  align-items: baseline;
  display: flex;
  gap: 0.35rem;
}

.ammonia-pareto-card__alarm-value .energy-summary-card__value,
.ammonia-pareto-card__alarm-value .ammonia-pareto-card__delta { margin: 0; }

.ammonia-pareto-card__delta {
  color: var(--text-muted);
  display: inline-flex;
  font-size: 0.95rem;
  font-weight: 700;
  gap: 0.25rem;
  margin-top: 0.1rem;
  white-space: nowrap;
}

.ammonia-pareto-card__delta--compact {
  font-size: 0.86rem;
  margin: 0;
}

.ammonia-pareto-card__delta--up i { color: #dc3545; }
.ammonia-pareto-card__delta--down i { color: #198754; }
.ammonia-pareto-card__delta--flat i { color: var(--text-muted); }

.machine-pareto-card__trend {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin: 0.6rem 0 0.75rem;
}

.machine-pareto-card__empty {
  color: var(--text-muted);
}

/* Scrolls in both axes independently — sticky header/first-column need this single element as
   their scrolling ancestor for both directions. A thin accent-tinted scrollbar keeps the
   overflow affordance visible at a glance instead of relying on the OS's auto-hiding default. */
.machine-pareto-card__scroll {
  margin-top: 0.75rem;
  border-radius: 0.6rem;
  max-height: 26rem;
  overflow-x: auto;
  overflow-y: auto;
  scrollbar-color: color-mix(in srgb, var(--energy-summary-accent) 45%, var(--text-muted)) transparent;
  scrollbar-width: thin;
}

.machine-pareto-card__scroll::-webkit-scrollbar { height: 0.55rem; width: 0.55rem; }
.machine-pareto-card__scroll::-webkit-scrollbar-track { background: transparent; }
.machine-pareto-card__scroll::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--energy-summary-accent) 45%, var(--text-muted));
  border-radius: 999px;
}
.machine-pareto-card__scroll::-webkit-scrollbar-corner { background: transparent; }

.machine-pareto-table {
  border-collapse: separate;
  border-spacing: 0;
  font-size: 0.82rem;
  width: 100%;
}

.machine-pareto-table thead th {
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.03em;
  min-width: 4.75rem;
  padding: 0.5rem 0.6rem;
  position: sticky;
  text-align: center;
  text-transform: uppercase;
  top: 0;
  white-space: nowrap;
  z-index: 1;
}

.machine-pareto-table tbody th {
  background: var(--surface);
  color: var(--text);
  font-size: 0.78rem;
  font-weight: 600;
  left: 0;
  padding: 0.45rem 0.6rem;
  position: sticky;
  text-align: left;
  white-space: nowrap;
  z-index: 1;
}

.machine-pareto-table__corner {
  left: 0;
  position: sticky;
  z-index: 2;
}

.machine-pareto-cell {
  color: var(--text);
  font-weight: 600;
  padding: 0.45rem 0.6rem;
  text-align: center;
  transition: background-color 0.15s ease;
  white-space: nowrap;
}

.machine-pareto-cell--interactive { cursor: help; }

.machine-pareto-cell i { font-size: 0.7rem; margin-left: 0.15rem; }

/* Equal outer columns keep the value at the true cell centre; a marker/delta begins immediately
   beside it in the right-hand column, so it is related to the number without shifting that number. */
.ammonia-pareto-cell__content {
  align-items: center;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
}

.ammonia-pareto-cell__value { grid-column: 2; }

.ammonia-pareto-cell__content > .ammonia-pareto-cell__alert,
.ammonia-pareto-cell__content > .ammonia-pareto-card__delta--compact {
  grid-column: 3;
  justify-self: start;
  margin: 0 0 0 0.35rem;
}

.ammonia-pareto-cell__content > .ammonia-pareto-cell__alert { margin-left: 0.42rem; }

.machine-pareto-card__legend {
  align-items: center;
  color: var(--text-muted);
  display: flex;
  font-size: 0.72rem;
  gap: 0.35rem;
  margin-top: 0.6rem;
}

.machine-pareto-legend-swatch {
  border-radius: 3px;
  display: inline-block;
  height: 0.6rem;
  width: 0.6rem;
}

.machine-pareto-legend-swatch--bad { background: #dc3545; margin-left: 0.5rem; }
.machine-pareto-legend-swatch--good { background: #198754; }
.machine-pareto-legend-swatch--bad:first-child { margin-left: 0; }

@media (max-width: 575.98px) {
  .machine-pareto-card__scroll { max-height: 20rem; }
}

/* ─── 21. Active Employee Selector Pulse ─────────────────────────────────── */
@keyframes employee-selector-pulse {
  0%   { border-color: #ffc107; box-shadow: 0 0 0 0 rgba(255, 193, 7, 0.6); }
  50%  { border-color: #ffc107; box-shadow: 0 0 0 6px rgba(255, 193, 7, 0); }
  100% { border-color: #ffc107; box-shadow: 0 0 0 0 rgba(255, 193, 7, 0); }
}
.employee-selector-pulse {
  animation: employee-selector-pulse 0.8s ease 2;
}

/* ─── Shared micro-label utility ─────────────────────────────────────────── */
.label-micro {
  font-size: 0.7rem;
  letter-spacing: .05em;
  font-weight: 600;
  text-transform: uppercase;
  color: #6c757d;
}

/* ─── Unit Details: current-state strip border accent ────────────────────── */
.unit-state-running  { border-left: 4px solid #198754 !important; }
.unit-state-idle     { border-left: 4px solid #ffc107 !important; }
.unit-state-downtime { border-left: 4px solid #dc3545 !important; }

/* ─── Unit Details: per-batch performance mini bar ──────────────────────── */
.batch-perf-track {
  width: 52px;
  height: 5px;
  background: #e9ecef;
  border-radius: 3px;
  overflow: hidden;
  flex-shrink: 0;
}
.batch-perf-fill,
.batch-quality-fill {
  height: 100%;
  width: 0;
  border-radius: 3px;
  transition: width 0.4s ease;
}

/* === 24. Unit drag-and-drop (admin) === */
/* Drag cursor and feedback states are injected inline per-page for admins only. */

/* === 25. Dark Mode Overrides ============================
   Bootstrap 5.3 color mode (data-bs-theme="dark") restyles all native
   Bootstrap components automatically. The rules below cover only the
   CUSTOM selectors that set explicit light surfaces/text/borders and
   would otherwise stay light. Status hues (green/amber/red/orange) keep
   their hue; only their light tints are remixed against the dark surface.
─────────────────────────────────────────────────────────── */
html[data-bs-theme="dark"] {

  /* --- Global text/links --- */
  h1 { color: var(--text); }
  a  { color: var(--link); }

  /* Bootstrap .bg-light utility is a fixed light grey (does not follow color mode);
     it is used for many card/panel/header surfaces, so lift it to the elevated
     surface so the panel reads clearly above the darker body. */
  .bg-light { background-color: var(--surface) !important; }

  /* Lift every card onto the elevated surface with a visible border so cards
     never blend into the body (the No.1 dark-mode complaint). */
  .card { --bs-card-bg: var(--surface); --bs-card-border-color: var(--border); }

  /* Bootstrap .table-light (used on most <thead>s) is a fixed light grey that
     does not follow color mode — remap its table variables to the dark surface
     so table headers stop rendering white. */
  .table-light,
  .table-light > th,
  .table-light > td,
  .table-light th,
  .table-light td {
    --bs-table-color: var(--text);
    --bs-table-bg: var(--surface-2);
    --bs-table-border-color: var(--border);
    --bs-table-striped-color: var(--text);
    --bs-table-active-color: var(--text);
    --bs-table-hover-color: var(--text);
    color: var(--text);
    border-color: var(--border);
  }

  /* A generic recessed header creates an unrelated dark strip across every table.
     Card-owned grids define their own surface; unscoped compact tables inherit their panel. */
  .table > thead > tr > th {
    background: transparent;
    color: var(--text-muted);
    border-color: var(--border);
  }

  /* Compact inner tables and report lists are already contained by a tinted
     panel/card. Let their header labels share that surface instead of painting
     a separate dark strip across the table. */
  .operations-detail-table > thead > tr > th,
  .report-table-card table.report-table > thead > tr > th {
    background: transparent;
  }

  .operations-detail-table > thead > tr > th { box-shadow: none; }

  /* .badge.bg-light + .text-dark renders dark-on-dark — make the chip readable. */
  .badge.bg-light { background-color: var(--surface-sunken) !important; color: var(--text) !important; border-color: var(--border) !important; }

  /* --- Login / generic light backgrounds --- */
  .login-page              { background-color: var(--surface-2); }
  .under-dev-page          { background: var(--surface-2); }
  .dev-title               { color: var(--text); }
  .dev-subtext             { color: var(--text-muted); }
  .custom-bg               { background: linear-gradient(to right, #1f2937, #111827); color: var(--text) !important; }

  /* --- Sidebar --- */
  #sidebar                 { background-color: var(--surface-2); border-right-color: var(--border); }
  .sidebar-link            { color: var(--text); }
  .sidebar-link-sub        { color: var(--text-muted); }
  .sidebar-link:hover { background-color: var(--surface-sunken); }
  .sidebar-link.active,
  .sidebar-link-sub.active,
  .sidebar-collapsed #sidebar .sidebar-link.active {
    background: color-mix(in srgb, var(--link) 12%, color-mix(in srgb, var(--surface) 78%, transparent));
    border-left-color: color-mix(in srgb, var(--link) 70%, var(--border));
    color: var(--link);
  }
  .sidebar-link.active:hover { background: color-mix(in srgb, var(--link) 16%, var(--surface)); }
  .sidebar-user-info       { background: var(--surface-2); border-top-color: var(--border); }
  .sidebar-logout-btn,
  .sidebar-logout-btn i    { color: var(--text) !important; }
  /* The dark `a { color: var(--link) }` above outranks .sidebar-user-card-action's
     own colour, so restate it here (hover/focus below still win on specificity). */
  .sidebar-user-card-action { color: var(--text); }
  .sidebar-user-card-action:hover,
  .sidebar-user-card-action:focus-visible { color: var(--link); }

  /* --- Cards --- */
  .electricity-card        { background: var(--surface); }
  .machine-card .card-header,
  .electricity-card .card-header { background-color: transparent; color: var(--text); }

  /* The dark `a { color: var(--link) }` above outranks the bare-class rule in §5,
     so the ideal-time icon needs its amber restated at this specificity to stay
     part of the warning family instead of reading as a stray link. */
  .machine-card-ideal-time-action { color: #fd7e14; }
  .machine-card-ideal-time-action:hover,
  .machine-card-ideal-time-action:focus { color: #ffa04d; }

  /* Untinted (running) machine cards get the elevated surface + border so they
     are as visible as the tinted (idle/downtime) cards. The :not() guard keeps
     the status tints below from being overridden. */
  .dashboard-card.machine-card:not(.idle-card):not(.downtime-card):not(.downtime-running-card) {
    background-color: var(--surface);
    border: 1px solid var(--border);
  }

  /* --- Machine / state cards (status tints remixed against dark surface) --- */
  /* idle / no-program → amber/orange warning (distinct from the red downtime). */
  .idle-card               { background-color: var(--surface); border-color: color-mix(in srgb, #fd7e14 62%, var(--border)); }
  .downtime-card           { background-color: color-mix(in srgb, #ffc107 14%, var(--surface)); }
  .running-label           { background-color: color-mix(in srgb, #198754 22%, var(--surface)); color: #a3cfbb; }
  .idle-label              { background-color: transparent; border-color: color-mix(in srgb, #fd7e14 62%, var(--border)); color: #fecba1; }
  .downtime-label          { background-color: color-mix(in srgb, #ffc107 20%, var(--surface)); color: #ffe69c; }
  .downtime-running-label,
  .alert-downtime-running,
  .btn-downtime-info       { background-color: color-mix(in srgb, #fd7e14 18%, var(--surface)); color: #fecba1; }
  .alert-idle              { background-color: color-mix(in srgb, #ffc107 16%, var(--surface)); color: #ffe69c; }

  /* --- Alarm cards --- */
  .alarm-card-warning      { background-color: color-mix(in srgb, #ffc107 16%, var(--surface)); border-color: color-mix(in srgb, #ffc107 40%, var(--surface)); }
  .alarm-card-error        { background-color: color-mix(in srgb, #dc3545 16%, var(--surface)); border-color: color-mix(in srgb, #dc3545 40%, var(--surface)); }

  /* --- Progress track --- */
  .progress                { background-color: var(--surface-sunken); }
  .batch-perf-track        { background: var(--surface-sunken); }

  /* --- Accordion forced-light override --- */
  .accordion-button:not(.collapsed) { background-color: var(--surface-2) !important; color: var(--text); }

  /* --- Agentic overlay backdrop: dark dashboards read fine at a stronger wash than the
     light-mode default (see §21) --- */
  .agentic-backdrop {
    background: color-mix(in srgb, var(--surface) 80%, transparent);
    backdrop-filter: blur(18px) saturate(115%);
    -webkit-backdrop-filter: blur(18px) saturate(115%);
  }

  /* --- CloEE Advisor panel + chat --- */
  .cloee-assistant-panel.open { background: var(--surface); border-left-color: var(--border); }
  .cloee-assistant-header  { background: var(--surface-2); border-bottom-color: var(--border); }
  .cloee-assistant-header h5 { color: var(--text); }
  .chat-bottom-bar-fixed   { background: var(--surface); border-top-color: var(--border); }
  .chat-input-animated     { background: var(--surface-2); border-color: var(--border); color: var(--text); }
  .user-message            { background: var(--surface-sunken); color: var(--text); }
  .assistant-content code  { background: var(--surface-sunken); color: var(--text); }
  .assistant-content table th { background: var(--surface-2); }
  .assistant-content table tbody tr:nth-child(even) { background: var(--surface-2); }
  .assistant-content table th,
  .assistant-content table td { border-color: var(--border); }
  .assistant-content blockquote { color: var(--text-muted); }

  /* --- Production-flow table card --- */
  .table-card-wrapper      { background: var(--surface); border-color: var(--border); }
  .table-card-header       { border-bottom-color: var(--border); }
  .table-card-body         { background: var(--surface); }
  .table-card-body .table thead th { color: var(--text-muted); }
  .label-micro             { color: var(--text-muted); }

  /* --- DataTables (default DataTables CSS does not follow Bootstrap mode) --- */
  /* The wrapper is layout only: a recessed fill turns every table footer into a separate band. */
  .dataTables_wrapper                       { background-color: transparent; }
  .dataTables_wrapper .dataTables_length label,
  .dataTables_wrapper .dataTables_filter label { color: var(--text); }
  .dataTables_wrapper .dataTables_length select,
  .dataTables_wrapper .dataTables_filter input { background-color: var(--surface); border-color: var(--border); color: var(--text); }
  .dataTables_wrapper .dataTables_info      { color: var(--text-muted); }
  /* pagination buttons are token-based in the base block (§10), so they
     follow the active theme automatically — no dark override needed. */
  /* table cells rendered by DataTables default theme */
  table.dataTable, table.dataTable th, table.dataTable td { color: var(--text); border-color: var(--border); }
  /* Direct-child combinators only — a descendant selector here would also
     paint the <tr> of any nested detail table living inside a DataTables
     child row (row.child()), since it sits inside this table's own <tbody>
     regardless of how deeply it's nested. See the .operations-detail-table
     override earlier in this file for the corresponding fix on the
     nested-table side (needed for the vendor DataTables CSS, which has the
     same unscoped-descendant issue and can't be edited here). */
  table.dataTable > tbody > tr { background-color: var(--surface); }
  table.dataTable.stripe > tbody > tr.odd,
  table.dataTable.display > tbody > tr.odd { background-color: var(--surface-2); }
}

/* === 21. Agentic Shell (Ask CloEE bar + centred conversation overlay) ===
   The docked bar is the single input in both idle and conversation states;
   submitting opens the overlay, whose backdrop blurs the page behind it.
   All colours use theme tokens so the shell follows light/dark automatically. */

/* --- Docked Ask CloEE bar --- */
.ask-cloee-bar {
  position: fixed;
  bottom: 24px;
  /* Centre within the content area (right of the fixed sidebar), not the whole
     viewport, so the bar never overlaps the sidebar's user/theme/logout footer.
     244px = sidebar (220px) + 12px inset each side; halved for the centre. */
  left: calc(50vw + 122px);
  transform: translateX(-50%);
  z-index: 1045;
  display: flex;
  align-items: flex-end;
  gap: 0.55rem;
  width: min(720px, calc(100vw - 244px - 48px));
  padding: 0.4rem 0.5rem 0.4rem 0.9rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 78%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
  /* Opening the overlay re-centres the bar on the conversation column instead of the
     sidebar-compensated content area, which is a real position change (different
     reference frame, not a bug) — but snapping to it instantly reads as a jump. Ease it
     over the same timescale as the overlay's own entrance so it reads as one motion. */
  transition: left 0.28s cubic-bezier(0.16, 1, 0.3, 1), width 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}

/* Collapsed sidebar shrinks to 60px (+12px inset each side = 84px content
   offset); recentre the bar in the wider content area. */
.sidebar-collapsed .ask-cloee-bar {
  left: calc(50vw + 42px);
  width: min(720px, calc(100vw - 84px - 48px));
}

.ask-cloee-input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: transparent;
  color: var(--text);
  font-size: 0.95rem;
  padding: 0.3rem 0.2rem;
  /* Auto-growing textarea: one line by default, up to 3 lines (JS-driven),
     then scroll. resize handle off; font matches the rest of the bar. */
  font-family: inherit;
  line-height: 1.4;
  resize: none;
  overflow-y: hidden;
  height: calc(1.4em + 0.6rem); /* single row + vertical padding */
  max-height: calc(1.4em * 3 + 0.6rem);
}

.ask-cloee-input::placeholder { color: var(--text-muted); }
.ask-cloee-input:focus { outline: none; }

.ask-cloee-send,
.ask-cloee-stop {
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

.ask-cloee-send {
  background: var(--link);
  border-color: var(--link);
  color: #fff;
}
.ask-cloee-send:hover { filter: brightness(1.08); }
.ask-cloee-send:disabled {
  opacity: 0.5;
  cursor: not-allowed;
  filter: none;
}

/* Stop takes Send's slot while the chat on screen is answering and nothing is typed. */
.ask-cloee-stop {
  background: var(--text);
  border-color: var(--text);
  color: var(--surface);
}
.ask-cloee-stop:hover,
.ask-cloee-stop:focus-visible { filter: brightness(1.15); }
.ask-cloee-stop:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.ask-cloee-send[hidden],
.ask-cloee-stop[hidden] { display: none; }

/* Subtle accent on the bar while a background answer is generating. */
.ask-cloee-bar.is-thinking {
  border-color: var(--link);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18), 0 0 0 1px var(--link) inset;
}

/* Inline "CloEE is thinking …" hint — behaves like an animated placeholder over
   the input. Shown only while thinking and the input is empty; typed text wins. */
.ask-cloee-thinking {
  position: absolute;
  left: 1.1rem;
  bottom: 0.4rem; /* aligns with the input's baseline (bar padding-bottom) */
  height: calc(1.4em + 0.6rem); /* matches the single-row input height */
  display: none;
  align-items: center;
  gap: 0.45rem;
  color: var(--text); /* label reads like normal text; dots carry the accent */
  font-size: 0.95rem;
  pointer-events: none;
}
.ask-cloee-bar.is-thinking:not(.has-input) .ask-cloee-thinking {
  display: inline-flex;
}

.ask-cloee-dots {
  display: inline-flex;
  align-items: center;
  gap: 0.28rem;
  height: 1em;
}
.ask-cloee-dots span {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--link);
  opacity: 0.5;
  /* Reuses the in-chat typing indicator's up/down bounce (see §typing-dot). */
  animation: typing-bounce 1.2s infinite;
}
.ask-cloee-dots span:nth-child(2) { animation-delay: 0.2s; }
.ask-cloee-dots span:nth-child(3) { animation-delay: 0.4s; }

/* Green accent once the answer is ready (mirrors the thinking state). */
.ask-cloee-bar.is-ready {
  border-color: var(--bs-success);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18), 0 0 0 1px var(--bs-success) inset;
}

/* Background "answer ready" notice — a pill that floats just above the bar. */
.ask-cloee-notice {
  position: fixed;
  bottom: 88px;
  left: calc(50vw + 122px);
  transform: translateX(-50%);
  z-index: 1046;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  max-width: min(720px, calc(100vw - 244px - 48px));
  padding: 0.5rem 0.95rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  font-size: 0.9rem;
  cursor: pointer;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.18);
  animation: ask-cloee-notice-in 0.22s ease;
  transition: left 0.28s cubic-bezier(0.16, 1, 0.3, 1), max-width 0.28s cubic-bezier(0.16, 1, 0.3, 1);
}
.ask-cloee-notice[hidden] { display: none; }
.ask-cloee-notice:hover { filter: brightness(1.03); }
.ask-cloee-notice .bi { color: var(--bs-success); }
.ask-cloee-notice.is-error .bi { color: var(--bs-danger); }

.sidebar-collapsed .ask-cloee-notice { left: calc(50vw + 42px); }
/* The chat's one queued prompt, waiting above the input until the server starts it. Styled like the
   user's own message (it is one, just not sent yet) with a muted "Queued" label; it only shows while
   the conversation is open, so it never meets the closed-bar "answered" pill. Anchored to the bar,
   it follows the bar's re-centring. When the prompt starts, the panel moves it into the transcript. */
.ask-cloee-queued {
  position: absolute;
  right: 0.25rem;
  bottom: calc(100% + 0.6rem);
  max-width: min(80%, 32rem);
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  padding: 0.55rem 0.4rem 0.55rem 0.95rem;
  border: 1px solid var(--border);
  border-radius: 1.2rem;
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 6px 22px rgba(0, 0, 0, 0.12);
  transform-origin: bottom right;
}
.ask-cloee-queued[hidden],
body:not(.agentic-open) .ask-cloee-queued { display: none; }
.ask-cloee-queued.is-entering { animation: ask-cloee-queued-in 0.22s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.ask-cloee-queued.is-leaving { animation: ask-cloee-queued-out 0.18s ease-in both; }
@keyframes ask-cloee-queued-in {
  from { opacity: 0; transform: translateY(10px) scale(0.97); }
  to   { opacity: 1; transform: none; }
}
@keyframes ask-cloee-queued-out {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(6px) scale(0.97); }
}

.ask-cloee-queued-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
}
.ask-cloee-queued-label {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 600;
}
.ask-cloee-queued-text {
  font-size: 0.9rem;
  font-weight: 500;
  line-height: 1.35;
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.ask-cloee-queued-cancel {
  flex: 0 0 auto;
  width: 28px;
  height: 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--text-muted);
  font-size: 0.75rem;
  cursor: pointer;
}
.ask-cloee-queued-cancel:hover,
.ask-cloee-queued-cancel:focus-visible {
  border-color: var(--border);
  background: var(--surface-2);
  color: var(--text);
}
.ask-cloee-queued-cancel:disabled { opacity: 0.5; cursor: not-allowed; }

@media (prefers-reduced-motion: reduce) {
  .ask-cloee-queued.is-entering,
  .ask-cloee-queued.is-leaving { animation: none; }
  .chat-inner-scroll { transition: none; }
}

@keyframes ask-cloee-notice-in {
  from { opacity: 0; transform: translateX(-50%) translateY(6px); }
  to   { opacity: 1; transform: translateX(-50%) translateY(0); }
}

/* --- Centred conversation overlay --- */
.agentic-overlay {
  position: fixed;
  inset: 0;
  z-index: 1035;
  display: none;
}
.agentic-overlay.open { display: block; }

/* The backdrop is the panel's only ground — the dialog above it paints nothing — so the wash
   has to carry text legibility on its own. Mixed from --surface (not --surface-sunken) so
   messages sit on the same value they would inside a card. Light default is a lighter wash
   than dark (see the dark-mode override in §25): --surface is pure white in light mode and
   most pages behind it are themselves pale, so an 80% wash over that leaves nothing to blur
   into visibility — dark mode's busier, more colorful dashboards read fine at 80%. */
.agentic-backdrop {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--surface) 58%, transparent);
  backdrop-filter: blur(20px) saturate(150%);
  -webkit-backdrop-filter: blur(20px) saturate(150%);
}

/* Full-bleed and completely chrome-free: no fill, border, radius or shadow, so the blurred
   page reads through the whole surface instead of being hidden behind a floating card. */
.agentic-dialog {
  --agentic-header-inset: 0.85rem;
  --agentic-header-control-size: 2.75rem;
  position: absolute;
  inset: 0;
  padding: 0 clamp(1rem, 3vw, 2.5rem) 84px; /* bottom inset clears the docked bar */
  display: flex;
  flex-direction: column;
  background: transparent;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
}

/* Edge-to-edge would stretch messages across the full viewport, so the conversation itself
   stays a readable centred column while the rails hold the outer edges. */
.agentic-overlay .chat-outer-wrapper {
  width: 100%;
  max-width: 72rem;
  margin-left: auto;
  margin-right: auto;
}

/* Smooth entrance: backdrop fades in, dialog eases up while keeping the -50%
   horizontal centering. Keyframes (not transitions) so they replay each time the
   overlay flips display:none → block. */
.agentic-overlay.open .agentic-backdrop {
  animation: agenticBackdropIn 0.25s ease both;
}
.agentic-overlay.open .agentic-dialog {
  animation: agenticDialogIn 0.32s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes agenticBackdropIn {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@keyframes agenticDialogIn {
  from { opacity: 0; transform: translateY(14px) scale(0.995); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .agentic-overlay.open .agentic-backdrop,
  .agentic-overlay.open .agentic-dialog { animation: none; }
  .ask-cloee-bar,
  .ask-cloee-notice { transition: none; }
}

.agentic-close {
  position: absolute;
  top: var(--agentic-header-inset);
  right: 1rem;
  z-index: 2;
  width: var(--agentic-header-control-size);
  height: var(--agentic-header-control-size);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Translucent: on a chrome-free shell an opaque chip would be the only solid object
     on screen. */
  border: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  color: var(--text);
  box-shadow: none;
  cursor: pointer;
}
.agentic-close:hover { background: var(--surface-sunken); }

.agentic-body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  padding: var(--agentic-header-inset) 1rem 0.75rem;
  overflow: hidden;
}

.agentic-overlay .session-toolbar {
  min-height: var(--agentic-header-control-size);
  display: flex;
  align-items: center;
  /* A hairline under the active chat's title — otherwise it reads as loose text floating
     above the conversation rather than a header for it. */
  border-bottom: 1px solid color-mix(in srgb, var(--border) 60%, transparent);
  margin: 0 calc(var(--agentic-header-control-size) + 0.75rem) 0.75rem 0 !important;
  padding: 0 0 0.6rem !important;
}

.agentic-overlay .session-picker-toggle {
  min-height: var(--agentic-header-control-size);
}

/* The reused assistant_panel keeps its own input bar for legacy use, but inside
   the overlay the docked Ask CloEE bar is the single input — hide the panel's. */
.agentic-overlay #chat-bottom-bar { display: none; }

@media (min-width: 1200px) {
  /* Centred on the conversation column like the messages below it (the mobile rule keeps a
     right gutter instead, because there the close button sits over the toolbar). */
  .agentic-overlay .session-toolbar {
    max-width: 72rem;
    margin: 0 auto 0.75rem !important;
  }
}

@media (max-width: 991.98px) {
  /* Tighter side gaps on small screens, but still inside the content area so the
     bar clears the sidebar footer. */
  .ask-cloee-bar {
    width: min(720px, calc(100vw - 244px - 24px));
  }
  .sidebar-collapsed .ask-cloee-bar {
    width: min(720px, calc(100vw - 84px - 24px));
  }
  .agentic-dialog {
    padding: 0 0.75rem 84px;
  }
}

/* === 25. Machine Card (shared: dashboard + chat) =========================
   The themed machine-card states, warning labels and gauge wrapper, extracted
   from the dashboard's inline <style> so the same markup (macros/machine_card.html)
   renders identically on the dashboard AND inside the AI chat.

   Status tints mix against var(--surface) (NOT white) so they read in dark mode.
   The --color-job/idle/downtime vars are set per-factory by the dashboard's inline
   :root block; fallbacks here keep chat cards correct on pages that don't set them.
──────────────────────────────────────────────────────────────────────────── */

/* Idle-only card (no active program) — warning outline without a filled tint. */
.idle-card {
  --machine-card-accent: color-mix(in srgb, #fd7e14 62%, var(--border));
  background-color: var(--surface) !important;
  border: 2px solid var(--machine-card-accent) !important;
}
/* Idle + registered downtime — red, the most severe state */
.downtime-card {
  --machine-card-accent: color-mix(in srgb, var(--color-downtime, #dc3545) 45%, var(--surface));
  background-color: color-mix(in srgb, var(--color-downtime, #dc3545) 14%, var(--surface)) !important;
  border: 2px solid var(--machine-card-accent) !important;
}
/* Running despite a registered downtime */
.downtime-running-card {
  --machine-card-accent: color-mix(in srgb, var(--color-downtime, #dc3545) 38%, var(--surface));
  border: 2px solid var(--machine-card-accent) !important;
}

/* Dashboard machine cards use explicit status strokes.  Keeping the accent and
   border on the same custom property prevents the neutral card border from
   winning when the page refreshes a no-program or downtime card in place. */
#dashboard-cards-row .dashboard-card.machine-card.idle-card {
  --machine-card-accent: #fd7e14;
  border-color: var(--machine-card-accent) !important;
}
#dashboard-cards-row .dashboard-card.machine-card.downtime-card,
#dashboard-cards-row .dashboard-card.machine-card.downtime-running-card {
  --machine-card-accent: var(--color-downtime, #dc3545);
  border-color: var(--machine-card-accent) !important;
}

/* Live batch-overrun states complement the compact header indicator. Downtime
   remains visually dominant when both states are present. */
.overrun-warning-card:not(.downtime-card):not(.downtime-running-card) {
  --machine-card-accent: #fd7e14;
  background-color: color-mix(in srgb, #fd7e14 10%, var(--surface)) !important;
  border: 2px solid var(--machine-card-accent) !important;
}
.overrun-critical-card:not(.downtime-card):not(.downtime-running-card) {
  --machine-card-accent: #dc3545;
  background-color: color-mix(in srgb, #dc3545 12%, var(--surface)) !important;
  border: 2px solid var(--machine-card-accent) !important;
}

/* Footer badges are reserved for actionable configuration guidance. */
.warning-label {
  border-radius: 0.35rem;
  border: 1px solid transparent;
  padding: 0.25rem 0.5rem;
  font-size: 0.82rem;
  text-align: center;
  margin-top: auto !important;
  margin-bottom: 0.5rem !important;
}
.no-config-label {
  border-color: #dc3545 !important;
  background-color: color-mix(in srgb, #dc3545 14%, var(--surface)) !important;
  color: #842029;
  font-weight: 700;
}

/* Card body flex layout to push downtime labels to bottom */
.machine-card .card-body {
  display: flex;
  flex-direction: column;
}

/* Labels */
.running-label  { border-color: var(--color-job, #198754)  !important; }
.idle-label {
  background-color: transparent !important;
  border-color: color-mix(in srgb, #fd7e14 62%, var(--border)) !important;
}
.downtime-label {
  border-color: var(--color-downtime, #dc3545) !important;
  background-color: color-mix(in srgb, var(--color-downtime, #dc3545) 15%, var(--surface)) !important;
}
.downtime-running-label {
  border-color: var(--color-downtime, #dc3545) !important;
  background-color: color-mix(in srgb, var(--color-downtime, #dc3545) 12%, var(--surface)) !important;
  font-weight: 700;
}
.machine-card .warning-label .reason-text,
.cloee-chat-machine-card .warning-label .reason-text {
  display: block;
  font-weight: 400;
  margin-top: 0.12rem;
}

/* Per-card gauge container — definite, width-derived height (see resize-loop note
   in cloee_gauge.js / dashboard.html). aspect-ratio + the gauge's
   maintainAspectRatio:false break the Chart.js resize feedback loop at any DPR. */
.gauge-wrapper {
  aspect-ratio: 2.2 / 1;
  overflow: hidden;
}

/* Dark-mode tinted-label text (tints already remix against --surface) */
html[data-bs-theme="dark"] .no-config-label { color: #f1aeb5; }
html[data-bs-theme="dark"] .downtime-label,
html[data-bs-theme="dark"] .downtime-running-label { color: #ffe69c; }

/* Chat-scoped cards/components: compact, scan-first presentation inside chat.
   Centred, not left-hugged — same reasoning as .cloee-domain-card above. */
.cloee-chat-card,
.cloee-chat-machine-card {
  display: block;
  max-width: 430px;
  color: var(--text);
  text-decoration: none;
  margin: 0.5rem auto;
}
.cloee-chat-card:hover,
.cloee-chat-machine-card:hover {
  color: var(--text);
}
.cloee-chat-machine-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.85rem;
  overflow: hidden;
  box-shadow: 0 10px 26px color-mix(in srgb, var(--text) 8%, transparent);
  transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}
.cloee-chat-machine-card,
.cloee-chat-machine-card:hover,
.cloee-chat-machine-card:focus,
.cloee-chat-machine-card:active,
.cloee-chat-machine-card *,
.cloee-chat-machine-card:hover *,
.cloee-chat-machine-card:focus *,
.cloee-chat-machine-card:active * {
  color: inherit;
  text-decoration: none !important;
}
.cloee-chat-machine-card:hover,
.cloee-chat-machine-card:focus {
  border-color: color-mix(in srgb, var(--link) 34%, var(--border));
  box-shadow: 0 16px 34px color-mix(in srgb, var(--text) 12%, transparent);
  transform: translateY(-2px);
}
.cloee-chat-machine-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.65rem;
  padding: 0.7rem 0.85rem;
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
}
.cloee-chat-machine-title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-weight: 800;
  letter-spacing: 0;
}
.cloee-chat-state-pill {
  flex: 0 0 auto;
  border: 1px solid color-mix(in srgb, #198754 35%, var(--border));
  border-radius: 999px;
  padding: 0.18rem 0.55rem;
  color: #198754;
  background: color-mix(in srgb, #198754 10%, var(--surface));
  font-size: 0.72rem;
  font-weight: 700;
}
.idle-card .cloee-chat-state-pill,
.cloee-chat-state-pill--caution {
  border-color: color-mix(in srgb, #fd7e14 45%, var(--border));
  color: #b45309;
  background: color-mix(in srgb, #fd7e14 15%, var(--surface));
}
.cloee-chat-state-pill--alarm {
  border-color: color-mix(in srgb, #dc3545 45%, var(--border));
  color: #dc3545;
  background: color-mix(in srgb, #dc3545 12%, var(--surface));
}
.downtime-card .cloee-chat-state-pill,
.downtime-running-card .cloee-chat-state-pill {
  border-color: color-mix(in srgb, #dc3545 45%, var(--border));
  color: #dc3545;
  background: color-mix(in srgb, #dc3545 12%, var(--surface));
}
.cloee-chat-machine-body {
  display: grid;
  grid-template-columns: minmax(130px, 0.82fr) minmax(0, 1fr);
  gap: 0.75rem;
  align-items: center;
  padding: 0.85rem;
  background: var(--surface);
}
.cloee-chat-machine-facts {
  min-width: 0;
}
.cloee-chat-card .cloee-chat-card-line {
  font-size: 0.9rem;
  margin-bottom: 0.35rem;
}
.cloee-chat-machine-card .cloee-chat-card-line {
  border-bottom: 1px solid var(--border);
  font-size: 0.84rem;
  line-height: 1.35;
  margin: 0;
  padding: 0.4rem 0;
}
.cloee-chat-machine-card .cloee-chat-card-line:last-child {
  border-bottom: 0;
}
.cloee-chat-machine-card .cloee-chat-card-line strong {
  color: var(--text-muted);
  display: block;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
}
.cloee-chat-machine-card .warning-label {
  grid-column: 1 / -1;
  margin: 0.15rem 0 0 !important;
}
.cloee-chat-card .gauge-wrapper,
.cloee-chat-machine-card .gauge-wrapper {
  max-width: 170px;
  aspect-ratio: 2.2 / 1;
  overflow: hidden;
  margin-left: auto;
  margin-right: auto;
}
.cloee-chat-card-placeholder,
.cloee-chat-card-error {
  max-width: 430px;
  margin: 0.5rem 0;
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.88rem;
}
.cloee-chat-card-error {
  border-color: color-mix(in srgb, #dc3545 40%, var(--border));
  background: color-mix(in srgb, #dc3545 10%, var(--surface));
}

/* Multiple machine cards flow 2-across and wrap instead of stacking down the chat.
   Cards drop their standalone max-width/margin so they fill the grid cell. */
.cloee-chat-machine-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.6rem;
  margin: 0.5rem 0;
  max-width: 600px;
}
.cloee-chat-machine-grid .cloee-chat-machine-card,
.cloee-chat-machine-grid .cloee-chat-card-placeholder,
.cloee-chat-machine-grid .cloee-chat-card-error {
  max-width: none;
  margin: 0;
}

/* Centred, not left-hugged: these are small single-purpose cards (a short list) meant to read as
   compact objects, so they keep a width cap — unlike the table/KPI cards below, which fill the
   message width instead. */
.cloee-factory-list-card,
.cloee-factory-units-card,
.cloee-unit-list-card {
  margin: 0.75rem auto 0.9rem;
  max-width: 720px;
}
/* The "did you mean?" picker isn't a short list — its grid can hold every valid name (16+ chips),
   and a multi-name miss stacks two of those. Same reasoning as .cloee-domain-card: fills the
   message width instead of floating as a narrower, centred island. */
.cloee-name-picker-card {
  margin: 0.75rem 0 0.9rem;
  max-width: 100%;
  box-sizing: border-box;
}
.cloee-factory-list-card,
.cloee-factory-units-card,
.cloee-unit-list-card,
.cloee-name-picker-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 0.85rem;
  padding: 0.75rem;
}
/* "Did you mean?" picker reads as a gentle prompt, not an error — warm amber accent. */
.cloee-name-picker-card {
  border-color: color-mix(in srgb, #f0ad4e 30%, var(--border));
  background:
    linear-gradient(135deg, color-mix(in srgb, #f0ad4e 10%, transparent), transparent 52%),
    var(--surface);
}
.cloee-name-picker-title {
  min-width: 0;
  font-weight: 800;
  color: var(--text);
}
/* Upfront explainer for a multi-name miss — set only when there's more than one entry, so a
   single-name card never shows it (empty :empty rule keeps the layout gap-free either way). */
.cloee-name-picker-hint {
  color: var(--text-muted);
  font-size: 0.82rem;
  margin-bottom: 0.65rem;
}
.cloee-name-picker-hint:empty {
  display: none;
}
/* A multi-name miss (e.g. a comparison naming two unknown factories) stacks one entry — title
   + count + chip grid — per unresolved name in the same card. */
.cloee-name-picker-entries {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}
.cloee-name-picker-entry + .cloee-name-picker-entry {
  padding-top: 0.9rem;
  border-top: 1px dashed color-mix(in srgb, #f0ad4e 25%, var(--border));
}
/* Once an entry has a pick, its title confirms the choice and the un-picked chips dim (each
   chip's own opacity, never the grid's — an ancestor opacity would dim the picked chip too,
   since it composites the whole subtree regardless of a child's own opacity) — a picked entry
   reads as "resolved", not identical to the still-open one beside it. */
.cloee-name-picker-entry-picked .cloee-name-picker-title {
  color: color-mix(in srgb, #198754 70%, var(--text));
}
.cloee-name-picker-entry-picked .cloee-name-chip-grid .cloee-name-chip:not(.cloee-name-chip-picked) {
  opacity: 0.5;
}
.cloee-factory-list-card {
  border-color: color-mix(in srgb, var(--link) 18%, var(--border));
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--link) 9%, transparent), transparent 48%),
    var(--surface);
}
.cloee-factory-units-card {
  border-color: color-mix(in srgb, #198754 18%, var(--border));
  background:
    linear-gradient(135deg, color-mix(in srgb, #198754 9%, transparent), transparent 52%),
    var(--surface);
}
.cloee-list-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  color: var(--text);
  font-weight: 800;
  margin-bottom: 0.65rem;
}
.cloee-list-card-count {
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}
.cloee-factory-chip-grid,
.cloee-unit-chip-grid,
.cloee-name-chip-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(112px, 1fr));
  gap: 0.45rem;
}
.cloee-factory-chip,
.cloee-unit-chip,
.cloee-name-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 2.15rem;
  border: 1px solid color-mix(in srgb, var(--link) 22%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--link) 7%, var(--surface));
  color: var(--text);
  font-weight: 700;
  font-size: 0.88rem;
  text-decoration: none;
  transition: border-color 0.15s ease, background 0.15s ease, transform 0.15s ease, box-shadow 0.15s ease;
}
/* Chips rendered as links (factory/unit deep-links) read as pressable. The color
   reset beats `.assistant-content a` (equal specificity, declared later) so chips
   keep their token text colour instead of the default link blue. */
a.cloee-factory-chip,
a.cloee-unit-chip,
a.cloee-name-chip,
a.cloee-factory-units-head {
  cursor: pointer;
  color: var(--text);
}
a.cloee-unit-chip:hover,
a.cloee-unit-chip:focus-visible,
a.cloee-name-chip:hover,
a.cloee-name-chip:focus-visible {
  color: var(--text);
  text-decoration: none;
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--link) 55%, var(--border));
  background: color-mix(in srgb, var(--link) 14%, var(--surface));
  box-shadow: 0 4px 12px color-mix(in srgb, var(--text) 10%, transparent);
}
/* The close-match suggestion is pre-highlighted so the likely answer stands out. */
.cloee-name-chip-suggested {
  border-color: color-mix(in srgb, #f0ad4e 55%, var(--border));
  background: color-mix(in srgb, #f0ad4e 16%, var(--surface));
}
/* A multi-entry name-picker holds off sending until every grid has a pick, so the picked chip in
   each grid needs its own persistent, unmissable state (distinct from the hover/focus transform
   above, which fades on mouse-out) — a checkmark plus a full-strength fill even once the rest of
   the grid dims via .cloee-name-picker-entry-picked. */
.cloee-name-chip-picked {
  border-color: color-mix(in srgb, #198754 65%, var(--border));
  background: color-mix(in srgb, #198754 22%, var(--surface));
  font-weight: 800;
  opacity: 1 !important;
}
.cloee-name-chip-picked::before {
  content: "✓ ";
}
a.cloee-factory-chip:hover,
a.cloee-factory-chip:focus-visible {
  color: var(--text);
  text-decoration: none;
  transform: translateY(-1px);
  border-color: color-mix(in srgb, #198754 55%, var(--border));
  background: color-mix(in srgb, #198754 15%, var(--surface));
  box-shadow: 0 4px 12px color-mix(in srgb, var(--text) 10%, transparent);
}
.cloee-factory-chip {
  justify-content: flex-start;
  gap: 0.45rem;
  min-height: 2.55rem;
  border-color: color-mix(in srgb, #198754 24%, var(--border));
  border-radius: 0.7rem;
  background: color-mix(in srgb, #198754 9%, var(--surface));
  padding: 0 0.75rem;
}
.cloee-factory-chip i {
  color: #198754;
  font-size: 1rem;
  line-height: 1;
}
.cloee-factory-units-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0.65rem;
}
.cloee-factory-units-group {
  min-width: 0;
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background: color-mix(in srgb, var(--surface-2) 55%, var(--surface));
  padding: 0.65rem;
}
.cloee-factory-units-head {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--text);
  font-size: 0.92rem;
  font-weight: 800;
  line-height: 1.2;
  margin-bottom: 0.55rem;
  text-decoration: none;
}
a.cloee-factory-units-head:hover,
a.cloee-factory-units-head:focus-visible {
  color: var(--text);
}
a.cloee-factory-units-head:hover span:nth-child(2),
a.cloee-factory-units-head:focus-visible span:nth-child(2) {
  text-decoration: underline;
  text-decoration-color: color-mix(in srgb, #198754 60%, var(--border));
  text-underline-offset: 2px;
}
.cloee-factory-units-head i {
  color: #198754;
  flex: 0 0 auto;
}
.cloee-factory-units-head span:nth-child(2) {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cloee-factory-units-count {
  margin-left: auto;
  flex: 0 0 auto;
  min-width: 1.55rem;
  border-radius: 999px;
  background: color-mix(in srgb, #198754 14%, var(--surface));
  color: #198754;
  font-size: 0.72rem;
  font-weight: 800;
  line-height: 1.55rem;
  text-align: center;
}
.cloee-factory-units-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.cloee-factory-units-chips .cloee-unit-chip {
  min-height: 1.85rem;
  padding: 0 0.65rem;
  font-size: 0.8rem;
}
html[data-bs-theme="dark"] .cloee-factory-units-count {
  color: #75b798;
}
.cloee-kpi-grid {
  display: grid;
  /* Capped, not flexed: with only a handful of tiles, letting them fill a card that's now
     up to 1152px wide would leave each one mostly empty padding around a single number.
     A fixed max keeps tiles a sane stat-tile size — the table below is what should use the
     extra room (see .cloee-domain-table, which is already width: 100%). */
  grid-template-columns: repeat(auto-fit, minmax(145px, 220px));
  gap: 0.65rem;
}
.cloee-kpi-tile {
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background: var(--surface);
  padding: 0.75rem;
  min-width: 0;
}
.cloee-kpi-value {
  color: var(--text);
  font-size: 1.35rem;
  font-weight: 800;
  line-height: 1.05;
}
.cloee-kpi-label {
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1.25;
  margin-top: 0.35rem;
}

/* Factory OEE overview card (prepare_oee_overview_card → enhanceCloeeComponents). */
.cloee-oee-card {
  /* Fills the message width like the prose around it instead of floating as a narrower
     island — the KPI tiles and gauge column cap their own growth (.cloee-oee-kpis,
     .cloee-oee-gauge), so the extra room gets used, not just stretched.
     A container, not a viewport media query: this same card renders in a narrow docked chat
     rail or a wide agentic-overlay column, independent of the actual viewport width — see
     .cloee-oee-kpis below, which keys off the card's own width. */
  container-type: inline-size;
  margin: 0.75rem 0 0.9rem;
  max-width: 100%;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--link) 9%, transparent), transparent 52%),
    var(--surface);
  border: 1px solid color-mix(in srgb, var(--link) 18%, var(--border));
  border-radius: 0.85rem;
  padding: 0.85rem;
}
.cloee-oee-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.cloee-oee-title {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--text);
  font-weight: 800;
  text-decoration: none;
}
.cloee-oee-title:hover {
  color: var(--link);
}
.cloee-oee-hero {
  display: grid;
  grid-template-columns: minmax(150px, 0.7fr) minmax(0, 1.3fr);
  gap: 0.85rem;
  align-items: center;
}
.cloee-oee-gauge-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
}
.cloee-oee-gauge {
  width: 100%;
  max-width: 180px;
}
.cloee-oee-gauge-caption {
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}
/* Beside the gauge: the KPI row, then batch counts stacked directly under it — not a separate
   full-width section below the whole hero. */
.cloee-oee-right {
  display: flex;
  flex-direction: column;
  gap: 0.65rem;
  min-width: 0;
}
/* Was a fixed 2-column grid — always stretched to fill, however wide the card got. Same
   capped auto-fit as .cloee-kpi-grid, but a smaller cap: this grid shares the hero row with
   the gauge column, so its own track is narrower than the full card — a 200px cap left the
   4th of 4 tiles wrapping onto its own row instead of sitting alongside the other three. Forced
   to a flat 4-up row once the container query below confirms there's room (auto-fit's own math
   can still strand the 4th tile even when a 4-across row would in fact fit). */
.cloee-oee-kpis {
  grid-template-columns: repeat(auto-fit, minmax(110px, 165px));
}
.cloee-oee-section-label {
  color: var(--text-muted);
  font-size: 0.74rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  margin: 0.85rem 0 0.45rem;
}
/* The batch-section label sits right under the KPI row via .cloee-oee-right's flex gap — the
   generic top margin above is for the per-unit-KPIs label instead, which follows the whole hero
   as its own full-width section and still needs it. */
.cloee-oee-batch-section .cloee-oee-section-label {
  margin-top: 0;
}
.cloee-oee-batches {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(72px, 1fr));
  gap: 0.5rem;
}
.cloee-oee-batch-chip {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.1rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  background: var(--surface-2);
  padding: 0.45rem 0.3rem;
}
.cloee-oee-batch-num {
  color: var(--text);
  font-size: 1.1rem;
  font-weight: 800;
  line-height: 1;
}
.cloee-oee-batch-label {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 700;
}
.cloee-oee-units-scroll {
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
}
.cloee-oee-units-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
}
.cloee-oee-units-table th,
.cloee-oee-units-table td {
  padding: 0.4rem 0.55rem;
  text-align: right;
  white-space: nowrap;
  border-bottom: 1px solid var(--border);
}
.cloee-oee-units-table th:first-child,
.cloee-oee-units-table td:first-child {
  text-align: left;
}
.cloee-oee-units-table thead th {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  background: var(--surface-2);
}
.cloee-oee-units-table tbody tr:last-child td {
  border-bottom: 0;
}
.cloee-oee-unit-link {
  color: var(--link);
  font-weight: 700;
  text-decoration: none;
}
.cloee-oee-unit-link:hover {
  text-decoration: underline;
}
/* Card-width, not viewport-width (.cloee-oee-card sets container-type above): this card can
   render in a narrow docked chat rail even on a wide desktop viewport, so a viewport media query
   here would miss exactly the case that needs it — a real user hit this narrow-rail case with
   the 2-column hero still active below, leaving the KPI grid squeezed into a track too thin for
   even 2 columns (a stack of 4 lonely tiles beside an oddly-centred gauge). Below 640px the hero
   collapses to one column instead — gauge full-width on top, then the KPI+batch column below it
   at the card's FULL width, where auto-fit can actually spread the tiles out. At/above 640px the
   2-column hero returns and the next query forces a flat 4-up KPI row — same threshold both ways
   so there's no dead zone where the hero is 2-column but too narrow for a sane KPI layout. */
@container (max-width: 639.98px) {
  .cloee-oee-hero {
    grid-template-columns: 1fr;
  }
  /* Forced to a flat 2x2 rather than left to auto-fit: at the card's full (but still <640px)
     width, auto-fit's own math can land on an awkward 3-then-1 split instead of an even grid. */
  .cloee-oee-kpis {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@container (min-width: 640px) {
  .cloee-oee-kpis {
    grid-template-columns: repeat(4, minmax(100px, 1fr));
  }
}

/* ---- Downtime summary card (chat) ------------------------------------------ */
.cloee-downtime-card {
  /* Fills the message width like the prose around it — same reasoning as .cloee-domain-card
     below; the KPI tiles cap their own growth (.cloee-downtime-kpis). Card-width, not
     viewport-width: this card can render in a narrow docked chat rail even on a wide desktop
     viewport, so .cloee-downtime-kpis below keys off the card's own width via @container. */
  container-type: inline-size;
  margin: 0.75rem 0 0.9rem;
  max-width: 100%;
  background:
    linear-gradient(135deg, color-mix(in srgb, #dc3545 8%, transparent), transparent 52%),
    var(--surface);
  border: 1px solid color-mix(in srgb, #dc3545 16%, var(--border));
  border-radius: 0.85rem;
  padding: 0.85rem;
}
.cloee-downtime-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.cloee-downtime-title {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  color: var(--text);
  font-weight: 800;
  text-decoration: none;
}
.cloee-downtime-title:hover {
  color: var(--link);
}
/* Forced column counts rather than left to auto-fit: at most 5 tiles (4 without
   Uncategorized), so a flat row reads better than auto-fit's own math, which can land on an
   awkward 3-then-1/2 split at in-between widths. Same technique as .cloee-oee-kpis above. */
.cloee-downtime-kpis {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
@container (min-width: 420px) {
  .cloee-downtime-kpis {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@container (min-width: 860px) {
  .cloee-downtime-kpis {
    grid-template-columns: repeat(5, minmax(0, 1fr));
  }
}
.cloee-downtime-empty {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--text-muted);
  font-weight: 600;
  padding: 0.35rem 0;
}
.cloee-downtime-empty .bi {
  color: #198754;
}
.cloee-downtime-bar-wrap {
  position: relative;
}
.cloee-downtime-bar {
  display: flex;
  height: 0.7rem;
  margin: 0.85rem 0 0.6rem;
  border-radius: 999px;
  overflow: hidden;
  background: var(--surface-sunken);
}
.cloee-downtime-seg {
  height: 100%;
  min-width: 2px;
  cursor: help;
  outline: none;
}
.cloee-downtime-seg:not(:last-child) {
  border-right: 1px solid var(--surface);
}
/* Themed hover/focus tooltip shared by every bar segment — sits above the bar (never below,
   where it would overlap the reason chips) and follows the hovered segment via `left`. */
.cloee-downtime-bar-tooltip {
  position: absolute;
  left: 0;
  bottom: 100%;
  z-index: 2;
  margin-bottom: 0.4rem;
  min-width: max-content;
  max-width: min(15rem, 92%);
  padding: 0.32rem 0.5rem;
  border: 1px solid color-mix(in srgb, var(--downtime-accent) 38%, var(--border));
  border-radius: 0.4rem;
  background: var(--surface);
  box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.14);
  color: var(--text);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.2;
  pointer-events: none;
  text-align: center;
  transform: translateX(-50%);
}
.cloee-downtime-bar-tooltip[hidden] { display: none; }
.cloee-downtime-bar-tooltip strong { color: var(--text); }
.cloee-downtime-reason-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}
.cloee-downtime-reason-chip {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  border: 1px solid color-mix(in srgb, var(--reason-color) 35%, var(--border));
  background: color-mix(in srgb, var(--reason-color) 12%, var(--surface));
  border-radius: 999px;
  padding: 0.18rem 0.6rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--text);
}
.cloee-downtime-reason-dot {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 999px;
  background: var(--reason-color);
  flex: 0 0 auto;
}
.cloee-downtime-ongoing {
  margin-top: 0.75rem;
  border-top: 1px solid var(--border);
  padding-top: 0.6rem;
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.cloee-downtime-ongoing-line {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.82rem;
  font-weight: 700;
  color: #dc3545;
}
html[data-bs-theme="dark"] .cloee-downtime-ongoing-line {
  color: #f1aeb5;
}
.cloee-downtime-ongoing-line .cloee-downtime-ongoing-unit,
.cloee-downtime-ongoing-line .cloee-downtime-ongoing-unit:hover,
.cloee-downtime-ongoing-line .cloee-downtime-ongoing-unit:focus {
  color: inherit;
  text-decoration: none;
  text-underline-offset: 2px;
}
.cloee-downtime-ongoing-line .cloee-downtime-ongoing-unit:hover,
.cloee-downtime-ongoing-line .cloee-downtime-ongoing-unit:focus {
  text-decoration: underline;
}
html[data-bs-theme="dark"] .cloee-downtime-reason-chip {
  color: var(--text);
}
@media (max-width: 575.98px) {
  .cloee-downtime-kpis {
    grid-template-columns: 1fr;
  }
}

/* ---- Generic domain cards for interactive AI tools ------------------------- */
.cloee-domain-card {
  /* Fills the message width like the prose around it, instead of floating as a narrower
     island. This card's container ranges from a docked-panel width up to the agentic
     overlay's 1152px conversation column; capping the card itself to some fixed width
     either left a dead gutter (left-hugged) or an equally odd floating block (centred) —
     the KPI tiles and table inside cap their own growth instead (.cloee-kpi-grid /
     .cloee-domain-table, the latter already width: 100%), so the extra room gets used. */
  margin: 0.75rem 0 0.9rem;
  max-width: 100%;
  box-sizing: border-box;
  background:
    linear-gradient(135deg, color-mix(in srgb, var(--link) 8%, transparent), transparent 52%),
    var(--surface);
  border: 1px solid color-mix(in srgb, var(--link) 16%, var(--border));
  border-radius: 0.85rem;
  padding: 0.85rem;
}
/* Downtime-events list card: same red accent as .cloee-downtime-card (the aggregate summary
   card) so the two downtime cards read as one visual family instead of the generic blue tint. */
.cloee-domain-card--downtime {
  background:
    linear-gradient(135deg, color-mix(in srgb, #dc3545 8%, transparent), transparent 52%),
    var(--surface);
  border-color: color-mix(in srgb, #dc3545 16%, var(--border));
}
/* Nokia advisor cards carry identity and magnitude colour only — a per-card accent, the fixed
   phase hues, heatmap intensity, and a direction arrow on a period delta. They still carry no
   inferred status verdict: meter data cannot support "this reading is unsafe", so nothing here
   tints a value red against a threshold the way an ammonia or overrun card legitimately does. */
.cloee-domain-card--nokia {
  --nokia-card-accent: var(--sev-setup);
  width: 100%;
  background: var(--surface);
  border-color: var(--border);
  border-left: 3px solid color-mix(in srgb, var(--nokia-card-accent) 55%, var(--border));
}
.cloee-domain-card--nokia .cloee-domain-title i {
  color: var(--nokia-card-accent);
}

/* The hero is the card's answer: one figure, large, before anything else. Everything the card
   used to open with — six equal tiles and up to four searchable tables — now ranks below it. */
.cloee-card-hero {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 0.6rem;
  margin: 0.15rem 0 0.75rem;
}
.cloee-card-hero__figure {
  display: flex;
  align-items: baseline;
  gap: 0.25rem;
  margin: 0;
}
.cloee-card-hero__value {
  color: var(--text);
  font-size: 2rem;
  font-weight: 800;
  line-height: 1.05;
  letter-spacing: -0.02em;
}
/* The hero inherits the severity of the tile it replaced, but only where the app already owns a
   threshold (a count of things wrong). Nokia heroes never set one — see the identity-not-verdict
   rule on .cloee-domain-card--nokia. */
.cloee-card-hero__value.cloee-cell-critical { color: #dc3545; }
.cloee-card-hero__value.cloee-cell-warn { color: #b45309; }
html[data-bs-theme="dark"] .cloee-card-hero__value.cloee-cell-critical { color: #f1aeb5; }
html[data-bs-theme="dark"] .cloee-card-hero__value.cloee-cell-warn { color: #fecba1; }

/* A hero that is a label rather than a measurement — the robot's current activity. Names run
   long and wrap badly at the figure size, so they get their own step down. */
.cloee-card-hero__value--text {
  font-size: 1.3rem;
  letter-spacing: 0;
}
.cloee-card-hero__unit {
  color: var(--text-muted);
  font-size: 1rem;
  font-weight: 700;
}
.cloee-card-hero__caption {
  flex: 1 1 100%;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.78rem;
  line-height: 1.35;
}
/* The delta chip reuses section 30's arrow pairing verbatim: the arrow carries direction, the
   tint carries whether that direction is welcome, and neither outweighs the hero figure. */
.cloee-card-hero .nokia-kpi-card__delta {
  font-size: 0.8rem;
}

/* One disclosure per card. The full tables live in here, unchanged, one click away. */
.cloee-card-details {
  margin-top: 0.75rem;
  border-top: 1px solid var(--border);
  padding-top: 0.5rem;
}
.cloee-card-details__summary {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  cursor: pointer;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
  list-style: none;
}
.cloee-card-details__summary::-webkit-details-marker {
  display: none;
}
.cloee-card-details__summary::before {
  content: "\F285";
  font-family: "bootstrap-icons";
  font-size: 0.8rem;
  transition: transform 0.15s ease;
}
.cloee-card-details[open] > .cloee-card-details__summary::before {
  transform: rotate(90deg);
}
.cloee-card-details__summary:hover,
.cloee-card-details__summary:focus-visible {
  color: var(--text);
}

/* Follow-up chips: the Core counterpart of the Nokia intent picker. A card answers, and these
   are the two or three questions the answer implies — a click sends the literal prompt through
   window.sendChatMessage, so it spends one ordinary quota unit like any other question. */
.cloee-card-followups {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
  margin-top: 0.85rem;
  padding-top: 0.7rem;
  border-top: 1px solid var(--border);
}
.cloee-card-followups__label {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}
.cloee-card-followup {
  min-height: 1.85rem;
  padding: 0.2rem 0.7rem;
  font-size: 0.8rem;
}

/* A chip rendered as a <button> (the intent picker, and now these) got no hover at all: the
   pressed treatment below was scoped to a.cloee-name-chip, and a button defaults to
   `cursor: default`. */
button.cloee-name-chip {
  cursor: pointer;
}
button.cloee-name-chip:disabled {
  cursor: default;
}
button.cloee-name-chip:hover:not(:disabled),
button.cloee-name-chip:focus-visible:not(:disabled) {
  color: var(--text);
  transform: translateY(-1px);
  border-color: color-mix(in srgb, var(--link) 55%, var(--border));
  background: color-mix(in srgb, var(--link) 14%, var(--surface));
  box-shadow: 0 4px 12px color-mix(in srgb, var(--text) 10%, transparent);
}

/* --- R3: a card that could not load --------------------------------------------------------
   The box names the cause and, where retrying can help, carries the control to do it. */
.cloee-card-retry {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  margin-left: 0.55rem;
  font-size: 0.8rem;
  vertical-align: middle;
}
button.cloee-card-retry:disabled {
  cursor: default;
  opacity: 0.6;
}

/* Shared hover/focus readout for every card visual — one themed bubble instead of the native
   `title` attribute, which waits about a second, cannot be themed, changes nothing on screen to
   say an element is even hoverable, and never appears for a keyboard or touch user. The anchor
   owns the bubble, so it must be the section around a scroll region, never the region itself. */
.cloee-hover-tip-anchor {
  position: relative;
}
.cloee-hover-tip {
  position: absolute;
  left: 0;
  bottom: 100%;
  z-index: 3;
  min-width: max-content;
  max-width: 13rem;
  padding: 0.3rem 0.5rem;
  border: 1px solid color-mix(in srgb, var(--nokia-card-accent, var(--link)) 38%, var(--border));
  border-radius: 0.4rem;
  background: var(--surface);
  box-shadow: 0 0.25rem 0.65rem rgba(0, 0, 0, 0.18);
  color: var(--text);
  font-size: 0.72rem;
  font-weight: 700;
  line-height: 1.25;
  pointer-events: none;
  text-align: center;
  transform: translateX(-50%);
  white-space: normal;
}
.cloee-hover-tip[hidden] {
  display: none;
}

/* Inline SVG sparkline. No chart library: it inherits currentColor so it re-themes with the
   card, has no canvas to resize, and renders correctly while the chat panel is still hidden.
   The guide and marker are HTML rather than SVG because preserveAspectRatio="none" stretches
   the drawing horizontally, which would render a circle as an ellipse of arbitrary width. */
.cloee-nokia-spark-wrap {
  position: relative;
  margin-block: 0.15rem 0.5rem;
  border-radius: 0.4rem;
  touch-action: pan-y;
}
.cloee-nokia-spark-wrap:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}
.cloee-nokia-spark {
  display: block;
  width: calc(100% - 0.5rem);
  margin-inline: 0.25rem;
  height: 3.25rem;
  overflow: visible;
  color: var(--nokia-card-accent);
  cursor: crosshair;
}
.cloee-nokia-spark__guide {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  border-left: 1px dashed color-mix(in srgb, var(--nokia-card-accent) 65%, transparent);
  pointer-events: none;
}
.cloee-nokia-spark__dot {
  position: absolute;
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--nokia-card-accent);
  box-shadow: 0 0 0 2px var(--surface);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.cloee-nokia-spark__guide[hidden],
.cloee-nokia-spark__dot[hidden] {
  display: none;
}
.cloee-nokia-spark__band {
  fill: currentColor;
  opacity: 0.16;
  stroke: none;
}
.cloee-nokia-spark__line {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
  vector-effect: non-scaling-stroke;
}
.cloee-nokia-spark__line--muted {
  stroke: var(--text-muted);
  stroke-dasharray: 3 2;
  opacity: 0.8;
}

/* Ranked magnitude rows: a name, a reading, and a bar (section 30's .nokia-meter-row idea,
   scoped to the chat bubble). Replaces reading a nine-column table to find the biggest number. */
.cloee-nokia-rank {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0.15rem 0 0.25rem;
}
.cloee-nokia-rank__row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 0.1rem 0.5rem;
  /* Negative margin keeps the highlight flush with the card's own text column. */
  margin-inline: -0.35rem;
  padding: 0.15rem 0.35rem;
  border-radius: 0.4rem;
  cursor: default;
}
.cloee-nokia-rank__row:hover,
.cloee-nokia-rank__row:focus-visible {
  background: color-mix(in srgb, var(--nokia-card-accent) 10%, transparent);
  outline: none;
}
.cloee-nokia-rank__row:focus-visible {
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--link) 65%, transparent);
}
.cloee-nokia-rank__row:hover .cloee-nokia-rank__fill,
.cloee-nokia-rank__row:focus-visible .cloee-nokia-rank__fill {
  background: var(--nokia-card-accent);
}
.cloee-nokia-rank__row:hover .cloee-nokia-rank__name,
.cloee-nokia-rank__row:focus-visible .cloee-nokia-rank__name {
  color: var(--text);
}
.cloee-nokia-rank__name {
  color: var(--text-muted);
  font-size: 0.76rem;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.cloee-nokia-rank__value {
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 700;
  white-space: nowrap;
}
.cloee-nokia-rank__track {
  grid-column: 1 / -1;
  height: 0.35rem;
  border-radius: 999px;
  background: var(--surface-sunken);
  overflow: hidden;
}
.cloee-nokia-rank__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: color-mix(in srgb, var(--nokia-card-accent) 70%, var(--surface));
}

/* Share bar legend. The bar itself is the page-side .nokia-phase-share component. */
.cloee-nokia-share {
  margin: 0.25rem 0 0.5rem;
}
.cloee-nokia-share .cloee-domain-section-title {
  margin-top: 0;
}
.cloee-nokia-share__legend {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem 0.75rem;
  margin-top: 0.35rem;
}
.cloee-nokia-share__legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--text-muted);
  font-size: 0.74rem;
  font-weight: 600;
  cursor: default;
}
/* Pointing at a slice and pointing at its legend entry are the same question, so both light the
   pair up — otherwise reading the bar means matching a colour by eye against the legend. */
.cloee-nokia-share__legend-item.is-active {
  color: var(--text);
}
.cloee-nokia-share .nokia-phase-share__segment {
  cursor: default;
  transition: filter 0.12s ease;
}
.cloee-nokia-share .nokia-phase-share__segment.is-active,
.cloee-nokia-share .nokia-phase-share__segment:focus-visible {
  filter: brightness(1.2);
  outline: none;
}
.cloee-nokia-share .nokia-phase-share__segment:focus-visible {
  box-shadow: inset 0 0 0 2px var(--surface);
}
.cloee-nokia-share__swatch {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 0.2rem;
  background: var(--nokia-phase-color, var(--text-muted));
}

/* Disclosure footnote: the forecast's screening caveats, a clamped limit, a truncation note. */
.cloee-card-note {
  margin: 0.35rem 0 0;
  color: var(--text-muted);
  font-size: 0.72rem;
  line-height: 1.4;
}
.cloee-domain-section-title {
  margin: 0.9rem 0 0.45rem;
  color: var(--text);
  font-size: 0.82rem;
  font-weight: 750;
}
.cloee-nokia-heatmap-scroll {
  max-width: 100%;
  overflow-x: auto;
  padding-bottom: 0.3rem;
}
.cloee-nokia-robot-timeline {
  min-height: 8rem;
  margin-top: 0.75rem;
}
.cloee-nokia-intent-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}
.cloee-nokia-intent-options .cloee-name-chip:disabled {
  cursor: default;
  opacity: 0.58;
}
.cloee-domain-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.75rem;
}
.cloee-domain-title {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
  color: var(--text);
  font-weight: 800;
  text-decoration: none;
}
/* A card header that navigates and one that does not were the same bold black text, so the
   card's main way out to the dashboard only announced itself once the cursor was already on it.
   The chevron is drawn only when an href survived buildDomainCardShell's removeAttribute. */
a.cloee-domain-title[href]::after {
  content: "\F285";
  font-family: "bootstrap-icons";
  font-size: 0.78rem;
  font-weight: 400;
  color: var(--text-muted);
  transition: transform 0.15s ease, color 0.15s ease;
}
a.cloee-domain-title:hover,
a.cloee-domain-title:focus-visible {
  color: var(--link);
}
a.cloee-domain-title:hover::after,
a.cloee-domain-title:focus-visible::after {
  color: var(--link);
  transform: translateX(2px);
}
a.cloee-domain-title:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 3px;
  border-radius: 0.3rem;
}
.cloee-domain-title span {
  overflow-wrap: anywhere;
}
.cloee-domain-kpis {
  grid-template-columns: repeat(auto-fit, minmax(100px, 165px));
  margin-bottom: 0.75rem;
}
/* Period energy has exactly three decision KPIs: total, monitored-fleet coverage and the
   top consumer. Keep those three tiles aligned even in a narrow chat rail; compact metric text
   prevents a long total from forcing a fourth row at phone width. */
.cloee-domain-kpis.cloee-energy-period-kpis {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.cloee-energy-period-kpis .cloee-kpi-tile {
  padding: 0.65rem;
}
.cloee-energy-period-kpis .cloee-kpi-value {
  font-size: clamp(0.78rem, 4vw, 1.35rem);
  overflow-wrap: anywhere;
}
.cloee-domain-table-scroll {
  overflow: auto;
  max-width: 100%;
  max-height: 31rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  margin-top: 0.6rem;
}
.cloee-domain-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.82rem;
}
.cloee-domain-table th,
.cloee-domain-table td {
  padding: 0.42rem 0.55rem;
  border-bottom: 1px solid var(--border);
  white-space: nowrap;
  vertical-align: top;
}
.cloee-domain-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  background: var(--surface-2);
}
.cloee-domain-table tbody tr:last-child td {
  border-bottom: 0;
}
.cloee-domain-table a {
  color: var(--link);
  font-weight: 700;
  text-decoration: none;
}
.cloee-domain-table a:hover {
  text-decoration: underline;
}
.cloee-factory-energy-table {
  min-width: 40rem;
}
.cloee-factory-energy-table th:first-child,
.cloee-factory-energy-table td:first-child {
  min-width: 7.5rem;
}
.cloee-factory-energy-table td {
  white-space: normal;
}
.cloee-factory-energy-utility {
  display: grid;
  gap: 0.18rem;
  min-width: 13rem;
}
.cloee-factory-energy-utility__value {
  color: var(--text);
  font-size: 1rem;
  font-weight: 800;
  line-height: 1.2;
}
.cloee-factory-energy-utility__coverage,
.cloee-factory-energy-utility__top,
.cloee-factory-energy-utility__status {
  color: var(--text-muted);
  font-size: 0.74rem;
  font-weight: 650;
  line-height: 1.3;
}
.cloee-factory-energy-utility__top {
  overflow-wrap: anywhere;
}
@media (max-width: 420px) {
  .cloee-factory-energy-table { min-width: 34rem; }
  .cloee-factory-energy-utility { min-width: 11rem; }
}
.cloee-domain-table td.cloee-alarm-count-cell {
  cursor: pointer;
}
.cloee-domain-table td.cloee-alarm-count-cell:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 1px;
  border-radius: 999px;
}
.cloee-alarm-count-chip::after {
  content: '▸';
  margin-left: 0.3rem;
  font-size: 0.65rem;
  opacity: 0.75;
}
.cloee-domain-table td.cloee-alarm-count-cell:hover .cloee-alarm-count-chip {
  background: color-mix(in srgb, var(--link) 16%, var(--surface));
  border-color: color-mix(in srgb, var(--link) 42%, var(--border));
}
.cloee-domain-table td.cloee-alarm-count-cell[aria-expanded="true"] .cloee-alarm-count-chip {
  background: color-mix(in srgb, var(--link) 18%, var(--surface));
}
.cloee-domain-table td.cloee-alarm-count-cell[aria-expanded="true"] .cloee-alarm-count-chip::after {
  content: '▾';
}
.cloee-domain-table tr.cloee-domain-table-row--expanded > td {
  background: color-mix(in srgb, var(--link) 5%, var(--surface));
}
/* Row hover. These tables reach eight and nine columns inside a fixed-height scroll region, and
   without a highlight there is nothing tying the value under the cursor to the row it belongs
   to — the reader tracks it by holding a finger on the screen. Sits after the expanded-row rule
   so hovering an open row still reads as hovered. */
.cloee-domain-table tbody tr:not(.cloee-domain-table-detail-row):hover > td {
  background: color-mix(in srgb, var(--link) 9%, var(--surface));
}
/* A row with exactly one destination opens it from anywhere in the row (makeRowClickable). The
   pointer cursor is only ever set on those rows, so it never promises a click that does nothing. */
.cloee-domain-table tbody tr.cloee-domain-table-row--linked {
  cursor: pointer;
}

/* Only shown at the width where columns are actually hidden, so the truncation is disclosed
   rather than silent. Appended by appendHiddenColumnsHint. */
.cloee-table-narrow-hint {
  display: none;
  color: var(--text-muted);
  font-weight: 600;
}

/* Below 480px a card table keeps its first three columns — the first carries the row's identity
   and its link — and hides the rest. Everything stays reachable by scrolling sideways, and the
   hint above says how much is over there. A colSpan row (the empty-state row, an expanded alarm
   detail) is a single cell, so :nth-child never reaches it. */
@media (max-width: 480px) {
  .cloee-domain-table th:nth-child(n + 4),
  .cloee-domain-table td:nth-child(n + 4) {
    display: none;
  }
  .cloee-table-narrow-hint {
    display: inline;
  }
}
.cloee-domain-table tr.cloee-domain-table-detail-row > td {
  white-space: normal;
  padding: 0;
  border-bottom: 0;
}
.cloee-domain-table tr.cloee-domain-table-detail-row .operations-detail-table {
  font-size: 0.78rem;
}
.cloee-domain-table-count {
  margin-top: 0.45rem;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}
.cloee-mini-table-panel {
  min-width: 0;
  margin-top: 0.4rem;
}
.cloee-mini-table-controls {
  /* Search at one end, Export table at the other — the same split the configuration table's
     controls already use. */
  justify-content: space-between;
  margin-bottom: 0.45rem;
}
.cloee-mini-table-export {
  font-size: 0.78rem;
  padding: 0.28rem 0.6rem;
}
.cloee-mini-table-search-field input {
  width: min(14rem, 100%);
}
.cloee-config-table-panel {
  min-width: 0;
  margin-top: 0.4rem;
}
.cloee-config-table-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.15rem 0 0.55rem;
}
.cloee-config-search-field {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  margin: 0;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}
.cloee-config-search-field::before {
  font-family: "bootstrap-icons";
  content: "\F52A";
  font-size: 0.95rem;
  line-height: 1;
}
.cloee-config-search-field input,
.cloee-config-filter {
  min-height: 2rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text);
  padding: 0.28rem 0.7rem;
  font-size: 0.82rem;
}
.cloee-config-search-field input {
  width: min(16rem, 100%);
  margin-left: 0;
}
.cloee-config-search-field input::placeholder {
  color: var(--text-muted);
}
.cloee-config-duration-filter {
  margin: 0;
}
.cloee-config-filter {
  width: 10.5rem;
}
.cloee-config-table-scroll {
  /* One sticky header plus 12 visible body rows; additional rows scroll inside the card. */
  max-height: 31rem;
  overflow: auto;
}
.cloee-config-table {
  min-width: 40rem;
}
.cloee-cycle-table-controls {
  justify-content: flex-start;
}
.cloee-cycle-table-controls .cloee-config-search-field {
  margin-left: auto;
}
.cloee-cycle-table {
  min-width: 46rem;
}
.cloee-config-table th,
.cloee-config-table td {
  height: 2.4rem;
}
.cloee-config-table th:first-child,
.cloee-config-table td:first-child {
  min-width: 13rem;
  white-space: normal;
  overflow-wrap: anywhere;
}
.cloee-cycle-table th:first-child,
.cloee-cycle-table td:first-child {
  min-width: 11rem;
}
.cloee-config-table thead th {
  position: sticky;
  top: 0;
  z-index: 1;
}
.cloee-config-sort-btn {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.45rem;
  width: 100%;
  min-height: 1.8rem;
  border: 0;
  background: transparent;
  color: inherit;
  padding: 0;
  font: inherit;
  font-weight: 800;
  text-align: left;
}
.cloee-config-sort-btn i {
  color: var(--text-muted);
  font-size: 0.9rem;
}
/* A sortable header that looks and hovers like static text gets treated as static text. A button
   defaults to `cursor: default`, so nothing here said "click me" except a 0.9rem icon. */
.cloee-config-sort-btn {
  cursor: pointer;
  border-radius: 0.3rem;
}
.cloee-config-sort-btn:hover,
.cloee-config-sort-btn:focus-visible {
  color: var(--text);
}
.cloee-config-sort-btn:hover i,
.cloee-config-sort-btn:focus-visible i {
  color: var(--link);
}
.cloee-config-sort-btn:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 1px;
}
.cloee-config-table-count {
  float: none;
  margin-top: 0.45rem;
  padding-top: 0;
  color: var(--text-muted);
  font-size: 0.78rem;
  font-weight: 700;
}
.cloee-config-empty-row {
  color: var(--text-muted);
  font-weight: 700;
  text-align: center;
}
.cloee-config-action-cell {
  text-align: center;
  width: 2.6rem;
}
.cloee-config-edit-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border: 1px solid var(--border);
  border-radius: 0.4rem;
  color: var(--text-muted);
  font-size: 0.85rem;
}
.cloee-config-edit-btn:hover,
.cloee-config-edit-btn:focus-visible {
  border-color: var(--link);
  color: var(--link);
}
/* Severity coloring for numeric cells (e.g. warning overrun %). Text-only tints — the
   dark overrides keep them readable on a dark surface. */
.cloee-domain-table td.cloee-cell-critical {
  color: #dc3545;
  font-weight: 700;
}
.cloee-domain-table td.cloee-cell-warn {
  color: #b45309;
  font-weight: 600;
}
html[data-bs-theme="dark"] .cloee-domain-table td.cloee-cell-critical {
  color: #f1aeb5;
}
html[data-bs-theme="dark"] .cloee-domain-table td.cloee-cell-warn {
  color: #fecba1;
}
/* Same severity tint on a KPI tile (e.g. an overrun % tile) — text-only, same colors as the
   table-cell variant above so a tile and a cell agree when a card shows the same metric both ways. */
.cloee-kpi-tile.cloee-cell-critical .cloee-kpi-value {
  color: #dc3545;
}
.cloee-kpi-tile.cloee-cell-warn .cloee-kpi-value {
  color: #b45309;
}
html[data-bs-theme="dark"] .cloee-kpi-tile.cloee-cell-critical .cloee-kpi-value {
  color: #f1aeb5;
}
html[data-bs-theme="dark"] .cloee-kpi-tile.cloee-cell-warn .cloee-kpi-value {
  color: #fecba1;
}
.cloee-domain-chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  max-height: 12rem;
  overflow: auto;
  margin-top: 0.65rem;
}
.cloee-domain-chip {
  display: inline-flex;
  align-items: center;
  min-height: 1.65rem;
  border: 1px solid color-mix(in srgb, var(--link) 24%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--link) 8%, var(--surface));
  color: var(--text);
  padding: 0.18rem 0.62rem;
  font-size: 0.78rem;
  font-weight: 700;
  text-decoration: none;
  transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.15s, box-shadow 0.15s;
}
/* Beats the blanket `.assistant-content a:hover { text-decoration: underline }` on
   specificity, but that rule sets no color/background of its own, so an explicit
   `text-decoration: none` here is still required alongside it. Lift + shadow (not just a
   colour shift) is what reads as "clickable" for a pill that carries no underline. */
a.cloee-domain-chip:hover {
  color: var(--link);
  border-color: color-mix(in srgb, var(--link) 45%, var(--border));
  background: color-mix(in srgb, var(--link) 16%, var(--surface));
  text-decoration: none;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px color-mix(in srgb, var(--link) 22%, transparent);
}
a.cloee-domain-chip:active {
  transform: translateY(0) scale(0.96);
  box-shadow: none;
}
.cloee-domain-empty {
  color: var(--text-muted);
  font-weight: 700;
  padding: 0.25rem 0;
}
@media (max-width: 575.98px) {
  .cloee-domain-kpis {
    grid-template-columns: 1fr 1fr;
  }
  .cloee-config-table-controls {
    align-items: stretch;
    flex-direction: column;
  }
  .cloee-cycle-table-controls .cloee-config-search-field {
    margin-left: 0;
  }
  .cloee-mini-table-controls {
    align-items: stretch;
    flex-direction: column;
  }
  .cloee-config-duration-filter,
  .cloee-config-search-field {
    width: 100%;
  }
  .cloee-config-filter,
  .cloee-config-search-field input {
    width: 100%;
  }
  .cloee-domain-table {
    font-size: 0.78rem;
  }
}

html[data-bs-theme="dark"] .cloee-chat-state-pill { color: #75b798; }
html[data-bs-theme="dark"] .idle-card .cloee-chat-state-pill,
html[data-bs-theme="dark"] .cloee-chat-state-pill--caution { color: #fecba1; }
html[data-bs-theme="dark"] .downtime-card .cloee-chat-state-pill,
html[data-bs-theme="dark"] .downtime-running-card .cloee-chat-state-pill,
html[data-bs-theme="dark"] .cloee-chat-state-pill--alarm { color: #f1aeb5; }

/* Sticky operational headers need an opaque surface while scrolling, but it must be the same
   surface as their card rather than a separate dark strip. */
html[data-bs-theme="dark"] .operations-data-card table.operations-data-table > thead > tr > th,
html[data-bs-theme="dark"] .configuration-page .configuration-data-table > thead > tr > th,
html[data-bs-theme="dark"] .admin-page .table > thead > tr > th {
  background: var(--surface);
  box-shadow: none;
}

/* Notification recipient matrix: the bounded scroll area keeps large customer
   lists usable without losing the recipient or event labels. Keep it aligned
   with the other configuration data tables even though it is rendered by JS. */
.configuration-page .notif-rules-matrix-scroll {
  max-height: min(65vh, 44rem);
  overflow: auto;
  border: 1px solid color-mix(in srgb, var(--configuration-card-accent) 22%, var(--border));
  border-radius: .9rem;
  background: var(--surface);
}

.configuration-page .notif-rules-matrix {
  min-width: max-content;
  margin: 0;
  --bs-table-hover-bg: transparent;
}

.configuration-page .notif-rules-matrix > thead > tr > th {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: .7rem .85rem;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  white-space: nowrap;
  box-shadow: 0 1px 0 var(--border);
}

.configuration-page .notif-rules-matrix > tbody > tr > td {
  padding: .72rem .85rem;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  color: var(--text);
  vertical-align: middle;
}

.configuration-page .notif-rules-matrix .notif-rules-matrix-recipient {
  position: sticky;
  left: 0;
  z-index: 1;
  background: color-mix(in srgb, var(--surface-2) 58%, var(--surface));
  box-shadow: 1px 0 0 var(--border);
}

.configuration-page .notif-rules-matrix th.notif-rules-matrix-recipient {
  z-index: 3;
  background: var(--surface-2);
}

.configuration-page .notif-rules-matrix > tbody > tr:hover > td,
.configuration-page .notif-rules-matrix > tbody > tr:hover > .notif-rules-matrix-recipient {
  background: color-mix(in srgb, var(--configuration-card-accent) 7%, var(--surface));
}

@media (max-width: 575.98px) {
  .cloee-chat-machine-body {
    grid-template-columns: 1fr;
  }
  .cloee-chat-machine-card .gauge-wrapper {
    width: 180px;
  }
}

/* === 26. Machine Card Gauge Alert Flip ===
   ─────────────────────────────────────────────────────────────────────────────
   A unit whose running job has no ideal time scores 0% performance, so its gauge
   shows a confident 0% that is indistinguishable from a genuinely failing furnace.
   The gauge box rotates to a warning face on a slow page-wide cycle (driven by
   static/machine_card_alerts.js) to name the cause.

   Both faces stay laid out at the wrapper's full size — the canvas is only rotated
   away, never hidden — because a zero-width Chart.js canvas re-enters the resize
   loop documented in cloee_gauge.js. The 3D context lives on .machine-card-gauge-flip
   rather than on .gauge-wrapper, whose overflow:hidden would flatten preserve-3d.
   ───────────────────────────────────────────────────────────────────────────── */
/* A container, so the alert face can size its type off the gauge box rather than the
   viewport: the same card is 150px wide normally and 120px with the assistant panel
   open, and a fixed icon size overflowed the shorter box at the narrow end. */
.machine-card-gauge-stage {
    perspective: 600px;
    container-type: inline-size;
}

.machine-card-gauge-flip {
    position: relative;
    width: 100%;
    height: 100%;
    transform-style: preserve-3d;
    transition: transform 0.6s ease;
}

.machine-card-gauge-flip.is-flipped {
    transform: rotateY(180deg);
}

.machine-card-gauge-face {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.1rem;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

/* The back face is only reachable through the flip, so it stays out of the way
   (and out of hit-testing) while the gauge is up. No frame or fill: the oversized
   icon anchors the block, and the card's own border already bounds it. */
.machine-card-gauge-face--back {
    transform: rotateY(180deg);
    padding: 0.15rem 0.25rem;
    text-align: center;
}

/* Same amber as the unconfigured footer stripe and the idle/overrun indicators,
   mixed against --surface so var(--text) keeps its contrast margin in both themes.
   The icon stacks above the label — beside it, a label wrapping to two lines left
   the icon floating against the first line and the block read as unaligned. */
.machine-card-gauge-alert-title {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    line-height: 1.1;
    font-size: clamp(0.7rem, 10.5cqw, 0.95rem);
    font-weight: 700;
    text-align: center;
    text-wrap: balance;
    color: color-mix(in srgb, #fd7e14 72%, var(--text));
}

.machine-card-gauge-alert-title i {
    font-size: clamp(1.05rem, 17cqw, 1.7rem);
    line-height: 1;
    color: #fd7e14;
}

@media (prefers-reduced-motion: reduce) {
    .machine-card-gauge-flip {
        transition: none;
    }
}

/* === 27. Attention Center ===============================
   The shared current-attention pill and the factory-scoped side panel.

   Shell is a Bootstrap offcanvas, so nothing here positions, animates or dims the
   panel — only its internal layout and the severity language live below. Controls are
   plain Bootstrap (.btn, .btn-check, .form-select, .form-check, .form-control), which
   is why this section carries no button, input or focus-ring CSS of its own: §17
   already gives every .btn the app's pill shape and the correct hover/focus split.

   Severity is always icon + text + tint, never tint alone. Hue tokens (--sev-*) carry
   borders, icons and tints; labels stay var(--text) so they clear AA in both themes.
─────────────────────────────────────────────────────────── */

/* ---- Toolbar pill --------------------------------------------------------- */

.shared-attention-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--surface);
  box-shadow: 0 0.35rem 0.8rem rgba(0, 0, 0, 0.08);
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 700;
  line-height: 1.2;
  padding: 0.5rem 0.875rem;
  transition: border-color 0.15s, box-shadow 0.15s, background-color 0.15s;
  white-space: nowrap;
}

.shared-attention-trigger-value {
  color: var(--text-muted);
  font-size: 0.75rem;
  font-weight: 600;
}

.shared-attention-trigger.is-neutral {
  border-color: color-mix(in srgb, var(--sev-ok) 32%, var(--border));
}

.shared-attention-trigger.is-neutral > i {
  color: var(--sev-ok);
}

.shared-attention-trigger.is-danger,
.shared-attention-trigger.is-error {
  border-color: color-mix(in srgb, var(--sev-critical) 48%, var(--border));
  background: color-mix(in srgb, var(--sev-critical) 7%, var(--surface));
}

.shared-attention-trigger.is-danger > i,
.shared-attention-trigger.is-error > i {
  color: var(--danger-text);
}

/* Hover changes the surface; the ring is reserved for keyboard focus so the two
   states stay distinguishable. */
.shared-attention-trigger:hover {
  border-color: color-mix(in srgb, var(--link) 45%, var(--border));
  box-shadow: 0 0.45rem 1rem rgba(0, 0, 0, 0.12);
  color: var(--text);
}

.shared-attention-trigger:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

/* ---- Panel shell ---------------------------------------------------------- */

/* Above the docked Ask CloEE bar (1045) and the session popover (1050), below the
   toast container (1055) so a failure raised from inside the panel is still visible.

   Inset, rounded and shadowed rather than a flush full-height drawer, so it reads as
   the same kind of surface as the sidebar (14px radius) and the Ask CloEE dialog
   (16px radius, inset, blurred backdrop) instead of a browser-default panel. */
.attention-center.offcanvas {
  --bs-offcanvas-zindex: 1052;
  /* Wide enough for the filters and the unit picker to share one row. */
  --bs-offcanvas-width: min(34rem, calc(100vw - 2rem));
  --bs-offcanvas-border-width: 0;
  top: 1rem;
  right: 1rem;
  bottom: 1rem;
  height: auto;
  border: 1px solid var(--border);
  border-radius: 16px;
  background: var(--surface);
  box-shadow: 0 18px 48px rgba(0, 0, 0, 0.28);
  color: var(--text);
  overflow: hidden;
}

/* Matches the Ask CloEE overlay's backdrop rather than Bootstrap's flat black. */
.offcanvas-backdrop.show {
  background: color-mix(in srgb, var(--surface-sunken) 55%, transparent);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  opacity: 1;
}

.attention-center .offcanvas-header,
.attention-center__controls {
  flex: 0 0 auto;
}

/* Single row: picker on the left, freshness and close on the right. */
.attention-center__header {
  align-items: center;
  gap: 0.75rem;
  padding: 0.625rem 1rem 0.625rem 0.875rem;
  border-bottom: 1px solid var(--border);
}

.attention-center__heading {
  min-width: 0;
  flex: 1 1 auto;
}

.attention-center__eyebrow {
  display: block;
  color: var(--text-muted);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.attention-center__title {
  overflow: hidden;
  margin: 0;
  color: var(--text);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.25;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* The picker IS the title, so it carries the title's weight while still reading as a
   control: a resting border makes it discoverable, and the caret confirms it opens. */
.attention-center__factory-picker {
  min-width: 0;
}

.attention-center__factory-toggle {
  gap: 0.5rem;
  max-width: 100%;
  padding: 0.375rem 0.75rem;
}

.attention-center__factory-toggle > .bi-building {
  color: var(--text-muted);
  font-size: 0.875rem;
}

.attention-center__factory-caret {
  margin-left: auto;
  color: var(--text-muted);
  font-size: 0.75rem;
  transition: transform 0.15s ease;
}

.attention-center__factory-toggle[aria-expanded="true"] .attention-center__factory-caret {
  transform: rotate(180deg);
}

.attention-center__factory-menu {
  max-height: 18rem;
  min-width: 13rem;
  overflow-y: auto;
}

.attention-center__factory-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}


/* Only rendered when the snapshot is old enough to matter, so it reads as a caution
   rather than a permanent line of chrome. */
.attention-center__freshness {
  border-radius: 999px;
  background: color-mix(in srgb, var(--sev-warning) 16%, transparent);
  color: var(--warning-text);
  font-size: 0.6875rem;
  font-weight: 700;
  padding: 0.125rem 0.5rem;
  white-space: nowrap;
}

.attention-center__freshness[hidden] {
  display: none;
}

.attention-center__header-actions {
  display: flex;
  align-items: center;
  flex: 0 0 auto;
  gap: 0.5rem;
}

/* ---- Display settings ----------------------------------------------------- */

/* ---- Filters (they carry the counts) -------------------------------------- */

/* Filters and the unit picker share one row: they are one decision ("what am I
   looking at"), so splitting them across two rows read as two unrelated toolbars. */
.attention-center__controls {
  display: flex;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  padding: 0.875rem 1.25rem;
  border-bottom: 1px solid var(--border);
}

.attention-center__filters {
  flex: 0 1 auto;
  min-width: 0;
}

.attention-center__filters .btn {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  padding: 0.35rem 0.55rem;
  font-size: 0.8125rem;
  white-space: nowrap;
}

/* The number is part of the control that selects it, so a separate chip strip is not
   needed to report the same three totals. */
.attention-center__filter-count {
  --attention-accent: var(--text-muted);
  border-radius: 999px;
  /* Mixed against transparent, not a surface token, so the badge sits on whatever the
     button's own background is — including the tint the selected filter carries. */
  background: color-mix(in srgb, var(--attention-accent) 22%, transparent);
  color: inherit;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.2;
  padding: 0.0625rem 0.375rem;
}

.attention-center__filter-count[hidden] {
  display: none;
}

.attention-center__filter-count.is-danger {
  --attention-accent: var(--sev-critical);
  color: var(--danger-text);
}

.attention-center__filter-count.is-warning {
  --attention-accent: var(--sev-warning);
  color: var(--warning-text);
}

.attention-center__filter-count.is-configuration {
  --attention-accent: var(--sev-setup);
  color: var(--setup-text);
}

/* Same pill language as every other toolbar selector in the app. */
.attention-center__unit-filter {
  flex: 0 0 auto;
  min-width: 0;
}

.attention-center__unit-filter .selector-toggle {
  max-width: 9rem;
  padding: 0.35rem 0.65rem;
  font-size: 0.8125rem;
}

/* Long unit names truncate rather than pushing the picker onto its own row. */
.attention-center__unit-filter .selector-toggle > span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.attention-center__unit-filter .ds-menu {
  max-height: 16rem;
  overflow-y: auto;
}

/* ---- States --------------------------------------------------------------- */

.attention-center__state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
  margin: auto;
  max-width: 22rem;
  color: var(--text-muted);
  font-size: 0.8125rem;
  line-height: 1.45;
  padding: 2rem 1.25rem;
  text-align: center;
}

.attention-center__state[hidden] {
  display: none;
}

.attention-center__state > i {
  color: var(--border);
  font-size: 2.5rem;
}

.attention-center__state strong {
  color: var(--text);
  font-size: 0.875rem;
}

/* ---- Item list ------------------------------------------------------------ */

.attention-center__body {
  display: flex;
  flex-direction: column;
  padding: 0;
}

/* Never shrink. The body is the scroller and this is a flex child of it, so `1 1 auto`
   with `min-height: 0` let the list's *box* be squashed to the panel's height while its
   content overflowed — and a sticky child can only stick inside its parent's box. The
   unit headings therefore pinned for roughly the first panel-height of scrolling and
   then stopped. `0 0 auto` keeps the box as tall as its content, so every heading sticks
   for the whole of its own group. */
.attention-center__list {
  flex: 0 0 auto;
  padding: 0.25rem 1.25rem 0.75rem;
}

.attention-center__list[hidden] {
  display: none;
}

/* A unit heading has to read as a break in the list, not as another row: it opens its
   group with a rule twice the weight of the hairline between items, carries the unit at
   full text contrast, and keeps the group's tally on the right. Sticky, so the unit stays
   named while its items scroll — hence the opaque --surface fill. */
.attention-center__unit-heading {
  position: sticky;
  top: 0;
  z-index: 1;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin: 0;
  padding: 0.75rem 0 0.375rem;
  border-bottom: 2px solid color-mix(in srgb, var(--border) 90%, transparent);
  background: var(--surface);
  color: var(--text);
  font-size: 0.75rem;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Air above every group but the first, so the break is spatial as well as drawn. */
.attention-center__item + .attention-center__unit-heading {
  padding-top: 1.25rem;
}

.attention-center__unit-count {
  color: var(--text-muted);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  white-space: nowrap;
}

.attention-center__item {
  --attention-accent: var(--border);
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  padding: 0.625rem 0;
  border-top: 1px solid color-mix(in srgb, var(--border) 74%, transparent);
  color: var(--text);
}

/* The heading's own rule opens the group, so the first row needs no second one. */
.attention-center__unit-heading + .attention-center__item {
  border-top: 0;
}

/* Severity, type and the action on one row: the label and detail below then get the
   panel's full width, where a fixed 4.5rem cue column used to wrap every job name. */
.attention-center__item-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}

.attention-center__item.is-danger {
  --attention-accent: var(--sev-critical);
}

.attention-center__item.is-warning {
  --attention-accent: var(--sev-warning);
}

.attention-center__item.is-configuration {
  --attention-accent: var(--sev-setup);
}

.attention-center__item-cue {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--attention-accent);
  font-size: 0.6875rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.attention-center__item.is-danger .attention-center__item-cue {
  color: var(--danger-text);
}

.attention-center__item.is-warning .attention-center__item-cue {
  color: var(--warning-text);
}

.attention-center__item.is-configuration .attention-center__item-cue {
  color: var(--setup-text);
}

/* What kind of item this is. Neutral on purpose — severity owns the only hue in the row,
   so a new type can be added without inventing a colour or reading as a status. */
.attention-center__item-type {
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.0625rem 0.4375rem;
  background: color-mix(in srgb, var(--border) 22%, transparent);
  color: var(--text-muted);
  font-size: 0.625rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}

.attention-center__item-type[hidden] {
  display: none;
}

.attention-center__item-copy {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: 0.125rem;
}

/* Direct child only — the detail line below carries a <strong> of its own, and it must
   not inherit the label's size and colour. */
.attention-center__item-copy > strong {
  color: var(--text);
  font-size: 0.8125rem;
  font-weight: 600;
  line-height: 1.3;
}

.attention-center__item-copy > span {
  color: var(--text-muted);
  font-size: 0.75rem;
  line-height: 1.35;
}

/* The value that is out of line: the run's own duration against its ideal, or the
   downtime it is running through. Red plus weight, never red alone. */
.attention-center__item-flag {
  color: var(--danger-text);
  font-weight: 700;
}

.attention-center__item-actions {
  display: flex;
  align-items: center;
  margin-left: auto;
}

.attention-center__item-action {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  box-shadow: none;
  font-size: 0.75rem;
  font-weight: 600;
  padding: 0.25rem 0.375rem;
  text-decoration: none;
  white-space: nowrap;
}

.attention-center__item-action:hover {
  color: var(--text);
}

/* Invisible tripwire: scrolling it into view reveals the next page. It has height so
   the observer can catch it before the list actually ends, but shows nothing. */
.attention-center__sentinel {
  height: 1px;
}

.attention-center__sentinel[hidden] {
  display: none;
}

@media (max-width: 575.98px) {
  /* Full-bleed on phones — an inset card wastes width the list needs. Sized with 100%
     rather than 100vw, because 100vw counts the scrollbar and leaves a 1px seam. */
  .attention-center.offcanvas {
    --bs-offcanvas-width: 100%;
    top: 0;
    right: 0;
    bottom: 0;
    border: 0;
    border-radius: 0;
  }

  .attention-center__controls {
    flex-direction: column;
    align-items: stretch;
  }

  .attention-center__unit-filter .selector-toggle {
    max-width: 100%;
    width: 100%;
    justify-content: space-between;
  }
}

/* === 28. Ideal Time Modal ================================================
   components/ideal_time_modal.html — the app-wide "set ideal time" editor
   (window.CloeeIdealTime.open). Plain Bootstrap .modal/.form-control/.btn
   throughout, so this carries only the inline save-status language, matching
   the attention center's (§27) same contract for a status beside a button.
─────────────────────────────────────────────────────────── */

.cloee-ideal-time-status {
  display: inline-flex;
  align-items: center;
  margin-right: auto;
  color: var(--text-muted);
  font-size: 0.8125rem;
  font-weight: 600;
}

.cloee-ideal-time-status.is-success {
  color: var(--ok-text);
}

.cloee-ideal-time-status.is-error {
  color: var(--danger-text);
}

/* === 29. OEE Petal Chart ===================================================
   macros/oee_petal_chart.html — three-petal OEE gauge: Quality/Performance/
   Availability tile one rounded triangle around a hollow OEE core. Petal
   *shape* is not here and not in the macro: each petal's angular width
   tracks its metric, so static/oee_petal_chart.js writes the `d`. Class-based so every instance
   on a page shares these rules; the gradient fill/stroke is set inline
   per-instance by the macro (gradient ids are per-instance via svg_id, so a
   shared class-level url(#...) reference would only work for one instance
   per page).
─────────────────────────────────────────────────────────── */

.unit-preview-kpi { display: block; width: 100%; max-width: 240px; height: 208px; margin: .4rem auto 0; overflow: visible; }
/* Corner rounding is baked into the path (static/oee_petal_chart.js), not painted on with
   a fat round-joined stroke — a stroke would also close the gutters between petals. */
.unit-preview-kpi__petal { stroke: none; filter: drop-shadow(0 3px 6px rgba(0, 0, 0, .22)); }
/* Petals are pastel in both themes, so the on-petal text is a fixed dark ink rather than a theme token. */
.unit-preview-kpi__value { fill: #0f172a; font-size: 15px; font-weight: 800; text-anchor: middle; }
.unit-preview-kpi__label { fill: color-mix(in srgb, #0f172a 82%, transparent); font-size: 9px; font-weight: 700; text-anchor: middle; }
.unit-preview-kpi__oee-label { fill: var(--text-muted); font-size: 10px; font-weight: 700; letter-spacing: .07em; text-anchor: middle; }
.unit-preview-kpi__oee-value { fill: var(--text); font-size: 26px; font-weight: 800; text-anchor: middle; }

/* === 30. Nokia energy surfaces ==============================================
   pages/nokia/* — the three-phase live dashboard, the historical analysis page
   and the predictive page. Panels themselves reuse .operations-data-card and
   .operations-data-table (§ above); what lives here is only what those families
   don't cover: the KPI strip, the value-vs-limit meter row, the page-level
   status banner and the load heatmap.

   Every status colour comes from the severity tokens (--sev-*, --*-text) rather
   than a raw hex, and every tint is mixed against var(--surface) so it stays a
   tint in both themes instead of glowing on dark. Colour is never the only cue:
   each state also carries an icon and a word.
─────────────────────────────────────────────────────────── */

/* --- KPI strip ------------------------------------------------------------
   Modelled on .report-kpi-card (§ Reports) but self-contained: these carry a
   context sub-line rather than a delta chip, because on an energy page the
   useful framing is "83% of today's peak", not only "+4%". */
.nokia-kpi-grid {
  display: grid;
  /* min() rather than a bare 11rem: an auto-fit track can never shrink below its own
     minimum, so on a narrow viewport (or beside a non-collapsing sidebar) a fixed 11rem
     floor forces the whole grid to overflow the page horizontally. */
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
  gap: .5rem;
}

.nokia-kpi-card {
  --nokia-kpi-accent: var(--text-muted);
  display: flex;
  flex-direction: column;
  gap: .1rem;
  min-width: 0;
  padding: .6rem .75rem;
  border: 1px solid color-mix(in srgb, var(--nokia-kpi-accent) 28%, var(--border));
  border-radius: .8rem;
  background: linear-gradient(
    135deg,
    color-mix(in srgb, var(--nokia-kpi-accent) 10%, var(--surface)),
    var(--surface) 70%
  );
  color: var(--text);
}

.nokia-kpi-card--ok       { --nokia-kpi-accent: var(--sev-ok); }
.nokia-kpi-card--warning  { --nokia-kpi-accent: var(--sev-warning); }
.nokia-kpi-card--critical { --nokia-kpi-accent: var(--sev-critical); }
.nokia-kpi-card--info     { --nokia-kpi-accent: var(--sev-setup); }

.nokia-kpi-card__label {
  display: flex;
  align-items: center;
  gap: .3rem;
  color: var(--text-muted);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}

/* The icon is the non-colour half of the status cue, so it takes the accent hue
   while the value below stays var(--text) — a saturated accent as *text* on a
   mostly-surface tint fails AA in dark mode (frontend-ui-pitfalls). */
.nokia-kpi-card__icon { color: var(--nokia-kpi-accent); font-size: .85rem; }

.nokia-kpi-card__value {
  color: var(--text);
  font-size: 1.35rem;
  font-weight: 700;
  line-height: 1.15;
  white-space: nowrap;
}

.nokia-kpi-card__unit { color: var(--text-muted); font-size: .85rem; font-weight: 600; }

.nokia-kpi-card__context {
  margin: 0;
  color: var(--text-muted);
  font-size: .74rem;
  line-height: 1.3;
}

/* Period-over-period delta. The arrow carries the direction; the tinted text is
   kept muted-weight so the KPI value stays the loudest thing in the card. */
.nokia-kpi-card__delta { display: inline-flex; align-items: center; gap: .2rem; font-weight: 700; }
.nokia-kpi-card__delta--up   { color: var(--danger-text); }
.nokia-kpi-card__delta--down { color: var(--ok-text); }
/* Falling energy is good, rising power factor is good — direction and goodness are
   not the same axis, so a card can opt into the inverted pairing. */
.nokia-kpi-card__delta--inverted.nokia-kpi-card__delta--up   { color: var(--ok-text); }
.nokia-kpi-card__delta--inverted.nokia-kpi-card__delta--down { color: var(--danger-text); }

/* --- Value-vs-limit meter -------------------------------------------------
   Generalised from the ammonia limit rows: a name, the reading against its own
   limit or target band, a verdict word, and a bar. Grid quality, phase balance
   and voltage drift all read identically because they use the same component. */
.nokia-meter-row { padding: .5rem 0; border-top: 1px solid var(--border); }
.nokia-meter-row:first-child { border-top: 0; padding-top: 0; }

.nokia-meter-row__head {
  display: flex;
  align-items: baseline;
  gap: .4rem;
  flex-wrap: wrap;
  margin-bottom: .3rem;
}

.nokia-meter-row__name { color: var(--text-muted); font-size: .78rem; font-weight: 700; }
.nokia-meter-row__value { color: var(--text); font-size: 1.05rem; font-weight: 700; }
.nokia-meter-row__target { margin-left: auto; color: var(--text-muted); font-size: .75rem; }

.nokia-meter-row__status {
  display: inline-flex;
  align-items: center;
  gap: .22rem;
  padding: .05rem .4rem;
  border: 1px solid color-mix(in srgb, var(--nokia-meter-accent, var(--text-muted)) 34%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--nokia-meter-accent, var(--text-muted)) 12%, var(--surface));
  color: var(--text);
  font-size: .7rem;
  font-weight: 700;
  white-space: nowrap;
}

.nokia-meter-row__track {
  position: relative;
  height: .45rem;
  border-radius: 999px;
  background: var(--surface-sunken);
  overflow: hidden;
}

.nokia-meter-row__fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: var(--nokia-meter-accent, var(--text-muted));
  transition: width .25s ease;
}

/* Where the ideal sits on the track (33.3% for a balanced phase, mid-band for a
   voltage/frequency target). Dashed so it reads as a reference, not a reading. */
.nokia-meter-row__ideal {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 0;
  border-left: 2px dashed color-mix(in srgb, var(--text-muted) 70%, transparent);
}

.nokia-meter-row__note { margin: .25rem 0 0; color: var(--text-muted); font-size: .74rem; }

.nokia-meter-row--ok       { --nokia-meter-accent: var(--sev-ok); }
.nokia-meter-row--warning  { --nokia-meter-accent: var(--sev-warning); }
.nokia-meter-row--critical { --nokia-meter-accent: var(--sev-critical); }
.nokia-meter-row--neutral  { --nokia-meter-accent: var(--text-muted); }

/* --- Phase comparison table ----------------------------------------------
   The three phases side by side: the one comparison a three-phase panel exists
   to support, and the one the old three-separate-doughnuts layout prevented. */
.nokia-phase-table { width: 100%; border-collapse: collapse; font-size: .88rem; }
.nokia-phase-table th,
.nokia-phase-table td { padding: .4rem .5rem; border-bottom: 1px solid var(--border); }
.nokia-phase-table tr:last-child td { border-bottom: 0; }
.nokia-phase-table th {
  color: var(--text-muted);
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .05em;
  text-transform: uppercase;
}
.nokia-phase-table td { color: var(--text); font-variant-numeric: tabular-nums; }
.nokia-phase-table .nokia-phase-table__metric { font-weight: 600; }

/* Per-phase identity swatch. Fixed hues because they identify a conductor, not a
   status — a phase does not become "worse" by being a different colour. */
.nokia-phase-dot {
  display: inline-block;
  width: .6rem;
  height: .6rem;
  margin-right: .35rem;
  border-radius: 50%;
  vertical-align: baseline;
  background: var(--nokia-phase-color, var(--text-muted));
}

/* Stacked A/B/C share bar with the 33.3% ideal marked twice. */
.nokia-phase-share {
  position: relative;
  display: flex;
  height: 1.5rem;
  border-radius: .5rem;
  background: var(--surface-sunken);
  overflow: hidden;
}

.nokia-phase-share__segment {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  background: var(--nokia-phase-color, var(--text-muted));
  font-size: .72rem;
  font-weight: 700;
  /* The segment fill is a fixed identity hue, so the label on it gets its own
     opaque surface chip rather than gambling on contrast against the fill. */
}

.nokia-phase-share__label {
  padding: 0 .3rem;
  border-radius: .3rem;
  background: var(--surface);
  color: var(--text);
  white-space: nowrap;
}

.nokia-phase-share__ideal {
  position: absolute;
  top: 0;
  bottom: 0;
  border-left: 2px dashed var(--surface);
  pointer-events: none;
}

/* --- Load heatmap ---------------------------------------------------------
   Weekday x hour mean load. The tint carries magnitude; the tooltip and the
   legend carry the number, so the colour is never load-bearing on its own.
   An uncovered slot is deliberately drawn as an empty outline, not as zero. */
.nokia-heatmap { display: grid; grid-template-columns: auto repeat(24, minmax(0, 1fr)); gap: 2px; min-width: 34rem; }
.nokia-heatmap__corner,
.nokia-heatmap__hour,
.nokia-heatmap__day {
  color: var(--text-muted);
  font-size: .66rem;
  font-weight: 700;
  text-align: center;
}
.nokia-heatmap__day { padding-right: .35rem; text-align: right; line-height: 1.6rem; }
.nokia-heatmap__cell {
  height: 1.6rem;
  border-radius: .2rem;
  /* --nokia-heat is written per cell by the page (0-1 of the period's max). */
  background: color-mix(in srgb, var(--sev-setup) calc(var(--nokia-heat, 0) * 62%), var(--surface-sunken));
}
.nokia-heatmap__cell--empty {
  background: transparent;
  border: 1px dashed color-mix(in srgb, var(--border) 80%, transparent);
}
/* Nothing about a flat tinted square says it answers a question, so the cursor and a ring say
   it instead. Shared with the analysis page's own heatmap, whose caption already promises it. */
.nokia-heatmap__cell {
  cursor: default;
}
.nokia-heatmap__cell:hover {
  outline: 2px solid var(--text);
  outline-offset: -1px;
  border-radius: .2rem;
}
.nokia-heatmap__legend { display: flex; align-items: center; gap: .4rem; color: var(--text-muted); font-size: .74rem; }
.nokia-heatmap__legend-scale {
  width: 6rem;
  height: .5rem;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--surface-sunken), color-mix(in srgb, var(--sev-setup) 62%, var(--surface-sunken)));
}

/* --- Anomaly / signal lists (predictive page) ----------------------------- */
.nokia-list-row {
  --nokia-list-accent: var(--text-muted);
  display: flex;
  align-items: flex-start;
  gap: .6rem;
  padding: .55rem .1rem;
  border-top: 1px solid var(--border);
}
.nokia-list-row:first-child { border-top: 0; }
.nokia-list-row--warning  { --nokia-list-accent: var(--sev-warning); }
.nokia-list-row--critical { --nokia-list-accent: var(--sev-critical); }
.nokia-list-row__icon { color: var(--nokia-list-accent); font-size: 1rem; line-height: 1.3; }
.nokia-list-row__title { margin: 0; color: var(--text); font-size: .88rem; font-weight: 700; }
.nokia-list-row__detail { margin: .1rem 0 0; color: var(--text-muted); font-size: .78rem; line-height: 1.35; }
/* The assumption behind a modelled figure is part of the figure, not a footnote. */
.nokia-list-row__assumption { margin: .2rem 0 0; color: var(--text-muted); font-size: .72rem; font-style: italic; }
.nokia-list-row__value { margin-left: auto; color: var(--text); font-size: .88rem; font-weight: 700; white-space: nowrap; }

/* --- Shared chart shell ---------------------------------------------------
   A definite, width-derived height so a responsive chart can never drive its own
   container's size (the Chart.js/Plotly resize-loop footgun). */
.nokia-chart { width: 100%; min-height: 15rem; height: 34vh; max-height: 26rem; }
.nokia-chart--short { min-height: 11rem; height: 22vh; max-height: 17rem; }
.nokia-scroll-x { overflow-x: auto; }

/* === 31. Robot activity timeline ==========================================
   One machine's activity as a row of proportional segments.

   Every segment fills the same full-height band regardless of state (active/paused/stopped no
   longer sit on three separate lines — that was this component's original layout, retired per
   explicit product direction to match the reference chips, which are never staggered by state).
   State still reaches a screen reader via the aria label and tooltip; visually it is colour,
   icon and label only.

   The fill is a gradient of the catalogued identity hue — `var(--seg-color)` toward a darker
   shade of itself — rather than a flat tint, matching the reference's glossy-chip look, with
   white label text. Darkening-only is deliberate: it can only *raise* contrast against white
   relative to the base hue, and every catalogued hue was checked against white text (see
   `robot/catalogue.py`). `sorting_1` is the one colour too light for that (base hue
   measures 3.73:1 against white, 4.76:1 against dark text) — its override inverts the gradient
   toward white instead and pairs it with dark label text, for the same "only ever move the safe
   direction" reason.

   The interaction surface (sweep-to-zoom band, navigator strip) deliberately mirrors
   `.unit-timeline`'s, since operators move between the two pages.

   The component is deployment-agnostic (it knows `state`, not "robot"), so the OEE
   dashboard can mount it without inheriting Nokia vocabulary. */

.robot-timeline {
  position: relative;
  width: 100%;
}

.robot-timeline__toolbar {
  display: flex;
  justify-content: flex-end;
  margin-bottom: .35rem;
}

.robot-timeline__tools .btn {
  --bs-btn-padding-y: .12rem;
  --bs-btn-padding-x: .4rem;
  --bs-btn-font-size: .72rem;
  --bs-btn-color: var(--text-muted);
  --bs-btn-border-color: var(--border);
  --bs-btn-hover-color: var(--text);
  --bs-btn-hover-bg: var(--surface-2);
  --bs-btn-hover-border-color: var(--border);
}

/* A definite height: the bars are absolutely positioned, so without it the track
   collapses and nothing paints. `touch-action: none` hands every gesture to the
   pointer handlers — without it the browser claims horizontal drags for scrolling and
   the pan never fires on a trackpad or a touchscreen.

   `--robot-timeline-wash` is the colour every segment's fill is blended against (see
   `.robot-timeline__seg` below) — it has to be a real variable rather than assuming
   `--surface-sunken`, because the reference's own backdrop (`Vector`: `#FFFCF8`) is a warm
   near-white with no dark-mode counterpart in the token set. Light mode uses that reference
   value directly; dark mode falls back to the existing sunken-surface token below so segments
   still blend against whatever they are actually drawn on. */
.robot-timeline__track {
  position: relative;
  height: 5.5rem;
  border-radius: .5rem;
  --robot-timeline-wash: #fffcf8;
  background: var(--robot-timeline-wash);
  overflow: hidden;
  cursor: crosshair;
  touch-action: none;
  user-select: none;
}

html[data-bs-theme="dark"] .robot-timeline__track {
  --robot-timeline-wash: var(--surface-sunken);
}

.robot-timeline__track:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 2px;
}

.robot-timeline__grid,
.robot-timeline__bars {
  position: absolute;
  inset: 0;
}

.robot-timeline__grid-line {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
  opacity: .7;
}

/* Everything after "now". Shading it is what stops the empty right-hand half of a live
   day from reading as missing data rather than as time that has not happened yet. */
.robot-timeline__future {
  position: absolute;
  top: 0;
  bottom: 0;
  background: repeating-linear-gradient(
    -45deg,
    transparent 0 5px,
    color-mix(in srgb, var(--text) 5%, transparent) 5px 10px
  );
  border-left: 1px dashed color-mix(in srgb, var(--text) 35%, transparent);
  pointer-events: none;
}

/* The stretch swept by an in-flight drag-zoom. */
.robot-timeline__band {
  position: absolute;
  top: 0;
  bottom: 0;
  background: color-mix(in srgb, var(--link) 18%, transparent);
  border-inline: 1px solid var(--link);
  pointer-events: none;
}

/* --- Segments -------------------------------------------------------------
   Geometry is set inline as percentages of the *visible* window, so panning and
   zooming rewrite two inline styles per bar rather than rebuilding the DOM.

   Per explicit product direction (superseding this component's earlier three-band layout):
   every segment fills the same full-height band regardless of state — the reference chips are
   never staggered by state, only by colour, icon and label. State is still exposed to a screen
   reader via `_ariaLabel`/the tooltip; it is simply no longer a *visual* position.

   The fill is the catalogued identity hue blended 50% into the track's own backdrop — the
   reference's own tile is literally `background: linear-gradient(180deg, rgba(255,255,255,0) 0%,
   #FFFFFF 100%), #0057B8; opacity: 0.5`, i.e. a glazed solid hue drawn at half strength over
   `Vector`'s `#FFFCF8` backdrop, which is what makes the reference read as soft washes of colour
   rather than the app's usual saturated flat tints. `color-mix(..., var(--robot-timeline-wash))`
   reproduces that at full element opacity instead of the CSS `opacity` property, because the
   latter would fade the label badge (a child element) along with the fill. The label no longer
   sits on the fill at all — it lives on its own translucent chip (`.robot-timeline__seg-content`
   below), so the badge stays fully legible regardless of how light the wash makes the fill under
   it; that chip's own dark backdrop is what every catalogued hue is checked against (see
   `robot/catalogue.py`). `sorting_1` is the one entry too light to need the wash at all;
   its override below skips the blend and pairs the fill with a light chip instead of the usual
   dark one.

   No per-segment border-radius on the fill: adjacent segments touch with zero gap, so each one
   rounding all four of its own corners left a lens-shaped sliver of the *track's* background
   showing through at every boundary. The track's own `overflow: hidden` + `border-radius` already
   rounds the row's outer ends for free once segments are plain rectangles. The content chip is a
   separate, inset element, so it can carry its own radius without reopening that seam. */
.robot-timeline__seg {
  position: absolute;
  top: .15rem;
  height: 5.2rem;
  /* A nine-minute fault inside a sixteen-hour day rounds to well under a pixel.
     The floor keeps it visible; the ::before below keeps it clickable. */
  min-width: 2px;
  padding: 0;
  border: 0;
  background:
    linear-gradient(180deg, transparent 0%, color-mix(in srgb, white 30%, transparent) 100%),
    color-mix(in srgb, var(--seg-color, var(--text-muted)) 50%, var(--robot-timeline-wash, #fffcf8));
  color: var(--seg-text, #fff);
  cursor: inherit;
}

/* The one catalogued colour too light to need the wash blend at all (see the comment above
   `.robot-timeline__seg`) — full-strength fill and a light chip instead of the usual dark one.
   Coupled to a specific catalogue code deliberately: a future colour change to `sorting_1` needs
   a look here too, which is why `robot/catalogue.py` cross-references this rule. */
.robot-timeline__seg[data-event-code="sorting_1"] {
  background:
    linear-gradient(180deg, transparent 0%, color-mix(in srgb, white 55%, transparent) 100%),
    var(--seg-color, var(--text-muted));
  --seg-text: #1a1a1a;
}

.robot-timeline__seg[data-event-code="sorting_1"] .robot-timeline__seg-content {
  background: color-mix(in srgb, white 55%, transparent);
}

/* Press target (WCAG 2.5.8): a 2px-wide bar is not clickable, so the interactive
   area is widened invisibly around it without changing what is drawn. */
.robot-timeline__seg::before {
  content: "";
  position: absolute;
  inset: -6px -11px;
}

.robot-timeline__seg:hover { filter: brightness(1.1); }

.robot-timeline__seg:focus-visible {
  outline: 2px solid var(--link);
  outline-offset: 1px;
  z-index: 2;
}

/* Still running: the segment's right edge is "now", not something the robot reported. */
.robot-timeline__seg--ongoing {
  border-right: 2px dashed color-mix(in srgb, var(--seg-text, #fff) 70%, transparent);
}

/* A floating badge centred over the fill — matching the reference's own `Frame 294` (an
   icon-plus-label chip on a soft translucent card, not text stretched edge-to-edge across the
   tile). Absolutely positioned and centred by transform rather than flex-centred by the button,
   so its size stays intrinsic to its own content instead of stretching with the segment: every
   badge reads at the same height and weight regardless of how tall or wide the segment under it
   is, which is what makes the row read as one consistent family of chips rather than each
   segment styling its label differently. `max-width` is a percentage of the segment itself (its
   containing block, since both are `position: absolute`), so the badge never grows past its own
   segment's edges; the tier system in turn only shows it once there is room for what it holds. */
.robot-timeline__seg-content {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: .1rem;
  max-width: calc(100% - .7rem);
  padding: .25rem .5rem;
  border-radius: .45rem;
  background: color-mix(in srgb, black 16%, transparent);
  font-size: .7rem;
  font-weight: 600;
  line-height: 1.15;
}

.robot-timeline__seg-row {
  display: flex;
  align-items: center;
  gap: .3rem;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
}

.robot-timeline__seg-icon {
  flex: 0 0 auto;
  color: var(--seg-text, #fff);
}

/* `min-width: 0` overrides a flex item's content-sized default minimum — without it the label
   never actually shrinks to the ellipsis, no matter how little room the row has left. */
.robot-timeline__seg-label { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.robot-timeline__seg-duration {
  color: color-mix(in srgb, var(--seg-text, #fff) 78%, transparent);
  font-weight: 500;
  font-size: .62rem;
}

/* --- Detail degradation ---------------------------------------------------
   Set from the measured pixel width in _applyTiers(). Content is hidden outright
   rather than truncated: half a word is noise, an icon alone is still information. */
.robot-timeline__seg[data-tier="label"] .robot-timeline__seg-duration,
.robot-timeline__seg[data-tier="icon"] .robot-timeline__seg-duration,
.robot-timeline__seg[data-tier="icon"] .robot-timeline__seg-label,
.robot-timeline__seg[data-tier="bare"] .robot-timeline__seg-content { display: none; }

.robot-timeline__seg[data-tier="icon"] .robot-timeline__seg-content { padding: .25rem; }

/* At the bare tier the glare gradient would compress into a couple of pixels and read as noise,
   so it drops to the flat identity hue instead. No radius here either — same reason as the base
   rule: a rounded sliver next to its equally-rounded neighbour leaves the track peeking through
   at the seam. */
.robot-timeline__seg[data-tier="bare"] {
  background: var(--seg-color, var(--text-muted));
}

/* --- Axis -----------------------------------------------------------------*/
.robot-timeline__axis {
  position: relative;
  height: 1.1rem;
  margin-top: .2rem;
}

.robot-timeline__tick {
  position: absolute;
  transform: translateX(-50%);
  color: var(--text-muted);
  font-size: .68rem;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The end labels are pinned inside the plot; centred, half of each would be clipped. */
.robot-timeline__tick[data-anchor="start"] { transform: none; }
.robot-timeline__tick[data-anchor="end"] { transform: translateX(-100%); }

/* --- Navigator ------------------------------------------------------------
   A whole-period mini-map with a draggable window, so a zoomed-in view still shows
   where it sits and how much is either side of it. */
.robot-timeline__navigator {
  position: relative;
  height: 1.1rem;
  margin-top: .15rem;
  touch-action: none;
}

/* Nothing to navigate when the view already is the whole period — kept in the layout
   so the card does not change height as you zoom. */
.robot-timeline__navigator--full { opacity: .45; }

.robot-timeline__navigator-track {
  position: absolute;
  inset: 0;
  border-radius: .3rem;
  background: var(--surface-sunken);
  overflow: hidden;
  cursor: pointer;
}

.robot-timeline__navigator-seg {
  position: absolute;
  top: 20%;
  height: 60%;
  min-width: 1px;
  border-radius: 1px;
  background: var(--seg-color, var(--text-muted));
  opacity: .75;
}

.robot-timeline__navigator-window {
  position: absolute;
  top: -2px;
  bottom: -2px;
  min-width: .5rem;
  border: 1px solid var(--link);
  border-radius: .3rem;
  background: color-mix(in srgb, var(--link) 14%, transparent);
  cursor: grab;
}

.robot-timeline__navigator-window:active { cursor: grabbing; }

.robot-timeline__navigator-handle {
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: -4px;
  width: 8px;
  border-radius: 4px;
  background: var(--link);
  cursor: ew-resize;
}

.robot-timeline__navigator-handle--end { left: auto; right: -4px; }

.robot-timeline__empty {
  margin: 0;
  padding: 1.75rem .75rem;
  color: var(--text-muted);
  font-size: .82rem;
  text-align: center;
}

/* --- Tooltip --------------------------------------------------------------
   Its own element rather than a Bootstrap tooltip: it carries four lines, and it has
   to follow the pointer along a bar that may be a thousand pixels wide. */
.robot-timeline__tooltip {
  position: absolute;
  z-index: 5;
  display: flex;
  flex-direction: column;
  gap: .1rem;
  max-width: 17rem;
  padding: .4rem .55rem;
  border: 1px solid var(--border);
  border-radius: .45rem;
  background: var(--surface);
  box-shadow: 0 .5rem 1.25rem rgb(0 0 0 / 18%);
  color: var(--text-muted);
  font-size: .72rem;
  line-height: 1.35;
  pointer-events: none;
}

.robot-timeline__tooltip strong { color: var(--text); font-size: .78rem; }

/* --- Card chrome: day pills, legend, totals -------------------------------
   The header stays on one line at desktop width: the stacked name/total on the left, the
   day strip scrolling in the middle, the legend toggle pinned right. */
.robot-timeline-card__meta { min-width: 0; }

/* Sizing/truncation on top of `.operations-data-card__subtitle`'s stacked-under-title
   typography and spacing — the total is a live-updating figure, not prose, so it stays on one
   line rather than wrapping. */
.robot-timeline-card__total {
  min-width: 0;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* Adapted from the unit-preview day strip (pages/cloeecore/dashboard.html), kept local
   until that one is extracted into a shared component of its own. */
.robot-timeline-days {
  display: flex;
  /* Shrink-only: it takes the space left over between the title and the legend toggle
     rather than growing and pushing the toggle onto its own line. A flex item's default
     minimum is its content, so without `min-width: 0` the ten pills refuse to shrink,
     the strip never scrolls, and the page gains a horizontal scrollbar instead. */
  flex: 0 1 auto;
  min-width: 0;
  gap: .22rem;
  overflow-x: auto;
  scrollbar-width: none;
}

.robot-timeline-days::-webkit-scrollbar { display: none; }

.robot-timeline-day {
  flex: 0 0 auto;
  padding: .34rem .6rem;
  border: 1px solid transparent;
  border-radius: .42rem;
  background: transparent;
  color: var(--link);
  font-size: .72rem;
  font-weight: 700;
  white-space: nowrap;
}

.robot-timeline-day:hover { background: color-mix(in srgb, var(--text) 6%, var(--surface)); }

.robot-timeline-day.active {
  background: color-mix(in srgb, var(--text) 12%, var(--surface-2));
  color: var(--text);
}

/* Panning across a boundary puts two days on screen at once; the partial marker keeps
   the strip honest about that rather than picking a winner. */
.robot-timeline-day.partial {
  background: color-mix(in srgb, var(--text) 6%, var(--surface-2));
  color: var(--text);
}

/* A day with no events stays visible but inert — offering a click that lands on an
   empty chart is worse than showing that the day is empty. */
.robot-timeline-day--empty { color: var(--text-muted); opacity: .45; pointer-events: none; }

/* The legend is a disclosure, so it is dense by design: one line per chip, wrapping,
   rather than a grid that stretches four items across a 1400px card. */
.robot-timeline-legend {
  display: flex;
  flex-wrap: wrap;
  gap: .3rem .9rem;
  margin-top: .6rem;
  padding-top: .6rem;
  border-top: 1px solid var(--border);
}

.robot-timeline-legend__item {
  display: inline-flex;
  align-items: center;
  gap: .3rem;
  color: var(--text);
  font-size: .72rem;
}

.robot-timeline-legend__swatch {
  flex: 0 0 auto;
  width: .65rem;
  height: .65rem;
  border-radius: .18rem;
  background: var(--seg-color, var(--text-muted));
}

.robot-timeline-legend__icon { flex: 0 0 auto; color: var(--text-muted); }
/* The state word rides in the title attribute and the grouping, not as a third column:
   spelled out per chip it doubled the legend's height for information the chart's own
   vertical position already carries. */
.robot-timeline-legend__label { white-space: nowrap; }

/* --- Compact robot status strip (Nokia real-time page) ---------------------
   The full timeline lives on /nokia/robot; this is the one line the live page keeps, so the
   operator can still read the cell's state against the power figures beside it. One row at
   desktop width, wrapping to a stack on narrow screens rather than scrolling sideways. */
.robot-strip__row {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: .55rem .9rem;
  padding: .6rem .85rem;
}

/* Shrink-only, and `min-width: 0` so a long robot label truncates instead of forcing the
   metrics off the row (the same guard `.robot-timeline-card__meta` needs). */
/* The card-header chip is sized for a two-line heading; in a one-line strip it dominates the
   row, so it is scaled down here rather than a second icon class being invented. */
.robot-strip .operations-data-card__icon {
  width: 2rem;
  height: 2rem;
  border-radius: .6rem;
  font-size: .95rem;
}

.robot-strip__identity {
  display: flex;
  align-items: center;
  flex: 0 1 auto;
  min-width: 0;
  gap: .5rem;
}

/* The guard the identity's `min-width: 0` exists for: without it the heading sets the column's
   floor and a long label pushes the metrics off the row instead of truncating. */
.robot-strip__identity .operations-data-card__title {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A chip, not loose text beside the title: the state is the strip's one live reading and has
   to separate from the robot's name at a glance. `gap` rather than a space character, because
   the label arrives as a flex-item text node whose leading whitespace the layout strips. */
.robot-strip__state {
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  flex: 0 0 auto;
  padding: .12rem .5rem;
  border: 1px solid color-mix(in srgb, var(--seg-color, var(--text-muted)) 30%, var(--border));
  border-radius: 999px;
  background: color-mix(in srgb, var(--seg-color, var(--text-muted)) 12%, transparent);
  color: var(--text);
  font-size: .75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* Falls back to the muted text colour until a segment supplies its catalogue colour, so the
   dot never renders invisible on a first paint with no ongoing segment. */
.robot-strip__dot {
  width: .5rem;
  height: .5rem;
  border-radius: 50%;
  background: var(--seg-color, var(--text-muted));
  flex: 0 0 auto;
}

.robot-strip__metrics {
  display: flex;
  align-items: baseline;
  gap: 1.1rem;
  margin: 0 0 0 auto;
}

.robot-strip__metric { display: flex; align-items: baseline; gap: .35rem; }
.robot-strip__metric dt { color: var(--text-muted); font-size: .74rem; font-weight: 400; }
.robot-strip__metric dd {
  margin: 0;
  color: var(--text);
  font-size: .88rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.robot-strip__link { flex: 0 0 auto; font-size: .8rem; text-decoration: none; white-space: nowrap; }

@media (max-width: 575.98px) {
  .robot-strip__metrics { margin-left: 0; gap: .8rem; }
}

/* --- Robot page: activity state pills --------------------------------------
   The page's only surface of its own. Everything else it draws reuses
   .operations-data-card, .nokia-kpi-card and .nokia-phase-table unchanged. */
.robot-state-pill {
  display: inline-block;
  margin-left: .35rem;
  padding: .05rem .4rem;
  border-radius: .7rem;
  background: color-mix(in srgb, var(--robot-state-accent, var(--text-muted)) 16%, transparent);
  color: var(--robot-state-accent, var(--text-muted));
  font-size: .68rem;
  font-weight: 600;
  text-transform: capitalize;
  vertical-align: middle;
}

.robot-state-pill--active  { --robot-state-accent: var(--sev-ok); }
.robot-state-pill--paused  { --robot-state-accent: var(--sev-warning); }
.robot-state-pill--stopped { --robot-state-accent: var(--sev-critical); }

/* === 32. Date range picker =================================================
   The two-month range calendar (date_range_picker.js) behind "Custom range…" in the
   time-period bar. It is portalled to <body> rather than living in the toolbar, so it
   carries its own surface and stacking rather than inheriting the bar's.
   z-index sits above the sticky toolbar (1020) and below the Ask-CloEE bar (1045).
   Built entirely from theme tokens, so light/dark needs no override block. */
.cloee-drp {
    position: fixed;
    z-index: 1040;
    background: var(--surface-2);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: 0 0.75rem 1.75rem color-mix(in srgb, var(--text) 22%, transparent);
    padding: 0.75rem;
    color: var(--text);
    font-size: 0.8rem;
    /* The toolbar is pointer-events:none apart from an allowlist; this lives outside it,
       but be explicit so it can never inherit that. */
    pointer-events: auto;
}

.cloee-drp[hidden] { display: none !important; }

.cloee-drp__header {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.35rem;
}

.cloee-drp__spacer { flex: 1 1 auto; }

.cloee-drp__nav {
    border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    padding: 0.25rem 0.6rem;
    transition: border-color 0.15s, background-color 0.15s;
}

.cloee-drp__nav:hover,
.cloee-drp__nav:focus-visible {
    border-color: color-mix(in srgb, var(--link) 45%, var(--border));
    background: color-mix(in srgb, var(--link) 10%, var(--surface));
}

.cloee-drp__months {
    display: flex;
    gap: 1rem;
    align-items: flex-start;
}

/* Months are 5 or 6 weeks tall depending on where the 1st falls. Without a floor the whole
   popover — and the Apply button with it — jumps vertically each time you page a month. Derived
   from the row height (the 2rem day cell) plus the month label and weekday header, so it stays
   correct if the cell size changes. */
.cloee-drp__month { min-height: calc(6 * 2rem + 2.9rem); }

.cloee-drp__month-label {
    text-align: center;
    font-weight: 600;
    padding-bottom: 0.35rem;
    white-space: nowrap;
}

.cloee-drp__grid { border-collapse: collapse; }

.cloee-drp__grid th {
    color: var(--text-muted);
    font-size: 0.68rem;
    font-weight: 600;
    padding-bottom: 0.2rem;
    text-align: center;
    width: 2rem;
}

/* No cell padding: the in-range tint has to form one continuous band across a week. */
.cloee-drp__grid td { padding: 0; }

.cloee-drp__day {
    width: 2rem;
    height: 2rem;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--text);
    cursor: pointer;
    font-size: 0.78rem;
    line-height: 1;
    padding: 0;
    transition: background-color 0.12s, color 0.12s;
}

.cloee-drp__day:hover:not(:disabled) {
    background: color-mix(in srgb, var(--link) 16%, transparent);
    border-radius: 999px;
}

.cloee-drp__day:disabled {
    color: var(--text-muted);
    opacity: 0.4;
    cursor: not-allowed;
}

.cloee-drp__day.is-today { font-weight: 700; text-decoration: underline; }

.cloee-drp__day.in-range { background: color-mix(in srgb, var(--link) 14%, transparent); }

.cloee-drp__day.is-start,
.cloee-drp__day.is-end {
    background: var(--link);
    color: #fff;
    font-weight: 700;
}

.cloee-drp__day.is-start { border-radius: 999px 0 0 999px; }
.cloee-drp__day.is-end { border-radius: 0 999px 999px 0; }
.cloee-drp__day.is-start.is-end { border-radius: 999px; }

.cloee-drp__day:focus-visible {
    outline: 2px solid var(--link);
    outline-offset: -2px;
}

.cloee-drp__footer {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.6rem;
    padding-top: 0.6rem;
    border-top: 1px solid var(--border);
}

.cloee-drp__summary {
    flex: 1 1 auto;
    color: var(--text-muted);
    font-size: 0.75rem;
    min-width: 0;
}

.cloee-drp__btn {
    border: 1px solid color-mix(in srgb, var(--border) 70%, transparent);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    cursor: pointer;
    font-size: 0.75rem;
    font-weight: 600;
    padding: 0.35rem 0.9rem;
    transition: border-color 0.15s, background-color 0.15s;
}

.cloee-drp__btn:hover:not(:disabled),
.cloee-drp__btn:focus-visible:not(:disabled) {
    border-color: color-mix(in srgb, var(--link) 45%, var(--border));
}

.cloee-drp__btn--primary {
    background: color-mix(in srgb, var(--link) 14%, var(--surface));
    border-color: color-mix(in srgb, var(--link) 50%, var(--border));
}

.cloee-drp__btn:disabled { opacity: 0.45; cursor: not-allowed; }

/* Narrow screens: one month instead of two. The second month stays in the DOM (the JS
   renders monthsToShow regardless) but is hidden, so nothing needs to re-render on resize. */
@media (max-width: 700px) {
    .cloee-drp__months > .cloee-drp__month:nth-child(n + 2) { display: none; }
}

/* === 33. Facility floor plan ===============================================
   Settings → Facility Layout editor (static/floor_plan_editor.js), the dashboard facility
   overview minimap (macros/facility_overview.html) and the dashboard Map view with its
   machine tiles and "Not on plan" rail (macros/facility_map.html). Block fills reuse the
   dashboard's --color-job/idle/downtime so the map matches the machine cards.
─────────────────────────────────────────────────────────── */
/* --- Editor: setup steps --- */
.floor-plan-steps {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0.5rem;
    margin: 0 0 0.9rem;
    padding: 0;
    list-style: none;
}

.floor-plan-steps__item {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-width: 0;
    padding: 0.55rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: 0.75rem;
    background: var(--surface);
    transition: border-color 0.2s ease, background-color 0.2s ease;
}

.floor-plan-steps__marker {
    display: inline-grid;
    place-items: center;
    flex: 0 0 1.6rem;
    height: 1.6rem;
    border-radius: 50%;
    background: color-mix(in srgb, var(--text) 8%, var(--surface));
    color: var(--text-muted);
    font-size: 0.75rem;
    font-weight: 700;
}

.floor-plan-steps__copy { display: grid; min-width: 0; line-height: 1.25; }
.floor-plan-steps__copy strong { font-size: 0.82rem; }
.floor-plan-steps__copy small { overflow: hidden; color: var(--text-muted); font-size: 0.72rem; text-overflow: ellipsis; white-space: nowrap; }

.floor-plan-steps__item.is-current { border-color: color-mix(in srgb, var(--link) 45%, var(--border)); background: color-mix(in srgb, var(--link) 5%, var(--surface)); }
.floor-plan-steps__item.is-current .floor-plan-steps__marker { background: var(--link); color: #fff; }
.floor-plan-steps__item.is-done .floor-plan-steps__marker { background: color-mix(in srgb, #81bc48 24%, var(--surface)); color: transparent; position: relative; }

.floor-plan-steps__item.is-done .floor-plan-steps__marker::after {
    content: "\F26E"; /* bi-check-lg */
    position: absolute;
    color: color-mix(in srgb, #81bc48 70%, var(--text));
    font-family: "bootstrap-icons";
    font-size: 0.85rem;
}

/* --- Editor: workspace (canvas + inspector) --- */
.floor-plan-editor__workspace {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 19rem;
    gap: 1rem;
    align-items: start;
}

.floor-plan-editor__stage { display: grid; gap: 0.5rem; min-width: 0; }

/* Same dotted drafting well as the dashboard's expanded facility overview. */
.floor-plan-editor__canvas {
    min-width: 0;
    padding: clamp(0.5rem, 1.5vw, 1rem);
    border: 1px solid var(--border);
    border-radius: 0.75rem;
    background-color: color-mix(in srgb, var(--surface-2) 70%, var(--surface));
    background-image: radial-gradient(color-mix(in srgb, var(--text) 13%, transparent) 1px, transparent 1.2px);
    background-size: 18px 18px;
}

.floor-plan-editor__hints {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 1rem;
    margin: 0;
    padding: 0 0.25rem;
    list-style: none;
    color: var(--text-muted);
    font-size: 0.72rem;
}

.floor-plan-editor__hints li { display: inline-flex; align-items: center; gap: 0.25rem; }

.floor-plan-editor__hints kbd {
    padding: 0.05rem 0.3rem;
    border: 1px solid var(--border);
    border-bottom-width: 2px;
    border-radius: 0.3rem;
    background: var(--surface);
    color: var(--text);
    font-family: inherit;
    font-size: 0.66rem;
    box-shadow: none;
}

.floor-plan-editor__glyph {
    display: inline-grid;
    place-items: center;
    width: 0.8rem;
    height: 0.8rem;
    border: 1.5px solid var(--link);
    border-radius: 50%;
    background: var(--surface);
    font-size: 0.6rem;
    line-height: 1;
}

.floor-plan-editor__glyph.is-midpoint { border-color: var(--text-muted); color: var(--text-muted); font-weight: 700; }
.floor-plan-editor__glyph.is-rotate { color: var(--link); font-size: 0.55rem; }

.floor-plan-inspector {
    display: grid;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: 0.75rem;
    background: var(--surface);
}

.floor-plan-inspector__section { padding: 0.8rem 0.9rem; }
.floor-plan-inspector__section + .floor-plan-inspector__section { border-top: 1px solid var(--border); }

.floor-plan-inspector__title {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin: 0 0 0.6rem;
    font-size: 0.8rem;
    font-weight: 700;
}

.floor-plan-inspector__title .bi { color: var(--text-muted); }
.floor-plan-inspector__count { margin-left: auto; color: var(--text-muted); font-size: 0.72rem; font-weight: 600; font-variant-numeric: tabular-nums; }

.floor-plan-inspector .form-label { margin-bottom: 0.2rem; color: var(--text-muted); font-size: 0.72rem; font-weight: 600; }
.floor-plan-inspector__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.5rem; }
.floor-plan-inspector__grid .input-group-text { min-width: 2rem; justify-content: center; color: var(--text-muted); font-size: 0.72rem; }
.floor-plan-inspector__rotation { display: flex; gap: 0.5rem; align-items: center; }
.floor-plan-inspector__rotation .input-group { flex: 1 1 auto; min-width: 0; }

.floor-plan-inspector__row { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: 0.6rem; }
.floor-plan-inspector__row .form-check-label { font-size: 0.78rem; }
.floor-plan-inspector__segmented .btn { padding-inline: 0.7rem; font-size: 0.75rem; }

.floor-plan-inspector__link { margin-top: 0.4rem; padding: 0; color: var(--text-muted); font-size: 0.74rem; text-decoration: none; }
.floor-plan-inspector__link:hover,
.floor-plan-inspector__link:focus-visible { color: var(--link); }

.floor-plan-buildings { list-style: none; margin: 0 0 0.5rem; padding: 0; display: grid; gap: 0.25rem; }
.floor-plan-buildings__row { display: flex; align-items: center; gap: 0.25rem; }
.floor-plan-buildings__pick { flex: 1; min-width: 0; text-align: left; padding: 0.25rem 0.5rem; border: 1px solid var(--border); border-radius: 0.4rem; background: var(--surface); color: var(--text); font-size: 0.8rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.floor-plan-buildings__pick:hover { border-color: var(--link); }
.floor-plan-buildings__pick:focus { outline: none; border-color: var(--link); box-shadow: 0 0 0 0.15rem color-mix(in srgb, var(--link) 25%, transparent); }
.floor-plan-buildings__pick.is-invalid { border-color: var(--bs-danger); }
.floor-plan-buildings__pick[aria-current="true"] { border-color: var(--link); background: color-mix(in srgb, var(--link) 10%, var(--surface)); font-weight: 600; }

.floor-plan-inspector__progress { height: 0.35rem; overflow: hidden; border-radius: 999px; background: color-mix(in srgb, var(--text) 8%, var(--surface)); }
.floor-plan-inspector__progress span { display: block; width: 0; height: 100%; border-radius: inherit; background: #81bc48; transition: width 0.3s ease; }

.floor-plan-inspector__hint { margin: 0.5rem 0; color: var(--text-muted); font-size: 0.74rem; }

.floor-plan-inspector__chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem;
    max-height: 9.5rem;
    margin-bottom: 0.65rem;
    overflow-y: auto;
}

.floor-plan-inspector__chips:empty { display: none; }

.floor-plan-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.15rem;
    padding: 0.2rem 0.55rem 0.2rem 0.35rem;
    border: 1px dashed color-mix(in srgb, var(--link) 45%, var(--border));
    border-radius: 999px;
    background: color-mix(in srgb, var(--link) 5%, var(--surface));
    color: var(--text);
    font-size: 0.74rem;
    font-weight: 600;
    line-height: 1.3;
}

.floor-plan-chip .bi { color: var(--link); }
.floor-plan-chip:hover:not(:disabled),
.floor-plan-chip:focus-visible { border-style: solid; background: color-mix(in srgb, var(--link) 12%, var(--surface)); }

.floor-plan-inspector__actions { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.4rem; }

.floor-plan-inspector__empty { display: grid; justify-items: center; gap: 0.2rem; padding: 0.4rem 0.25rem; color: var(--text-muted); font-size: 0.74rem; text-align: center; }
.floor-plan-inspector__empty .bi { font-size: 1.2rem; }
.floor-plan-inspector__empty strong { color: var(--text); font-size: 0.8rem; }

@media (max-width: 991.98px) {
    .floor-plan-editor__workspace { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 575.98px) {
    .floor-plan-steps { grid-template-columns: minmax(0, 1fr); }
}

.floor-plan-svg {
    display: block;
    width: 100%;
    max-height: 70vh;
    /* The rotate knob of a block against the top wall sits above the plan area. */
    overflow: visible;
    touch-action: none;
    user-select: none;
    outline: none;
}

.floor-plan-svg:focus-visible { box-shadow: 0 0 0 0.2rem color-mix(in srgb, var(--link) 35%, transparent); border-radius: 0.5rem; }
.floor-plan-svg__area { fill-opacity: 1; stroke: none; }
.floor-plan-svg__grid-line { fill: none; stroke: color-mix(in srgb, var(--text) 7%, transparent); }

.floor-plan-svg__outline {
    fill: color-mix(in srgb, var(--surface) 88%, transparent);
    stroke: color-mix(in srgb, var(--text) 45%, transparent);
    stroke-linejoin: round;
    cursor: move;
}
.floor-plan-svg__outline.is-dim { fill: color-mix(in srgb, var(--surface) 60%, transparent); stroke: color-mix(in srgb, var(--text) 25%, transparent); }
.floor-plan-svg__outline:hover { stroke: color-mix(in srgb, var(--link) 70%, transparent); }
.floor-plan-svg__outline.is-selected { stroke: var(--link); }
/* A surface-coloured halo keeps the name readable over a block or area. */
.floor-plan-svg__building-name { fill: var(--text-muted); stroke: var(--surface); paint-order: stroke; stroke-linejoin: round; font-weight: 700; pointer-events: none; }

.floor-plan-svg__region { cursor: move; }
.floor-plan-svg__region rect,
.facility-plan__region rect {
    fill: color-mix(in srgb, var(--link) 7%, transparent);
    stroke: color-mix(in srgb, var(--link) 55%, var(--border));
    stroke-dasharray: 5 3;
}
.floor-plan-svg__region:hover rect,
.floor-plan-svg__region.is-selected rect { stroke: var(--link); }
.floor-plan-svg__region text { fill: var(--text-muted); font-weight: 700; pointer-events: none; }
.facility-plan__region { pointer-events: none; }
.facility-plan .facility-plan__region text {
    display: inline;
    fill: var(--text-muted);
    font-size: 2px;
    font-weight: 700;
    text-anchor: middle;
    dominant-baseline: auto;
}
.facility-plan--mini .facility-plan__region text { font-size: 4px; }
/* Only drawn on a multi-building plan; small and faded, so it reads as a caption, not a heading. */
/* Sits on the top wall like a tab: the text's bottom edge rests on the line, a little in from the corner. */
.facility-plan .facility-plan__building-name {
    display: inline;
    fill: var(--text-muted);
    opacity: 0.55;
    font-size: 1.1px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    text-anchor: start;
    dominant-baseline: text-after-edge;
    translate: 0.15em -0.25em;
    pointer-events: none;
}
.facility-plan--mini .facility-plan__building-name { font-size: 2.6px; }

.floor-plan-svg__block { cursor: move; }
.floor-plan-svg__block rect { stroke: color-mix(in srgb, var(--link) 55%, var(--border)); }
.floor-plan-svg__block.is-machine rect { fill: color-mix(in srgb, var(--link) 14%, var(--surface)); }
.floor-plan-svg__block.is-label rect { fill: color-mix(in srgb, var(--surface-sunken) 60%, var(--surface)); stroke: color-mix(in srgb, var(--text) 30%, transparent); stroke-dasharray: 4 3; }
.floor-plan-svg__block.is-unknown rect { fill: color-mix(in srgb, var(--sev-warning, #ffc107) 14%, var(--surface)); stroke: var(--sev-warning, #ffc107); stroke-dasharray: 4 3; }
.floor-plan-svg__block.is-selected rect { fill: color-mix(in srgb, var(--link) 24%, var(--surface)); stroke: var(--link); }
.floor-plan-svg__block:hover rect { stroke: var(--link); }

.floor-plan-svg__block text,
.facility-plan text {
    fill: var(--text);
    font-weight: 600;
    text-anchor: middle;
    dominant-baseline: central;
    pointer-events: none;
}

.floor-plan-svg__handle {
    fill: var(--surface);
    stroke: var(--link);
    cursor: grab;
}

.floor-plan-svg__handle.is-resize { cursor: nwse-resize; }
.floor-plan-svg__handle.is-selected { fill: var(--link); }
/* Rotate handle: a knob with a circular arrow and a matching cursor, so it can't be mistaken for resize. */
.floor-plan-svg__rotate {
    cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6.3 6.3A8 8 0 1 1 6.3 17.7M6.3 17.7v-4.6M6.3 17.7h4.6' stroke='white' stroke-width='4'/%3E%3Cpath d='M6.3 6.3A8 8 0 1 1 6.3 17.7M6.3 17.7v-4.6M6.3 17.7h4.6' stroke='black' stroke-width='2'/%3E%3C/g%3E%3C/svg%3E") 12 12, grab;
}
.floor-plan-svg__rotate line { stroke: var(--link); stroke-dasharray: 3 2; }
.floor-plan-svg__rotate-knob { fill: var(--surface); stroke: var(--link); transition: fill 0.15s ease; }
.floor-plan-svg__rotate-glyph { fill: none; stroke: var(--link); stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
.floor-plan-svg__rotate:hover .floor-plan-svg__rotate-knob,
.floor-plan-svg__rotate.is-active .floor-plan-svg__rotate-knob { fill: var(--link); }
.floor-plan-svg__rotate:hover .floor-plan-svg__rotate-glyph,
.floor-plan-svg__rotate.is-active .floor-plan-svg__rotate-glyph { stroke: var(--surface); }
.floor-plan-svg__rotate-path { fill: none; stroke: color-mix(in srgb, var(--link) 45%, transparent); stroke-dasharray: 4 4; pointer-events: none; }
.floor-plan-svg__angle {
    fill: var(--link);
    stroke: var(--surface);
    paint-order: stroke;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-anchor: middle;
    dominant-baseline: central;
    pointer-events: none;
}

.floor-plan-svg__midpoint { cursor: copy; opacity: 0.55; }
.floor-plan-svg__midpoint:hover { opacity: 1; }
.floor-plan-svg__midpoint circle { fill: var(--surface); stroke: var(--text-muted); }
.floor-plan-svg__midpoint path { stroke: var(--text-muted); pointer-events: none; }

/* Dashboard minimap: pinned to the viewport's bottom-right, above the Ask CloEE bar. It stays
   half-transparent until pressed (`is-active`, set by facility_overview.js) so it never hides the
   cards behind it. */
.facility-overview-anchor { height: 0; }

.facility-overview {
    position: fixed;
    right: 1.5rem;
    bottom: 5.5rem;
    z-index: 1040;
    width: 16rem;
    padding: 0.5rem 0.65rem 0.55rem;
    border: 1px solid color-mix(in srgb, var(--border) 80%, transparent);
    border-radius: 0.9rem;
    background: color-mix(in srgb, var(--surface) 80%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 0.4rem 1.2rem color-mix(in srgb, var(--text) 10%, transparent);
    opacity: 0.5;
    transition: opacity 0.2s ease, background-color 0.2s ease;
}

.facility-overview.is-active,
.facility-overview:has(:focus-visible) {
    opacity: 1;
    background: color-mix(in srgb, var(--surface) 96%, transparent);
}

.facility-overview__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem;
}

.facility-overview__title {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-muted);
    font-size: 0.66rem;
    font-weight: 600;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    white-space: nowrap;
}

.facility-overview__title .bi { color: #81bc48; font-size: 0.8rem; }

/* The drafting surface continues behind the toolbar, KPI row and the floating sidebar's gutter: the body paints
   it, because #main-content starts right of the sidebar. The floor itself adds no card or grid seam. */
body:has(#dashboard-map-row:not(.d-none)) {
    --facility-map-ground: color-mix(in srgb, var(--surface-2) 70%, var(--surface));
    background-color: var(--facility-map-ground);
    background-image: radial-gradient(color-mix(in srgb, var(--text) 14%, transparent) 1px, transparent 1.3px);
    background-size: 18px 18px;
}

#main-content:has(#dashboard-map-row:not(.d-none)) {
    position: relative;
    height: 100vh;
    min-height: 0;
    padding-bottom: 0;
    overflow: hidden;
    /* clip, not hidden: nothing here may scroll, so no scroll offset can shear the in-flow header. */
    overflow: clip;
}

/* Map view shares the dashboard KPI row above its full-width floor. Only the small minimap steps aside. */
#dashboard-page:has(> #dashboard-map-row:not(.d-none)) .facility-overview-anchor { display: none; }
/* The floating minimap would sit on top of the open chat conversation. */
body.agentic-open .facility-overview-anchor { display: none; }
#dashboard-page:has(> #dashboard-map-row:not(.d-none)) #oee-summary-row { position: relative; z-index: 5; }
/* The header is toolbar, then KPI row, in plain flow. The toolbar's sticky offset is measured against
   #main-content, which is a fixed-height scroller here rather than the page, so a wrapped (taller) toolbar
   or any scroll offset pinned it over the in-flow KPI row. Nothing scrolls in this view; it needs no pin. */
#dashboard-page:has(> #dashboard-map-row:not(.d-none)) .dashboard-toolbar-cq { position: relative; top: auto; }
/* State counts stay inline at the strip's right end; only a phone-width strip wraps them under the KPIs. */
#oee-summary-row.is-map .factory-kpi-strip { flex-wrap: nowrap; }
@media (max-width: 680px) {
    #oee-summary-row.is-map .factory-kpi-strip { flex-wrap: wrap; }
}
#dashboard-map-row:not(.d-none) { position: absolute; inset: 0 0 auto; z-index: 0; margin: 0; }

.facility-map {
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    height: var(--facility-map-height, calc(100vh - 14rem));
    min-height: 26rem;
    margin-inline: -0.75rem;
}

.facility-map__canvas {
    /* The panels answer to the canvas width, not the viewport's: the sidebar decides how much of it there is. */
    container: facility-map / inline-size;
    position: relative;
    display: flex;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
}

/* The page owns the drafting grid; the stage stays transparent while the plan pans under fixed controls. */
.facility-map__stage {
    position: relative;
    flex: 1 1 auto;
    min-width: 0;
    isolation: isolate;
    overflow: hidden;
    background: transparent;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;
}

.facility-map__stage.is-zoomed { cursor: grab; }
.facility-map__stage.is-panning,
.facility-map__stage.is-panning .facility-map-tile { cursor: grabbing; }

.facility-plan--map { position: absolute; inset: 0; width: 100%; height: 100%; overflow: hidden; }

/* Each building reads as a shape on the dotted ground: a solid wall over a faint floor, visible in both
   themes without becoming a card. */
.facility-plan--map .facility-plan__outline {
    fill: color-mix(in srgb, var(--surface) 55%, transparent);
    stroke: color-mix(in srgb, var(--text) 45%, transparent);
    stroke-width: 1.5px;
    filter: none;
}

.facility-plan--map .facility-plan__block.is-label rect {
    fill: color-mix(in srgb, var(--surface-sunken) 60%, var(--surface));
    stroke: color-mix(in srgb, var(--text) 22%, transparent);
    stroke-dasharray: 4 3;
    stroke-width: 1.25px;
}

.facility-plan--map .facility-plan__block.is-label .facility-plan__name { fill: var(--text-muted); stroke: none; font-weight: 600; }

/* ── Machine tiles ── Laid out in screen pixels over their footprint. Every semantic-zoom tier has a
   complete, deliberately centred summary: dot → compact → gauge → standard → full. The whole tile rotates
   with its stored block angle; text is --text on a light state tint, with an icon and label, so colour is
   never the only cue. */
.facility-map__tiles { position: absolute; inset: 0; pointer-events: none; }

.facility-map-tile {
    position: absolute;
    top: 0;
    left: 0;
    transform-origin: center;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
    padding: 0.3rem 0.45rem 0.3rem 0.55rem;
    overflow: hidden;
    container-type: size;
    contain: layout paint style;
    border: 1px solid color-mix(in srgb, var(--facility-state) 45%, var(--border));
    border-left: 3px solid var(--facility-state);
    border-radius: 0.55rem;
    background: color-mix(in srgb, var(--facility-state) 9%, var(--surface));
    box-shadow: 0 1px 2px color-mix(in srgb, var(--text) 10%, transparent);
    color: var(--text);
    font-size: 0.72rem;
    line-height: 1.25;
    cursor: pointer;
    pointer-events: auto;
    outline: none;
    transition: background-color 0.4s ease, border-color 0.4s ease, box-shadow 0.15s ease;
}

.facility-map-tile.status-unknown { border-style: dashed; border-left-style: solid; }
.facility-map-tile.is-offscreen { visibility: hidden; }

.facility-map-tile:hover,
.facility-map-tile:focus-visible {
    z-index: 2;
    box-shadow: 0 0 0 2px var(--link), 0 8px 20px color-mix(in srgb, var(--text) 18%, transparent);
}

.facility-map-tile__head { display: flex; align-items: center; justify-content: center; gap: 0.3rem; min-width: 0; }
.facility-map-tile[data-layout="split"] .facility-map-tile__head { justify-content: flex-start; }

.facility-map-tile__name {
    flex: 0 1 auto;
    min-width: 0;
    overflow: hidden;
    font-size: clamp(0.72rem, 12cqh, 0.95rem);
    font-weight: 800;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.facility-map-tile .integration-live-dot { position: static; flex: 0 0 auto; width: 6px; height: 6px; }
.facility-map-tile__live { flex: 0 0 auto; color: var(--sev-ok, #198754); font-size: 0.45rem; line-height: 1; }

.facility-map-tile__badges { display: inline-flex; flex: 0 0 auto; gap: 0.3rem; font-size: 0.85em; line-height: 1; }
.facility-map-tile__badge.is-downtime { color: var(--color-downtime, #dc3545); }
.facility-map-tile__badge.is-warning { color: #fd7e14; }
.facility-map-tile__badge.is-critical { color: #dc3545; }
.facility-map-tile__badge.is-no-ideal { color: var(--text-muted); }

/* Two arrangements, chosen by what fits (floor_plan.js tileLayout), never by tier: `stack` is the dashboard
   card — gauge over centred details — and `split` sets the gauge beside left-aligned details on a landscape
   tile whose details column still has room. Tiers only add or remove lines; nothing moves between them. */
.facility-map-tile__body { display: flex; flex: 1 1 auto; flex-direction: column; align-items: center; justify-content: center; gap: 0.15rem; min-height: 0; text-align: center; }
.facility-map-tile[data-layout="split"] .facility-map-tile__body { flex-direction: row; gap: clamp(0.6rem, 4cqw, 1.5rem); text-align: start; }

/* The gauge is its own container, so the reading scales with the arc and sits inside the bowl. Stacked, it takes
   the height the lines below leave it (the SVG keeps the arc on the box's floor); split, its width mirrors
   floor_plan.js SPLIT_GAUGE. */
.facility-map-tile__gauge { position: relative; flex: 1 1 0; align-self: stretch; min-height: 2.25rem; max-height: 5rem; container-type: size; }
.facility-map-tile__gauge svg { display: block; width: 100%; height: 100%; overflow: visible; }
.facility-map-tile[data-layout="split"] .facility-map-tile__gauge { flex: 0 0 auto; align-self: center; width: clamp(4.5rem, min(70cqh, 36cqw), 9rem); height: auto; min-height: 0; max-height: none; aspect-ratio: 100 / 56; }
.facility-map-tile[data-layout="split"][data-lod="full"] .facility-map-tile__gauge { width: clamp(6rem, min(80cqh, 36cqw), 13rem); }

.facility-map-tile__arc-track,
.facility-map-tile__arc { fill: none; stroke-width: 9; }
.facility-map-tile__arc-track { stroke: color-mix(in srgb, var(--text) 12%, var(--surface)); }
.facility-map-tile__arc { stroke: var(--tile-gauge, var(--text-muted)); transition: stroke-dasharray 0.6s ease, stroke 0.4s ease; }

/* 21% of the drawn arc's width: the arc is the box's width, or 100/56 of its height when that is smaller. */
.facility-map-tile__oee {
    position: absolute;
    right: 0;
    bottom: 0;
    left: 0;
    font-size: calc(min(100cqw, 178cqh) * 0.21);
    font-variant-numeric: tabular-nums;
    font-weight: 800;
    letter-spacing: -0.02em;
    line-height: 1;
    text-align: center;
}

.facility-map-tile__info { display: flex; flex: 0 0 auto; flex-direction: column; align-items: center; gap: 0.1rem; max-width: 100%; min-width: 0; }
.facility-map-tile[data-layout="split"] .facility-map-tile__info { flex: 0 1 auto; align-items: flex-start; }

.facility-map-tile__state { display: inline-flex; align-items: center; gap: 0.3rem; max-width: 100%; min-width: 0; font-weight: 700; white-space: nowrap; }
.facility-map-tile__state .bi,
.facility-map-tile__glyph .bi { color: color-mix(in srgb, var(--facility-state) 80%, var(--text)); }
.facility-map-tile__state-long { overflow: hidden; text-overflow: ellipsis; }
.facility-map-tile__state-short { display: none; }

.facility-map-tile__fact { display: flex; justify-content: center; gap: 0.3rem; max-width: 100%; min-width: 0; white-space: nowrap; }
.facility-map-tile[data-layout="split"] .facility-map-tile__fact { justify-content: flex-start; }
.facility-map-tile__fact[hidden] { display: none; }
.facility-map-tile__fact > :last-child { overflow: hidden; text-overflow: ellipsis; }
.facility-map-tile__fact-label { flex: 0 0 auto; color: var(--text-muted); }
/* A job name or downtime reason may take a second line before it is cut, flowing on from its label as one
   run of text; the tooltip and preview carry it whole. */
.facility-map-tile__fact--job:not([hidden]),
.facility-map-tile[data-lod="full"] .facility-map-tile__fact--reason:not([hidden]) {
    display: -webkit-box;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow-wrap: anywhere;
    white-space: normal;
}

.facility-map-tile__fact--job > *,
.facility-map-tile__fact--reason > * { display: inline; }
.facility-map-tile__fact--job > .facility-map-tile__fact-label,
.facility-map-tile__fact--reason > .facility-map-tile__fact-label { margin-inline-end: 0.3rem; }
/* Downtime reasons are free text; only a full tile has the room to say them. */
.facility-map-tile__fact--reason { display: none; }

.facility-map-tile__progress { align-self: stretch; display: flex; align-items: center; gap: 0.4rem; font-size: 0.68rem; font-variant-numeric: tabular-nums; }
.facility-map-tile__track { flex: 1 1 auto; height: 0.35rem; overflow: hidden; border-radius: 999px; background: color-mix(in srgb, var(--text) 12%, var(--surface)); }
.facility-map-tile__fill { display: block; width: 0; height: 100%; border-radius: inherit; background: var(--color-job, #198754); transition: width 0.6s ease; }
.facility-map-tile__progress.is-warning .facility-map-tile__fill { background: #fd7e14; }
.facility-map-tile__progress.is-critical .facility-map-tile__fill { background: #dc3545; }
.facility-map-tile__progress.is-unconfigured .facility-map-tile__track { display: none; }
.facility-map-tile__runtime { color: var(--text-muted); white-space: nowrap; }

.facility-map-tile__glyph { display: none; }

/* dot: the footprint in its state colour with the state icon, if there is room; details on hover. */
.facility-map-tile[data-lod="dot"] {
    align-items: center;
    justify-content: center;
    padding: 0;
    border-left-width: 1px;
    background: color-mix(in srgb, var(--facility-state) 30%, var(--surface));
}

.facility-map-tile[data-lod="dot"] > :not(.facility-map-tile__glyph) { display: none; }
.facility-map-tile[data-lod="dot"] .facility-map-tile__glyph { display: flex; font-size: clamp(0.5rem, 55cqmin, 0.95rem); }

@container (max-height: 18px) {
    .facility-map-tile__glyph { visibility: hidden; }
}

/* compact: name, short state and OEE reading on one centred line. This tier is not entered until they fit. */
.facility-map-tile[data-lod="compact"] { align-items: center; justify-content: center; gap: 0.08rem; padding: 0.2rem 0.35rem; }
.facility-map-tile[data-lod="compact"] .facility-map-tile__head { width: 100%; }
.facility-map-tile[data-lod="compact"] .facility-map-tile__name { font-size: clamp(0.66rem, 13cqw, 0.86rem); }
.facility-map-tile[data-lod="compact"] .facility-map-tile__body { flex: 0 0 auto; flex-direction: row; width: 100%; gap: 0.4rem; }
/* No arc here: the gauge shrinks to its reading, and stops being a container (a size-contained auto box is 0). */
.facility-map-tile[data-lod="compact"] .facility-map-tile__gauge { flex: 0 0 auto; align-self: center; min-height: 0; max-height: none; container-type: normal; }
.facility-map-tile[data-lod="compact"] :is(.facility-map-tile__gauge svg, .facility-map-tile__fact, .facility-map-tile__badges, .facility-map-tile__progress, .facility-map-tile__live, .integration-live-dot) { display: none; }
.facility-map-tile[data-lod="compact"] .facility-map-tile__oee { position: static; font-size: clamp(0.72rem, 11cqh, 0.88rem); }
.facility-map-tile[data-lod="compact"] .facility-map-tile__info { flex: 0 1 auto; }
.facility-map-tile[data-lod="compact"] .facility-map-tile__state { font-size: clamp(0.68rem, 10cqh, 0.82rem); }
.facility-map-tile[data-lod="compact"] .facility-map-tile__state-long { display: none; }
.facility-map-tile[data-lod="compact"] .facility-map-tile__state-short { display: inline; }

/* gauge: gauge, textual state and cycle progress. Job and start wait for standard (the tooltip has them). */
.facility-map-tile[data-lod="gauge"] { gap: 0.2rem; padding: 0.3rem 0.5rem; }
.facility-map-tile[data-lod="gauge"] .facility-map-tile__name { font-size: clamp(0.74rem, 12cqh, 0.95rem); }
.facility-map-tile[data-lod="gauge"] .facility-map-tile__gauge { max-height: 3.75rem; }
.facility-map-tile[data-lod="gauge"] .facility-map-tile__state { font-size: clamp(0.7rem, 10cqh, 0.86rem); }
.facility-map-tile[data-lod="gauge"] :is(.facility-map-tile__fact, .facility-map-tile__badges, .facility-map-tile__live, .integration-live-dot) { display: none; }

/* "Downtime (running)" outgrows a narrow gauge tile; the short label and the icon still say it. */
@container (max-width: 180px) {
    .facility-map-tile[data-lod="gauge"].status-downtime-running .facility-map-tile__state-long { display: none; }
    .facility-map-tile[data-lod="gauge"].status-downtime-running .facility-map-tile__state-short { display: inline; }
}

/* standard: + job and start (or idle time). */
.facility-map-tile[data-lod="standard"] { gap: 0.3rem; padding: 0.45rem 0.65rem; }
.facility-map-tile[data-lod="standard"] .facility-map-tile__body { font-size: clamp(0.75rem, min(8cqh, 4.2cqw), 0.9rem); }
.facility-map-tile[data-lod="standard"] .facility-map-tile__gauge { max-height: clamp(3rem, 30cqh, 7rem); }
.facility-map-tile[data-lod="standard"] :is(.facility-map-tile__badges, [data-slot="reason-row"]) { display: none; }

/* full: machine-card parity — + running dot, badges, state pill and downtime reason. Type and gauge grow with
   the tile, so a big footprint reads as one large card rather than a small cluster adrift in it. Container
   units resolve against an ancestor container, so tile-relative sizes go on the tile's children. */
.facility-map-tile[data-lod="full"] { gap: clamp(0.35rem, 2.5cqh, 0.9rem); padding: 0.6rem 0.8rem 0.65rem 0.9rem; }
.facility-map-tile[data-lod="full"] .facility-map-tile__name { font-size: clamp(0.95rem, min(10cqh, 5.5cqw), 1.5rem); }
.facility-map-tile[data-lod="full"] .facility-map-tile__body { gap: clamp(0.2rem, 2.5cqh, 1rem); font-size: clamp(0.78rem, min(5.6cqh, 3.4cqw), 1.1rem); }
.facility-map-tile[data-lod="full"][data-layout="split"] .facility-map-tile__body { gap: clamp(0.75rem, 5cqw, 2.5rem); }
.facility-map-tile[data-lod="full"] .facility-map-tile__gauge { max-height: clamp(4rem, 42cqh, 9rem); }
.facility-map-tile[data-lod="full"] .facility-map-tile__info { gap: 0.2em; }
.facility-map-tile[data-lod="full"] .facility-map-tile__state {
    margin-bottom: 0.1em;
    padding: 0.1em 0.6em 0.1em 0.45em;
    border-radius: 999px;
    background: color-mix(in srgb, var(--facility-state) 18%, var(--surface));
}

.facility-map-tile[data-lod="full"] .facility-map-tile__progress { gap: 0.6em; font-size: clamp(0.72rem, min(4.6cqh, 2.5cqw), 0.95rem); }
.facility-map-tile[data-lod="full"] .facility-map-tile__track { height: clamp(0.4rem, 3cqh, 0.6rem); }

/* A roomy split tile lines its fact values up in a column. */
@container (min-width: 360px) {
    .facility-map-tile[data-lod="full"][data-layout="split"] .facility-map-tile__fact-label { display: inline-block; min-width: 3.4em; }
}

/* A short full tile beside a downtime reason: start time is the line that gives way. */
@container (max-height: 150px) {
    .facility-map-tile[data-lod="full"]:has([data-slot="reason-row"]:not([hidden])) [data-slot="start-row"] { display: none; }
}

/* ── Floating panels over the canvas ── */
.facility-map__overlay {
    position: absolute;
    z-index: 4;
    right: 0.75rem;
    left: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    pointer-events: none;
}

.facility-map__overlay > * { pointer-events: auto; }
.facility-map__overlay--top { top: 0.75rem; align-items: flex-start; justify-content: space-between; }
.facility-map__overlay--bottom {
    /* facility_map.js raises this only when the docked Ask CloEE bar would cover the controls. */
    bottom: var(--facility-map-bottom-panel-offset, 0.75rem);
    justify-content: flex-end;
}

/* Building switcher: first in the bottom bar, so the header stays two rows. */
.facility-map__buildings {
    display: flex;
    align-items: center;
    gap: 0.15rem;
    min-width: 0;
    max-width: 100%;
    padding: 0.2rem;
    overflow-x: auto;
    scrollbar-width: none;
}

.facility-map__buildings::-webkit-scrollbar { display: none; }

.facility-map__building {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: 0.45rem;
    padding: 0.3rem 0.7rem;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.facility-map__building:hover { background: color-mix(in srgb, var(--text) 7%, transparent); color: var(--text); }
.facility-map__building:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }

.facility-map__building[aria-pressed="true"] {
    background: color-mix(in srgb, var(--link) 14%, var(--surface));
    box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--link) 45%, var(--border));
    color: var(--text);
}

.facility-map__panel {
    border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
    border-radius: 999px;
    background: color-mix(in srgb, var(--surface) 88%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 0.3rem 1rem color-mix(in srgb, var(--text) 10%, transparent);
}

/* One row that scrolls when the canvas is too narrow: a wrapped pill turns into a blob over the plan. */
.factory-kpi-strip { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; min-width: 0; width: 100%; }
.factory-kpi-strip .facility-map__kpis { min-width: 0; }
.factory-kpi-strip .facility-map__summary { flex: 0 0 auto; }
.factory-kpi-strip--map { width: 100%; }
@media (max-width: 680px) {
    #oee-summary-row .factory-kpi-strip { flex-wrap: wrap; }
    #oee-summary-row .facility-map__summary { margin-left: auto; }
}
.facility-map__kpis {
    display: flex;
    align-items: center;
    max-width: 100%;
    margin: 0;
    padding: 0.2rem 0.3rem;
    overflow-x: auto;
    scrollbar-width: none;
    overscroll-behavior-x: contain;
}

.facility-map__kpis::-webkit-scrollbar { display: none; }

.facility-map__kpi { display: flex; flex: 0 0 auto; align-items: baseline; gap: 0.4rem; padding: 0.2rem 0.7rem; white-space: nowrap; }
.facility-map__kpi + .facility-map__kpi { border-left: 1px solid var(--border); }

.facility-map__kpi dt {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.facility-map__kpi-short { display: none; }

.facility-map__kpi dd {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    margin: 0;
    color: color-mix(in srgb, var(--kpi-color, var(--text)) 65%, var(--text));
    font-size: 1.02rem;
    font-variant-numeric: tabular-nums;
    font-weight: 800;
}

.facility-map__kpi dd::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--kpi-color, var(--text-muted));
}

.facility-map__summary { justify-content: flex-end; }
.facility-map__summary .facility-overview__count { background: color-mix(in srgb, var(--surface) 88%, transparent); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }

/* A two-tone map scale; its length is a round distance capped in pixels (G.scaleBarFit). */
.facility-map__scale { align-items: center; gap: 0.55rem; margin-top: 0; padding: 0.45rem 0.8rem; font-size: 0.72rem; font-variant-numeric: tabular-nums; }

.facility-map__scale .facility-overview__scale-bar {
    height: 0.4rem;
    border: 1px solid var(--text-muted);
    border-radius: 1px;
    background: linear-gradient(90deg, var(--text-muted) 50%, transparent 50%);
    transition: width 0.15s ease;
}

.facility-map__scale .facility-overview__scale-label { min-width: 2.6rem; color: var(--text); font-weight: 600; }

.facility-map__zoom { display: inline-flex; align-items: center; padding: 0.15rem; }

.facility-map__zoom :is(button, a) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--text-muted);
    text-decoration: none;
}

.facility-map__zoom-link { margin-left: 0.15rem; box-shadow: inset 1px 0 0 var(--border); border-radius: 0 999px 999px 0 !important; }

.facility-map__zoom :is(button, a):hover:not(:disabled),
.facility-map__zoom :is(button, a):focus-visible {
    background: color-mix(in srgb, var(--link) 10%, var(--surface));
    color: var(--link);
}

.facility-map__zoom :is(button, a):focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.facility-map__zoom button:disabled { opacity: 0.4; cursor: default; }

.facility-map__zoom-level {
    min-width: 3rem;
    color: var(--text);
    font-size: 0.74rem;
    font-variant-numeric: tabular-nums;
    font-weight: 600;
    text-align: center;
}

/* ── Not on plan ── A rail beside the plan inside the canvas, so a machine with no place on the layout is
   visible without leaving the map. It is laid out, not floated: the stage is simply narrower while it is
   open, and facility_map.js re-fits the plan to the stage it leaves. Its width must never follow its
   content, or the re-fit would chase it. */
/* Not on plan: a pill in the bottom bar; its rows open in a floating card above it, over the plan. */
/* The left group (switcher, this pill) ends here; scale and zoom stay right. */
.facility-map__unplaced,
.facility-map__buildings:has(+ .facility-map__unplaced[hidden]) { margin-right: auto; }
.facility-map__unplaced { position: relative; }
/* Required: this stylesheet has no global [hidden] rule. */
.facility-map__unplaced[hidden],
.facility-map__unplaced-card[hidden] { display: none; }

.facility-map__unplaced-toggle {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.4rem 0.8rem;
    color: var(--text-muted);
    font-size: 0.78rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.facility-map__unplaced-toggle strong { color: var(--text); font-variant-numeric: tabular-nums; }
.facility-map__unplaced-toggle:hover,
.facility-map__unplaced-toggle[aria-expanded="true"] { color: var(--text); border-color: color-mix(in srgb, var(--link) 45%, var(--border)); }
.facility-map__unplaced-toggle:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }

.facility-map__unplaced-card {
    position: absolute;
    bottom: calc(100% + 0.5rem);
    left: 0;
    display: flex;
    flex-direction: column;
    width: min(17rem, calc(100vw - 2rem));
    max-height: min(26rem, 55vh);
    border: 1px solid color-mix(in srgb, var(--border) 85%, transparent);
    border-radius: 0.9rem;
    background: color-mix(in srgb, var(--surface) 92%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    box-shadow: 0 0.5rem 1.5rem color-mix(in srgb, var(--text) 14%, transparent);
}

.facility-map__unplaced-title {
    margin: 0;
    padding: 0.6rem 0.8rem 0.2rem;
    color: var(--text-muted);
    font-size: 0.66rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.facility-map__rows {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    max-height: 100%;
    margin: 0;
    padding: 0.4rem;
    overflow-y: auto;
    overscroll-behavior-y: contain;
    list-style: none;
    scrollbar-width: thin;
}

.facility-map__row { display: flex; align-items: stretch; gap: 0.2rem; min-width: 0; }

/* The machine card cut down to a narrow column: name and OEE, then the lines the tile would show. */
.facility-map-row {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 0.1rem;
    min-width: 0;
    padding: 0.35rem 0.5rem;
    border: 1px solid var(--border);
    border-left: 3px solid var(--facility-state);
    border-radius: 0.5rem;
    background: color-mix(in srgb, var(--facility-state) 8%, var(--surface));
    color: var(--text);
    text-align: left;
}

.facility-map-row:hover,
.facility-map-row:focus-visible { outline: 2px solid var(--link); outline-offset: 1px; }
.facility-map-row__head { display: flex; align-items: baseline; gap: 0.35rem; min-width: 0; }
.facility-map-row__head .bi { color: color-mix(in srgb, var(--facility-state) 80%, var(--text)); font-size: 0.8rem; }

/* Truncated, never wrapped: a long unit name must not widen the rail. */
.facility-map-row__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    font-size: 0.78rem;
    font-weight: 600;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.facility-map-row__oee { flex: 0 0 auto; font-size: 0.78rem; font-variant-numeric: tabular-nums; }
.facility-map-row__lines { display: flex; flex-direction: column; min-width: 0; }

.facility-map-row__line {
    display: flex;
    gap: 0.25rem;
    min-width: 0;
    overflow: hidden;
    color: var(--text-muted);
    font-size: 0.68rem;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.facility-map-row__line--reason { color: color-mix(in srgb, var(--color-downtime, #dc3545) 70%, var(--text-muted)); }
.facility-map-row__line-label { font-weight: 600; }
.facility-map-row__line > span { overflow: hidden; text-overflow: ellipsis; }

/* Admin only: opens the layout editor with this machine already dropped on the plan. */
.facility-map__row-place {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    border: 1px solid var(--border);
    border-radius: 0.5rem;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.8rem;
    text-decoration: none;
}

.facility-map__row-place:hover,
.facility-map__row-place:focus-visible { border-color: var(--link); color: var(--link); }

/* Display modes: the floor stays, the tools step back. The automatic idle mode
   returns on input; Core's explicit Display view exits through its own controls. */
html:is(.cloee-idle-display, .cloee-display-view) :is(.facility-map__overlay--bottom, .facility-map__buildings) { opacity: 0; pointer-events: none; }
html:is(.cloee-idle-display, .cloee-display-view) .facility-map__overlay--bottom > * { pointer-events: none; }

@media (prefers-reduced-motion: reduce) {
    .facility-map-tile,
    .facility-map-tile * { transition: none !important; animation: none !important; }
}

/* Selectors carry the overlay so they outrank the shared .facility-overview__summary/__scale rules below. */
@container facility-map (max-width: 760px) {
    .facility-map__overlay .facility-map__kpi { position: relative; gap: 0.3rem; padding: 0.15rem 0.4rem; }
    .facility-map__overlay .facility-map__kpi-short { display: inline; }
    /* Visually hidden, not display:none, so a screen reader still hears the full name. */
    .facility-map__overlay .facility-map__kpi-long { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
    .facility-map__overlay .facility-map__kpis { padding-inline: 0.15rem; }
    .facility-map__overlay .facility-map__kpi dt { font-size: 0.56rem; letter-spacing: 0.04em; }
    .facility-map__overlay .facility-map__kpi dd { gap: 0.25rem; font-size: 0.82rem; }
    .facility-map__overlay .facility-map__summary,
    .facility-map__overlay .facility-map__scale { display: none; }

}

@container facility-map (max-width: 380px) {
    .facility-map__overlay { right: 0.5rem; left: 0.5rem; gap: 0.35rem; }
    .facility-map__overlay--bottom { flex-wrap: nowrap; }
    .facility-map__overlay .facility-map__zoom-level { display: none; }
    .facility-map__overlay--bottom { justify-content: center; }
    .facility-map__overlay .facility-map__zoom :is(button, a) { width: 1.75rem; height: 1.75rem; }
}

/* Per-state machine counts in the Map view; they double as its colour legend. */
.facility-overview__summary {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.facility-overview__count {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.2rem 0.65rem 0.2rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.78rem;
    line-height: 1.4;
    white-space: nowrap;
}

.facility-overview__count strong { color: var(--text); font-weight: 700; font-variant-numeric: tabular-nums; }
.facility-overview__count .facility-overview__swatch { width: 0.55rem; height: 0.55rem; margin-right: 0; border-radius: 50%; }

.facility-overview__actions { display: flex; gap: 0.15rem; }

.facility-overview__btn {
    border: 0;
    border-radius: 0.4rem;
    background: transparent;
    color: var(--text-muted);
    font-size: 0.75rem;
    line-height: 1;
    padding: 0.25rem 0.3rem;
}

.facility-overview a.facility-overview__btn { display: inline-block; color: var(--text-muted); text-decoration: none; }

.facility-overview .facility-overview__btn:hover,
.facility-overview .facility-overview__btn:focus-visible { color: var(--text); background: color-mix(in srgb, var(--text) 8%, transparent); }

.facility-overview__body { margin-top: 0.35rem; }

/* Collapsed to its header: the smallest the overview gets — it has no close. */
.facility-overview.is-collapsed { width: auto; }
.facility-overview.is-collapsed .facility-overview__body { display: none; }

.facility-plan {
    display: block;
    width: 100%;
    overflow: visible;
}

.facility-plan--mini { max-height: 11rem; }

.facility-plan__outline {
    fill: color-mix(in srgb, var(--text-muted) 16%, transparent);
    stroke: var(--text-muted);
    stroke-width: 1.25px;
    stroke-linejoin: round;
}

.facility-plan__block rect {
    fill: var(--surface-sunken);
    stroke: color-mix(in srgb, var(--text) 25%, transparent);
    stroke-width: 1px;
    transition: fill 0.4s ease;
}

.facility-plan text { display: none; }
.facility-plan text.is-fitted { display: inline; }
.facility-plan__block.is-machine { cursor: pointer; outline: none; }
.facility-plan__block.is-machine:hover rect,
.facility-plan__block.is-machine:focus-visible rect { stroke: var(--link); stroke-width: 2px; }

/* State colours follow the machine cards (not the timeline palette): orange idle outline, red
   downtime, a lighter red for "running despite downtime". One variable per state feeds the block
   fill, the count swatch and the tooltip dot. */
:is(.facility-plan__block, .facility-overview__swatch, .facility-overview-tooltip__state, .facility-map-tile, .facility-map-row) {
    --facility-state: color-mix(in srgb, var(--text-muted) 45%, transparent);
}
:is(.facility-plan__block, .facility-overview__swatch, .facility-overview-tooltip__state, .facility-map-tile, .facility-map-row).status-running { --facility-state: var(--color-job, #198754); }
:is(.facility-plan__block, .facility-overview__swatch, .facility-overview-tooltip__state, .facility-map-tile, .facility-map-row).status-idle { --facility-state: #fd7e14; }
:is(.facility-plan__block, .facility-overview__swatch, .facility-overview-tooltip__state, .facility-map-tile, .facility-map-row).status-downtime { --facility-state: var(--color-downtime, #dc3545); }
:is(.facility-plan__block, .facility-overview__swatch, .facility-overview-tooltip__state, .facility-map-tile, .facility-map-row).status-downtime-running {
    --facility-state: color-mix(in srgb, var(--color-downtime, #dc3545) 50%, var(--surface));
}

.facility-plan__block.is-machine rect { fill: var(--facility-state); }
.facility-overview__swatch { background: var(--facility-state); }

/* A surface-coloured halo keeps labels readable on any state colour, in either theme. */
.facility-plan__block text {
    paint-order: stroke;
    stroke: color-mix(in srgb, var(--surface) 75%, transparent);
    stroke-linejoin: round; /* stroke-width is set in plan units by facility_overview.js */
}

/* Cross-highlight with the dashboard machine cards (facility_overview.js). Hovering a card wakes the
   minimap and spotlights that machine's block while the rest recede; hovering a block rings its card.
   Both halves use --link, the plan's own hover colour, so the link never reads as a machine state. */
.facility-overview.is-linked:not(.is-collapsed) {
    opacity: 1;
    background: color-mix(in srgb, var(--surface) 96%, transparent);
}

.facility-plan__block { transition: opacity 0.15s ease; }
.facility-plan.has-linked .facility-plan__block:not(.is-linked) { opacity: 0.3; }
.facility-plan__block.is-machine.is-linked rect { stroke: var(--link); stroke-width: 2px; }
.facility-plan__block.is-machine.is-linked { filter: drop-shadow(0 0 3px color-mix(in srgb, var(--link) 70%, transparent)); }

#dashboard-cards-row .machine-card.is-plan-linked,
#dense-bars-grid .dense-machine-card.is-plan-linked {
    outline: 2px solid var(--link);
    outline-offset: 3px;
    box-shadow: 0 0 0 6px color-mix(in srgb, var(--link) 16%, transparent), 0 12px 24px rgba(0, 0, 0, 0.18);
}

#dense-bars-grid .dense-machine-card.is-plan-linked { transform: translateY(-1px); }

.facility-overview__scale {
    display: flex;
    align-items: flex-end;
    gap: 0.4rem;
    margin-top: 0.3rem;
    color: var(--text-muted);
    font-size: 0.66rem;
}

.facility-overview__scale-bar {
    display: inline-block;
    height: 0.35rem;
    border: 1px solid var(--text-muted);
    border-top: 0;
}

.facility-overview__swatch {
    display: inline-block;
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 0.2rem;
    margin-right: 0.35rem;
    vertical-align: -0.05rem;
}

.facility-overview-tooltip {
    position: fixed;
    z-index: 1090;
    max-width: 16rem;
    padding: 0.25rem 0.5rem;
    border: 1px solid var(--border);
    border-radius: 0.4rem;
    background: var(--surface);
    color: var(--text);
    font-size: 0.75rem;
    line-height: 1.35;
    pointer-events: none;
    box-shadow: 0 0.25rem 0.75rem color-mix(in srgb, var(--text) 14%, transparent);
}

.facility-overview-tooltip > * { display: block; }
.facility-overview-tooltip > span { color: var(--text-muted); }

.facility-overview-tooltip__state::before {
    content: "";
    display: inline-block;
    width: 0.5rem;
    height: 0.5rem;
    margin-right: 0.35rem;
    border-radius: 50%;
    background: var(--facility-state);
}

.facility-overview-tooltip > .facility-overview-tooltip__state { color: var(--text); font-weight: 600; }

/* Narrow screens: stop floating over content and sit in the page flow instead, after the machine cards. */
@media (max-width: 767.98px) {
    .facility-overview-anchor { height: auto; margin-top: 0.75rem; }
    .facility-overview { position: static; width: 100%; opacity: 1; z-index: auto; }
}

/* Platform Admin → Usage & Advisor: adoption cards, parallel-chat limit, and run summary. */
.usage-advisor-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr));
  gap: 0.75rem;
}
.usage-advisor-kpi {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
  padding: 0.8rem;
  border: 1px solid var(--border);
  border-radius: 0.7rem;
  background: var(--surface);
}
.usage-advisor-kpi__label,
.usage-advisor-kpi > span:last-child {
  color: var(--text-muted);
  font-size: 0.75rem;
  line-height: 1.3;
}
.usage-advisor-kpi strong {
  color: var(--text);
  font-size: 1.4rem;
  font-variant-numeric: tabular-nums;
}
.usage-advisor-table-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.65rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  background: var(--surface-2);
}
.usage-advisor-table-toolbar label {
  display: grid;
  gap: 0.2rem;
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 600;
}
.usage-advisor-table-toolbar .form-select { min-width: 9rem; }
.admin-page .usage-advisor-users-table { min-width: 88rem; }
@media (max-width: 575.98px) {
  .usage-advisor-table-toolbar label,
  .usage-advisor-table-toolbar .form-select { width: 100%; }
}
.advisor-limit-input { width: 6rem; }
.advisor-operations-config__inner {
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px solid var(--border);
}
.advisor-run-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(9rem, 1fr));
  gap: 0.75rem;
  margin: 1rem 0 0;
}
.advisor-run-stats > div {
  padding: 0.6rem 0.8rem;
  border: 1px solid var(--border);
  border-radius: 0.6rem;
  background: var(--surface);
}
.advisor-run-stats dt {
  color: var(--text-muted);
  font-size: 0.72rem;
  font-weight: 600;
}
.advisor-run-stats dd {
  margin: 0.15rem 0 0;
  color: var(--text);
  font-size: 1.1rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.chat-audit-event {
  display: flex;
  align-items: flex-start;
  gap: 0.6rem;
  max-width: 82%;
  margin: 0.75rem auto;
  padding: 0.65rem 0.8rem;
  border: 1px solid color-mix(in srgb, var(--sev-warning) 36%, var(--border));
  border-radius: 0.65rem;
  background: color-mix(in srgb, var(--sev-warning) 10%, var(--surface));
  color: var(--text);
  font-size: 0.82rem;
}
.chat-audit-event > i { color: var(--text); font-size: 1rem; line-height: 1.3; }
.chat-audit-event strong,
.chat-audit-event span,
.chat-audit-event p { display: block; }
.chat-audit-event span,
.chat-audit-event p { margin: 0.12rem 0 0; color: var(--text-muted); }
.chat-audit-event p { overflow-wrap: anywhere; }
.admin-session-transcript-header {
  border-bottom-color: var(--border);
  background: var(--surface-2);
  color: var(--text);
}
