/* ===== Drawer: QueryBuilder (report filter conditions) ===== */
/* The default QueryBuilder uses inline-block with hardcoded min-widths (180px operator,
   300px value) that total ~580px+. Convert to flex so parts size proportionally at 600px. */

/* ----------------------------------------------------------------------- */
/* Containers: reset + base chrome                                          */
/* ----------------------------------------------------------------------- */

/* --- Reset default 4px margin on all query-builder containers --- */
.ui-refresh .query-builder .rules-group-container,
.ui-refresh .query-builder .rule-container,
.ui-refresh .query-builder .rule-placeholder {
    margin: 0;
}

/* --- Rule placeholder + draggable elements --- */
.ui-refresh .query-builder .rule-placeholder {
    border: none;
    border-top: 1px solid var(--accent-primary);
    background: var(--accent-subtle);
}
.ui-refresh .query-builder:has(.dragging) * {
    user-select: none; /* disable text selection while dragging the element for sorting */
}

/* --- Group container: token-align --- */
/* The polish below was originally scoped to `.ajax-drawer` only, where the
 * visibility-condition builder first lived. The reg-type form now hosts the
 * same widget inside an iframe-based slide-out (`body.sidebar`) instead of
 * `.ajax-drawer`, so the rules need to engage in both contexts. Drop the
 * `.ajax-drawer` qualifier — `.ui-refresh` is gate enough; any non-ui-refresh
 * page still gets the legacy chrome. */
.ui-refresh .query-builder .rules-group-container {
    border-color: var(--border-subtle);
    border-radius: var(--radius-lg);
    background: var(--bg-muted);
    padding: var(--space-3);
    touch-action: none;
}
.ui-refresh .query-builder .rules-group-container .rules-group-container,
.ui-refresh .query-builder .rules-group-container + .rule-container {
    margin-top: 10px;
}

/* --- Remove tree connector lines (they waste 15px left padding) --- */
.ui-refresh .query-builder .rules-list > *::before,
.ui-refresh .query-builder .rules-list > *::after {
    display: none;
}
.ui-refresh .query-builder .rules-list {
    padding-left: 0;
}

/* ----------------------------------------------------------------------- */
/* Rule row layout: flex conversion                                         */
/* ----------------------------------------------------------------------- */

/* --- Condition card: compact inline flex --- */
.ui-refresh .query-builder .rule-container {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    flex-wrap: nowrap;
    border-color: var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--bg-surface);
    padding: var(--space-2) var(--space-3);
    touch-action: none;
}

/* --- Override inline-block on all rule parts --- */
.ui-refresh .query-builder .rule-filter-container,
.ui-refresh .query-builder .rule-operator-container,
.ui-refresh .query-builder .rule-value-container,
.ui-refresh .query-builder .drag-handle {
    display: block;
    margin: 0;
    min-width: 0;
}

/* --- Proportional flex sizing --- */
.ui-refresh .query-builder .drag-handle {
    flex: 0 0 auto;
    color: var(--fg-subtle);
    font-size: var(--font-size-xs);
    order: -1;
}
.ui-refresh .query-builder .rule-filter-container {
    flex: 1.5 1 0;
}
.ui-refresh .query-builder .rule-operator-container {
    flex: 1 1 0;
    max-width: none;
}
.ui-refresh .query-builder .rule-value-container {
    flex: 1.2 1 0;
}

/* ----------------------------------------------------------------------- */
/* Selects & dropdowns                                                      */
/* ----------------------------------------------------------------------- */

/* --- Kill hardcoded min-widths on selects, and draw a single chevron --- */
.ui-refresh .query-builder .rule-filter-container select,
.ui-refresh .query-builder .rule-operator-container select {
    width: 100%;
    min-width: 0 !important;
    background-size: .6em !important;
    background-image: var(--select-chevron-image);
    background-position: calc(100% - 1.3em) center !important;
    background-repeat: no-repeat;
    appearance: none;
    padding-right: 30px;
}

/* --- Kill hardcoded min-widths on value inputs --- */
.ui-refresh .query-builder .rule-value-container > input,
.ui-refresh .query-builder .rule-value-container > select,
.ui-refresh .query-builder .rule-value-container button:not(.multiselect-clear-filter) {
    width: 100%;
    min-width: 0 !important;
}

/* --- Multiselect dropdown: fit content, cap at 300px --- */
.ui-refresh .ajax-drawer .query-builder .rule-value-container .dropdown-menu {
    width: auto;
    padding-inline: 0!important;
    max-width: 300px;
}

/* --- Multiselect dropdown: custom scrollbar --- */
.ui-refresh .query-builder .rule-value-container ul.dropdown-menu {
    overflow-x: hidden!important;
    overflow-y: auto!important;
    scrollbar-width: thin;
    scrollbar-gutter: auto; /* `stable` was adding a hidden "padding-right" in Chrome-based browsers */
    scrollbar-color: var(--primary) transparent;
    box-shadow: var(--sh-md);
}

