/* The Reports tab: the list's toolbar, tabs and card, the sharing drawer, the
   builder (the result fills the page; its settings sit in the docked settings
   drawer) and the report page. */

/* ── The list ────────────────────────────────────────────────────────── */

/* The toolbar as the mockup draws it: the pill search, a chip for each filter
   right beside it, and the sort chip at the row's end. A phone keeps the search
   on the list and folds the chips into the drawer (_list_toolbar.html). */
.reports-list__toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-sm);
}

.reports-list__toolbar--desk {
    flex: 1 1 auto;
    min-width: 0;
}

.reports-list__toolbar--stack {
    flex-direction: column;
    align-items: stretch;
}

.reports-list__fold {
    display: none;
}

/* The list's search wears the chips' white fill, hairline ring and height. The
   house search sheet (filter-bar.css) loads before this one, so its hover and
   focus borders are said again here, or the ring above would cover them. */
.reports-list__search .global-filter-control {
    height: var(--control-h-base);
    background: var(--color-card-bg);
    border-color: var(--color-border-hairline);
}

.reports-list__search .global-filter-control:hover {
    border-color: var(--color-grey-400);
}

.reports-list__search .global-filter-control:focus {
    border-color: var(--color-focus-ring);
}

/* The house header sends whatever follows its search to the row's far end
   (page-header.css). The mockup sets the chips right beside the search, so the
   first chip drops that margin (four classes beat its three) and only the sort
   rides the end. */
.global-page-header .reports-list__toolbar .global-page-search + .reports-list__filter {
    margin-left: 0;
}

.reports-list__sort {
    margin-left: auto;
}

.reports-list__toolbar--stack .reports-list__sort {
    margin-left: 0;
}

.reports-list__chip {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-xs);
    height: var(--control-h-base);
    padding: 0 var(--spacing-smd);
    border: 1px solid var(--color-border-hairline);
    border-radius: var(--radius-pill);
    background: var(--color-card-bg);
    color: var(--color-text);
    font-family: var(--font-family);
    font-size: var(--font-size-md);
    white-space: nowrap;
    cursor: pointer;
}

.reports-list__chip:hover {
    border-color: var(--color-grey-400);
}

.reports-list__chip.is-on {
    background: var(--color-action-tint);
    border-color: var(--color-action);
}

.reports-list__chip .bi-chevron-down {
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
}

/* A chip reads its field's word until a pick fills in the value. The value
   span holds no spaces, so it is empty when nothing is picked. */
.reports-list__chip-value:empty {
    display: none;
}

.reports-list__chip-value:not(:empty) + .reports-list__chip-word {
    display: none;
}

/* A filter's menu opens from its chip's left edge, like the dashboard's chips.
   The sort at the row's end keeps the house right edge, and a phone keeps the
   house bottom sheet. */
@media (min-width: 768px) {
    .reports-list__filter .global-action-dropdown-menu {
        left: 0;
        right: auto;
    }
}

/* The drawer's copy. The panel slides on a transform, so a bottom sheet inside
   it would pin to the panel rather than the screen: each menu opens in place
   under its chip instead. The search stays on the list, so the drawer hides its
   own copy, whose value still rides along with a pick. */
.reports-list__toolbar--stack .reports-list__search {
    display: none;
}

.reports-list__toolbar--stack .reports-list__chip {
    width: 100%;
}

.reports-list__toolbar--stack .reports-list__chip .bi-chevron-down {
    margin-left: auto;
}

.reports-list__toolbar--stack .global-action-dropdown-menu {
    position: static;
    width: auto;
    min-width: 0;
    max-width: none;
    margin: var(--spacing-xs) 0 0;
    border: 1px solid var(--color-grey-200);
    border-radius: var(--radius-md);
    box-shadow: none;
    overflow: hidden;
}

.reports-list__toolbar--stack .global-action-dropdown-menu::before {
    display: none;
}

.reports-list__toolbar--stack .global-action-dropdown-item:first-child {
    border-radius: var(--radius-none);
}

.reports-list__star {
    margin-right: var(--spacing-xs);
    font-size: var(--font-size-xs);
    color: var(--color-warning);
}

/* The list stands in its own card with a grey head band, as the mockup draws
   it. The card clips the band to its rounded corners, and the last row drops
   its rule so it never doubles the card's edge. */
.reports-list__card {
    overflow: hidden;
}

.reports-list__card .global-grid__head {
    padding: var(--spacing-smd) var(--spacing-md);
    background: var(--color-grey-50);
    border-bottom-color: var(--color-border-hairline);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
}

.reports-list__card tbody tr:last-child .global-grid__cell {
    border-bottom: 0;
}

/* Each row's menu sits at the row's end. */
.reports-list__card .global-grid__cell--filler {
    text-align: end;
}

.reports-list__name {
    font-weight: var(--font-weight-medium);
}

/* On a desk the grid's scroll box would cut a menu hung under its button, so
   the menu is fixed to the screen at the button's spot (_row_menu.html sets
   it). Both classes, so this beats main.css, which loads after this sheet. A
   phone keeps main.css's bottom sheet, which is fixed already. */
@media (min-width: 768px) {
    .global-action-dropdown-menu.reports-list__menu-panel {
        position: fixed;
        margin: var(--spacing-xs) 0;
    }
}

