/* ============================================================
 * NextGen MIS — Universal search & filter pattern
 * ------------------------------------------------------------
 * A clean toolbar above the table:
 *
 *   [ 🔍 Search…  ✕ ]                    [ ⚙ Filters · 2 ▾ ]  ✕ Clear all
 *   ┌── (inline panel, opens on toggle) ───────────────────────────────┐
 *   │  Province      District     LLG                                   │
 *   │  [control]     [control]    [control]   …                         │
 *   └───────────────────────────────────────────────────────────────────┘
 *   table…
 *
 *   • Live keyword search (clear with ✕), flush-left, fixed width.
 *   • "Filters" toggle (top-right, same line) opens an INLINE panel with
 *     all the filter fields — controls stay in place, so select2 / native
 *     selects open their single dropdown normally (no nested dropdowns).
 *   • The toggle carries an active-filter COUNT badge.
 *   • "Clear all" appears only when something's active.
 *   • Branded .ng-loader overlays the table during server round trips.
 *
 * refinements.js injects the toolbar around the existing #form-filter and
 * toggles the panel — it never moves the controls. Every hook
 * (#form-filter / #filter-submit / #filter-reset / filter_*) is preserved.
 * Authored in px; semantic tokens; ng- BEM.
 * ============================================================ */

/* ---------- SHELL (flat, flush with the table) ---------- */
.list-filter-panel.panel {
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
  box-shadow: none !important;
  margin: 0 0 var(--space-4) 0 !important;
  padding: 0 !important;
  overflow: visible !important;
}
.list-filter-panel.ng-has-toolbar > .panel-heading,
.list-filter-panel.ng-has-toolbar > .panel-footer { display: none !important; }

/* Keyword-only lists (no .list-filter-field chips): hide the empty panel body
   so the toolbar search sits flush above the table with no blank strip. */
.list-filter-panel.ng-filter-keyword-only > .panel-body { display: none !important; }

/* ---------- TOOLBAR ROW ---------- */
.ng-filter-bar {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
}
.ng-filter-bar__spacer { flex: 1 1 auto; }

/* ---------- KEYWORD SEARCH (fixed width, flush left) ---------- */
.ng-filter-search {
  position: relative;
  flex: 0 0 340px;
  width: 340px;
  max-width: 100%;
}
.ng-filter-search > .ng-filter-search__icon {
  position: absolute;
  left: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  width: 16px; height: 16px;
  pointer-events: none;
  background-color: var(--color-text-faint);
  -webkit-mask: url(/img/icons/phosphor/magnifying-glass.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/magnifying-glass.svg) center / contain no-repeat;
}
.ng-filter-search > .form-control {
  width: 100% !important;
  height: 40px !important;
  min-height: 40px !important;
  border-radius: var(--radius-md) !important;   /* design-system control radius (not a pill) */
  border-color: var(--color-filter-border) !important;  /* shared AA boundary — matches the chips */
  padding-left: 38px !important;
  padding-right: 36px !important;
}
.ng-filter-search__clear {
  position: absolute;
  right: 7px; top: 50%;
  transform: translateY(-50%);
  display: none;
  align-items: center; justify-content: center;
  width: 22px; height: 22px;
  padding: 0; border: 0;
  border-radius: var(--radius-full);
  background: transparent;
  color: var(--color-text-faint);
  font-size: 16px; line-height: 1;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard);
}
.ng-filter-search.is-filled .ng-filter-search__clear { display: inline-flex; }
.ng-filter-search__clear:hover,
.ng-filter-search__clear:focus-visible { background: var(--color-bg-sunken); color: var(--color-text-strong); }