/* ----------------------------------------------------------------------- */
/* Rule actions: delete button                                              */
/* ----------------------------------------------------------------------- */

/* --- Delete button: compact, subtle, error on hover --- */
.ui-refresh .query-builder .rule-actions {
    flex: 0 0 auto;
}
.ui-refresh .query-builder .rule-actions .btn,
.ui-refresh .query-builder .btn-danger {
    background: transparent !important;
    border: 1px solid var(--border-default) !important;
    color: var(--fg-muted) !important;
    min-width: 40px;
    aspect-ratio: 1 / 1;
    height: 100%;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
}
.ui-refresh .query-builder .rules-group-header .btn[data-delete] {
    background: transparent !important;
    border: 1px solid color-mix(in srgb, var(--fg-subtle) 20%, transparent) !important;
    color: var(--fg-muted) !important;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-md);
    transition: all var(--transition-fast);
}
.ui-refresh .query-builder .rule-actions .btn:hover,
.ui-refresh .query-builder .btn-danger:hover,
.ui-refresh .query-builder .rules-group-header .btn[data-delete]:hover {
    color: var(--color-error) !important;
    border-color: var(--color-error) !important;
    background: var(--color-error-bg) !important;
}
.ui-refresh .query-builder .has-error .error-container {
    display: none !important;
}

/* --- Rule header (contains delete button) — integrate into the flex row --- */
.ui-refresh .query-builder .rule-header {
    flex: 0 0 auto;
    order: 99;
    align-self: stretch;
}
.ui-refresh .query-builder .rule-header .pull-right,
.ui-refresh .query-builder .rule-header .float-end {
    float: none !important;
    height: 100%;
}

/* ----------------------------------------------------------------------- */
/* Group header: layout, and/or toggle, add-rule button                    */
/* ----------------------------------------------------------------------- */

.ui-refresh .query-builder .rules-group-header {
    display: flex;
    align-items: stretch;
    justify-content: flex-start;
    gap: var(--space-1);
    height: 38px;
}
.ui-refresh .query-builder .rules-group-header > .dropdown {
    margin-left: 0!important;
}
.ui-refresh .query-builder .rules-group-header .dropdown .dropdown-menu {
    padding-left: 0!important;
}
.ui-refresh .query-builder .rules-group-header .drag-handle {
    margin-right: 5px;
    margin-block: auto;
}
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions {
    background: var(--card);
    position: relative;
    display: inline-block;
    border-radius: 10px;
    vertical-align: middle;
    border: 1px solid var(--line);
    padding: 3px;
}
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions .btn.btn-default,
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions .btn.btn-default:not(.active) {
    background-color: transparent!important;
    color: var(--muted)!important;
    border-radius: var(--radius-md)!important;
    text-decoration: none!important;
    border: none;
    display: inline-flex!important;
}
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions .btn.btn-default:active,
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions .btn.btn-default:focus {
    box-shadow: none;
}
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions .btn.btn-default.active {
    background-color: var(--ink)!important;
    color: var(--paper)!important;
    border-radius: var(--radius-md)!important;
    border: none;
}

/* --- And/or toggle: accent colors instead of legacy Swoogo blue --- */
.ui-refresh .query-builder .rules-group-header .btn,
.ui-refresh .query-builder .group-conditions .btn {
    font-size: var(--font-size-xs);
    height: 100%;
    border-radius: var(--radius-md);
}
.ui-refresh .query-builder .group-conditions .btn-default:not(.active) {
    background-color: var(--bg-muted) !important;
    color: var(--fg-muted) !important;
    border-color: var(--border-default) !important;
}

/* --- Add rule (+) button: accent --- */
.ui-refresh .query-builder .btn-success,
.ui-refresh .query-builder button.btn.add-rule {
    background-color: var(--primary)!important;
    border: 1px solid var(--primary)!important;
    color: var(--fg-on-accent) !important;
    font-size: var(--font-size-xs);
    border-radius: var(--radius-md);
}
.ui-refresh .query-builder .btn-success:hover,
.ui-refresh .query-builder .rules-group-header :not(.dropdown.open) .btn.add-rule:hover {
    filter: brightness(1.12);
}

/* PR #2537 review: the "+" stretched chunkier than the and/or switcher and its
   regular-weight glyph read thin. Pin the button to the switcher's 38px outer
   box (the .rules-group-header height both stretch into), center the glyph,
   and use the solid FA face (weight 900) for a heavier "+". */