.reports-share__modes {
    margin-bottom: var(--spacing-md);
}

/* _share_drawer.html puts a note under this row whenever it has gate_words: when
   the report names a field behind the Booking money gate, the pay gate, or both.
   The note reads "This report shows Booking money, so only people who can see
   Booking money are offered here.", with "pay" or "Booking money and pay" in
   those two places. A Seats report that names only Base pay or Travel pay
   carries it with "pay". The middle choice then names the same words:
   "Everyone who can see Booking money (1)" is 306px wide on one line, so the
   three choices could not share equal columns. The row came to 522px in the
   drawer's 460px body, and the body's overflow-x: hidden cut the last choice
   to "Chosen peop". These rules find the row by the note: there each choice
   takes the width its own words need, and a long one wraps. A row with no
   note, a dashboard's among them, keeps its equal widths. */
.global-segmented.reports-share__modes:has(~ .reports-share__note) {
    grid-auto-columns: auto;
}

.reports-share__modes:has(~ .reports-share__note) .global-segmented__btn {
    white-space: normal;
}

.reports-share__note {
    margin-bottom: var(--spacing-md);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.reports-share__people {
    margin-bottom: var(--spacing-md);
}

.reports-share__person {
    display: flex;
    align-items: center;
    gap: var(--spacing-sm);
    margin: 0;
    cursor: pointer;
}

.reports-share__foot {
    display: flex;
    gap: var(--spacing-sm);
}

/* A phone drawer is as wide as the screen, so the choices take slimmer sides
   there. That keeps a dashboard's three on one line on a 320px phone. */
@media (max-width: 575.98px) {
    .reports-share__modes .global-segmented__btn {
        padding-inline: var(--spacing-xsm);
    }
}

/* The Share panel on a desk with the side menu open. From 1200px up a drawer
   pushes the page aside (drawer.css), and with the side menu open that left a
   dashboard about 430px in the middle at 1200px. So below the side menu
   (--sidebar-width, 256) + the panel (--drawer-width, 500) + the narrowest
   middle the dashboard's desk layout is drawn for (--reports-dash-min-middle,
   768: where its phone rules stop, and 1024 - 256 with the side menu open),
   1524 in all, the dashboard's Share panel floats over the page as every drawer
   does under 1200px and a side panel does on a phone: no push, the scrim, flush
   under the header, the overlay halo, the page held still (Nick, 09-26). A
   media query cannot read a custom property, so the query holds the sum, .02
   under it, and test_dashboard_page.py pins the two together. */
.reports-dash {
    --reports-dash-min-middle: 768px;
}

@media (min-width: 1200px) and (max-width: 1523.98px) {
    .global-app-layout:not(.is-sidebar-collapsed):has(.reports-dash ~ #report-share-drawer) {
        --content-push: 0px;
    }

    .global-app-layout:not(.is-sidebar-collapsed)
        .reports-dash ~ #report-share-drawer > .global-drawer-scrim {
        display: block;
        left: 0;
    }

    .global-app-layout:not(.is-sidebar-collapsed)
        .reports-dash ~ #report-share-drawer > .global-drawer-panel {
        top: var(--drawer-top);
        border-left: 0;
        border-top-left-radius: var(--radius-none);
        box-shadow: var(--shadow-modal);
    }

    body.is-drawer-lock:has(.global-app-layout:not(.is-sidebar-collapsed)
        .reports-dash ~ #report-share-drawer) {
        overflow: hidden;
    }
}

@media (max-width: 767.98px) {
    .reports-list__new-dashboard {
        display: none;
    }

    /* The phone list keeps its search and folds the chips and the sort into
       the drawer behind the sliders button. */
    .reports-list__toolbar--desk .reports-list__filter,
    .reports-list__toolbar--desk .reports-list__sort {
        display: none;
    }

    .global-page-header .reports-list__toolbar--desk .global-page-search {
        flex: 1 1 auto;
        max-width: none;
    }

    .reports-list__fold {
        display: block;
    }

    /* The house header strip scrolls sideways with its bar hidden, which cut
       the last tab off on a phone. This strip wraps instead (page-header.css). */
    .global-page-header__tabs .global-tabs.reports-list__tabs {
        flex-wrap: wrap;
        overflow-x: visible;
    }
}

/* ── The builder ─────────────────────────────────────────────────────── */

/* The head is one card row: the back arrow, the name read as a title, then the
   actions, pushed to the end by the spacer. The save form draws no box of its
   own, so its name and buttons sit in the row itself. Only the name gives way
   when the row is tight, and on a desk the row itself never wraps. It pads,
   spaces its buttons and stands off the result as the header card on the
   People, Bills and Opps pages does (components/page-header.css). */
.reports-builder__head {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: center;
    gap: var(--spacing-xsm);
    padding: var(--spacing-smd) var(--spacing-md);
    margin-bottom: var(--spacing-mdlg);
}

.reports-builder__head > *,
.reports-builder__save > * {
    flex: none;
}

.reports-builder__back {
    margin-right: auto;
    font-size: var(--font-size-sm);
    text-decoration: none;
}

/* The name sits right after the back arrow, the record pages' own
   (global-record-header__back). Its margin and the row's gap keep the space the
   house header bar leaves between the arrow and the title. */
.reports-builder__back-arrow {
    order: -2;
    margin-right: var(--spacing-xsm);
}