/* ---------- "FILTERS" TOGGLE (top-right, with count) ---------- */
.ng-filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  height: 40px;
  padding: 0 var(--space-4);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  background: var(--color-bg-surface);
  color: var(--color-text-default);
  font-family: var(--font-family-display);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-base);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard),
              border-color var(--motion-fast) var(--ease-standard),
              color var(--motion-fast) var(--ease-standard);
}
.ng-filter-toggle:hover { background: var(--color-bg-raised); border-color: var(--color-border-strong); }
.ng-filter-toggle:focus-visible { outline: var(--focus-ring-width) solid var(--focus-ring-color); outline-offset: 2px; }
.ng-filter-toggle__icon {
  width: 16px; height: 16px; flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask: var(--ng-icon-sliders) center / contain no-repeat;
          mask: var(--ng-icon-sliders) center / contain no-repeat;
}
.ng-filter-toggle__count {
  display: inline-flex;
  align-items: center; justify-content: center;
  min-width: 20px; height: 20px;
  padding: 0 6px;
  border-radius: var(--radius-full);
  background: var(--color-brand-secondary-hover);   /* brand green (sage-700) — white text ~6.7:1, AA */
  color: #fff;
  font-family: var(--font-family-data);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  line-height: 1;
}
.ng-filter-toggle__count[hidden] { display: none; }
.ng-filter-toggle__caret {
  width: 12px; height: 12px; flex: 0 0 auto;
  background-color: var(--color-text-faint);
  -webkit-mask: url(/img/icons/phosphor/caret-down.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/caret-down.svg) center / contain no-repeat;
  transition: transform var(--motion-base) var(--ease-standard);
}
.list-filter-panel.is-open .ng-filter-toggle__caret { transform: rotate(180deg); }
/* Panel-open signifier — darker border + a subtle background tint (the same
   warm tint as the chips, for cohesion), animated by the toggle's existing
   border/background transition. Scoped to :not(.is-active) so the stronger
   green "filters applied" state below still wins when both hold. Qualified with
   .panel + !important to out-rank Metronic's deep .portlet button styling. */
.list-filter-panel.panel.is-open .ng-filter-toggle:not(.is-active) {
  border-color: var(--color-border-strong) !important;
  background: var(--color-chip-bg) !important;
}
/* Engaged look when filters are applied — brand green, consistent with the
   count badge and the green focus treatment on the controls below. Text/caret
   use sage-700 (~6.7:1 on the sage-50 wash) so the label stays AA. */
.ng-filter-toggle.is-active { border-color: var(--color-brand-secondary); color: var(--color-brand-secondary-hover); background: var(--color-brand-secondary-soft); }
.ng-filter-toggle.is-active .ng-filter-toggle__caret { background-color: var(--color-brand-secondary-hover); }

/* ---------- ADVANCED FILTERS (disclosure) ----------
   The list-filter panel reuses the report-builder disclosure component
   (.ng-report-advanced-toggle / .ng-report-advanced in _report-builder.css) so
   the "Advanced filters" pill reads identically to the report screens. Two
   context tweaks: the report toggle indents by the report row-label gutter
   (--ng-report-label-w), which doesn't exist here, so pin it flush-left; and
   tighten the revealed panel's own checkbox spacing. */
.list-filter-panel .ng-report-advanced-toggle { margin-left: 0; }
.list-filter-panel .ng-report-advanced .checkbox { margin: 0; }

/* ---------- CLEAR ALL ---------- */
.ng-filter-clear {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  height: 40px;
  padding: 0 var(--space-3);
  border: 0;
  background: transparent;
  color: var(--color-text-muted);
  font-family: var(--font-family-ui);
  font-weight: var(--font-weight-medium);
  font-size: var(--font-size-sm);
  cursor: pointer;
  border-radius: var(--radius-md);
  transition: background-color var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard);
}
.ng-filter-clear::before {
  content: "";
  width: 14px; height: 14px; flex: 0 0 auto;
  background-color: currentColor;
  -webkit-mask: url(/img/icons/phosphor/x.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/x.svg) center / contain no-repeat;
}
.ng-filter-clear:hover { background: var(--color-bg-sunken); color: var(--color-text-strong); }
.ng-filter-clear[hidden] { display: none !important; }

/* ---------- INLINE FILTER ROW (opens on toggle) ----------
   Revealed below the toolbar as a single line of compact "lozenge" filter
   controls (wrapping only when the viewport can't hold them). No heavy panel
   box — it reads as a continuation of the toolbar. */