.ui-refresh .query-builder .rules-group-header .dropdown > .btn.add-rule,
.ui-refresh .query-builder .rules-group-header > .btn.add-rule {
    box-sizing: border-box;
    height: 38px;
    width: 38px;
    padding: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
/* The and/or switcher's 1px --line border reads as visibly shorter than this
   button's solid fill even though both stretch to the same 38px box — a
   framed pill next to a flat block looks off by a few px. Nudge the
   switcher's box slightly taller to compensate, instead of styling the
   button to match the switcher. */
.ui-refresh .query-builder .rules-group-header .btn-group.group-conditions {
    margin-block: -0.5px;
}
.ui-refresh .query-builder .rules-group-header .btn.add-rule > i {
    font-weight: 900;
}

/* --- "New filter" add buttons, outside .query-builder ---
   `.add-filter` (report and mobile filter builders) and `.btn-add-condition`
   (the querybuilder empty state) are siblings of `.query-builder`, not
   descendants, so the accent rules above never reach them. They fell through to
   the generic `.btn-default:hover`, which only swaps the background to
   --bg-muted — the same grey these widgets use for inactive controls, so
   hovering read as "disabled". Keep the resting look and make hover read as an
   action. `.disabled` is excluded because report-filters.js really does disable
   this button while a filter row is incomplete.

   `!important` on the first two only: components.css declares
   `background: var(--bg-muted) !important` on `.btn-default:hover` and
   `border-color: var(--panel-border) !important` on `.btn-default`, and no
   amount of specificity beats an important declaration. Its `color` is not
   important, so this rule wins that one on specificity alone. */
.ui-refresh .btn-default.add-filter:not(.disabled):hover,
.ui-refresh .btn-default.add-filter:not(.disabled):focus,
.ui-refresh .btn-add-condition:not(.disabled):hover,
.ui-refresh .btn-add-condition:not(.disabled):focus {
    background-color: var(--primary-tint) !important;
    border-color: var(--accent-primary) !important;
    color: var(--accent-primary);
}

/* ----------------------------------------------------------------------- */
/* Empty state                                                              */
/* ----------------------------------------------------------------------- */

/* Empty-state placeholder shown by VisibilityConditionInput when no rules are
 * configured. Boxed in a bordered card with centered content. */
.ui-refresh .empty-message.visibility-conditions {
    margin: 0;
    padding: var(--space-2);
    border: 1px solid var(--input-border);
    border-radius: var(--radius-md);
    display: flex;
    flex-direction: column;
    align-items: center;
}

/* ----------------------------------------------------------------------- */
/* Legacy report filter builder (ReportFilterInput) on plain pages          */
/* ----------------------------------------------------------------------- */

/* `widgets/views/ReportFilterInput.php` reuses the `.query-builder` class name but is
   unrelated markup: a `<table>` of filter rows (report/_filter.php), used by every report
   whose `report_on_model` falls outside Report::useAdvancedFilters()'s whitelist. Nothing
   above this section reaches it — those rules target the QueryBuilder plugin's own markup.

   This mirrors the `.ajax-drawer`-scoped treatment added for the Contacts filters drawer
   (swoogo/www#2519), applied here without the `.ajax-drawer` qualifier for every other
   caller of this widget (the *-multiple-update configure pages, report/_form, report/_modal,
   badge-field agenda filters, etc.) that render it on a plain page instead. Kept as a
   separate, non-overlapping block on purpose — see that PR's own comments for why its rules
   stay scoped to `.ajax-drawer` rather than being merged with these. */

/* --- "Show records where": label above its select, set apart from the rows --- */
.ui-refresh .query-builder .filter-operator {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

/* --- Empty state: boxed, matching .empty-message.visibility-conditions above --- */
.ui-refresh .query-builder .filter-empty {
    padding: var(--space-4);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    text-align: center;
}

/* --- Kill hardcoded sizing on the attribute/condition selects, and draw a single
       chevron — mirrors the QueryBuilder plugin's own select treatment above, applied to
       ReportFilterInput's plain `<select>` elements. --- */
.ui-refresh .query-builder .attribute-select,
.ui-refresh .query-builder .condition-select {
    min-width: 0 !important;
    background-size: .6em !important;
    background-image: var(--select-chevron-image);
    background-position: calc(100% - 1.3em) center !important;
    background-repeat: no-repeat;
    appearance: none;
    padding-right: 30px;
}

/* --- "Show records where" operator select: same chevron treatment. Built with
       `Html::activeDropDownList()` (ReportFilterInput.php) rather than
       `$form->field()->dropdownList()`, so it never picks up `ActiveField::dropdownList()`'s
       automatic `new-ui-select` class and falls back to the browser's native arrow — see
       swoogo/www#978. Mirrors the `.ajax-drawer`-scoped rule above, without the qualifier. --- */
.ui-refresh .query-builder .filter-operator select {
    background-size: .6em !important;
    background-image: var(--select-chevron-image);
    background-position: calc(100% - 1.3em) center !important;
    background-repeat: no-repeat;
    appearance: none;
    padding-right: 30px;
}

/* --- Multiselect dropdown (value column): fit content, cap at 300px, custom scrollbar —
       same treatment as the QueryBuilder plugin's value dropdown above. --- */
.ui-refresh .query-builder .value-td .dropdown-menu {
    width: auto;
    padding-inline: 0 !important;
    max-width: 300px;
}
.ui-refresh .query-builder .value-td ul.dropdown-menu {
    overflow-x: hidden !important;
    overflow-y: auto !important;
    scrollbar-width: thin;
    scrollbar-gutter: auto;
    scrollbar-color: var(--primary) transparent;
    box-shadow: var(--sh-md);
}
.ui-refresh .query-builder .btn-group > .multiselect.dropdown-toggle {
    background-color: var(--card, transparent) !important;
}

/* --- "New filter" row --- */
.ui-refresh .query-builder > .text-center {
    margin-top: var(--space-3);
}

/* --- "New filter": neutral at rest, accent on hover ---
   `backend.css` carries `.query-builder .btn.btn-default { background-color: #0A69FA
   !important; color: white }` — legacy blue — which outranks
   `.ui-refresh .btn-default { background: var(--bg-page) !important }` (components.css) at
   three compound selectors to two. This button and the trash beside it both paint solid
   blue until something more specific says otherwise; four selectors here wins, and
   `!important` is required because the declaration being beaten is itself important.

   Resting state is restated as the plain refreshed `.btn-default`; hover gets the accent
   tint (the generic `.btn-default:hover` --bg-muted reads as "disabled" on this control).
   `:not(.disabled)` because report-filters.js really does disable this while a row is being
   fetched. `:focus-visible`, not `:focus`, matches the convention components.css uses for
   every other button — the accent state should not stick after a mouse click. */
.ui-refresh .query-builder .add-filter {
    background: var(--bg-page) !important;
    border-color: var(--panel-border) !important;
    color: var(--fg-default) !important;
}
.ui-refresh .query-builder .add-filter:not(.disabled):hover,
.ui-refresh .query-builder .add-filter:not(.disabled):focus-visible {
    background: var(--primary-tint) !important;
    border-color: var(--accent-primary) !important;
    color: var(--accent-primary) !important;
}

/* --- Delete: flatten the btn-default to the icon-button treatment used by
       `.lt-cell-actions .lr-icon` in components.css.

   Three legacy rules have to be beaten, two of them `!important`:
     - `backend.css`'s `.query-builder .btn.btn-default { background-color: #0A69FA
       !important; color: white }` — the same legacy blue as above.
     - `.ui-refresh .btn-default:hover { background: var(--bg-muted) !important }` — reads
       as nothing happening on hover.
     - `.new-form .btn-default.active` (active-form.css) paints another solid #0A69FA with
       an inset shadow and white text; `.active`/`:active` are pinned to the resting look.

   `border: 0` handles a fourth, `border-color: var(--panel-border) !important` — a width of
   zero makes the colour moot. `:focus-visible` rather than `:focus` on the hover rule, so
   the red wash does not stick after the confirmation popover is dismissed by mouse. */
.ui-refresh .query-builder .delete-filter,
.ui-refresh .query-builder .delete-filter:active,
.ui-refresh .query-builder .delete-filter.active,
.ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition,
.ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition:active,
.ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition.active {
    display: inline-grid;
    place-items: center;
    /* width: 28px;
    height: 28px; */
    aspect-ratio: 1 / 1;
    padding: 0;
    background: transparent !important;
    /* border: 0; */
    border-radius: var(--radius-sm);
    box-shadow: none;
    color: var(--fg-muted) !important;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition:hover,
.ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition:focus-visible,
.ui-refresh .query-builder .delete-filter:hover,
.ui-refresh .query-builder .delete-filter:focus-visible {
    color: var(--color-error) !important;
    border-color: var(--color-error) !important;
    background: var(--color-error-bg) !important;
}
.ui-refresh .query-builder .table > tbody > tr:hover > td {
    background-color: transparent !important;
}

/* ----------------------------------------------------------------------- */
/* Delete confirmation popover (bootstrap-confirmation2) — plain pages      */
/* ----------------------------------------------------------------------- */

/* report-filters.js wires the trash button to bootstrap-confirmation2, whose template is a
   Bootstrap 3 popover (h3.popover-title question, .confirmation-buttons.text-center with a
   joined btn-group: a.btn[data-apply] Yes / a.btn[data-dismiss] No). `.ui-refresh .popover`
   already tokenizes the surface/border/arrow; it doesn't touch the button pair, which
   arrives with a green Yes and red No (report-filters.js passes `btnOkClass: 'btn-success'`
   / `btnCancelClass: 'btn-danger'` — the destructive action is the green one). Re-skinned
   here keyed on `[data-apply]`/`[data-dismiss]` (the plugin's own template attributes, not
   the colour classes). Mirrors swoogo/www#2519's `.ajax-drawer`-scoped version for every
   other caller of this widget. */
.ui-refresh .query-builder .popover.confirmation {
    padding: 0;
    border-radius: var(--radius-lg);
}
.ui-refresh .query-builder .popover.confirmation .popover-title {
    padding: var(--space-4) var(--space-4) var(--space-2);
    background: none;
    border-bottom: 0;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    line-height: 1.4;
    white-space: normal;
}
.ui-refresh .query-builder .popover.confirmation .popover-content {
    padding: 0 var(--space-4) var(--space-4);
}
.ui-refresh .query-builder .popover.confirmation .confirmation-content:empty {
    display: none;
}
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons .btn-group {
    display: flex;
    gap: var(--space-2);
}
/* The four resets beat `.ui-refresh .query-builder .btn-danger` further up this file, which
   turns anything `.btn-danger` inside a `.query-builder` into a square 40px icon button
   aimed at the QueryBuilder plugin's own delete-rule button — this popover is inserted as a
   sibling of the trash button, i.e. inside `#filters.query-builder`, so the No button
   (`btnCancelClass: 'btn-danger'`) was being sized as an icon button next to a normal-height
   Yes. Five compound selectors beats three, so no `!important` is needed. */
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons .btn {
    flex: 1;
    margin: 0;
    min-width: 0;
    aspect-ratio: auto;
    height: var(--btn-height);
    padding: var(--btn-padding);
    border-radius: var(--radius-md) !important;
    font-size: var(--font-size-xs);
}
/* The icons are `glyphicon glyphicon-ok`/`glyphicon glyphicon-remove` (the plugin's
   defaults). This app ships Font Awesome, not the Bootstrap 3 glyphicon font, so they
   render as tofu or nothing — the Yes/No labels carry it on their own. */
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons .btn > i {
    display: none;
}
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-apply] {
    background: var(--red-60) !important;
    border-color: var(--red-60) !important;
    color: white !important;
}
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-apply]:hover,
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-apply]:focus {
    background: var(--red-70) !important;
    border-color: var(--red-70) !important;
}
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-dismiss] {
    background: var(--bg-page) !important;
    border-color: var(--panel-border) !important;
    color: var(--fg-default) !important;
}
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-dismiss]:hover,
.ui-refresh .query-builder .popover.confirmation .confirmation-buttons [data-dismiss]:focus {
    background: var(--bg-muted) !important;
}