.reports-builder__save {
    display: contents;
}

/* The name is a bordered box of a control's height, as option C draws it: the
   name in the heading weight, the empty box's placeholder in the body weight.
   A name longer than its room ends in an ellipsis until it is focused. */
.reports-builder__name {
    order: -1;
    flex: 0 1 22.5rem;
    min-width: 0;
    height: var(--control-h-base);
    text-overflow: ellipsis;
    padding: 0 var(--spacing-smd);
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-heading);
    color: var(--color-text);
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.reports-builder__name::placeholder {
    font-weight: var(--font-weight-body);
    color: var(--color-text-muted);
}

/* The hover darkens the border as the house text box does. */
.reports-builder__name:hover {
    border-color: var(--color-text-muted);
}

.reports-builder__name:focus {
    border-color: var(--color-focus-ring);
    outline: 0;
    box-shadow: var(--shadow-focus-ring);
}

.reports-builder__spacer {
    flex: 1 1 auto;
}

/* The More menu's own Add to dashboard is the phone's; a desk has the button.
   The head in the selector outranks the menu item's own display rule. */
.reports-builder__head .reports-builder__more-add {
    display: none;
}

/* On a desk the result card reaches down toward the foot of the window however
   short the result is, so the chart has room to stand; the head card and the gaps
   round it take the rest. Print keeps the card's own height. */
@media screen and (min-width: 768px) {
    .reports-builder__result {
        display: flex;
        flex-direction: column;
        min-height: calc(100vh - var(--drawer-top) - 7.5rem);
    }

    .reports-builder__result > [aria-live] {
        display: flex;
        flex: 1 1 auto;
        flex-direction: column;
    }

    .reports-builder__result .reports-canvas {
        flex: 1 1 auto;
    }
}

/* ── The settings drawer's doors ─────────────────────────────────────── */

/* A door sits inside the settings list's panel, as the seat editor sits inside
   the opportunity form's drawer. That panel is transformed, so it is the box a
   door is measured from: the door starts at its top edge and ends at its foot. */
.reports-settings [data-builder-door] {
    inset-block: 0;
}

/* A door's fields are the platform's chips as buttons: outline while unused,
   filled once picked. The unused ones wrap under their source's name, and a
   long name wraps inside its pill rather than running past the drawer. */
.reports-panel__pills {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
}

.reports-panel__pill {
    max-width: 100%;
    white-space: normal;
    text-align: start;
}

.reports-panel__pill:hover:not(:disabled) {
    border-color: var(--color-text-muted);
}

/* A pill past a limit, or a locked field, reads as out of reach, the way a view
   type that cannot be picked does (drawer-content.css). */
.reports-panel__pill:disabled {
    opacity: 0.55;
}

/* The Filters door */
.reports-panel__built-in-words {
    display: flex;
    flex-direction: column;
}

.reports-panel__list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.reports-panel__row {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    padding: var(--spacing-xs) 0;
    font-size: var(--font-size-sm);
}

.reports-panel__row-name {
    flex: 1 1 auto;
    min-width: 0;
}

/* The icon button brings its own size and padding; the row only lifts it to the top. */
.reports-panel__remove {
    align-self: flex-start;
}

/* The Values, Group by and Date doors */

/* A picked pill's picker, how to measure a value or the step a date groups by,
   takes the rest of its row. */
.reports-panel__value-fn,
.reports-panel__bucket {
    flex: 1 1 0;
    min-width: 0;
}

/* The range's words stay on one line and end in an ellipsis when the drawer is too
   narrow for them. */