.list-filter-panel > .panel-body {
  background: transparent !important;
  border: 0 !important;
  padding: 0 !important;
  display: none;                         /* closed by default */
}
.list-filter-panel.is-open > .panel-body,
.list-filter-panel.ng-collapsed.is-open > .panel-body {   /* defensive vs stray .ng-collapsed */
  display: block !important;
  margin-top: var(--space-3);
}

/* ----- INLINE one-row variant (data-filter-inline, ≤3 filters) -----
   Always open, no "Filters" toggle: the action button, optional search, the field
   chips and "Clear all" all share the .list-filter-fields flex row, so the CTA +
   filters sit on ONE line. A page with no CTA + no search is simply the field row. #538 */
.list-filter-panel.ng-filter-inline.is-open > .panel-body { margin-top: 0; }   /* no toolbar above to clear */
.ng-filter-inline .list-filter-fields > .list-filter-action { flex: 0 0 auto; margin: 0; }
.ng-filter-inline .list-filter-fields > .list-filter-action .btn { height: 40px; }   /* match the 40px field chips */
.ng-filter-inline .list-filter-fields > .ng-filter-search--inline {
  flex: 0 0 340px;
  width: 340px;
  max-width: 100%;
  margin: 0;
}
.ng-filter-inline .list-filter-fields > .ng-filter-clear--inline { flex: 0 0 auto; }
/* "Filter by" label + the filter group are pushed to the RIGHT (the label takes the
   row's free space via margin-left:auto); the CTA + optional search stay on the left. */
.ng-filter-inline .list-filter-fields > .ng-filter-by {
  flex: 0 0 auto;
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  height: 40px;
  color: var(--color-text-muted);
  font-family: var(--font-family-ui);
  font-size: var(--font-size-sm);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
}
/* ≤3-filter pages use STANDARD DS form inputs (not the tinted chip): the white input
   fill + the 1px input border + the control radius, so they match the rest of the form
   system. The toggle-panel variant (>3 filters) keeps the rounded chip. #538 */
.list-filter-panel.ng-filter-inline .list-filter-fields > .list-filter-field {
  border-radius: var(--radius-md);
  background: var(--color-input-bg);
  border: 1px solid var(--color-input-border);
}
/* ----- Responsive collapse (dynamic) — refinements.js measures the inline row and adds
   .ng-filter-collapsed when it can't fit one line. Collapsed: the "Filter by" label + the
   fields hide behind a "Filters" toggle and reveal stacked below it on click (.is-fopen),
   like the >3-filter pattern. Desktop (no class) is untouched — the toggle stays hidden. */
.ng-filter-inline .list-filter-fields > .ng-filter-inline__toggle { display: none; }
.ng-filter-inline.ng-filter-collapsed .list-filter-fields > .ng-filter-inline__toggle {
  display: inline-flex;
  margin-left: auto;
}
.ng-filter-inline.ng-filter-collapsed .list-filter-fields > .ng-filter-by,
.ng-filter-inline.ng-filter-collapsed .list-filter-fields > .list-filter-field,
.ng-filter-inline.ng-filter-collapsed .list-filter-fields > .ng-filter-clear--inline { display: none; }
/* …revealed below the toggle when open: each filter on its own full-width line */
.ng-filter-inline.ng-filter-collapsed.is-fopen .list-filter-fields > .ng-filter-by,
.ng-filter-inline.ng-filter-collapsed.is-fopen .list-filter-fields > .list-filter-field,
.ng-filter-inline.ng-filter-collapsed.is-fopen .list-filter-fields > .ng-filter-clear--inline {
  display: inline-flex;
  flex: 1 1 100%;
  max-width: none;
  margin-left: 0;
}
/* "Filter by" reads as a small section header above the stacked fields */
.ng-filter-inline.ng-filter-collapsed.is-fopen .list-filter-fields > .ng-filter-by {
  height: auto;
  margin-top: var(--space-2);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
}
.ng-filter-inline.is-fopen .ng-filter-inline__toggle .ng-filter-toggle__caret { transform: rotate(180deg); }