.ui-refresh .query-builder .responsive-grid > tbody > tr > td {
    border-top: 0 !important;
    border-bottom-color: var(--input-border) !important;
}

.ui-refresh .query-builder .responsive-grid > tbody > tr:last-child > td {
    border-bottom: 0 !important;
}

.ui-refresh .query-builder .responsive-grid > tbody > tr > td:last-child {
    width: 40px;
}

/* --- Filter row: desktop stays a single line ---
   Unlike the drawer (~632px content width, where the row genuinely doesn't fit and has to
   restack), a plain page has room for attribute/condition/value/delete side by side — so
   the row keeps its natural table layout here. `.ui-refresh .table`/`.table-striped`
   (components.css) already tokenize the borders/stripe/hover generically; no extra rule
   needed for this breakpoint. */

/* --- Filter row -> card (narrow/mobile only) ---
   `ReportFilterInput.php` registers its own inline breakpoint that forces
   `table/thead/tbody/th/td/tr` to `display: block` — collapsing the table into a plain stack
   that still carries table/table-striped's borders and zebra tint, which reads as a layout
   accident rather than a design. Style the now-block `<tr>` as a card instead, and give the
   stacked `<td>`s breathing room. Cell order is: mobile header (.visible-xs: trash icon +
   "Filter N"), attribute, condition, value — `.hidden-xs` (desktop-only delete cell) is
   already hidden by Bootstrap at this width, so the mobile header's own trash icon is the
   only delete action here.

   Matches the widget's own two-part breakpoint exactly (not components.css's usual 768px):
   narrow phones OR any tablet-class device (min/max-device-width 768–1024px) regardless of
   actual viewport/orientation — the widget collapses to blocks on both, so this has to fire
   on both too, or a tablet gets the collapsed markup without the card styling. */