.reports-panel__range-btn .global-drawer__rowbtn-value {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A fixed popover inside a sliding drawer panel is placed by the panel's edge and
   lands out of sight, and one hung from its row would be cut off by the drawer's
   scroll box with Apply out of sight. So the Date door's range and the Filters
   door's value picker open in the flow under their rows and the drawer's body
   scrolls, on a desk and on a 390-wide phone alike. */
.reports-settings .global-toolbar__menu {
    position: static;
    min-width: 0;
    box-shadow: none;
}

/* The range opens a small step under its Range row. */
.reports-panel__range .global-toolbar__menu {
    margin-top: var(--spacing-xs);
}

/* The narrow panel stacks the presets above the months, so the rail's line runs under it. */
.reports-settings .global-date-range__rail {
    flex: 1 1 100%;
    padding-right: 0;
    padding-bottom: var(--spacing-smd);
    border-right: 0;
    border-bottom: 1px solid var(--color-border);
}

/* Two columns of named ranges, four rows in sight, so the month sits close under them. */
.reports-settings .global-date-range__presets {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    max-height: 8rem;
}

/* The panel has room for one month, across its width. The second month hides and the
   first shows its forward arrow too, which moves the view one month, as the pair's
   arrows do (date-range-calendar.js). */
.reports-settings .global-date-range__month {
    flex: 1 1 100%;
}

.reports-settings .global-date-range__month + .global-date-range__month {
    display: none;
}

.reports-settings .global-date-range__nav.is-blank {
    visibility: visible;
}

.reports-settings .global-date-range__grid {
    grid-template-columns: repeat(7, minmax(0, 1fr));
}

/* Apply stays in sight: while the month runs past the bottom of the drawer, the
   footer holds to that edge and the days scroll under it. */
.reports-settings .global-date-range__footer {
    position: sticky;
    bottom: 0;
    background: var(--color-card-bg);
}

/* ── The result ──────────────────────────────────────────────────────── */

.reports-result__empty {
    color: var(--color-text-muted);
}

.reports-result__callout {
    margin-bottom: var(--spacing-sm);
}

.reports-result__withheld,
.reports-result__note {
    margin: var(--spacing-xs) 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* When the result was worked out, and Refresh beside it. */
.reports-result__run {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
    margin: var(--spacing-sm) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.reports-result__refresh-form {
    display: flex;
}

.reports-result__refresh {
    flex: none;
}

.reports-result__scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
}

.reports-result__table td,
.reports-result__table th {
    white-space: nowrap;
}

.reports-result__kpis {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: var(--spacing-md);
}

.reports-result__kpi {
    padding: var(--spacing-md);
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.reports-result__kpi-label {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-xs) var(--spacing-sm);
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.reports-result__kpi-value {
    margin: 0;
    font-size: var(--font-size-h2);
    font-weight: var(--font-weight-medium);
}

/* The change since the period before: an arrow up or down, then its words. */
.reports-result__kpi-delta {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2xs);
    margin: 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* The arrow as tall as the words' capitals. */
.reports-result__kpi-delta .bi {
    font-size: var(--font-size-h4);
    line-height: 1;
}

.reports-result__kpi-delta.is-up {
    color: var(--color-success-text);
}

.reports-result__kpi-delta.is-down {
    color: var(--color-error-text);
}

.reports-result__chart {
    position: relative;
    height: 24rem;
    max-height: 60vh;
}

/* ── The result card, on the builder and the report page ─────────────── */

/* The head names what the result shows, the body holds it, the foot says when
   it ran. The head and the foot reach the card's edges. */
.reports-canvas {
    padding: 0;
    overflow: hidden;
}

.reports-canvas__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
    padding: var(--spacing-smd) var(--spacing-md);
    border-bottom: 1px solid var(--color-border-hairline);
}

.reports-canvas__title {
    margin: 0;
    font-size: var(--font-size-h4);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
}

.reports-canvas__meta {
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

/* The body takes whatever height the card has spare, so the foot sits at its bottom. */
.reports-canvas__body {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: var(--spacing-smd);
    padding: var(--spacing-md);
}

.reports-canvas__body > * {
    margin: 0;
}

/* A number stands in the middle of the room the body has. */
.reports-canvas__body > .reports-result__kpis {
    flex: 1 1 auto;
    align-content: center;
}

/* A report's totals sit on top of its chart at their own height; only a KPI's
   number takes the room the body has spare. */
.reports-canvas__body > .reports-result__kpis--total {
    flex: none;
}

.reports-canvas__foot {
    padding: var(--spacing-sm) var(--spacing-md);
    border-top: 1px solid var(--color-border-hairline);
}

/* When it ran, and Refresh, sit at the foot's right, as option C draws them. */
.reports-canvas__foot .reports-result__run {
    justify-content: flex-end;
    margin: 0;
}

/* One number fills the card: centred and large, its label and date chip above
   it. Several numbers keep a box each. */
.reports-canvas .reports-result__kpi {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--spacing-sm);
    text-align: center;
}

.reports-canvas .reports-result__kpi:only-child {
    padding: var(--spacing-xl) 0 var(--spacing-2xl);
    background: transparent;
    border: 0;
}

.reports-canvas .reports-result__kpi-label {
    justify-content: center;
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-heading);
    color: var(--color-text-secondary);
}

.reports-canvas .reports-result__kpi-label .global-chip {
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-medium);
}

/* On the result card the change reads as a pill: green when the number rose,
   red when it fell, grey when it held. */
.reports-canvas .reports-result__kpi-delta {
    padding: var(--spacing-xs) var(--spacing-smd);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
    background: var(--color-surface-subtle);
    border-radius: var(--radius-pill);
}

.reports-canvas .reports-result__kpi-delta.is-up {
    color: var(--color-success-text);
    background: var(--status-success-bg);
}

.reports-canvas .reports-result__kpi-delta.is-down {
    color: var(--color-error-text);
    background: var(--status-danger-bg);
}

.reports-canvas .reports-result__kpi:only-child .reports-result__kpi-value {
    font-size: var(--font-size-display-lg);
    line-height: var(--line-height-heading);
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

/* The table under the chart, in a hairline box of its own. */
.reports-canvas .reports-result__scroll {
    border: 1px solid var(--color-border-hairline);
    border-radius: var(--radius-md);
}

.reports-canvas .reports-result__table {
    margin-bottom: 0;
}

.reports-canvas .reports-result__table th,
.reports-canvas .reports-result__table td {
    padding: var(--spacing-sm) var(--spacing-smd);
    border-color: var(--color-border-hairline);
}

.reports-canvas .reports-result__table th {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
    background: var(--color-surface-subtle);
}

.reports-canvas .reports-result__table tfoot td {
    font-weight: var(--font-weight-medium);
    background: var(--color-surface-subtle);
}

.reports-canvas .reports-result__table > :last-child > tr:last-child > * {
    border-bottom-width: 0;
}

/* ── The report page ─────────────────────────────────────────────────── */

.reports-page__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-sm);
    margin-bottom: var(--spacing-md);
}

.reports-page__title {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-sm);
    min-width: 0;
}