/* One-line CHIP row — flush-left with the search box above. Each filter is an
   equal-width, subtly-tinted lozenge holding just its control (the control's
   placeholder / selected value is the label — no separate visible label, to
   avoid the "Province + All provinces" double-up). Distinct from the white
   search field via the tinted fill + a thin AA-contrast (≥3:1) border. */
.list-filter-panel .list-filter-fields {
  display: flex !important;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin: 0 !important;
  padding: 0 !important;
}
/* Multi-row layouts (e.g. service inbox): stack explicit filter lines with the
   same 8px rhythm as the horizontal chip gap — no Bootstrap .row/.col padding. */
.list-filter-panel .list-filter-fields-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0 !important;
  padding: 0 !important;
}
/* Bootstrap's .row ships clearfix ::before/::after. In our flex row they become
   phantom flex items — the ::before sits first, and the row's `gap` then pushes
   the first chip 8px right of the search field. Remove them so the first chip
   is flush-left with the search box above. */
.list-filter-panel .list-filter-fields::before,
.list-filter-panel .list-filter-fields::after {
  display: none !important;
  content: none !important;
}
/* Neutralise the shared partial's col padding (.list-filter-fields > [col]
   { padding-left: 8px }) so the FIRST chip's left edge sits flush under the
   search field above. Higher specificity than both the partial and Bootstrap. */
.list-filter-panel .list-filter-fields > .list-filter-field {
  display: inline-flex;
  align-items: center;
  position: relative;                            /* anchor for the per-field clear (×) + caret */
  flex: 0 1 220px;                               /* cap width at 220px — never the unwieldy full-row stretch */
  min-width: 150px;
  max-width: 220px;
  height: 40px;
  /* asymmetric: text keeps a 12px left gap; the caret/clear hug the right (8px) */
  padding: 0 var(--space-2) 0 var(--space-3) !important;
  background: var(--color-chip-bg);              /* subtle warm tint (vs the white search box) */
  border: var(--border-width-emphasis) solid var(--color-filter-border);  /* 2px, AA-contrast (≥3:1), matches search */
  border-radius: var(--radius-full);             /* full-rounded pill */
  float: none !important;
  margin: 0 !important;
}
.list-filter-panel .list-filter-field:hover {
  border-color: var(--color-input-border-hover);
}
/* A chip the current selection has made meaningless — today only the batch
   status filter while "Archived" is showing, where every status leg is
   archived-exclusive so the pair can only ever return nothing. Dimmed in place
   rather than hidden: the control staying put (with a title explaining why) is
   what tells the operator the filter still exists. */
.list-filter-panel .list-filter-field.is-disabled {
  background: var(--color-input-bg-disabled);
  border-color: var(--color-input-border);
  cursor: not-allowed;
}
.list-filter-panel .list-filter-field.is-disabled:hover {
  border-color: var(--color-input-border);
}
/* Defeat _forms.css's blanket `.form-control[disabled] { background-color: … }
   !important` — inside a chip the control is meant to be transparent, and the
   grey belongs to the lozenge, not to a second box drawn inside it. */
.list-filter-panel .list-filter-field.is-disabled .form-control[disabled] {
  background-color: transparent !important;
  color: var(--color-text-muted);
  cursor: not-allowed;
}
.list-filter-panel .list-filter-field.is-disabled::after {
  opacity: 0.5;                                  /* the ::after caret */
}
/* Subtle focus state: brand-green border + soft sage ring. Also covers select2's
   focused + open states — its dropdown is appended to <body>, so :focus-within
   alone drops the instant the dropdown opens, leaving the chip with no cue. */
.list-filter-panel .list-filter-field:focus-within,
.list-filter-panel .list-filter-field:has(.select2-container--focus),
.list-filter-panel .list-filter-field:has(.select2-container--open) {
  border-color: var(--color-brand-secondary);
  box-shadow: var(--shadow-input-focus);
}
/* Label kept for screen readers (for/id association) but visually removed —
   the control's placeholder/value carries the meaning, so no double-up. */
