/* ──────────────────────────────────────────────────────────────────────
   device-detail.css — chrome for the device-detail redesign.
   Loaded only by flask_app/templates/devices/device_detail.html.
   PR-3 of the device-detail refactor — see
   memory-bank/tasks/feature-v0.8.0-stage-1/analysis/phase-1/
   DEVICE-DETAIL-PLAN.md.

   Token hygiene:
   - Brand + status colours use --color-* tokens already defined in
     flask_app/static/css/design-system.css (loaded globally).
   - Grayscale uses --device-gray-*, scoped to .device-detail-page so it
     can't leak into other pages. Values match the --cp-gray-* scale
     (compliance/_tokens.css) — when design-system.css grows a global
     gray scale, this block can be deleted and the var() refs will fall
     through to the global definition.
   ────────────────────────────────────────────────────────────────────── */

.device-detail-page,
.devices-page,
.gateways-page,
.gateway-detail-page,
.tenants-page,
.positioning-page,
.network-health-page {
    /* SINGLE source of truth for v0.8.0 analyze-section page chrome
       (device-detail, devices list, gateways list, gateway-detail,
       standalone positioning).
       All pages share:
         - the same --device-gray-* scale (matches --cp-gray-*)
         - the same 88rem max-width (matches compliance .fw-page +
           .compliance-landing)
         - the same left-aligned padding
       The .dd-* component rules (.dd-hero, .dd-kpi*, .dd-stage, .dd-rail*)
       below are not scoped to the wrapper — they apply wherever the
       markup appears. Add new analyze-section pages to this selector
       to inherit the wrapper styling. */
    --device-gray-50: #f9fafb;
    --device-gray-100: #f3f4f6;
    --device-gray-200: #e5e7eb;
    --device-gray-300: #d1d5db;
    --device-gray-400: #9ca3af;
    --device-gray-500: #6b7280;
    --device-gray-600: #4b5563;
    --device-gray-700: #374151;
    --device-gray-800: #1f2937;
    --device-gray-900: #111827;

    /* Width + padding come from design-system.css :root variables so
       a single edit there updates every page (compliance + analyze). */
    max-width: var(--page-max-width);
    margin: 0;
    padding: var(--page-padding);
    color: var(--device-gray-900);
    font-family: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
    font-size: 14px;
    line-height: 1.5;
}

.device-detail-page h1,
.device-detail-page h2,
.device-detail-page h3,
.devices-page h1,
.devices-page h2,
.devices-page h3,
.gateways-page h1,
.gateways-page h2,
.gateways-page h3,
.gateway-detail-page h1,
.gateway-detail-page h2,
.gateway-detail-page h3,
.tenants-page h1,
.tenants-page h2,
.tenants-page h3,
.positioning-page h1,
.positioning-page h2,
.positioning-page h3,
.network-health-page h1,
.network-health-page h2,
.network-health-page h3 {
    font-family: "Ubuntu Sans", sans-serif;
    margin: 0;
}

/* ── Hero header ────────────────────────────────────────────────────── */
.dd-hero {
    background: #fff;
    border: 1px solid var(--device-gray-200);
    border-radius: 0.75rem;
    padding: 1.125rem 1.25rem;
    margin-bottom: 1rem;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.dd-hero-title-block {
    min-width: 0;
}

.dd-hero-title {
    /* Canonical page-title typography — same Ubuntu Sans Medium 30px
       brand-green as ``.patitur-main-page-title`` (see design-tokens.css
       §h1 / .patitur-main-page-title). One type pattern across every
       page that has a header — list pages using the page-title macro,
       detail pages using the .dd-hero card chrome, org and tenant
       routes alike. Layout properties (inline-flex + gap + flex-wrap)
       stay so the title sits beside the EUI badge / pill cluster
       inside the hero card. */
    font-family: var(--font-display);
    font-weight: var(--fw-medium);
    font-size: var(--fs-2xl);
    line-height: 28px;
    color: var(--color-brand-green);
    letter-spacing: normal;
    margin: 0;
    display: inline-flex;
    align-items: baseline;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.dd-hero-eui {
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.8125rem;
    font-weight: 500;
    color: var(--device-gray-500);
}

.dd-hero-pills {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    margin-top: 0.5rem;
}

.dd-hero-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    flex-shrink: 0;
}

/* ── Action chip (matches device-detail mockup chip pattern) ────────── */
.dd-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    font-size: 0.75rem;
    font-weight: 500;
    border: 1px solid var(--device-gray-300);
    color: var(--device-gray-700);
    background: #fff;
    cursor: pointer;
    font-family: inherit;
    transition:
        background-color 0.12s,
        border-color 0.12s;
}
.dd-chip:hover {
    background: var(--device-gray-50);
    border-color: var(--device-gray-400);
}
.dd-chip svg {
    width: 13px;
    height: 13px;
    flex-shrink: 0;
}

/* ── Pills (re-uses the production --color-status-pill-* token pairs) */
.dd-pill {
    display: inline-flex;
    align-items: center;
    gap: 0.3125rem;
    padding: 0.1875rem 0.625rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}
/* Modifier — slightly de-emphasized weight for status/window pills
   layered next to a panel title (Signal-tab window count, Map-tab
   gateways-heard tag). Replaces the inline ``style="font-weight: 500;"``
   pattern that used to live on those call sites. */