/* The name wears the house page title (.global-page-header__title, page-header.css),
   which sets its size; this sheet loads later, so a size here would win over it. */
.reports-page__name {
    margin: 0;
}

.reports-page__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
}

/* A dashboard's More menu holds its own Share for a phone; a desk has the
   button. The head in the selector outranks the menu item's own display rule. */
.reports-page__head .reports-dash__more-share {
    display: none;
}

/* The foot a print shows: the rules the run applied and when it ran. On the
   screen the head's chip and the card's run line say the same. */
.reports-page__foot {
    display: none;
    margin-top: var(--spacing-md);
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

.reports-page__foot p {
    margin: 0;
}

/* ?print=1: the bare page with no chrome, the same shape a print gets. */
.reports-page--print .reports-page__foot {
    display: block;
}

/* On a phone the head card keeps one row, and the settings drawer's panels slide
   in from the right (global-drawer-panel--side, components/drawer.css) when the
   gear opens them. */
@media (max-width: 767.98px) {
    /* The row keeps the back arrow, the name, Save, More and the gear; Add to
       dashboard moves into More. The name takes what is left, at the body
       size a phone needs so a tap on it never zooms the page. */
    .reports-builder__head {
        gap: var(--spacing-xs) var(--spacing-sm);
        padding: var(--spacing-sm);
    }

    .reports-builder__back-arrow {
        margin-right: 0;
    }

    .reports-builder__name {
        flex: 1 1 0;
        padding: 0 var(--spacing-sm);
        font-size: var(--font-size-base);
    }

    .reports-builder__spacer,
    .reports-builder__add {
        display: none;
    }

    .reports-builder__head .reports-builder__more-add {
        display: flex;
    }
}

/* A dashboard: its tiles on a twelve-column grid. A small tile takes a third
   of a row, a medium half, a large the whole row; on a phone every tile takes
   the row. The grid is its own, never the Bootstrap row. */
.reports-dash__grid {
    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--spacing-md);
}

/* The quick filter chips lead the head's action row. On a desk they wrap
   inside a strip of their own (see the home's rules below); on a phone
   dashboard-filters.js moves them into the Filters drawer, where they stack,
   and the Filters button takes their place in the row. */
.reports-dash__chips {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-xs);
}

/* A dashboard's chips stand at the control height and the body size, as the
   mockup draws them, and a chip with nothing picked reads solid like the rest:
   the shared toolbar's small dashed offer is the list pages' look. A set chip
   keeps the toolbar's action tint and border. */
.reports-dash__chips .global-toolbar__chip {
    height: var(--control-h-base);
    padding: 0 var(--spacing-smd);
    color: var(--color-text);
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-body);
}

.reports-dash__chips .global-toolbar__chip--add {
    border-style: solid;
    border-color: var(--color-border-hairline);
    background: var(--color-card-bg);
}

.reports-dash__chips .global-toolbar__chip--add:hover {
    border-color: var(--color-grey-400);
    color: var(--color-text);
}

.reports-dash__chips .global-toolbar__chip .bi-chevron-down {
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    opacity: 1;
}

.reports-dash__chips-home {
    display: contents;
}

/* On a desk screen the chips' home is a box of its own in the action row, so
   five chips no longer push the buttons onto a second line. The row takes all
   the room the name leaves; the strip takes what the buttons leave and wraps
   its chips inside itself; the buttons never shrink, so Refresh, Share, Add
   report and More stay on the first line at the right. The strip keeps room
   for about two chips side by side; where the name leaves less than that, as
   on a tablet, the whole row drops below the name and takes the full width,
   with the buttons still on its first line at the right. The name keeps its
   place after the back link, and it lines up with the first line of chips. A
   home with no strip in it (no chips, or a phone that moved them into the
   drawer) still draws nothing, and print keeps its own head. */
@media screen and (min-width: 768px) {
    .reports-page__head:has(> .reports-dash__actions) {
        align-items: baseline;
    }

    .reports-page__head:has(> .reports-dash__actions) > .reports-builder__back {
        margin-right: 0;
    }

    .reports-page__head:has(> .reports-dash__actions) > .reports-page__title {
        flex-grow: 0;
    }

    .reports-dash__actions {
        flex: 1 1 0;
        flex-wrap: nowrap;
        align-items: flex-start;
        justify-content: flex-end;
    }

    .reports-dash__chips-home:has(> .reports-dash__chips) {
        display: block;
        flex: 1 1 auto;
        min-width: var(--reports-chip-strip-w);
    }

    .reports-dash__chips-home .reports-dash__chips {
        justify-content: flex-end;
    }

    .reports-dash__actions > .btn,
    .reports-dash__actions > .global-action-dropdown {
        flex: none;
    }

    /* The buttons keep the chips' height now that the row no longer stretches
       them to it. */
    .reports-dash__actions > .btn {
        min-height: var(--control-h-base);
        white-space: nowrap;
    }
}

/* On a desk each chip's menu opens under its chip, and the date menu holds
   its two months side by side. That is wider than the room a chip near the
   screen's right edge leaves, so a menu that would run off the screen slides
   left until it ends a gap short of the edge. The chip hands its menu's left
   edge in as --reports-menu-left (_dashboard_chips.html); the phone drawer
   keeps the months stacked. */