.list-filter-panel .list-filter-label {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: 0 !important;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
/* The control blends into the tinted chip — no border/fill of its own — and
   fills the full chip width so the value text spans the lozenge and the
   caret/arrow lands hard against the right edge. */
.list-filter-panel .list-filter-field .form-control,
.list-filter-panel .list-filter-field .select2-selection,
.list-filter-panel .list-filter-field .select2-selection--single {
  height: 30px !important;
  min-height: 30px !important;
  border: 0 !important;
  background: transparent !important;
  box-shadow: none !important;
  border-radius: 0 !important;
  width: 100% !important;
  min-width: 0 !important;
}
.list-filter-panel .list-filter-field .select2-container { width: 100% !important; min-width: 0 !important; }

/* Selected value uses (almost) the full chip width. The shared _forms.css rule
   reserves 64px on the right via :has(.select2-selection__clear) — sized for
   wide form selects, it truncated the value far too early in a narrow chip
   ("East New Britain" → "M…"). Reserve only what the × (22) + caret (16)
   actually need. The :has() selector below matches _forms.css's specificity
   and wins by load order (_filters imports after _forms). */
.list-filter-panel .list-filter-field .select2-selection--single { padding: 0 !important; }
.list-filter-panel .list-filter-field .select2-selection__rendered,
.list-filter-panel .list-filter-field .select2-selection__rendered:has(.select2-selection__clear) {
  flex: 1 1 auto !important;          /* fill the chip (minus the caret) so the value uses all the room */
  width: auto !important;
  min-width: 0 !important;
  padding-left: 0 !important;
  padding-right: 50px !important;     /* room for the × + caret only — text gets the rest */
  line-height: 30px !important;
  overflow: hidden !important;
  text-overflow: ellipsis !important;
  white-space: nowrap !important;
}
/* Every dropdown chip (native <select> + select2 — both keep a <select> child)
   carries ONE consistent caret. The native select's own arrow was stripped by the
   transparent control fill, and select2's triangle differs; replace both with a
   single phosphor caret-down so every dropdown plainly reads as a dropdown. The chip
   is position:relative, so the caret anchors to its right edge. */
.list-filter-panel .list-filter-field:has(> select)::after {
  content: "";
  position: absolute;
  right: var(--space-3);
  top: 50%;
  transform: translateY(-50%);
  width: 12px; height: 12px;
  pointer-events: none;                          /* clicks fall through to the control */
  background-color: var(--color-text-muted);
  -webkit-mask: url(/img/icons/phosphor/caret-down.svg) center / contain no-repeat;
          mask: url(/img/icons/phosphor/caret-down.svg) center / contain no-repeat;
}
.list-filter-panel .list-filter-field .select2-selection__arrow { display: none !important; }   /* ::after replaces it */
/* Same for the multi-select: _forms.css draws its chevron via
   .select2-selection--multiple::after (the multi has no arrow element), which
   would double up with the chip's ::after caret above. */
.list-filter-panel .list-filter-field .select2-selection--multiple::after { content: none; }
/* A multi-select chip grows downward when its tags wrap (same rule the report
   builder gives its multi fields) instead of spilling out of the fixed 40px pill.
   Both layers need it: the pill, and the selection box inside it — the shared
   chip rule above pins .select2-selection to a fixed 30px, which would centre
   the wrapped tags and overflow them out both edges.
   border-radius also has to drop from the single-select's full pill (9999px) to
   the report builder's --radius-lg for a grown multi ("grows for selected
   chips", _report-builder.css): a stadium radius is computed off the box's own
   height, so once the chip grows past ~40px tall the curve balloons and eats
   into the top-right corner — clipping the ×/caret exactly there. */
.list-filter-panel .list-filter-fields > .list-filter-field:has(> select[multiple]) {
  height: auto;
  min-height: 40px;
  border-radius: var(--radius-lg);
  align-items: stretch;            /* chain the pill height down to the selection box (below) */
}
/* A grown chip must not re-centre its 40px siblings mid-air — top-align the row,
   same move as .ng-report-row. :has-scoped so rows without a multi keep their
   existing geometry. */
.list-filter-panel .list-filter-fields:has(> .list-filter-field > select[multiple]) {
  align-items: flex-start;
}
/* Make the selection box coextensive with the pill in EVERY state (empty, one
   tag, grown): field stretches container, container/`.selection` are flex so
   the stretch reaches the selection ul. Without this the sub-40px selection
   centres inside the pill with a few px of top offset — and the × below is
   anchored to the selection (position:relative in _forms.css), so its "first
   line" pin would drift against the field-anchored caret's. */
.list-filter-panel .list-filter-field:has(> select[multiple]) .select2-container,
.list-filter-panel .list-filter-field:has(> select[multiple]) .select2-container .selection {
  display: flex;
  flex: 1 1 auto;
  min-width: 0;
}
.list-filter-panel .list-filter-field .select2-selection--multiple {
  height: auto !important;         /* !important: matches the specificity of the 30px chip rule above */
  min-height: 30px !important;
}
/* The single-value contract above (30px line, nowrap + ellipsis) is wrong for a
   tag LIST: it inflated every tag to a 30px line box. Let rows size naturally,
   spaced by a row-gap + the rendered's own vertical padding instead of the
   vendor's per-tag margin-top (zeroed with the tint below). */
.list-filter-panel .list-filter-field .select2-selection--multiple .select2-selection__rendered {
  line-height: var(--line-height-base) !important;
  white-space: normal !important;
  row-gap: var(--space-1);
  padding-top: var(--space-1) !important;
  padding-bottom: var(--space-1) !important;
}
/* The inline search doubles as the placeholder ("All records") when empty.
   _forms.css pins its inset at 24px — right for a full-width form field, but on
   top of the pill's own 12px padding it put the placeholder at 36px while every
   other chip's value sits at 12px. The pill padding IS the inset here. */
.list-filter-panel .list-filter-field .select2-search--inline .select2-search__field {
  padding-left: 0 !important;
}
/* Once anything is selected, select2 blanks the placeholder attribute and
   shrinks the field to 0.75em — but even that stub can't fit beside a
   full-width tag in a 220px chip, so it wrapped onto its own EMPTY line: a
   dead ~30px band under the tags. Collapse it to zero-width when it has no
   placeholder to show. Typing in the (invisible) field still filters the open
   dropdown — same trade the report builder makes with its collapsed search. */
.list-filter-panel .list-filter-field .select2-search--inline .select2-search__field[placeholder=''] {
  width: 0 !important;             /* defeats select2's inline width */
  min-width: 0 !important;
  padding: 0 !important;
  margin: 0 !important;
}
/* The caret and the whole-field × are `top: 50%` so they sit centred in the
   fixed 40px single-select pill. Once a multi-select grows past that (wrapped
   tags), 50% recentres them on the TOTAL box height — landing beside the
   second tag rather than in the top-right corner. Pin them to the centre of
   the original 40px band instead (both anchors' tops coincide with the pill's,
   via the stretch chain above), so they stay put as the box grows. */
.list-filter-panel .list-filter-field:has(> select[multiple])::after,
.list-filter-panel .list-filter-field:has(> select[multiple]) .select2-selection__clear {
  top: 20px !important;
}
/* Tag fill / border / text come from _forms.css, which now tints every select2
   multi via color-mix so the tags knock back in dark mode. Only the chip-
   specific geometry lives here.
   Margins: _forms' 12px margin-left doubled the pill's own 12px padding into a
   24px tag inset (chip values sit at 12px); the vendor's margin-top staggered
   the rows — spacing now comes from the rendered's row-gap + padding above. */
.list-filter-panel .list-filter-field .select2-selection__choice {
  margin: 0 var(--space-1) 0 0 !important;
  /* A tag a few px too long for the chip's ~146px line must ellipsize, not
     fold into a two-line tag (flex items shrink below content by default).
     The 8px headroom (vs a plain 100%) keeps the tag + its 4px margin + the
     zero-width collapsed search <li> on ONE flex line — at a full 100% the
     margin pushed the empty <li> onto its own line, whose input height opened
     a dead band under the last tag. */
  max-width: calc(100% - 8px);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.list-filter-panel .list-filter-field select.form-control {
  -webkit-appearance: none !important; appearance: none !important;   /* drop the OS arrow; ::after is the caret */
  padding: 0 26px 0 0 !important;                                     /* clear the caret */
}
/* Text inputs leave room on the right for their own clear (×). */
.list-filter-panel .list-filter-field input.form-control { padding: 0 26px 0 0 !important; }

/* ----- Per-field clear (×) — ONE shared style for the select2 allowClear and
   the injected text-field button, matching the keyword search's ×: round,
   faint, hover fills grey. Absolutely positioned + vertically centred (the
   vendor float left the × sitting high / off-centre). ----- */
.list-filter-panel .list-filter-field .select2-selection__clear,
.list-filter-panel .list-filter-field .ng-field-clear {
  position: absolute !important;
  top: 50% !important;
  transform: translateY(-50%) !important;
  float: none !important;
  display: inline-flex !important;
  align-items: center !important;
  justify-content: center !important;
  width: 22px !important;
  height: 22px !important;
  margin: 0 !important;
  padding: 0 !important;
  border: 0 !important;
  border-radius: var(--radius-full) !important;
  background: transparent !important;
  color: var(--color-text-faint) !important;
  font-size: 16px !important;
  font-weight: var(--font-weight-regular) !important;
  line-height: 1 !important;
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--ease-standard), color var(--motion-fast) var(--ease-standard);
}
/* select2 × sits just left of the caret; the text-field × goes to the far
   right (no caret to clear). */
.list-filter-panel .list-filter-field .select2-selection__clear { right: 28px !important; }   /* sits left of the caret (12px) */
.list-filter-panel .list-filter-field .ng-field-clear { right: 4px !important; }
.list-filter-panel .list-filter-field .ng-field-clear[hidden] { display: none !important; }
.list-filter-panel .list-filter-field .select2-selection__clear:hover,
.list-filter-panel .list-filter-field .select2-selection__clear:focus-visible,
.list-filter-panel .list-filter-field .ng-field-clear:hover,
.list-filter-panel .list-filter-field .ng-field-clear:focus-visible {
  background: var(--color-bg-sunken) !important;
  color: var(--color-text-strong) !important;
}

/* ---------- BRANDED TABLE LOADER ---------- */
.ng-table-loading {
  position: absolute;
  inset: 0;
  z-index: var(--z-sticky);
  display: none;
  align-items: flex-start;
  justify-content: center;
  padding-top: 80px;
  background: rgba(255, 255, 255, 0.66);
}
/* Dark veil so the table-redraw loader (shown on sort/filter of a server-side
   DataTable) doesn't flash white over the dark table. Mirrors --color-bg-app dark. */
:root[data-theme="dark"] .ng-table-loading {
  background: rgba(22, 21, 19, 0.66);
}
.ng-table-loading.is-visible { display: flex; }

/* ---------- ICON TOKEN (sliders-horizontal, baked) ---------- */
:root {
  --ng-icon-sliders: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 256 256'%3E%3Cpath d='M40,88H73a32,32,0,0,0,62,0h81a8,8,0,0,0,0-16H135a32,32,0,0,0-62,0H40a8,8,0,0,0,0,16Zm64-24A16,16,0,1,1,88,80,16,16,0,0,1,104,64ZM216,168H183a32,32,0,0,0-62,0H40a8,8,0,0,0,0,16h81a32,32,0,0,0,62,0h33a8,8,0,0,0,0-16Zm-64,24a16,16,0,1,1,16-16A16,16,0,0,1,152,192Z'/%3E%3C/svg%3E");
}

/* ---------- LIST BULK ACTIONS ----------
   Top-left action bar on list pages — revealed (via JS) only when one or
   more rows are selected. Sits above the search/filter toolbar. */
.list-bulk-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.list-bulk-actions__count {
  margin-right: var(--space-1);
  font-size: var(--font-size-sm);
  color: var(--color-text-muted);
}

/* ---------- RESPONSIVE ---------- */
@media (max-width: 767px) {
  .ng-filter-search { flex: 1 1 100%; width: 100%; }
  .ng-filter-bar__spacer { display: none; }
}