.dd-pill-medium {
    font-weight: 500;
}
.dd-pill-online {
    background: var(--color-status-pill-bg-online, #e8f9f3);
    color: var(--color-status-pill-text-online, #1a7f5f);
}
.dd-pill-offline {
    background: var(--color-status-pill-bg-danger, #ffe8e8);
    color: var(--color-status-pill-text-danger, #c93636);
}
.dd-pill-warning {
    background: var(--color-status-pill-bg-warning, #fff3e8);
    color: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-pill-info {
    background: var(--color-status-pill-bg-info, #e8f6ff);
    color: var(--color-status-pill-text-info, #2e7db5);
}
.dd-pill-neutral {
    background: var(--color-status-pill-bg-neutral, #f3f4f6);
    color: var(--color-status-pill-text-neutral, #6b7280);
}
.dd-pill-importance-low {
    background: var(--color-status-pill-bg-info, #e8f6ff);
    color: var(--color-status-pill-text-info, #2e7db5);
}
.dd-pill-importance-medium {
    background: var(--color-status-pill-bg-warning, #fff3e8);
    color: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-pill-importance-high {
    background: var(--color-status-pill-bg-warning, #fff3e8);
    color: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-pill-importance-critical {
    background: var(--color-status-pill-bg-danger, #ffe8e8);
    color: var(--color-status-pill-text-danger, #c93636);
}
/* v0.9.2 device State — lifecycle pill (operational / pending) + reason chip
   (warn / error / benign). Reuses the status-pill colour tokens. Orthogonal to
   the connectivity badge; raw enum values never rendered (mapped in
   constants/devices.py via DeviceStateView). */
.dd-pill-state-operational {
    background: var(--color-status-pill-bg-online, #e8f9f3);
    color: var(--color-status-pill-text-online, #1a7f5f);
}
.dd-pill-state-pending {
    background: var(--color-status-pill-bg-warning, #fff3e8);
    color: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-chip-reason {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.4375rem;
    border-radius: 0.375rem;
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0.02em;
}
.dd-chip-reason-warn {
    background: var(--color-status-pill-bg-warning, #fff3e8);
    color: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-chip-reason-error {
    background: var(--color-status-pill-bg-danger, #ffe8e8);
    color: var(--color-status-pill-text-danger, #c93636);
}
.dd-chip-reason-benign {
    background: var(--color-status-pill-bg-info, #e8f6ff);
    color: var(--color-status-pill-text-info, #2e7db5);
}
.dd-pill-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    display: inline-block;
}
.dd-pill-dot.online {
    background: var(--color-chart-status-online, #22e5a1);
}
.dd-pill-dot.offline {
    background: var(--color-chart-status-offline, #ff5e5e);
}
.dd-pill-dot.warning {
    background: var(--color-chart-importance-medium, #fe9239);
}
.dd-pill-dot.acked {
    background: var(--color-chart-importance-low, #51c0ff);
}
.dd-pill-dot.resolved {
    background: var(--color-chart-status-online, #22e5a1);
}

/* ── KPI strip ──────────────────────────────────────────────────────
   Default is 6 tiles (device-detail). Add ``.dd-kpi-strip-5`` for the
   devices/gateways list pages; ``.dd-kpi-strip-4`` for tighter strips
   (gateways list per PR-8 §3.2). The breakpoint behaviour is shared. */
.dd-kpi-strip {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: 0.75rem;
    margin-bottom: 1rem;
}
.dd-kpi-strip.dd-kpi-strip-5 {
    grid-template-columns: repeat(5, minmax(0, 1fr));
}
.dd-kpi-strip.dd-kpi-strip-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
}
@media (max-width: 1100px) {
    .dd-kpi-strip,
    .dd-kpi-strip.dd-kpi-strip-5,
    .dd-kpi-strip.dd-kpi-strip-4 {
        grid-template-columns: repeat(3, minmax(0, 1fr));
    }
}
@media (max-width: 700px) {
    .dd-kpi-strip,
    .dd-kpi-strip.dd-kpi-strip-5,
    .dd-kpi-strip.dd-kpi-strip-4 {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.dd-kpi {
    background: #fff;
    border: 1px solid var(--device-gray-200);
    border-radius: 0.75rem;
    padding: 0.875rem 1rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
}
.dd-kpi-label {
    font-size: 0.6875rem; /* matches .kpi-tile-label */
    font-weight: 700;
    color: var(--device-gray-500);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.dd-kpi-value {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 1.5rem; /* 24px — slight reduction from 1.75rem because 6 tiles cramp */
    color: var(--device-gray-900);
    line-height: 1.15;
}
.dd-kpi-value-unit {
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--device-gray-500);
    margin-left: 0.1875rem;
}
.dd-kpi-sub {
    font-size: 0.6875rem;
    color: var(--device-gray-500);
    margin-top: 0.125rem;
}
.dd-kpi-sub-empty {
    color: var(--device-gray-400);
    font-style: italic;
}

/* ── Stage: tab content + always-on rail ──────────────────────────── */
.dd-stage {
    display: grid;
    /* Rail width comes from --page-rail-width in design-system.css —
       single source of truth shared with future analyze pages. PR-7
       had 320px; PR-8 slimmed to 240px to free horizontal space for
       wide tables. Bump the var to revisit. */
    grid-template-columns: minmax(0, 1fr) var(--page-rail-width);
    gap: 1.125rem;
    /* Rail collapse (plan 03): animate the rail column when
       .rail-collapsed toggles. Expanded template is unchanged. */
    transition: grid-template-columns 0.2s ease;
}
/* Modifier — pages that don't ship a right rail (currently /tenants per
   LIST-PAGES-REDESIGN.md §"Tab structure per page"). Collapses the
   stage to a single full-width column instead of leaving an empty
   rail gutter. */
.dd-stage.dd-stage-no-rail {
    grid-template-columns: minmax(0, 1fr);
}
@media (max-width: 1100px) {
    .dd-stage,
    .dd-stage.rail-collapsed {
        grid-template-columns: 1fr;
    }
}
/* Devices LIST squeeze fix. The list table carries a ~800px min-width; beside
   the 240px rail it drops below that between ~1100-1400px, so its right columns
   (Last Seen / Actions) scroll-clip *under* the rail. Stack the rail below the
   full-width table until the viewport can hold the table's min-width + the rail.
   Scoped to .devices-page only — detail pages keep the 1100px breakpoint, their
   main column is flexible (chart), not min-width-bound. Headroom left for the
   upcoming device-State column (wider table). */
@media (max-width: 1400px) {
    .devices-page .dd-stage,
    .devices-page .dd-stage.rail-collapsed {
        grid-template-columns: 1fr;
    }
}

/* == Right-rail collapse (plan 03 / handoff .generated/handoff-alerts)
   ===================================================================
   Additive only -- the base .dd-stage above keeps its
   minmax(0,1fr) var(--page-rail-width) template and .dd-stage-no-rail
   modifier. One chevron at the top of the rail collapses both cards
   into a ~44px vertical strip, freeing horizontal width for the table.
   Same pattern/glyph as the left-nav + tenant-map gateway-rail
   collapses. NOTE: the handoff snippet redeclared a conflicting base
   .dd-stage in design-system.css; that was intentionally NOT taken
   (the canonical rule lives here) -- see plan 03 sec 2.1. */
.dd-stage.rail-collapsed {
    grid-template-columns: minmax(0, 1fr) 44px;
}

/* Toggle row sits above the cards: right-aligned when expanded,
   centered over the strip when collapsed. */
.dd-rail-toggle-row {
    display: flex;
    justify-content: flex-end;
}
.dd-stage.rail-collapsed .dd-rail-toggle-row {
    justify-content: center;
}
.dd-rail-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: 1px solid #e5e7eb;
    background: #fff;
    border-radius: 6px;
    color: #6b7280;
    cursor: pointer;
    padding: 0;
    transition:
        background 0.15s,
        color 0.15s,
        border-color 0.15s;
    flex: none;
}
.dd-rail-toggle:hover {
    background: var(--color-panel-header-tinted, #f5fbf7);
    color: #065f46;
    border-color: #bbf7d0;
}
.dd-rail-toggle:focus-visible {
    outline: 2px solid #25af88;
    outline-offset: 2px;
}
.dd-rail-toggle svg {
    transition: transform 0.2s;
}
.dd-stage.rail-collapsed .dd-rail-toggle svg {
    transform: rotate(180deg);
}

/* Collapsed: card body hides; header reorients to a vertical text
   strip (same writing-mode trick as the tenant-map gateway rail).
   The titles are wrapped in a <span> in
   _alerts_page_content_generic.html for this rule to match.

   SCOPING: these MUST be qualified by .dd-stage-rail. The Coverage-map
   card on the Map tab reuses .dd-rail-card* but lives in
   .dd-stage-main; an unscoped `.dd-stage.rail-collapsed
   .dd-rail-card-header` matched it too, so collapsing the rail forced
   the "Coverage map" header to flex-column and `> :not(span)` hid the
   Expand button (the "title + Expand on two lines / chrome breaks when
   collapsed" bug). Rail-only keeps the vertical-strip trick where it
   belongs and leaves main-column cards untouched. */
.dd-stage.rail-collapsed .dd-stage-rail .dd-rail-card-body {
    display: none;
}
.dd-stage.rail-collapsed .dd-stage-rail .dd-rail-card-header {
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    padding: 14px 4px;
    border-bottom: 0;
    min-height: 140px;
}
.dd-stage.rail-collapsed .dd-stage-rail .dd-rail-card-header > span {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    letter-spacing: 0.04em;
    font-size: 12px;
}
/* Collapsed strip shows only the rotated label -- hide any other
   header children (e.g. the gateway-rail "See all" aux link) so the
   44px strip stays clean. */
.dd-stage.rail-collapsed .dd-stage-rail .dd-rail-card-header > :not(span) {
    display: none;
}
.dd-stage-main {
    min-width: 0;
    /* Wide tables (devices list table has 7 columns including Actions)
       can exceed the 1fr column at narrow viewports — without
       overflow-x:auto they render *under* the 320px rail and clip the
       Actions column. Scoped to direct table descendants so the rest of
       the page chrome stays in normal flow. */
    overflow-x: hidden;
}
.dd-stage-main > div,
.dd-stage-main .table-container,
.dd-stage-main .table-container-box {
    max-width: 100%;
    overflow-x: auto;
}

/* == Tab patterns v2 (plan 04 / handoff .generated/handoff-tabs-pattern-v1)
   ===================================================================
   Three components, one canonical class family. Supersedes the §5.1b
   .dd-main-tab-bar (kept its operator-approved underline look; v2 adds
   Rule 1 equal-width grid + the L1/L2 hierarchy + a pills component for
   view-settings). Codebase deltas vs. the raw handoff CSS: dual
   `button, a` selectors (several bars are <a>, incl. the HTMX
   metric/resolution pills which are <a role="button">), token vars
   with hex fallbacks (Phase-1 graceful-degradation convention), ASCII
   comments. JS is id/.active/data-tab based and never keyed off the
   bar class, so the .dd-main-tab-bar -> .patitur-tab-bar rename is
   CSS+template-only. The old .gateway-detail-page flex:0 0 auto
   override is dropped -- obsolete under fit-content (every bar now
   hugs content). .dd-tab-content:not(.active) (below) is unchanged. */

/* -- L1 underline tabs. Rule 1: equal-width tracks sized to the widest
   label; the bar hugs its content and never stretches to fill. -- */
.patitur-tab-bar {
    display: inline-grid;
    grid-auto-flow: column;
    grid-auto-columns: 1fr;
    width: fit-content;
    gap: 0.25rem;
    padding: 0;
    background: transparent;
    border: none;
    border-bottom: 1px solid var(--border-base, #e5e7eb);
    border-radius: 0;
    margin-bottom: 1rem;
    /* The "mystery vertical symbol next to the Positioning tab" was a
       macOS vertical scrollbar. A blocked third-party stylesheet
       (Flowbite CDN, possibly its tab/tablist preset) applies
       ``overflow: auto`` to this container; combined with the active
       button's ``margin-bottom: -1px`` + the bar's ``border-bottom:
       1px`` the bar reports 1 px of vertical overflow (clientHeight 42,
       scrollHeight 43), enough to trigger the OS scrollbar gutter.
       ``!important`` is required because the third-party rule we're
       overriding has higher cascade specificity (we couldn't introspect
       it across CORS), and tab bars never legitimately need scrolling.
       Without !important, a stale ``overflow: auto`` keeps winning. */
    overflow: visible !important;
}
.patitur-tab-bar button,
.patitur-tab-bar a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.5rem;
    padding: 0.625rem 1rem; /* 10/16px per spec */
    font-size: 0.875rem; /* 14px */
    font-weight: 500;
    border: none;
    border-bottom: 2px solid transparent; /* reserve the underline slot */
    border-radius: 0;
    color: var(--fg-4, #6b7280); /* inactive = text-muted */
    background: transparent;
    cursor: pointer;
    font-family: inherit;
    white-space: nowrap;
    text-decoration: none;
    margin-bottom: -1px; /* sit the underline over the bar's base rule */
    transition:
        color 0.12s,
        border-color 0.12s;
}
.patitur-tab-bar button:hover,
.patitur-tab-bar a:hover {
    background: transparent;
    color: var(--fg-2, #333);
}
.patitur-tab-bar button.active,
.patitur-tab-bar a.active {
    background: transparent;
    color: var(--fg-1, #101828);
    border-bottom-color: var(--color-brand-green, #25af88);
}
.patitur-tab-bar button:focus-visible,
.patitur-tab-bar a:focus-visible {
    outline: 2px solid var(--color-brand-green, #25af88);
    outline-offset: -2px;
    border-radius: 4px;
}
.patitur-tab-bar button svg,
.patitur-tab-bar a svg {
    width: 1rem;
    height: 1rem;
    flex-shrink: 0;
}
.dd-tab-count {
    font-size: 0.6875rem;
    font-weight: 600;
    padding: 1px 7px;
    border-radius: 9999px;
    background: var(--device-gray-100);
    color: var(--device-gray-500);
}
.patitur-tab-bar button.active .dd-tab-count,
.patitur-tab-bar a.active .dd-tab-count {
    background: rgba(37, 175, 136, 0.14); /* brand-green tint */
    color: var(--color-brand-green, #25af88);
}

/* -- L2 underline tabs. Rule 2: same component, visibly subordinate to
   L1 (smaller, lighter, on a tinted strip, 1.5px inset underline so
   the strip's bottom border stays continuous). -- */
.patitur-tab-bar--l2 {
    border-bottom: none; /* the .l2-tab-strip owns the baseline */
}
.patitur-tab-bar--l2 button,
.patitur-tab-bar--l2 a {
    padding: 0.5rem 1.125rem; /* 8/18px per spec */
    font-size: 0.8125rem; /* 13px */
    color: #9ca3af;
    border-bottom-width: 0;
}
.patitur-tab-bar--l2 button:hover,
.patitur-tab-bar--l2 a:hover {
    color: #4a5565;
}
.patitur-tab-bar--l2 button.active,
.patitur-tab-bar--l2 a.active {
    color: var(--color-brand-green, #25af88);
    box-shadow: inset 0 -1.5px 0 var(--color-brand-green, #25af88);
    border-bottom-color: transparent;
}
.l2-tab-strip {
    padding: 0 12px;
    background: #f9fafb;
    border-bottom: 1px solid var(--border-base, #e5e7eb);
}

/* -- Segmented pills. Rule 3: a view-setting toggle (same content,
   different rendering rule -- e.g. heat-map metric / H3 resolution),
   NOT navigation. Sized to content; does not follow Rule 1. The
   tenant heat-map bars are <a role="button"> (HTMX re-render of the
   same panel via #tenantHeatmapSwapTarget), so anchors are styled
   too. -- */
.patitur-tab-pills {
    display: inline-flex;
    gap: 4px;
    background: #f9fafb;
    padding: 4px;
    border-radius: 8px;
    border: 1px solid var(--border-base, #e5e7eb);
}
.patitur-tab-pills button,
.patitur-tab-pills a {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 0.375rem 0.75rem; /* 6/12px per spec */
    font-size: 0.75rem; /* 12px */
    font-weight: 500;
    border-radius: 6px;
    border: none;
    background: transparent;
    color: #4a5565;
    font-family: inherit;
    cursor: pointer;
    white-space: nowrap;
    text-decoration: none;
    transition:
        background 0.15s,
        color 0.15s;
}
.patitur-tab-pills button:hover:not(.active),
.patitur-tab-pills a:hover:not(.active) {
    background: #fff;
    color: #1f2937;
}
.patitur-tab-pills button.active,
.patitur-tab-pills a.active {
    background: var(--color-brand-green, #25af88);
    color: #fff;
}

/* Off-state uses :not(.active) so its specificity beats Tailwind
   single-class utilities like ``flex`` / ``block`` that callers may
   put on the wrapper (the tenant-detail Map sub-tabs do, so the map
   fills the column height when active). The active state has no
   explicit display rule on purpose — the element falls back to its
   natural display (``block`` for sections/divs) or to whatever
   utility class the caller applied (``flex`` for the heat-map
   wrapper that needs the column-height fill). */
.dd-tab-content:not(.active) {
    display: none;
}

/* ── Right rail card chrome (filled by PR-4 / PR-5) ───────────────── */
.dd-rail-card {
    background: #fff;
    border: 1px solid var(--device-gray-200);
    border-radius: 0.75rem;
    overflow: hidden;
}
.dd-rail-card + .dd-rail-card {
    margin-top: 0.875rem;
}
.dd-rail-card-header {
    padding: 0.75rem 0.875rem;
    font-size: 0.75rem;
    font-weight: 700;
    color: var(--device-gray-500);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    border-bottom: 1px solid var(--device-gray-100);
    display: flex;
    align-items: center;
    justify-content: space-between;
}
/* Body padding mirrors the header so the rail content has a visible
   12/14 px gutter on every side. Without this rule the body text sat
   flush to the card border (operator feedback: "no spacing"). Cards
   that need a different inner layout (e.g. dd-rail-bar-row with its
   own padded rows) can override on more specific selectors. */
.dd-rail-card-body {
    padding: 0.75rem 0.875rem;
}

/* Leaflet-managed containers should never grow a UA scrollbar. Same
   pattern as the .patitur-tab-bar fix above: a CORS-blocked third-
   party stylesheet (Flowbite, likely its responsive-table preset)
   applies ``overflow-x: auto`` on map containers and the small extra
   tile/SVG-pane content past the viewport triggers a 2 px scrollbar
   gutter on the bottom edge. Leaflet does its own clipping via
   absolute positioning on the panes; the container itself never
   needs scrollbars. ``!important`` because the third-party rule has
   higher cascade specificity. */
.leaflet-container {
    overflow: hidden !important;
}

/* Configuration-tab card width — the .dd-rail-card / .dd-rail-row
   chrome was designed for the 240 px right-rail (label + value
   tight against each other). On the gateway-detail Configuration
   tab those same cards live in the full-width .dd-stage-main, where
   ``justify-content: space-between`` smears the label and value to
   opposite ends with a huge empty gap between. Pinning the card to a
   readable max-width keeps the operator's eye-track short. Scoped to
   the Configuration tab only — other tabs (Map, Devices, Alerts,
   Positioning) host full-width content that the rule should NOT
   touch. */
#gw-tabpanel-config .dd-rail-card,
#device-tabpanel-config .dd-rail-card {
    max-width: 640px;
}

/* Positioning-toolbar mode buttons — the Method / Clusters / Radial-
   scatter trio. Previously only had Tailwind utilities (px-3 py-1.5
   font-medium), so the inactive Clusters button rendered as plain
   text and read like a label. These rules give the unpressed state a
   hover affordance and the aria-pressed=true state a brand-tinted fill
   so the operator can tell at a glance which mode is active. */
.pos-mode-btn {
    background: #fff;
    color: var(--device-gray-700, #344054);
    cursor: pointer;
    transition:
        background 0.12s,
        color 0.12s;
}
.pos-mode-btn:hover:not(:disabled):not([aria-pressed="true"]) {
    background: var(--device-gray-50, #f9fafb);
    color: var(--device-gray-900, #101828);
}
.pos-mode-btn[aria-pressed="true"] {
    background: rgba(37, 175, 136, 0.12);
    color: var(--color-brand-green, #25af88);
}
.pos-mode-btn:disabled {
    cursor: not-allowed;
}
.dd-rail-card-header-aux {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 0.6875rem;
    color: var(--device-gray-700);
    letter-spacing: 0;
    text-transform: none;
}
.dd-rail-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.5rem 0.875rem;
    font-size: 0.75rem;
    border-bottom: 1px solid var(--device-gray-50);
}
.dd-rail-row:last-child {
    border-bottom: none;
}
.dd-rail-row-label {
    color: var(--device-gray-500);
    flex-shrink: 0;
}
.dd-rail-row-value {
    color: var(--device-gray-900);
    font-weight: 500;
    text-align: right;
    min-width: 0;
    overflow-wrap: anywhere;
}
.dd-rail-row-value.mono {
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.6875rem;
}

/* Standalone monospace utility — same stack as .dd-rail-row-value.mono
   but usable on any element that doesn't already carry the rail-row
   value chrome (e.g. inline coordinate strings inside a flex row). */
.dd-mono {
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

/* ── Rail proportion-bar rows (Status / Importance breakdown cards on
   the devices + gateways list rails — PR-8). Two-line row: top has a
   label on the left and ``count · pct`` on the right; below sits a 4 px
   track with a coloured fill. Inline ``style="width: N%"`` drives the
   fill width; class drives the colour. */
.dd-rail-bar-row {
    padding: 0.5rem 0.875rem;
    border-bottom: 1px solid var(--device-gray-50);
    font-size: 0.75rem;
}
.dd-rail-bar-row:last-child {
    border-bottom: none;
}
.dd-rail-bar-row-meta {
    display: flex;
    justify-content: space-between;
    margin-bottom: 0.25rem;
}
.dd-rail-bar-row-label {
    color: var(--device-gray-700);
    font-weight: 500;
}
.dd-rail-bar-row-count {
    color: var(--device-gray-500);
    font-size: 0.6875rem;
    font-variant-numeric: tabular-nums;
}
.dd-rail-bar-track {
    height: 4px;
    background: var(--device-gray-100);
    border-radius: 2px;
    overflow: hidden;
}
.dd-rail-bar-fill {
    height: 100%;
    background: var(--device-gray-400);
    transition: width 0.2s ease;
}

.dd-rail-bar-fill-online {
    background: var(--color-status-pill-text-online, #1a7f5f);
}
.dd-rail-bar-fill-offline {
    background: var(--color-status-pill-text-danger, #c93636);
}
.dd-rail-bar-fill-critical {
    background: var(--color-status-pill-text-danger, #c93636);
}
.dd-rail-bar-fill-high {
    background: #ff5e5e;
}
.dd-rail-bar-fill-medium {
    background: var(--color-status-pill-text-warning, #b86e0f);
}
.dd-rail-bar-fill-low {
    background: var(--color-status-pill-text-info, #2e7db5);
}
.dd-rail-bar-fill-unknown {
    background: var(--device-gray-400);
}

/* ── Recent alerts (rail card 3) ───────────────────────────────────────
   Mirrors device-detail-tenant.html mockup: 4px severity bar, two-line
   meta (LAF + severity, then alert name), right-aligned timestamp. The
   row is a button (HTMX click → alert details modal); the bar uses
   ``align-self: stretch`` so it spans the full row height regardless of
   how the meta wraps. */
.dd-rail-alert {
    display: grid;
    grid-template-columns: 4px 1fr auto;
    gap: 0.625rem;
    padding: 0.625rem 0.875rem;
    border-bottom: 1px solid var(--device-gray-100);
    background: none;
    border-left: none;
    border-right: none;
    border-top: none;
    width: 100%;
    text-align: left;
    cursor: pointer;
    font-family: inherit;
    font-size: 0.75rem;
    color: inherit;
    align-items: center;
}
.dd-rail-alert:last-child {
    border-bottom: none;
}
.dd-rail-alert:hover {
    background: var(--device-gray-50);
}
.dd-rail-alert-bar {
    background: var(--color-status-pill-text-warning, #b86e0f);
    border-radius: 2px;
    align-self: stretch;
}
/* Severity-bar palette. Critical uses the danger pill token; low uses
   the info pill token. High (#ff5e5e) and medium (#fe9239) don't have
   1:1 equivalents in design-system.css today — high is a *lighter*
   red than --color-status-pill-text-danger so the bar stack stays
   visually distinct row-to-row, and medium (#fe9239) matches
   GATEWAY_DIFFERENCE_COLOR in flask_app/constants/signal_metrics.py.
   Worth a follow-up to mint --color-severity-bar-{high,medium} tokens
   if the palette gets reused elsewhere, but until then the partial
   var() coverage is intentional, not a typo. */
.dd-rail-alert.sev-critical .dd-rail-alert-bar {
    background: var(--color-status-pill-text-danger, #c93636);
}
.dd-rail-alert.sev-high .dd-rail-alert-bar {
    background: #ff5e5e;
}
.dd-rail-alert.sev-medium .dd-rail-alert-bar {
    background: #fe9239;
}
.dd-rail-alert.sev-low .dd-rail-alert-bar {
    background: var(--color-status-pill-text-info, #2e7db5);
}
.dd-rail-alert-meta {
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.125rem;
}
.dd-rail-alert-laf {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 0.625rem;
    letter-spacing: 0.04em;
    color: var(--color-status-pill-text-warning, #b86e0f);
    text-transform: uppercase;
}
.dd-rail-alert.sev-critical .dd-rail-alert-laf {
    color: #c93636;
}
.dd-rail-alert.sev-high .dd-rail-alert-laf {
    color: #ff5e5e;
}
.dd-rail-alert.sev-low .dd-rail-alert-laf {
    color: var(--color-status-pill-text-info, #2e7db5);
}
.dd-rail-alert-name {
    font-weight: 600;
    color: var(--device-gray-900);
    overflow-wrap: anywhere;
}
.dd-rail-alert-time {
    font-size: 0.625rem;
    color: var(--device-gray-500);
    align-self: center;
    white-space: nowrap;
}

/* ── Empty-state placeholder (Alerts tab + rail before PR-4 / PR-5) ── */
.dd-empty-state {
    background: #fff;
    border: 1px dashed var(--device-gray-300);
    border-radius: 0.75rem;
    padding: 2.5rem 1.5rem;
    text-align: center;
    color: var(--device-gray-500);
    font-size: 0.875rem;
}
.dd-empty-state .dd-empty-state-title {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 600;
    color: var(--device-gray-700);
    margin-bottom: 0.375rem;
    font-size: 0.9375rem;
}
/* Modifier — compact variant for rail cards and KPI tile sub-areas
   where the full 2.5rem padding feels heavy. Replaces the inline
   ``style="padding:1.25rem 0.875rem;"`` + ``style="font-size:0.6875rem;"``
   patterns that used to live on those call sites. */
.dd-empty-state-compact {
    padding: 1.25rem 0.875rem;
}
.dd-empty-state-compact .dd-empty-state-aux {
    font-size: 0.6875rem;
}

/* ── Signal-tab per-gateway chrome (Wave-0) ───────────────────────────
   Field-tab bar / window selector / mode bar / gateway chip bar / per-
   gateway summary cards. All scoped to .dd-signal-panel so they don't
   leak into other panels that use the same dashboard-card chrome.
   See memory-bank/tasks/feature-v0.8.0-stage-1/analysis/phase-2/
   DEVICE-DETAIL-WAVE-0-PLAN.md §3.6 for the design and
   device-detail-redesigned.html lines 271-398 for the visual target. */

.dd-field-bar {
    display: flex;
    align-items: center;
    gap: 0.375rem;
    flex-wrap: wrap;
    padding: 0.875rem 0 0.75rem;
    border-bottom: 1px solid var(--device-gray-100);
    margin-bottom: 0.875rem;
}
.dd-field-bar-label {
    font-size: 0.6875rem;
    font-weight: 700;
    color: var(--device-gray-500);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin-right: 0.25rem;
}
.dd-field-bar-divider {
    width: 1px;
    align-self: stretch;
    background: var(--device-gray-200);
    margin: 0 0.375rem;
}
.dd-field-tab {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.75rem;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--device-gray-600);
    background: var(--device-gray-50);
    border: 1px solid var(--device-gray-200);
    border-radius: 0.5rem;
    cursor: pointer;
    font-family: inherit;
    transition:
        background-color 0.12s,
        color 0.12s;
}
.dd-field-tab:hover {
    background: #fff;
    color: var(--device-gray-900);
}
.dd-field-tab.active {
    background: var(--device-gray-900);
    color: #fff;
    border-color: var(--device-gray-900);
}
.dd-field-unit {
    font-size: 0.625rem;
    opacity: 0.7;
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}
/* The ``info-help-icon`` markup comes from
   flask_app/static/css/compliance/tooltip.css — colour passes through
   when nested inside an active (dark) field tab. */
.dd-field-tab.active .info-help-icon svg {
    color: rgba(255, 255, 255, 0.75);
}

.dd-window-bar {
    display: inline-flex;
    background: var(--device-gray-100);
    border-radius: 0.5rem;
    padding: 0.1875rem;
    gap: 0.125rem;
}
.dd-window-bar button {
    padding: 0.3125rem 0.75rem;
    font-size: 0.75rem;
    font-weight: 500;
    border-radius: 0.375rem;
    color: var(--device-gray-500);
    background: transparent;
    border: none;
    cursor: pointer;
    font-family: "Ubuntu Sans", sans-serif;
    min-width: 2.25rem;
}
.dd-window-bar button.active {
    background: var(--device-gray-900);
    color: #fff;
}

.dd-mode-bar {
    display: inline-flex;
    background: var(--device-gray-100);
    border-radius: 0.625rem;
    padding: 0.1875rem;
    gap: 0.125rem;
}
.dd-mode-bar button {
    padding: 0.375rem 0.875rem;
    font-size: 0.75rem;
    font-weight: 500;
    border-radius: 0.5rem;
    color: var(--device-gray-500);
    background: transparent;
    border: none;
    cursor: pointer;
    font-family: inherit;
}
.dd-mode-bar button.active {
    background: var(--color-brand-green, #25af88);
    color: #fff;
}
.dd-mode-bar button:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}

.dd-gw-chip-bar {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    padding: 0.875rem 0;
    border-bottom: 1px solid var(--device-gray-100);
    background: var(--device-gray-50);
    margin: 0 -0.875rem 0.875rem;
    padding-left: 0.875rem;
    padding-right: 0.875rem;
}
.dd-gw-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.375rem 0.75rem;
    border-radius: 9999px;
    border: 1.5px solid var(--device-gray-300);
    background: #fff;
    font-size: 0.75rem;
    font-weight: 600;
    color: var(--device-gray-700);
    cursor: pointer;
    user-select: none;
    font-family: inherit;
    transition:
        opacity 0.12s,
        border-color 0.12s;
}
.dd-gw-chip-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    flex-shrink: 0;
}
.dd-gw-chip:not(.on) {
    opacity: 0.45;
    text-decoration: line-through;
    background: var(--device-gray-50);
}
.dd-gw-chip.on {
    /* Per-gateway colour piped via inline ``--gw-color`` custom prop
       in the template — keeps the palette server-side per
       constants/signal_metrics.py:GATEWAY_PALETTE without inflating
       this stylesheet with N hard-coded colours. */
    border-color: var(--gw-color, var(--device-gray-300));
}
.dd-gw-chip-aggregate {
    border-style: dashed;
}

.dd-gw-summary-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 0.75rem;
    padding-top: 0.875rem;
    border-top: 1px solid var(--device-gray-100);
    margin-top: 0.875rem;
}
.dd-gw-summary {
    border: 1px solid var(--device-gray-200);
    border-radius: 0.625rem;
    padding: 0.75rem 0.875rem;
    transition: opacity 0.12s;
}
.dd-gw-summary.off {
    opacity: 0.45;
}
.dd-gw-summary-head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 0.5rem;
    margin-bottom: 0.5rem;
}
.dd-gw-summary-name {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 0.8125rem;
    color: var(--device-gray-900);
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.dd-gw-summary-dot {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 50%;
    flex-shrink: 0;
}
.dd-gw-summary-eui {
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.625rem;
    color: var(--device-gray-500);
    margin-top: 0.125rem;
    margin-left: 1.125rem;
}
.dd-gw-summary-stats {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 0.5rem;
}
.dd-gw-stat-label {
    font-size: 0.5625rem;
    font-weight: 700;
    color: var(--device-gray-500);
    text-transform: uppercase;
    letter-spacing: 0.05em;
}
.dd-gw-stat-value {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 0.9375rem;
    color: var(--device-gray-900);
    margin-top: 0.125rem;
}
.dd-gw-stat-unit {
    font-size: 0.625rem;
    font-weight: 500;
    color: var(--device-gray-500);
    margin-left: 0.125rem;
}

.dd-gw-status-tag {
    font-size: 0.625rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    flex-shrink: 0;
}
/* Signal-band swatches (mirror flask_app/constants/signal_metrics.py
   BAND_COLORS — single source of truth across Python, CSS, and the
   gateway-marker JS which reads ``entry.band_color`` directly).
   Strong/fair share their tints with --color-status-pill-*-online and
   --color-status-pill-*-warning; weak intentionally uses a softer red
   (#b91c1c) than the full-danger pill (#c93636) so a gateway in the
   Weak band reads distinct from a fully offline device. Keep the
   literals — consolidating into shared CSS vars here would couple the
   "weak signal" semantic to "offline device", which they aren't. */
.dd-gw-status-tag-strong {
    background: #e8f9f3;
    color: #1a7f5f;
}
.dd-gw-status-tag-fair {
    background: #fff3e8;
    color: #b86e0f;
}
.dd-gw-status-tag-weak {
    background: #fee2e2;
    color: #b91c1c;
}
.dd-gw-status-tag-unknown {
    background: var(--device-gray-100);
    color: var(--device-gray-500);
}

/* Rail "Gateways heard" card rows — one row per gateway, click-through
   to gateway-detail. Compact two-column stats footer keeps the row
   under 70px so 5 rows fit in the rail without scroll. */
.dd-rail-gateway {
    display: block;
    padding: 0.625rem 0.875rem;
    border-bottom: 1px solid var(--device-gray-100);
    text-decoration: none;
    color: inherit;
    transition: background-color 0.12s;
}
.dd-rail-gateway:last-child {
    border-bottom: none;
}
.dd-rail-gateway:hover {
    background: var(--device-gray-50);
}
.dd-rail-gateway-name {
    display: block;
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 0.8125rem;
    color: var(--device-gray-900);
    margin-bottom: 0.125rem;
}
.dd-rail-gateway-eui {
    display: block;
    font-family:
        ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    font-size: 0.625rem;
    color: var(--device-gray-500);
    margin-bottom: 0.375rem;
}
.dd-rail-gateway-stats {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0.375rem;
    font-size: 0.6875rem;
}
.dd-rail-gateway-stat-label {
    color: var(--device-gray-500);
    margin-right: 0.25rem;
}
.dd-rail-gateway-stat-value {
    color: var(--device-gray-900);
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
}

/* ── Network Health (stage-1 phase-1 §3.2 Lite) ────────────────────
   Standalone Network Health page chrome. Mirrors the analyze-section
   wrapper rule above; the KPI grid + placeholder pill below are
   page-specific so they don't leak. The phase-2 tiles render in a
   muted state so the operator sees what's coming without confusing
   "0" with "not implemented." */
/* Network Health KPI tiles use the canonical design-system .dd-kpi
   classes verbatim (same look as /gateways + /devices + /alerts) —
   the prior bespoke .nh-kpi-grid / .nh-kpi-tile / .nh-kpi-label /
   .nh-kpi-value / .nh-kpi-fraction / .nh-kpi-sub variants were
   removed in favour of .dd-kpi-strip / .dd-kpi / .dd-kpi-label /
   .dd-kpi-value / .dd-kpi-value-unit / .dd-kpi-sub. Only the
   icon-inline-with-label modifier + accent variants live here. */
.nh-kpi-label-icon {
    display: inline-flex;
    align-items: center;
    margin-right: 0.375rem;
    color: var(--device-gray-400, #9ca3af);
    vertical-align: -2px;
}
/* Headline-tile colour accents — applied to the 5 .dd-kpi tiles that
   answer health questions (Gateways online, Open alerts, Mean RSSI,
   Resilient positioning, Fragile cells). Two reinforcing channels
   per tile (coloured value text + tinted leading icon). The other
   4 count-context tiles (Active devices, Devices located, Good-
   signal band, Signal clusters) stay neutral so colour means
   something. Hexes mirror SIGNAL_BAND_STRONG/FAIR/WEAK_COLOR in
   constants/signal_metrics.py — same palette the hero verdict and
   the redundancy map cells read against. Flat fills only, no
   asymmetric thick edges or shadows (those read as bevels). */
.dd-kpi.nh-kpi-accent-green .dd-kpi-value,
.dd-kpi.nh-kpi-accent-green .nh-kpi-label-icon {
    color: #1a7f5f;
}
.dd-kpi.nh-kpi-accent-amber .dd-kpi-value,
.dd-kpi.nh-kpi-accent-amber .nh-kpi-label-icon {
    color: #b86e0f;
}
.dd-kpi.nh-kpi-accent-red .dd-kpi-value,
.dd-kpi.nh-kpi-accent-red .nh-kpi-label-icon {
    color: #b91c1c;
}
.nh-kpi-tile--accent-neutral {
    /* Sentinel — applied when the underlying value is None (the
       headline tile literally has nothing to verdict). Same look as
       the base .nh-kpi-tile so the absence reads as "no data yet";
       icon stays in its neutral grey default. */
}

/* Hero verdict banner — single coloured strip above the KPI grid,
   answers "should I worry?" at a glance. Driven by the same
   resilient_positioning_pct the map cells aggregate against.
   Compact one-line layout: bold label + trailing summary on the
   same row, no stacked eyebrow row. Flat 1px border — no
   asymmetric thick edge (read as a bevel); the verdict pop comes
   from the bg tint + the label colour. */
.nh-verdict {
    border: 1px solid;
    border-radius: 0.5rem;
    padding: 0.625rem 1rem;
    margin-bottom: 1rem;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0.625rem;
}
.nh-verdict-label {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 1rem;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    flex-shrink: 0;
}
.nh-verdict-summary {
    font-size: 0.875rem;
    color: var(--device-gray-700, #374151);
    margin: 0;
    flex: 1;
    min-width: 0;
}
.nh-verdict--robust {
    background: #ecfdf5;
    border-color: #1a7f5f;
}
.nh-verdict--robust .nh-verdict-label {
    color: #1a7f5f;
}
.nh-verdict--mixed {
    background: #fffbeb;
    border-color: #b86e0f;
}
.nh-verdict--mixed .nh-verdict-label {
    color: #b86e0f;
}
.nh-verdict--fragile {
    background: #fef2f2;
    border-color: #b91c1c;
}
.nh-verdict--fragile .nh-verdict-label {
    color: #b91c1c;
}
.nh-verdict--unknown {
    background: var(--device-gray-50, #f9fafb);
    border-color: var(--device-gray-300, #d1d5db);
}
.nh-verdict--unknown .nh-verdict-label {
    color: var(--device-gray-600, #4b5563);
}

/* Org-page worst-tenants table — chrome uses Tailwind utility
   classes inline in the template (matches the design-system pattern
   the policies + glossary + compliance tables use). Only the two
   table-specific bits that don't reduce cleanly to Tailwind live
   here: the sortable column-header button + the per-row verdict
   pill colour variants. */
.nh-sort-btn {
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
    padding: 0;
    background: transparent;
    border: 0;
    font: inherit;
    color: inherit;
    text-transform: inherit;
    letter-spacing: inherit;
    cursor: pointer;
}
.nh-sort-btn:hover,
.nh-sort-btn:focus-visible {
    color: var(--device-gray-900, #101828);
    outline: none;
}
.nh-sort-arrow {
    min-width: 0.75rem;
    text-align: center;
    color: var(--device-gray-400, #9ca3af);
    font-weight: 700;
}
/* Per-row verdict pill — same palette the hero banner + map cells
   use, just shrunk for the table cell. */
.nh-org-tenants-pill {
    display: inline-block;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    font-size: 0.6875rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.nh-org-tenants-pill--robust {
    background: #ecfdf5;
    color: #1a7f5f;
}
.nh-org-tenants-pill--mixed {
    background: #fffbeb;
    color: #b86e0f;
}
.nh-org-tenants-pill--fragile {
    background: #fef2f2;
    color: #b91c1c;
}
.nh-org-tenants-pill--unknown {
    background: var(--device-gray-100, #f3f4f6);
    color: var(--device-gray-600, #4b5563);
}

/* Phase-2 pill — mirrors the alert-map "Per-device disabled" affordance:
   visible-but-not-faked. Operator reads "we know this exists, it's not
   yet wired" without seeing a zero that could be misread as a real
   value. */
.nh-phase-pill {
    display: inline-flex;
    align-items: center;
    padding: 0.125rem 0.5rem;
    border-radius: 9999px;
    background: var(--device-gray-100, #f3f4f6);
    color: var(--device-gray-600, #4b5563);
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

/* Map-area placeholder card — same dashed-border / muted-bg posture
   as the phase-2 KPI tiles. */
.nh-map-placeholder {
    background: var(--device-gray-50, #f9fafb);
    border: 1px dashed var(--device-gray-300, #d1d5db);
    border-radius: 0.75rem;
    padding: 2.5rem 1.25rem;
    text-align: center;
}
.nh-map-placeholder-inner {
    max-width: 38rem;
    margin: 0 auto;
}
.nh-map-placeholder-icon {
    width: 2.5rem;
    height: 2.5rem;
    color: var(--device-gray-300, #d1d5db);
    margin: 0 auto 0.75rem;
    display: block;
}
.nh-map-placeholder-title {
    font-family: "Ubuntu Sans", sans-serif;
    font-weight: 700;
    font-size: 1rem;
    color: var(--device-gray-700, #374151);
    margin: 0 0 0.5rem;
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.nh-map-placeholder-body {
    font-size: 0.8125rem;
    color: var(--device-gray-500, #6b7280);
    margin: 0;
    line-height: 1.5;
}
.nh-map-placeholder-actions {
    margin: 1rem 0 0;
    font-size: 0.8125rem;
}
.nh-heatmap-container,
.nh-redundancy-container {
    min-height: 540px;
    border: 1px solid var(--device-gray-200, #e5e7eb);
    border-radius: 0.75rem;
    background: #fff;
    overflow: hidden;
}
.nh-heatmap-footnote {
    margin: 0.5rem 0 0;
    font-size: 0.75rem;
    color: var(--device-gray-500, #6b7280);
    text-align: right;
}

/* ============================================================
   Cluster Posterior tab (FE 1.4, v0.9.0) — tier hero, posterior
   bars, factor waterfall. Flat fills only (no bevels). Tokens
   from design-tokens.css.
   ============================================================ */

.dd-layout {
    display: grid;
    grid-template-columns: 1fr;
    gap: 16px;
}

/* ── Tier hero ─────────────────────────────────────────────── */
.tier-hero {
    border: 1px solid var(--border-base);
    border-radius: 10px;
    padding: 16px 18px;
    background: var(--bg-page);
    margin-bottom: 16px;
}
.tier-hero-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}
.tier-hero-pill {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 6px 12px;
    border-radius: 9999px;
    font-weight: var(--fw-semibold);
    border: 1px solid var(--border-base);
    color: var(--fg-2);
}
.tier-hero-pill .shape-i {
    display: inline-flex;
}
.tier-hero-pill.definitely {
    color: var(--color-brand-green);
    border-color: var(--color-brand-green);
}
.tier-hero-pill.probably {
    color: var(--sev-medium-fg);
    border-color: var(--sev-medium-fg);
}
.tier-hero-pill.weakly {
    color: var(--sev-high-fg);
    border-color: var(--sev-high-fg);
}
.tier-hero-pill.unclustered {
    color: var(--fg-4);
    border-color: var(--border-base);
}
.tier-hero-cluster-link {
    font-weight: var(--fw-semibold);
    color: var(--color-brand-green);
}
.tier-hero-confidence {
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: var(--fs-lg, 1.125rem);
    color: var(--fg-1);
    text-align: right;
}
.tier-hero-confidence-sub {
    display: block;
    font-family: var(--font-base, inherit);
    font-size: var(--fs-xs);
    font-weight: 400;
    color: var(--fg-4);
}
.tier-hero-secondary {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 22px;
    margin-top: 12px;
    font-size: var(--fs-sm);
    color: var(--fg-3);
}

/* ── Card with head ────────────────────────────────────────── */
.card-with-head {
    border: 1px solid var(--border-base);
    border-radius: 10px;
    margin-bottom: 16px;
    background: var(--bg-card, #fff);
}
.card-with-head .head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 16px;
    border-bottom: 1px solid var(--border-base);
}
.card-with-head .head h3 {
    font-size: var(--fs-sm);
    font-weight: var(--fw-semibold);
    color: var(--fg-1);
    margin: 0;
}
.card-with-head .head .sub {
    font-size: var(--fs-xs);
    color: var(--fg-4);
}
.card-with-head .body {
    padding: 14px 16px;
}

/* ── Posterior bars ────────────────────────────────────────── */
.posterior-row {
    display: grid;
    grid-template-columns: 22px 1fr 2fr 44px;
    align-items: center;
    gap: 10px;
    padding: 5px 0;
    font-size: var(--fs-sm);
}
.posterior-row .icon {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: var(--bg-page);
    color: var(--fg-3);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: var(--fs-xs);
    border: 1px solid var(--border-base);
}
.posterior-row.most-likely .icon {
    background: var(--color-brand-green);
    color: #fff;
    border-color: var(--color-brand-green);
}
.posterior-row .name {
    font-weight: 500;
    color: var(--fg-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.posterior-row .name .muted {
    opacity: 0.7;
    font-style: italic;
}
.posterior-row.most-likely .name {
    color: var(--color-brand-green);
    font-weight: 600;
}
.posterior-row .bar {
    height: 8px;
    background: var(--bg-page);
    border-radius: 9999px;
    overflow: hidden;
}
.posterior-row .fill {
    height: 100%;
    background: var(--sev-medium-fg);
    border-radius: 9999px;
}
.posterior-row.most-likely .fill {
    background: var(--color-brand-green);
}
.posterior-row.background .fill {
    background: var(--fg-5);
}
.posterior-row .pct {
    text-align: right;
    font-family: var(--font-mono);
    font-weight: 700;
    font-size: var(--fs-sm);
    color: var(--fg-1);
}
.posterior-entropy {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin-top: 12px;
    padding-top: 10px;
    border-top: 1px solid var(--border-base);
    font-size: var(--fs-xs);
    color: var(--fg-4);
}
.posterior-entropy .val {
    font-family: var(--font-mono);
    color: var(--fg-2);
    font-weight: 600;
}

/* ── Factor waterfall ──────────────────────────────────────── */
.waterfall-row {
    display: grid;
    grid-template-columns: 1fr 2fr 56px;
    align-items: center;
    gap: 10px;
    padding: 4px 0;
    font-size: var(--fs-sm);
}
.waterfall-row .label {
    color: var(--fg-2);
}
.waterfall-track {
    height: 8px;
    background: var(--bg-page);
    border-radius: 4px;
    position: relative;
    overflow: hidden;
}
.waterfall-fill {
    display: block;
    height: 100%;
    border-radius: 4px;
}
.waterfall-fill.pos {
    background: var(--color-brand-green);
}
.waterfall-fill.neg {
    background: var(--sev-high-fg);
}
.waterfall-row .val {
    text-align: right;
    font-family: var(--font-mono);
    font-weight: 700;
}
.waterfall-row .val.pos {
    color: var(--color-brand-green);
}
.waterfall-row .val.neg {
    color: var(--sev-high-fg);
}
.waterfall-total {
    display: grid;
    grid-template-columns: 1fr 56px;
    gap: 10px;
    margin-top: 10px;
    padding-top: 10px;
    border-top: 1px solid var(--border-base);
    font-weight: var(--fw-semibold);
}
.waterfall-total .val {
    text-align: right;
    font-family: var(--font-mono);
    font-weight: 700;
    color: var(--fg-1);
}
.waterfall-footer {
    margin-top: 12px;
    font-size: var(--fs-xs);
    color: var(--fg-4);
}