.reports-dash__chips-home .global-toolbar__menu-wrap {
    --reports-menu-left: 0px;
}

.reports-dash__chips-home .global-toolbar__menu {
    translate: min(0px, calc(100vw - var(--reports-menu-left) - 100% - var(--spacing-md)));
}

.reports-dash__chips-home .global-date-range__body {
    flex-wrap: nowrap;
}

.reports-dash__fold {
    display: none;
}

.reports-dash__chips-drawer .reports-dash__chips {
    flex-direction: column;
    align-items: stretch;
    gap: var(--spacing-md);
}

/* In the drawer a chip's menu opens in line under its chip. The sliding panel
   would carry a floating menu down by the panel's own top edge. */
.reports-dash__chips-drawer .global-toolbar__menu-wrap {
    flex-direction: column;
    align-items: stretch;
    gap: var(--spacing-xs);
}

.reports-dash__chips-drawer .global-toolbar__menu {
    position: static;
    min-width: 0;
    width: 100%;
    box-shadow: none;
}

/* A chip's list of values lies in its menu between the box and Clear, the way
   the toolbar's own chip menus list theirs. The site combobox floats its list,
   and here the list covered Clear, so a click where Clear sat picked the first
   value. The list keeps its height cap and scroll from the site sheet, and it
   drops the border and shadow that drew a second card inside the menu. The up
   class the combobox adds near the screen's foot moves only a floating list.
   In the phone drawer the open list pushes the chips under it down. Each step
   is a direct child, so a combobox the date popover holds deeper stays as is. */
.reports-dash__chips .global-toolbar__menu > .global-cs > .global-cs-menu {
    position: static;
    margin-top: var(--spacing-xs);
    border: 0;
    box-shadow: none;
}

/* A lock after a tab's name says some of that dashboard is hidden from this
   reader. It sits a size under the name so it reads as a mark on the tab. */
.reports-dash__tab-lock {
    font-size: var(--font-size-xs);
}

/* One chip and, for an editor, its Remove x right after it, the way the
   mockup's builder chips carry their x. On a desk the pair sits in the chip
   strip as one piece, so the strip wraps it whole; a reader's row holds the
   chip alone. The x keeps its size wherever the row runs short. In the drawer
   the x stands beside its chip, level with the chip while its menu opens in
   line below. The row starts with the chip's label, which shows only in the
   drawer: it sits above the chip and its x, the way the mockup's drawer names
   each field, and the chip takes the room the x leaves, never pushing the x
   onto a line of its own. */
.reports-dash__chip-row {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2xs);
}

.reports-dash__remove-filter {
    flex: none;
}

.reports-dash__chips-drawer .reports-dash__chip-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--spacing-xs) var(--spacing-sm);
}

.reports-dash__chips-drawer .reports-dash__chip-row .global-toolbar__menu-wrap {
    flex: 1 1 0;
    min-width: 0;
}

.reports-dash__chip-label {
    display: none;
}

.reports-dash__chips-drawer .reports-dash__chip-label {
    display: block;
    flex-basis: 100%;
}

/* An editor adds a quick filter from the Filter chip that ends the chip strip
   on a desk, or from the dashed Add filter row at the foot of the drawer, drawn
   like the grid's Add report cell. Each shows only in its own place. */
.reports-dash__chips-drawer .reports-dash__add-chip {
    display: none;
}

.reports-dash__add-filter {
    display: none;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-xsm);
    width: 100%;
    padding: var(--spacing-sm);
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
    background: none;
    border: 1px dashed var(--color-grey-300);
    border-radius: var(--radius-md);
}

.reports-dash__add-filter:hover {
    color: var(--color-text);
    border-color: var(--color-grey-500);
}

.reports-dash__chips-drawer .reports-dash__add-filter {
    display: flex;
}

@media (max-width: 767.98px) {
    .reports-dash__fold {
        display: block;
    }

    /* Share moves into More, so the actions keep one row and More never
       drops onto a line of its own. */
    .reports-dash__actions {
        flex-wrap: nowrap;
    }

    .reports-dash__actions .reports-dash__share {
        display: none;
    }

    .reports-page__head .reports-dash__more-share {
        display: flex;
    }

    /* The strip keeps one row and scrolls sideways, as the record header's tabs
       do, with no bar under it. Each tab already keeps its own width on a phone
       (page-tabs.css). */
    .reports-dash__tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        overscroll-behavior-x: contain;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
    }

    .reports-dash__tabs::-webkit-scrollbar {
        display: none;
    }
}

/* An empty dashboard's shared empty state spans the whole grid, above the add cell. */
.reports-dash__full-row {
    grid-column: span 12;
}

/* An editor's last cell on the grid, dashed so it never reads as a tile. It
   opens the same dialog as the head's Add report. */
.reports-dash__add-tile {
    display: flex;
    grid-column: span 4;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-xsm);
    min-height: 7.5rem;
    font-size: var(--font-size-md);
    color: var(--color-text-secondary);
    background: none;
    border: 1px dashed var(--color-grey-300);
    border-radius: var(--radius-card-lg);
}

.reports-dash__add-tile:hover {
    color: var(--color-text);
    border-color: var(--color-grey-500);
}

/* The tile's menu may hang past the card's edge. The card has no padding of
   its own: its head, body and foot each pad themselves, as the dashboard
   mockup draws a tile. */