@media only screen and (max-width: 760px),
       (min-device-width: 768px) and (max-device-width: 1024px) {
    .ui-refresh .query-builder .responsive-grid {
        border: 0;
        background: none;
    }
    .ui-refresh .query-builder .responsive-grid > tbody > tr {
        display: block;
        border: 1px solid var(--border-subtle);
        border-radius: var(--radius-md);
        background: var(--bg-surface);
        padding: var(--space-3);
        margin-bottom: var(--space-3);
    }
    /* table-striped tints odd rows; the card owns its own background now. */
    .ui-refresh .query-builder .responsive-grid.table-striped > tbody > tr:nth-of-type(odd) {
        background: var(--bg-surface);
    }
    .ui-refresh .query-builder .responsive-grid > tbody > tr > td {
        border: 0;
        padding: 0;
    }
    .ui-refresh .query-builder .responsive-grid > tbody > tr:hover > td {
        background: none;
    }
    .ui-refresh .query-builder .responsive-grid > tbody > tr > td + td {
        margin-top: var(--space-2);
    }
    /* Mobile header (trash icon + "Filter N" label): separate it from the fields below
       with a divider instead of just whitespace. The trash link comes first in the DOM
       (report/_filter.php) and relies on Bootstrap's `.pull-right` float to sit at the end —
       floats don't apply inside a flex container, so `margin-left: auto` reproduces the
       same "pushed to the far edge" placement instead. */
    .ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs {
        display: flex !important;
        align-items: center;
        padding-bottom: var(--space-2);
        margin-bottom: var(--space-2);
        border-bottom: 1px solid var(--border-subtle);
        font-weight: var(--font-weight-medium);
    }
    .ui-refresh .query-builder .responsive-grid > tbody > tr > td.visible-xs .delete-condition.pull-right {
        margin-left: auto;
        order: 2;
    }
}

