.dashboard-page-container-volume {
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.dashboard-popout-top-strip-ops .popout-ops-select-wrap {
    padding: 0 !important;
    min-width: 150px;
    max-width: 170px;
}

.dashboard-popout-top-strip-ops .popout-ops-actions-row {
    padding: 0 !important;
    gap: 2px;
    justify-content: flex-end;
    flex-wrap: nowrap;
}

.pdf-capture-surface {
    position: fixed;
    left: -10000px;
    top: 0;
    width: 700px;
    padding: 0;
    z-index: -1;
    pointer-events: none;
    opacity: 1;
    background: #ffffff;
}

/* Progress overlay styles live in the shared ReportExportProgressOverlay component. */

.pdf-capture-grid {
    display: grid;
    grid-template-columns: 1fr !important;
    gap: 12px;
    width: 700px;
    justify-items: center;
    min-height: 0;
}

/* Capture cells are sized just tall enough to contain a typical report-view
   tile (header + marker description + Current State + Recommendations + risk
   footer) and a typical graph-view tile (header + chart + chip footer). The
   live grid renders these much taller (320px+) because each grid cell needs
   to fit the maximum chart/content variant; for capture we deliberately
   shrink to ~200px so the resulting images don't carry big internal
   whitespace bands when scaled into a 4-row landscape PDF page. The capture
   cell aspect (640 / 200 = 3.2) was picked so each tile renders ~130mm
   wide × ~40mm tall in the PDF — almost full column width with no wasted
   side margins. If you change the capture height here, also bump the
   headerRatio constant in app.js (compliance-overview-v2 branch) so the
   PDF-drawn header underline still lines up with the captured header. */
.pdf-capture-grid .dashboard-cell-paper {
    width: 640px !important;
    height: 200px !important;
    min-height: 200px !important;
    max-height: 200px !important;
}

/* Force-hide irrelevant view content per captured card so output is exclusively report or graph view. */
.pdf-capture-surface [id^="pdf-report-"] .cell-body {
    display: none !important;
}

.pdf-capture-surface [id^="pdf-graph-"] .report-view-content,
.pdf-capture-surface [id^="pdf-graph-"] .cell-report-body {
    display: none !important;
}

/* Suppress the duplicate marker title on the right (graph) tile — keep the
   header bar height so the body content remains aligned with the left tile. */
.pdf-capture-surface [id^="pdf-graph-"] .cell-title-wrap {
    visibility: hidden;
}

/* Pack the report body's content at the top instead of vertically centring it.
   The live grid uses justify-content:center inside .cell-report-body to balance
   the section blocks against tall (320px+) cards; in capture mode that creates
   big floating whitespace bands above + below the content because the tile is
   height-constrained but the content doesn't fill it. flex-start collapses
   that whitespace so what we capture is the actual content, not padded air.
   Tightened gap (5 → 3) and reduced padding-top so the body packs even
   denser inside the smaller capture cell. */
.pdf-capture-surface .cell-report-body {
    flex: 1 1 auto;
    height: auto !important;
    justify-content: flex-start !important;
    gap: 3px !important;
    padding-top: 4px !important;
}

/* The PDF draws one continuous line across both cards in JS, so suppress
   the per-card header underline inside the capture (otherwise the rasterised
   sub-pixel stroke wouldn't match the PDF-drawn vector line). */
.pdf-capture-surface .cell-header {
    border-bottom: none !important;
}

/* PDF capture should look like the live cards, minus interactive header icons. */
.pdf-capture-surface .tile-head-actions,
.pdf-capture-surface .tile-report-download-icon {
    display: none !important;
}

.dashboard-grid-scroll-with-filters {
    min-height: auto;
    justify-content: flex-start;
}

/* Compliance Overview's fill-panel scroll container is a simple vertical
   scroller — no inner flex column. (Consult-Volume Data adds extra flex
   layout for its bullet-chart rows in its own page CSS.) */
.dashboard-grid-scroll-fill-panel {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

/* Compliance Overview-specific column header — flex column with a 5px gap
   between the title and its underline, no fixed positioning. Differs from
   the Consult Volume Data version which uses position:relative + absolute
   ::after to align the underline with the column edges. */
.dashboard-col-header {
    font-size: 0.82rem;
    font-weight: 700;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    text-align: center;
    padding: 2px 0 6px 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 5px;
}

.dashboard-col-header::after {
    content: '';
    display: block;
    height: 2px;
    width: 100%;
    background: currentColor;
    border-radius: 0;
    opacity: 0.75;
}

/* Popout-only stack rules. The portal shell is now locked to a 1400 px
   minimum content width (see css/_tokens.css --gpc-portal-min-content),
   so the regular logged-in surface never reflows below that — users
   below the lock get a horizontal scrollbar instead of a stacked
   layout. The popout window (`?popout=1`) still renders inside its own
   tab/iframe at whatever width the user sized it to, so the narrow-
   viewport stack rules below remain valuable there. Scoping every rule
   to .dashboard-popout-main keeps them firing in popout mode only. */
@media (max-width: 959px) {
    .dashboard-popout-main .dashboard-page-container-volume {
        min-height: auto;
    }

    .dashboard-popout-main .dashboard-grid-scroll-fill-panel {
        overflow: visible;
        flex: none;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel {
        min-height: auto;
        display: grid;
        grid-template-columns: 1fr;
        gap: 12px;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-col-headers {
        display: none;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-wrapper {
        flex: none;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-wrapper,
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-cards,
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-cards > .mud-grid {
        display: contents;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-label,
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-label-spacer {
        display: none;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-row-cards > .mud-grid {
        height: auto;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .mud-grid-item {
        display: block;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .mud-grid-item > .mud-paper,
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-cell-paper {
        height: auto;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-section-hdr {
        display: block;
        padding: 4px 0;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-col-header {
        text-align: center;
        align-items: center;
    }

    .dashboard-popout-main .dashboard-grid-inner-fill-panel .dashboard-col-header::after {
        width: 100%;
        margin: 0 auto;
    }

    /* Column-first stacking for consult volume cards */
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-hdr-col1 { order: 0; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c1r1 { order: 1; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c1r2 { order: 2; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c1r3 { order: 3; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-hdr-col2 { order: 4; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c2r1 { order: 5; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c2r2 { order: 6; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c2r3 { order: 7; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-hdr-col3 { order: 8; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c3r1 { order: 9; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c3r2 { order: 10; }
    .dashboard-popout-main .dashboard-grid-inner-fill-panel .v-c3r3 { order: 11; }
}

/* ───────────────────────────────────────────────────────────────────
   Empty state for PA/GPM landing on Compliance Overview without a
   doctor selected (#4). Host fills the available compliance-grid
   height so the card sits dead-centre — both vertically and
   horizontally — in whatever space the marker grid would have used.
   ─────────────────────────────────────────────────────────────────── */
.cg-empty-state-host {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    /* Match the height the .cg-col-grid would have occupied: it is the
       only direct child of .dashboard-grid-inner in this branch, so
       we anchor to the viewport-minus-chrome budget the grid uses. */
    flex: 1 1 auto;
    min-height: calc(100vh - 240px);
    padding: 24px;
    box-sizing: border-box;
}

.cg-empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    gap: 14px;
    padding: 56px 40px;
    width: 100%;
    max-width: 640px;
    background: rgba(255, 255, 255, 0.97);
    border: 1px solid rgba(122, 134, 168, 0.18);
    border-radius: 14px;
    box-shadow: 0 4px 18px rgba(52, 56, 78, 0.08);
}

.cg-empty-state-icon {
    width: 72px;
    height: 72px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: linear-gradient(135deg, rgba(86, 92, 130, 0.12), rgba(52, 56, 78, 0.10));
    color: #34384E;
}

.cg-empty-state-icon .mud-icon-root {
    font-size: 38px;
    width: 38px;
    height: 38px;
}

.cg-empty-state-title {
    font-size: 1.25rem;
    font-weight: 600;
    color: #2A2E40;
    line-height: 1.3;
}

.cg-empty-state-body {
    font-size: 0.95rem;
    color: #5A6478;
    line-height: 1.55;
    max-width: 480px;
}

/* ── Column-major compliance grid ── */
.cg-col-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 6px;
    flex: 1;
    /* Fill the compliance scroll host without exceeding viewport height */
    min-height: 100%;
    align-items: stretch;
    /* Floor the grid at 1240 px so each column stays at least ~410 px
       wide (1240 ÷ 3 ≈ 413, minus the 6 px gaps and column padding).
       Below that the cards squash and the inner prose / chart content
       gets clipped. The portal lock on .logged-in-main (1400 px,
       css/layouts/logged-in.css) sits above this, so on a desktop the
       grid renders at the locked width and never hits this floor; on
       a narrower viewport the grid pushes through the page container
       (overflow: visible — see .dashboard2-page.mud-container below)
       and the .logged-in-layout's overflow-x: auto kicks in to give
       the user horizontal pan, exactly as the rest of the locked
       portal does. */
    min-width: 1240px;
}

/* Remove white gap between compliance group header and shaded column panel */
.cg-col-headers {
    margin-bottom: 0 !important;
}

.cg-col-head-grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 6px;
    width: 100%;
    /* Match the .cg-col-grid floor so the column headers and the
       column body stay aligned at every viewport — without this the
       headers would shrink to viewport width while the body clings to
       1240 px, producing a header-vs-body horizontal mismatch on
       narrow viewports. */
    min-width: 1240px;
}

/* Each column is position:relative so summary cell overlays anchor to it */
.cg-column {
    display: flex;
    flex-direction: column;
    /* Gap and padding tightened from 19/13 → 12/10 → 8/6 to fit 4 rows
       comfortably in the same viewport (12-tile / 4-row layout). */
    gap: 8px;
    position: relative;
    padding: 6px 0 6px 0;
    border-radius: 0 0 8px 8px;
    min-height: 100%;
    overflow: visible; /* allow overlay to escape the column bounds */
}

/* Lighter full-height column shading under each group header */
.cg-column-c1 { background: rgba(122, 184, 224, 0.05); }
.cg-column-c2 { background: rgba(74, 165, 176, 0.05); }
.cg-column-c3 { background: rgba(91, 96, 128, 0.05); }

/* Card header tints use the old group-header background colors */
.cg-column-c1 .cell-header { background: rgba(122, 184, 224, 0.22); }
.cg-column-c2 .cell-header { background: rgba(74, 165, 176, 0.22); }
.cg-column-c3 .cell-header { background: rgba(91, 96, 128, 0.22); }
.cg-column .cell-header { border-top: 1px solid #e2e2e2; }

/* Compliance group headers as filled tabs */
.cg-group-header {
    border-radius: 8px 8px 0 0;
    padding: 19px 10px 6px 10px;
    border-top: 1px solid rgba(0, 0, 0, 0.07);
    border-left: 1px solid rgba(0, 0, 0, 0.07);
    border-right: 1px solid rgba(0, 0, 0, 0.07);
    border-bottom: 1px solid #e6e6e6;
    box-sizing: border-box;
    color: #ffffff !important;
    min-height: 49px;
    display: flex;
    align-items: center;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
}

.cg-group-header::after {
    display: none;
}

.cg-group-header-c1 { background: #7AB8E0; }
.cg-group-header-c2 { background: #4AA5B0; }
.cg-group-header-c3 { background: #5B6080; }

/* Nudge cards in uniformly under each group header */
.cg-column > .dashboard-cell-paper {
    margin-left: 6px;
    margin-right: 6px;
}

/* Consult Analytics 2: let the container stretch to the full available width.
   Use .logged-in-main prefix so this beats the layout's .logged-in-main .mud-container rule. */
.logged-in-main .dashboard2-page.mud-container,
.dashboard2-page.mud-container {
    max-width: 100% !important;
    width: 100% !important;
    padding-top: 28px !important;
    /* Left and right padding raised from 8 → 16 px so that, combined with
       the 12 px on .dashboard-grid-inner, the total panel inset is 28 px
       on each side — matching the Consult Volume Data page. */
    padding-left: 16px !important;
    padding-right: 16px !important;
    min-height: calc(100vh - 64px) !important;
    display: flex;
    flex-direction: column;
    /* Both axes hidden here. With the .cg-col-grid floor at 1240 px
       (added below) and the .logged-in-main lock at 1400 px (set in
       css/layouts/logged-in.css), the compliance grid fits inside
       this container at every viewport, so there's nothing horizontal
       to bubble up through the page chain — horizontal scroll lives
       at .logged-in-layout, which already has overflow-x: auto and
       owns the layout-level pan. Vertical scroll happens INSIDE the
       inner .dashboard-grid-scroll-with-filters host (overflow-y:
       auto, below). The earlier attempt at splitting these axes
       (`overflow-x: visible; overflow-y: hidden`) hit the CSS spec
       quirk that promotes a `visible` axis to `auto` when paired
       with a non-`visible` axis, which silently broke the inner
       scroll host's vertical scroll — reverted to the simple
       `overflow: hidden` here. */
    overflow: hidden;
}

/* Popout should keep tight top spacing; normal page keeps the larger offset. */
.dashboard-popout-main .dashboard2-page.mud-container {
    padding-top: 8px !important;
}

/* ── Height lock for the standard portal page container ─────────────
   The rule above sets `min-height: calc(100vh - 64px)` (a floor) but
   no max-height (no ceiling). When the cards' total content height
   exceeded viewport-minus-app-bar — e.g. on a narrower portal viewport
   where each column is ~457 px wide and inline body text wraps to
   more lines per card — the page container grew taller than the
   viewport. The inner `.dashboard-grid-scroll-with-filters` is
   `flex: 1` of this container, so it grew with the parent and never
   exceeded its own height — its `overflow-y: auto` therefore never
   engaged, and the user fell through to document-level scroll
   instead of dashboard-area scroll. That's the "vert scrolling
   appears too late" symptom: the user has to scroll the whole
   document past the app bar and column headers before seeing
   anything new, instead of scrolling within a fixed scrollport that
   keeps the column headers pinned.

   Adding `max-height: calc(100vh - 64px)` here closes that ceiling.
   Combined with the existing min-height floor, the standard portal
   container is now a fixed height = viewport - app bar, so the
   inner scroll host stays a fixed-size scrollport and its own
   overflow-y: auto handles vertical pan correctly when card content
   exceeds it.

   Scoped to `.logged-in-main .dashboard2-page.mud-container` only so
   the popout chain is unaffected — popout has no app bar (the -64
   constant doesn't apply) and its own .dashboard-popout-main rules
   in css/site.css already manage popout-specific scroll behavior. */
.logged-in-main .dashboard2-page.mud-container {
    max-height: calc(100vh - 64px) !important;
}

/* Consult Analytics 2: card baseline height. The flex rule below
   (`.cg-column > .dashboard-cell-paper:not(.dashboard-cell-short) {
   flex: 1 1 0; }`) actually drives the live grid sizing; this height
   only kicks in for off-grid placements (e.g. PDF capture pages
   override it to 320 px). Reduced from 206 → 165 px for the 4-row
   layout fallback. */
.dashboard2-page .dashboard-cell-paper:not(.dashboard-cell-short) {
    height: 165px !important;
}

/* Tighten the paper's bottom padding so the risk-score footer sits closer
   to the bottom edge. The shared DashboardCell.razor sets it to 6px; here
   we drop to 2px on the compliance overview only. The .cell-wrapper rule
   below is kept in sync (height/margin/padding-bottom) so the wrapper
   still fills the paper edge to edge. */
.dashboard2-page .dashboard-cell-paper {
    padding-bottom: 2px !important;
}

/* Unify card heading colour, casing, and size across all 12 data tiles. */
.dashboard2-page .cell-title {
    color: #4A5568 !important;
    font-size: 0.8rem !important;
    font-weight: 700 !important;
    letter-spacing: 0.07em !important;
    text-transform: uppercase !important;
}

.dashboard2-page .dashboard-cell-paper.dashboard-cell-short {
    height: 44px !important;
    min-height: 44px !important;
}

/* Let Dashboard2 card heights apply (disable stretch-to-fill) */
.dashboard2-page .cg-column > .dashboard-cell-paper:not(.dashboard-cell-short) {
    flex: 0 0 auto !important;
}

.dashboard2-page .cg-column > .dashboard-cell-paper.dashboard-cell-short {
    flex: 0 0 auto !important;
}

/* In compliance mode, keep shaded columns filling visible page area */
.dashboard2-page .dashboard-grid-scroll.dashboard-grid-scroll-with-filters {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    /* This element owns the page's vertical scroll: the page container
       above is `overflow: hidden` and `min-height: calc(100vh - 64px)`
       so the inner host renders at exactly the visible content height,
       and `overflow-y: auto` here gives the user a vertical scrollbar
       when the cards' total height exceeds it. Horizontal axis stays
       `hidden` — the .cg-col-grid floor (1240 px) sits below the
       .logged-in-main lock (1400 px), so the grid always fits inside
       the page container without needing to bubble overflow upward. */
    overflow-y: auto;
    overflow-x: hidden;
}

/* Report view inherits the base rule's `overflow-y: auto`. Earlier this
   block forced `overflow-y: hidden` to avoid a "scrollbar jump" when the
   user flipped all tiles into report view, on the assumption that report
   content always fit inside the inner host. That assumption is no longer
   safe: the 180 px card floor (see `.cg-column > .dashboard-cell-paper`
   below) lets the 4-card column legitimately exceed the host's height
   when the page-container `max-height: calc(100vh - 64px)` lock is in
   effect, so the host MUST keep its scrollbar in report view too -
   otherwise cards 3 and 4 are unreachable on short windows. */

.dashboard2-page .dashboard-grid-scroll.dashboard-grid-scroll-with-filters > .dashboard-grid-inner {
    flex: 1;
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

/* In compliance mode, let the 4 cards per column stretch to fill panel height.
   The 180 px floor stops cards collapsing to header-only when the page
   container's `max-height: calc(100vh - 64px)` lock leaves the inner scroll
   host short. With basis 0 + shrink 1 the flex algorithm gives each card
   `column_height / 4`; this floor clamps that distribution at 180 px and
   pushes the column above the host's height, so the host's `overflow-y: auto`
   takes over and the user scrolls through cards instead of seeing them
   crushed to title strips. */
.dashboard2-page .cg-column > .dashboard-cell-paper:not(.dashboard-cell-short) {
    flex: 1 1 0 !important;
    height: auto !important;
    min-height: 180px;
}

/* Report view: hide card bodies, keep headers, risk-score footer, chip/help hover overlays, and report-view-only sections.
   Keyed off the per-cell .tile-report-view class so each tile can toggle independently.

   IMPORTANT: descendant (no `>`) between `.dashboard-cell-content` and
   `.tile-report-view` is intentional. When the trial soft/hard lock is
   active, each tile is wrapped in `<TrialWatermark>` which injects an
   extra `.trial-watermark-host` div between the dashboard cell and the
   tile's `.cell-wrapper`. With a direct-child combinator the rule stops
   matching once that wrapper is present, the graph view stays visible
   alongside the report view, and every Compliance Overview tile renders
   "report + graph + watermark" stacked on top of each other (Item C.2 of
   the post-signup walkthrough fix). The `>` between `.tile-report-view`
   and `:nth-child(n+2)` stays because that's selecting the cell's OWN
   direct children — never anything wrapped further. */
.cg-col-grid .dashboard-cell-content .tile-report-view > :nth-child(n+2):not(.cell-risk-score-footer):not([class$="-status-text"]):not([class$="-help-text"]):not(.report-view-content):not(.tile-risk-chip):not(.tile-report-download-icon):not(.cell-footer) {
    display: none !important;
}

/* Per-tile graph/report toggle icon. Sits in the card header actions cluster, next to the help icon. */
.dashboard2-page .tile-view-toggle-icon {
    font-size: 0.82rem;
    color: #8A9AB0;
    cursor: pointer;
    flex-shrink: 0;
    transition: color 0.15s ease;
    user-select: none;
}
.dashboard2-page .tile-view-toggle-icon:hover {
    color: #4A5568;
}

/* ─────────── Graph/Report card flip animation (shared across all 9 data tiles) ───────────
   Two-phase 3D flip: the card rotates out to 90deg (edge-on, invisible), content swaps while
   invisible, then it rotates back in from -90deg.

   The animation is applied to the OUTER MudPaper (.dashboard-cell-paper) via the `:has()`
   selector, so the white card surface, shadow, and contents all rotate as a single unit —
   no static background showing through during the flip. Easings are tuned so momentum
   carries through the midpoint (fast in the middle, decelerating at the outer ends). */
.dashboard2-page .dashboard-cell-paper:has(.tile-flip-out),
.dashboard2-page .dashboard-cell-paper:has(.tile-flip-in) {
    will-change: transform, box-shadow;
    transform-origin: center center;
    backface-visibility: hidden;
    box-shadow: 0 14px 34px rgba(23, 28, 50, 0.22) !important;
}
.dashboard2-page .dashboard-cell-paper:has(.tile-flip-out) {
    animation: dashboard2-tile-flip-out 360ms cubic-bezier(0.45, 0.05, 0.7, 0.25) forwards;
}
.dashboard2-page .dashboard-cell-paper:has(.tile-flip-in) {
    animation: dashboard2-tile-flip-in 360ms cubic-bezier(0.3, 0.75, 0.55, 0.95) forwards;
}

/* The dashboard2-tile-flip-out / dashboard2-tile-flip-in keyframes
   live in wwwroot/css/shared/dashboard2.css (linked globally from App.razor)
   — NOT in a .razor.css companion. Blazor's CSS-isolation pipeline
   rewrites @keyframes names with a per-component scope id, which
   would break the `animation:` references below. Keeping them in a
   plain static CSS file ensures the names stay global. */

/* ── Shared cell structure tokens ────────────────────────────────────────
   Every dashboard card (all 9 marker cells) shares these structural rules.
   Cell-specific body content lives in the per-component style blocks. */

/* WRAPPER — fixed geometry. Same shell for every card. Body/header/footer
   cannot escape this box (overflow:hidden is the safety rail).
   Bottom padding/margin shrunk in lockstep with the paper override above
   (6 → 2) so the wrapper still aligns with the paper edges. */
.dashboard2-page .cell-wrapper {
    width: calc(100% + 20px);
    height: calc(100% + 10px);
    margin: -8px -10px -2px -10px;
    padding: 8px 10px 2px 10px;
    border-radius: 6px;
    display: flex;
    flex-direction: column;
    overflow: hidden;
    transition: background 0.15s ease, box-shadow 0.25s ease;
}

/* DashboardCell host must stretch so wrapper/header geometry lands flush. */
.dashboard2-page .dashboard-cell-content {
    justify-content: flex-start;
    align-items: stretch;
    padding: 0;
    min-height: 0;
}

/* HEADER — fixed height. Identical for every card. Title may not wrap.
   align-items:center on this flex row + line-height:1 on the title block
   guarantees the title and right-side icon sit on the same vertical axis. */
.dashboard2-page .cell-header {
    flex: 0 0 24px;
    height: 24px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: -8px -10px 4px -10px;
    padding: 0 10px;
    border-radius: 6px 6px 0 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.07);
    overflow: hidden;
    line-height: 1;
}

.dashboard2-page .cell-header > * {
    line-height: 1;
}

.dashboard2-page .cell-title-wrap {
    display: flex;
    align-items: center;
    gap: 4px;
    min-width: 0;
    flex: 1;
}

.dashboard2-page .cell-title {
    font-size: .76rem;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--cell-accent, #5B6080);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

/* Compliance Overview tile-number badge — sits to the left of the card
   title inside .cell-title-wrap. The badge uses each card's --cell-accent
   so the colour visually matches the title text for that tile, keeping the
   header reading as a single coherent colour cluster. */
.dashboard2-page .cell-tile-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 9px;
    background: var(--cell-accent, #5B6080);
    color: #fff;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.01em;
    line-height: 1;
}

/* Help and status icons */
.dashboard2-page .cell-help-icon {
    font-size: 0.82rem;
    color: var(--cell-accent, #5B6080);
    cursor: pointer;
    flex-shrink: 0;
}

/* Graph view tuning: after increasing card heights, scale chart canvases down a bit
   so they keep the previous visual balance within each tile. */
.dashboard2-page .cell-wrapper:not(.tile-report-view) .nq-chart,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .nq-gauge,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .ct-chart-area,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .avgbill-chart-area,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .cr-box-chart,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .rx-donut-wrap,
.dashboard2-page .cell-wrapper:not(.tile-report-view) .uc-donut-wrap {
    transform: scale(0.92);
    transform-origin: top center;
}

.dashboard2-page .cell-wrapper:not(.tile-report-view) .cv-bullet-chart {
    height: 42px !important;
}
.dashboard2-page .cell-status-icon { font-size: 0.82rem; cursor: pointer; flex-shrink: 0; }

/* Status and help overlay panels — fill the body flex space */
.dashboard2-page .cell-status-text {
    font-size: 0.72rem;
    line-height: 1.55;
    color: #5A6478;
    padding: 4px 6px;
    border-radius: 6px;
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    text-align: center;
}
.dashboard2-page .cell-help-text {
    font-size: 0.72rem;
    line-height: 1.55;
    color: #5A6478;
    padding: 4px 6px;
    border-radius: 6px;
    flex: 1;
    display: flex;
    align-items: center;
    text-align: center;
    justify-content: center;
}

/* BODY — fills the space between header and footer. Always overflow:hidden. */
.dashboard2-page .cell-body { flex: 1; min-height: 0; overflow: hidden; }

/* ── end shared cell structure ─────────────────────────────────────────── */

/* ╔══════════════════════════════════════════════════════════════════════╗
   ║ DEBUG BORDERS (currently hidden — uncomment to re-enable)            ║
   ║ Outlines every structural section with a 1px coloured border so we   ║
   ║ can see, with our eyes, that header / body / footer line up across   ║
   ║ all 9 cards in both views. Each colour = one structural section.    ║
   ║   wrapper  → magenta                                                 ║
   ║   header   → blue                                                    ║
   ║   body     → green                                                   ║
   ║   footer   → red    (chip baseline lives in here)                    ║
   ║ Search for "DEBUG BORDERS" to find this block.                       ║
   ╚══════════════════════════════════════════════════════════════════════╝ */
/*
.dashboard2-page .cell-wrapper { outline: 1px solid magenta; outline-offset: -1px; }
.dashboard2-page .cell-header  { outline: 1px solid #2a6cdf; outline-offset: -1px; }
.dashboard2-page .cell-body    { outline: 1px solid #2a9d4f; outline-offset: -1px; }
.dashboard2-page .cell-footer  { outline: 1px solid #d12a2a; outline-offset: -1px; }
.dashboard2-page .cell-report-body { outline: 1px dashed #2a9d4f; outline-offset: -1px; }
.dashboard2-page .tile-risk-chip   { box-shadow: 0 0 0 1px #d12a2a inset, 0 0 0 2px white; }
*/
/* End DEBUG BORDERS ───────────────────────────────────────────────────── */

/* Card-header actions cluster (toggle + help icon) on the right of each data card header */
.dashboard2-page .tile-head-actions {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    flex-shrink: 0;
}

/* FOOTER — fixed height. Identical for every card. Contents are flex-row,
   vertically centred, right-aligned. Anything a card puts in here fits the
   fixed shape; it cannot make the footer grow. */
.dashboard2-page .cell-footer {
    flex: 0 0 24px;
    height: 24px;
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    padding: 0 8px;
    overflow: hidden;
}

.dashboard2-page .tile-risk-chip {
    font-size: 0.60rem;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 6px;
    cursor: pointer;
    white-space: nowrap;
    letter-spacing: 0.02em;
    min-width: 76px;
    text-align: center;
}

/* Standardised download-icon for the per-card "exception report" download.
   Pinned to the SAME fixed position relative to .dashboard-cell-paper on
   every card so the icon always lands ~10px clear of the chip's left edge,
   vertically centred against it. Cards opt in by stamping
   <span class="tile-report-download-icon"><MudTooltip>...<i class="fa-download" /></MudTooltip></span>
   from inside their template — no per-cell positioning rules. The chip is
   min-width:76px + ~14px h-padding ≈ 90px wide (chip sits at right:8px,
   bottom:10px), so right:90px puts the icon ~10px clear of the chip's
   left edge and bottom:11px optically centres a ~13.6px-tall icon against
   the chip. */
.dashboard2-page .tile-report-download-icon {
    line-height: 1;
}

/* The download glyph inside the anchor span — red by default (only
   shown when the chip is red), darker on hover, greyed-out +
   non-interactive in the trial state via the
   .tile-report-download-icon-disabled modifier. Targets the
   FontAwesome class instead of the bare element selector because
   Razor's parser otherwise misreads it as an HTML tag. */
.dashboard2-page .tile-report-download-icon .fa-download {
    font-size: 0.85rem;
    color: #D74D49;
    cursor: pointer;
    transition: color 0.15s ease;
}
.dashboard2-page .tile-report-download-icon .fa-download:hover {
    color: #B71C1C;
}
.dashboard2-page .tile-report-download-icon .fa-download.tile-report-download-icon-disabled,
.dashboard2-page .tile-report-download-icon .fa-download.tile-report-download-icon-disabled:hover {
    color: #B0B0B0;
    cursor: not-allowed;
}

/* In report view, hide the in-card help (?) icon. The graph-view shows it normally. */
.dashboard2-page .tile-report-view [class$="-help-icon"] {
    display: none !important;
}

/* Report-view body: Marker Description + Current State + Recommendations sections rendered inside each data card.
   Inter-section gap and font sizes are tuned so the prose fits inside the
   180 px card floor (~120 px body) when the page-height lock clamps cards. */
.dashboard2-page .cell-report-body {
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 2px 6px 0 6px;
    flex: 1;
    min-height: 0;
    overflow: hidden;
    align-items: stretch;
    text-align: left;
    justify-content: center;
}

/* Popout: compress vertical chrome so all 12 compliance cards fit viewport without scroll */
.dashboard-popout-main .dashboard2-page .cg-col-grid {
    min-height: 0;
    height: 100%;
    gap: 10px;
}

.dashboard-popout-main .dashboard2-page .cg-column {
    min-height: 0;
    /* Tighter gap/padding inside the popout so 4 cards stack without
       triggering a vertical scroll. */
    gap: 7px;
    padding-top: 6px;
    padding-bottom: 6px;
}

.dashboard-popout-main .dashboard2-page .cg-column > .dashboard-cell-paper {
    margin-left: 8px;
    margin-right: 8px;
}

/* Popout: do not clip wrapper negative margins used by shared card header geometry. */
.dashboard-popout-main .dashboard2-page .cg-column .dashboard-cell-content {
    overflow: visible !important;
}

.dashboard2-page .cell-report-body .crb-section {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-height: 0;
    align-items: stretch;
    text-align: left;
    margin-bottom: 0;
}

.dashboard2-page .cell-report-body .crb-section:last-child {
    margin-bottom: 0;
}

/* Peg the Marker Description (first section) at the top of the report body,
   and vertically centre the remaining sections (Current State +
   Recommendations) as a group in the space below. The pair of auto margins
   on sections 2 and 3 distributes leftover space equally above section 2 and
   below section 3, producing a balanced "quote at top, narrative centred"
   layout. */
.dashboard2-page .cell-report-body .crb-section:first-child {
    margin-top: 4px;
    padding-bottom: 4px;
}

.dashboard2-page .cell-report-body .crb-section:nth-child(2) {
    margin-top: auto;
}

.dashboard2-page .cell-report-body .crb-section:nth-child(2):last-child {
    margin-bottom: auto;
}

.dashboard2-page .cell-report-body .crb-section:nth-child(3):last-child {
    margin-bottom: auto;
}

.dashboard2-page .cell-report-body .crb-label,
.dashboard2-page .cell-report-body .crb-marker-text,
.dashboard2-page .cell-report-body .crb-recs,
.dashboard2-page .cell-report-body .crb-recs li {
    text-align: left;
}

.dashboard2-page .cell-report-body .crb-label {
    font-size: 0.62rem;
    font-weight: 700;
    color: #4A5568;
    letter-spacing: 0.02em;
    line-height: 1;
    text-transform: none;
}

.dashboard2-page .cell-report-body .crb-marker-text {
    font-size: 0.62rem;
    font-weight: 700;
    color: #4A5568;
    letter-spacing: 0.02em;
    line-height: 1;
    text-transform: none;
    font-style: italic;
    padding-left: 0;
    padding-right: 0;
    /* Pull the description to the full card width, bypassing the 6px left/right
       gutter that .cell-report-body applies to the rest of the content. */
    margin-left: -6px;
    margin-right: -6px;
    text-align: center;
}

.dashboard2-page .cell-report-body .crb-recs {
    margin: 0;
    padding-left: 6px;
    list-style: none;
    font-size: 0.62rem;
    color: #444;
    line-height: 1.35;
    overflow: hidden;
    min-height: 0;
}

.dashboard2-page .cell-report-body .crb-recs li {
    margin-bottom: 3px;
    list-style: none;
}

/* Placeholder row rendered inside the Recommendations <ul> when there are no
   active recommendations for a marker (i.e. the marker is compliant). Styled
   muted + italic so it reads as an informational note rather than an
   actionable item. */
.dashboard2-page .cell-report-body .crb-recs li.crb-rec-empty {
    color: #8A95A8;
    font-style: italic;
    margin-bottom: 0;
}

/* Current State entries flow as a single paragraph instead of stacked
   lines. We identify the Current State <ul> by the per-card highlight
   custom property (`--crb-cs-highlight-color`) every cell sets there;
   Recommendations <ul> doesn't carry that property so it stays as a
   list. Single-entry Current States are visually unchanged — `display:
   inline` on a lone item still renders as one line. */
.dashboard2-page .cell-report-body .crb-recs[style*="--crb-cs-highlight-color"] li {
    display: inline;
    margin-bottom: 0;
}

.dashboard2-page .cell-report-body .crb-recs[style*="--crb-cs-highlight-color"] li + li::before {
    content: " ";
}

/* Inline emphasis for the key phrase / value inside a Current State
   sentence — colour matches the chip for the card's risk level so the
   risk can be read at a glance from the body copy without scanning to
   the chip. The colour is supplied per-card via the
   --crb-cs-highlight-color CSS custom property set on the parent
   .crb-recs ul; falls back to the severe-risk red so an unset
   variable still reads as a strong "this is the key bit". */
.dashboard2-page .cell-report-body .crb-cs-highlight {
    color: var(--crb-cs-highlight-color, #DC2626);
    font-weight: 700;
}

/* Risk Score widget — lives inside .cell-footer as a flex item that fills
   the left side of the footer. The chip / download icon sit alongside it,
   all vertically centred by .cell-footer's align-items:center. */
.dashboard2-page .cell-risk-score-footer {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 6px;
    color: #6a7485;
}

.dashboard2-page .cell-risk-score-footer .crs-label {
    font-size: 0.72rem;
    font-weight: 700;
    color: #4A5568;
    letter-spacing: 0.02em;
    line-height: 1;
    text-transform: none;
    white-space: nowrap;
    flex: 0 0 auto;
}

.dashboard2-page .cell-risk-score-footer .crs-bar {
    flex: 1;
    min-width: 0;
    height: 6px;
    background: #e8e8e8;
    border-radius: 3px;
    overflow: hidden;
}

.dashboard2-page .cell-risk-score-footer .crs-bar-fill {
    height: 100%;
    border-radius: 3px;
    transition: width 0.4s ease;
}

.dashboard2-page .cell-risk-score-footer .crs-value {
    flex: 0 0 auto;
    font-size: 0.72rem;
    font-weight: 700;
    min-width: 36px;
    text-align: right;
    color: #3b4354;
}

/* Popout-only narrow-viewport rules. The .dashboard-popout-top-strip
   selectors above are already popout-prefixed in their own selectors;
   the .cg-col-grid / .cg-col-head-grid stacks were not, so they used
   to fire on the regular logged-in surface and produced the "3-column
   compliance grid suddenly stacks to 1 column at 960 px viewport"
   jumbling. Scoping them to .dashboard-popout-main keeps the popout
   stack working while the locked desktop portal stays at three
   columns regardless of viewport width. */
@media (max-width: 959px) {
    .dashboard-popout-top-strip {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    .dashboard-popout-top-strip-ops {
        justify-content: flex-start;
    }

    .dashboard-popout-top-strip-ops .popout-ops-select-wrap {
        min-width: 0;
        width: 100%;
    }

    /* Reset the standard portal's 1240 px floor (set on the unscoped
       .cg-col-grid / .cg-col-head-grid rules above) inside the
       popout's narrow-viewport mode — popout @ <960 is intentionally
       responsive (single column stack), so we don't want the floor
       forcing it back to 1240 px wide when the popout window is, say,
       525 px wide. The standard portal still inherits the floor
       because this rule is scoped to .dashboard-popout-main. */
    .dashboard-popout-main .cg-col-grid {
        grid-template-columns: 1fr;
        min-width: 0;
    }
    .dashboard-popout-main .cg-col-head-grid {
        grid-template-columns: 1fr;
        min-width: 0;
    }
}