.reports-tile {
    grid-column: span 6;
    min-height: 7.5rem;
    overflow: visible;
}

/* A number keeps its own height beside a taller chart instead of stretching
   to the row's height. */
.reports-tile:has(.reports-result__kpis) {
    align-self: start;
}

/* A chart tile with its totals on top still stretches to its row, as every
   chart tile does. */
.reports-tile:has(.reports-result__kpis--total) {
    align-self: auto;
}

.reports-tile--s {
    grid-column: span 4;
}

.reports-tile--m {
    grid-column: span 6;
}

.reports-tile--l {
    grid-column: span 12;
}

/* The name on the left and the tools at the head's right end, as the mockup
   sets a tile's head. */
.reports-tile__head {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
    padding: var(--spacing-smd) var(--spacing-sm) var(--spacing-xs) var(--spacing-md);
}

/* The name at the body's size. On a desk it is cut short with an ellipsis
   when the tile is narrow, so the tools keep their place; a phone wraps it. */
.reports-tile__title {
    flex: 1 1 auto;
    min-width: 0;
    margin: 0;
    overflow: hidden;
    font-size: var(--font-size-md);
    font-weight: var(--font-weight-medium);
    color: var(--color-text);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.reports-tile__title a {
    color: inherit;
    text-decoration: none;
}

/* An editor's tools at the end of the head: the size control, the grip that
   drags the tile, and the tile's menu. */
.reports-tile__tools {
    display: flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--spacing-xs);
    margin-left: auto;
}

.reports-tile__sizes .global-segmented__btn {
    min-width: 2rem;
    padding: 0 var(--spacing-xs);
    font-size: var(--font-size-xs);
}

.reports-tile__grip {
    color: var(--color-grey-400);
    cursor: grab;
}

.reports-tile__grip:active {
    cursor: grabbing;
}

.reports-tile__menu-rule {
    margin: var(--spacing-xs) 0;
}

/* The Add filter dialog's picks, one full-width button each. */
.reports-move-tile__list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xs);
}

.reports-move-tile__target {
    text-align: left;
}

.reports-tile__body {
    flex: 1 1 auto;
    min-width: 0;
    padding: 0 var(--spacing-md) var(--spacing-md);
}

/* In a tile a number stands flat on the card, as the mockup draws it: no box
   of its own, large, with its change under it. One number needs no label,
   since the tile's name says what it counts; several keep theirs. */
.reports-tile .reports-result__kpi {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2xs);
    padding: 0;
    background: none;
    border: 0;
}

.reports-tile .reports-result__kpi:only-child .reports-result__kpi-label {
    display: none;
}

.reports-tile .reports-result__kpi-value {
    font-size: var(--font-size-display);
    font-weight: var(--font-weight-heading);
    line-height: var(--line-height-heading);
    color: var(--color-text);
    font-variant-numeric: tabular-nums;
}

/* A chart in a tile is shorter than one on its own page. */
.reports-tile .reports-result__chart {
    height: 16rem;
    max-height: 40vh;
}

/* A tile's table heads read in sentence case on a pale band, as the dashboard
   mockup draws them; the builder's card keeps the house capitals. */
.reports-tile .reports-result__table th {
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
    text-transform: none;
    letter-spacing: normal;
    background: var(--color-grey-50);
}

/* The one sentence a tile shows instead of a result, and its button. */
.reports-tile__state {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-sm);
    padding: var(--spacing-md) 0;
    color: var(--color-text-muted);
}

.reports-tile__message {
    margin: 0;
}

.reports-tile__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-xs);
    padding: 0 var(--spacing-md) var(--spacing-sm);
}

/* Each quick filter the tile runs under reads as a small grey pill, the way the
   dashboard mockup draws a tile's foot. */
.reports-tile__filter {
    padding: var(--spacing-2xs) var(--spacing-sm);
    font-size: var(--font-size-xs);
    color: var(--color-text-secondary);
    background: var(--color-grey-100);
    border-radius: var(--radius-pill);
}