/* ----------------------------------------------------------------------- */
/* Read-only variant (popover or plain panel, e.g. matching-contacts modal) */
/* ----------------------------------------------------------------------- */

/* .read-only-visibility — backend.css sets hardcoded white backgrounds.
   Override with semantic surface tokens so the condition cards adapt
   automatically in both light and dark modes, wherever this renders. */
.ui-refresh .read-only-visibility .rule-container,
.ui-refresh .read-only-visibility .rules-group-container {
    background: var(--bg-surface) !important;
    border-color: var(--border-strong) !important;
}
.ui-refresh .read-only-visibility .rules-group-header {
    color: var(--fg-muted) !important;
}
.ui-refresh .read-only-visibility .rule-section-container.operator {
    background: var(--bg-muted) !important;
    color: var(--fg-default) !important;
}
.ui-refresh .read-only-visibility .rules-list > ::after,
.ui-refresh .read-only-visibility .rules-list > ::before {
    border-color: var(--border-strong) !important;
}

/* ----------------------------------------------------------------------- */
/* Legacy report filter builder (ReportFilterInput) inside the AjaxDrawer   */
/* ----------------------------------------------------------------------- */

/* `widgets/views/ReportFilterInput.php` reuses the `.query-builder` class name but is
   unrelated markup: a `<table>` of filter rows, used by every report whose
   `report_on_model` falls outside Report::useAdvancedFilters()'s whitelist — contacts
   among them. Everything above styles the QueryBuilder plugin and never reaches it.

   The table itself is left alone. `web/js/report-filters.js` appends the `<tr>` that
   ReportController::actionCreateFilter returns straight into `table tbody`, and walks
   `closest('tr')` to delete, so the markup has to survive intact — the restack below is
   CSS-only for that reason. */

/* --- Attribute / condition / operator selects: draw the same chevron as every other
   select in the app. All three (`_filter.php`'s two, plus the "Show records where" operator
   select in `widgets/views/ReportFilterInput.php`) are built with `Html::activeDropDownList()`
   rather than `$form->field()->dropdownList()`, so none of them pick up
   `ActiveField::dropdownList()`'s automatic `new-ui-select` class
   (`components/ActiveField.php:52-56`) and fall back to the browser's native arrow —
   sitting noticeably closer to the edge than the value column's multiselect trigger beside
   them. `.filter-operator select` reaches the operator select by its wrapping `<p>` since it
   carries no class of its own beyond the generic `form-control`. */
.ui-refresh .ajax-drawer .query-builder .attribute-select,
.ui-refresh .ajax-drawer .query-builder .condition-select,
.ui-refresh .ajax-drawer .query-builder .filter-operator select {
    appearance: none;
    background-image: var(--select-chevron-image);
    background-size: .6em;
    background-position: calc(100% - 1.3em) center;
    background-repeat: no-repeat;
    padding-right: 30px;
}

/* --- Value multiselect trigger: restore the chevron gutter ---
   `layout.css`'s `.ajax-drawer .sidebar-form .multiselect.dropdown-toggle` rule (written
   for the input-group-btn caret case) collapses this trigger's padding to
   `0 var(--space-3) !important`, which also wipes out bootstrap-multiselect.css's own
   30px right-padding gutter reserved for its background-image chevron. With the gutter
   gone, `.multiselect-selected-text` (flex: 1, min-width: 0) expands into that space and
   a long selection renders behind the chevron instead of stopping short of it. Restore
   the gutter for this trigger specifically — six classes here beats the five on the
   layout.css rule, so no risk of it winning back on a future edit there. */
.ui-refresh .ajax-drawer .query-builder .value-td .multiselect.dropdown-toggle {
    padding-right: 30px !important;
}

/* --- Reset filters: a text action on the panel heading row. `.sidebar-panel-title-row`
       is a plain flex row with no justification, so `margin-left: auto` is what pushes
       this to the right edge. Deliberately not `.reset-filters` — backend.css gives that
       class a fixed 32px left margin for sitting beside the legacy sidebar's <h4>. --- */
.ui-refresh .ajax-drawer .report-filters-reset {
    margin-left: auto;
    padding: 0;
    border: 0;
    background: none;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-normal);
    color: var(--accent-primary);
    transition: color var(--transition-fast);
}
.ui-refresh .ajax-drawer .report-filters-reset:hover,
.ui-refresh .ajax-drawer .report-filters-reset:focus {
    text-decoration: underline;
}

/* --- "Show records where": label above its select, set apart from the rows --- */
.ui-refresh .ajax-drawer .query-builder .filter-operator {
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
    margin-bottom: var(--space-3);
}

/* --- Empty state: boxed, matching .empty-message.visibility-conditions above --- */
.ui-refresh .ajax-drawer .query-builder .filter-empty {
    padding: var(--space-4);
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    text-align: center;
}

/* --- "New filter" row: `.ui-refresh .ajax-drawer p` zeroes every margin --- */
.ui-refresh .ajax-drawer .query-builder > .text-center {
    margin-top: var(--space-3);
}

/* --- "New filter": neutral at rest, accent on hover ---
   `backend.css` carries `.query-builder .btn.btn-default { background-color: #0A69FA
   !important; color: white }` — legacy blue, and at three compound selectors it outranks
   `.ui-refresh .btn-default { background: var(--bg-page) !important }` (components.css:136,
   two). So this button and the trash beside it both painted solid blue until something more
   specific said otherwise. Four selectors here wins; `!important` is required because the
   declaration being beaten is itself important.

   Resting state is therefore restated as the plain refreshed `.btn-default`, and hover gets
   the accent tint — without that, hover would fall through to
   `.ui-refresh .btn-default:hover`, whose --bg-muted is the same grey these widgets use for
   inactive controls, so it reads as "disabled".

   `:not(.disabled)` because report-filters.js:83 really does disable this while a row is
   being fetched. `:focus-visible`, not `:focus`, so the accent state does not stick after a
   mouse click — that is the convention components.css:101 uses for every other button.

   Scoped to `.ajax-drawer` on purpose: the iframe sidebar's copy of this button is PR
   #2451's to fix, and keeping the scopes apart keeps the two out of each other's way at
   merge. --- */
.ui-refresh .ajax-drawer .query-builder .add-filter {
    background: var(--bg-page) !important;
    border-color: var(--panel-border) !important;
    color: var(--fg-default) !important;
}
.ui-refresh .ajax-drawer .query-builder .add-filter:not(.disabled):hover,
.ui-refresh .ajax-drawer .query-builder .add-filter:not(.disabled):focus-visible {
    background: var(--primary-tint) !important;
    border-color: var(--accent-primary) !important;
    color: var(--accent-primary) !important;
}

/* --- Delete: flatten the btn-default to the icon-button treatment used by
       `.lt-cell-actions .lr-icon` in components.css.

   Three legacy rules have to be beaten, two of them `!important`:
     - `backend.css`'s `.query-builder .btn.btn-default { background-color: #0A69FA
       !important; color: white }` — legacy blue. This is what put a blue tile behind the
       icon, and at three compound selectors it also outranks the ui-refresh rule below.
     - `.ui-refresh .btn-default:hover { background: var(--bg-muted) !important }`
       (components.css:142) — the same grey these widgets use for inactive controls, so
       hover read as nothing happening.
     - `.new-form .btn-default.active` (active-form.css:15) paints another solid #0A69FA
       with an inset shadow and white text. The drawer's ActiveForm carries `new-form`, so
       the pressed state flashed blue too; `.active`/`:active` are pinned to the resting look.

   `border: 0` handles a fourth, `border-color: var(--panel-border) !important` — a width of
   zero makes the colour moot. `:focus-visible` rather than `:focus` on the hover rule, so
   the red wash does not stick after the popover is dismissed by mouse. --- */