.reports-tile__note {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

/* The grey block a tile shows until its door answers. */
.reports-tile__skeleton {
    flex: 1 1 auto;
    min-height: 10rem;
    margin: var(--spacing-md);
    background: var(--color-border);
    border-radius: var(--radius-sm);
    animation: reports-tile-pulse 1.2s ease-in-out infinite;
}

@keyframes reports-tile-pulse {
    0%,
    100% {
        opacity: 0.4;
    }

    50% {
        opacity: 0.8;
    }
}

@media (max-width: 767.98px) {
    .reports-tile,
    .reports-tile--s,
    .reports-tile--m,
    .reports-tile--l,
    .reports-dash__add-tile {
        grid-column: span 12;
    }

    /* Each size button and the grip, the one spot a drag starts, give a finger
       the house touch target. The grip's icon keeps its size. */
    .reports-tile__sizes .global-segmented__btn,
    .reports-tile__grip {
        min-width: var(--control-h-touch);
        min-height: var(--control-h-touch);
    }

    .reports-tile__grip {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

    /* Beside the tools a name had about 92px, and a word wider than that
       split. So the head wraps: a name that does not fit beside the tools
       takes the first row whole, and the tools go to the row under it, still
       at the head's end. */
    .reports-tile__head {
        flex-wrap: wrap;
    }

    /* The name wraps onto more lines and shows whole, and the tools keep
       their place at the head's end. */
    .reports-tile__title {
        white-space: normal;
        overflow-wrap: anywhere;
    }
}

/* Print (calendar-events.css keeps the same shape): the chrome goes, and so do
   each page's tools. On a report the actions and the run line go, the foot
   shows, and the chart takes the page's width. On the builder the head's tools
   and the settings drawer go, its panels and its scrim with it. On a dashboard
   the tab strip, the chips, any open drawer,
   each tile's tools and the Add report cell go, and a tile prints flat and whole
   on one page. ?print=1 marks the grid data-dash-print and prints once the last
   tile has drawn, which can come a moment before the loading sheet lifts, so
   the sheet goes too. A drawer such as Share lands beside the dashboard in the
   page box, not inside it, so the drawer rules look from the page box down.
   A chart's box takes the page's width at its screen height (shorter in a
   tile) and never the screen's cap, and charts.js redraws each chart to that
   box as the page prints. A canvas not redrawn in time shrinks to the page's
   width rather than running off its edge.
   This block sits after the tile rules so a flat tile wins in print. */
@media print {
    .global-sidebar,
    .global-app-header,
    .global-notice-slot,
    .reports-builder__back,
    .reports-page__actions,
    .reports-builder__head,
    .reports-builder__save,
    .reports-builder .reports-settings,
    .reports-canvas__foot,
    .reports-result__run,
    .reports-result__refresh,
    .reports-dash__tabs,
    .reports-dash__chips,
    .reports-dash__fold,
    .reports-tile__menu,
    .reports-tile__grip,
    .reports-tile__sizes,
    .reports-dash__add-tile,
    .global-app-content:has(> .reports-dash) > .global-loading-screen--gate,
    .global-app-content:has(> .reports-dash) .global-drawer-panel,
    .global-app-content:has(> .reports-dash) .global-drawer-scrim {
        display: none !important;
    }

    .global-app-content {
        padding: 0 !important;
    }

    .reports-page__foot {
        display: block;
    }

    .reports-result__chart {
        width: 100%;
        height: 24rem;
        max-height: none;
    }

    .reports-tile .reports-result__chart {
        height: 16rem;
        max-height: none;
    }

    .reports-result__chart canvas {
        max-width: 100%;
        height: auto !important;
    }

    .reports-tile {
        break-inside: avoid;
        box-shadow: none;
    }
}

/* The admin's Usage card under the list: the ledger's sums in the result's KPI shape. */
.reports-usage {
    margin-top: var(--spacing-lg);
}

.reports-usage__card {
    padding: var(--spacing-md);
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}

.reports-usage__title {
    margin: 0 0 var(--spacing-md);
    font-size: var(--font-size-h3);
}

.reports-usage__subtitle {
    margin: var(--spacing-md) 0 var(--spacing-xs);
    font-size: var(--font-size-base);
}

.reports-usage__slowest {
    margin: 0;
    padding-left: var(--spacing-lg);
}

/* One cell per day of the window, oldest first: the count over the day. */
.reports-usage__days {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
    margin: 0;
    padding: 0;
    list-style: none;
}

.reports-usage__day {
    display: flex;
    flex-direction: column;
    align-items: center;
    min-width: 3rem;
    padding: var(--spacing-xs);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
}

.reports-usage__day-runs {
    font-weight: var(--font-weight-medium);
}

.reports-usage__day-label {
    font-size: var(--font-size-xs);
    color: var(--color-text-muted);
}

.reports-usage__note {
    margin: var(--spacing-md) 0 0;
    font-size: var(--font-size-sm);
    color: var(--color-text-muted);
}

/* The admin's Spend grid: a row per channel, a column per month, each cell an amount. */
.reports-spend {
    padding: var(--spacing-md);
}

.reports-spend__lead {
    margin: 0 0 var(--spacing-xs);
    color: var(--color-text-secondary);
}

/* Holds its height while empty, so the grid does not jump when a cell saves. */
.reports-spend__status {
    min-height: 1.25rem;
    margin: 0 0 var(--spacing-sm);
    font-size: var(--font-size-sm);
    color: var(--color-text-secondary);
}

.reports-spend__status--refused {
    color: var(--color-error);
}

.reports-spend__scroll {
    overflow-x: auto;
    overscroll-behavior-x: contain;
}

.reports-spend__grid {
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--font-size-sm);
}

/* The channel column stays put while the months scroll under it. */
.reports-spend__channel {
    position: sticky;
    left: 0;
    padding: var(--spacing-xs) var(--spacing-sm);
    background: var(--color-card-bg);
    font-weight: var(--font-weight-medium);
    text-align: left;
    white-space: nowrap;
}

.reports-spend__month {
    padding: var(--spacing-xs) var(--spacing-sm);
    font-weight: var(--font-weight-medium);
    color: var(--color-text-secondary);
    text-align: right;
    white-space: nowrap;
}

.reports-spend__cell {
    padding: var(--spacing-xs);
}

.reports-spend__input {
    width: 7rem;
    padding: var(--spacing-xs) var(--spacing-sm);
    background: var(--color-card-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    color: var(--color-text);
    font-size: var(--font-size-sm);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

.reports-spend__input--saved {
    border-color: var(--color-success);
}

.reports-spend__input[aria-invalid="true"] {
    border-color: var(--color-error);
}