.ui-refresh .ajax-drawer .query-builder .delete-filter,
.ui-refresh .ajax-drawer .query-builder .delete-filter:active,
.ui-refresh .ajax-drawer .query-builder .delete-filter.active {
    display: inline-grid;
    place-items: center;
    width: 28px;
    height: 28px;
    padding: 0;
    background: transparent !important;
    border: 0;
    border-radius: var(--radius-sm);
    box-shadow: none;
    color: var(--fg-muted) !important;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.ui-refresh .ajax-drawer .query-builder .delete-filter:hover,
.ui-refresh .ajax-drawer .query-builder .delete-filter:focus-visible {
    background: var(--danger-soft) !important;
    color: var(--danger-primary) !important;
}
/* --- Row hover: the delete icon is the ONLY thing that reacts ---
   `components.css`'s generic `.ui-refresh .table > tbody > tr:hover > td { background-color:
   var(--state-hover) }` tints every cell in a hovered `.table` row. That rule is written for
   real data grids; here it painted a 4% grey behind each field, and because the delete cell
   is shrink-wrapped to the 28x28 button it read as a hard-edged square sitting behind the
   button's own rounded highlight — two stacked backgrounds. Clear it on every cell, then let
   the button alone carry the hover.

   Beaten on specificity, no `!important` needed: four classes here to that rule's two. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr:hover > td {
    background-color: transparent;
}
/* Hovering anywhere in the card gives the icon's own box — already `border-radius:
   var(--radius-sm)` above — a grey fill, so it reads as a rounded button rather than a bare
   icon. `:not(:hover)` hands off cleanly to the pink rule above once the cursor is actually
   on the button, so the two never fight over the background. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr:hover .delete-filter:not(:hover) {
    background: var(--bg-muted) !important;
}

/* --- Filter row -> card ---
   The four-column table row squeezes both selects too tight to read their labels, on any
   screen size — not just the drawer's own ~632px. Restack it the same way at every width:
   field on the first line, condition and value on the second, delete pinned top-right. One
   card layout for mobile and desktop means one visual language and one thing to maintain,
   instead of a second "Filter N" mobile-only header row duplicating what the card's own
   delete button already does. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid {
    display: block;
    margin: 0;
    background: none;
}
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
}

/* Mirrors the QueryBuilder `.rule-container` above, so both builders read the same. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) auto;
    gap: var(--space-2);
    align-items: center;
    border: 1px solid var(--border-subtle);
    border-radius: var(--radius-md);
    background: var(--bg-surface);
    padding: var(--space-2) var(--space-3);
}
/* table-striped tints odd rows; the card owns its own background now. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid.table-striped > tbody > tr:nth-of-type(odd) {
    background: var(--bg-surface);
}
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td {
    display: block;
    border: 0;
    padding: 0;
    min-width: 0;
}
/* `_filter.php` renders the value cell with an inline `style="min-width:250px"`, meant for
   the old table layout where that column had the whole row's remaining width to spend. An
   inline style beats this rule's `min-width: 0` above outright regardless of selector
   specificity, so on a truly narrow screen this alone forced the card (and the whole drawer)
   to overflow horizontally instead of letting the grid track shrink. `!important` is the only
   way to beat an inline style. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td.value-td {
    min-width: 0 !important;
}

/* The mobile-only "Filter N" header cell (`report/_filter.php`'s first `<td>`) duplicates
   the card's own delete button and has no desktop equivalent, so it's dropped everywhere
   in this drawer, not just above 768px. Both Bootstrap's own `.visible-xs { display: block
   !important }` (below 768px) and the widget's inline `registerCss()` copy of the same rule
   (`widgets/views/ReportFilterInput.php`, for the 768-1024 tablet device-width range) need
   beating — hence the `!important` and the specificity margin over both (one class, one
   element each) to survive either one firing. Being a child of a `display: grid` row also
   makes it a grid item regardless of its own `display` value unless that value is `none`,
   so anything short of fully hidden would auto-place into a stray extra row. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid td.visible-xs {
    display: none !important;
}

/* The delete button's own cell is `hidden-xs` (Bootstrap only ever meant it for desktop,
   paired with the `visible-xs` header cell above as its mobile stand-in). Now that this
   whole row is one unconditional card, Bootstrap's own `.hidden-xs { display: none
   !important }` below 768px would remove it exactly where the drawer needs it most —
   force it back with the same specificity-over-!important approach as `visible-xs` above. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid td.hidden-xs {
    display: block !important;
}

/* Cell order in `report/_filter.php` is: mobile header (hidden above), attribute, condition,
   value, delete. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td:nth-child(2) {
    grid-area: 1 / 1 / 2 / 3;
}
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td:nth-child(3) {
    grid-area: 2 / 1 / 3 / 2;
}
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td:nth-child(4) {
    grid-area: 2 / 2 / 3 / 3;
}
/* Row 1 only, so `align-items: center` lines it up with the field select rather than
   with the middle of the whole card. Column 3 stays empty on row 2, which also keeps
   the condition and value cells' right edge flush with the field above them. */
.ui-refresh .ajax-drawer .query-builder .responsive-grid > tbody > tr > td:nth-child(5) {
    grid-area: 1 / 3 / 2 / 4;
}
