/* ── Shared filter bar ──────────────────────────────────────────
   The index-page filter component: plain controls (.filter-input /
   .filter-select), the primary bar (.filter-bar-primary with search, selects
   and toggle pills) and the "More filters" popover. Promoted here from
   cashbook.css / invoices.css — it's used by cashbook, invoices, vendors,
   experts and donor-invoice views. Loads right after base.css; feature files
   add feature-specific containers on top. */

/* The plain filter form: controls and a Filter button in one wrapping row.
   The invoice index, vendor show and the admin index pages all use it. */
.filter-row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 1.25rem;
}

/* When the controls carry stacked .filter-field labels (vendor show's
   linked-invoices filter), bottom-align the row's buttons with the controls
   instead of centering them against the taller labelled fields. */
.filter-row .filter-field ~ .btn { align-self: flex-end; }

/* Outlined text field / select at density -3 (40px) so filters sit on one
   line with the 40px buttons beside them. */
.filter-input,
.filter-select {
  height: 40px;
  padding: 0 0.875rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-extra-small);
  font: var(--md-sys-typescale-body-medium);
  letter-spacing: var(--md-sys-typescale-body-medium-tracking);
  color: var(--md-sys-color-on-surface);
  background-color: var(--md-sys-color-surface-container-lowest);
  outline: none;
  transition:
    border-color var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard),
    box-shadow var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}

.filter-select {
  appearance: none;
  background-image: var(--dropdown-arrow);
  background-repeat: no-repeat;
  background-position: right 0.5rem center;
  background-size: 24px;
  padding-right: 2.5rem;
}

.filter-input:hover:not(:focus),
.filter-select:hover:not(:focus) {
  border-color: var(--md-sys-color-on-surface);
}

.filter-input { flex: 1; min-width: 180px; }
.filter-select { min-width: 160px; }

/* A select sizes itself to its longest option; cap it so one long project
   name can't squeeze the search field or push the row's button to a new line.
   Direct children only: inside a stacked .filter-field (a column flexbox) a
   flex-basis would become the control's height. */
.filter-row > .filter-input { flex: 1 1 14rem; }
.filter-row .filter-select { max-width: 14rem; text-overflow: ellipsis; }

.filter-input:focus,
.filter-select:focus {
  border-color: var(--md-sys-color-primary);
  box-shadow: inset 0 0 0 1px var(--md-sys-color-primary);
}

.filter-bar {
  margin-bottom: 1rem;
}

/* M3's list-filtering pattern: a search field on its own row, filter chips
   wrapping below it, all straight on the page with no container. */
.filter-bar-primary {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 0.5rem;
}

/* The search field fills its row; "Clear all" (when shown) sits at the row's
   end beside it, where it can never wrap onto a line of its own. */
.filter-search {
  position: relative;
  flex: 1 1 18rem;
  display: flex;
  align-items: center;
}

.filter-search-icon {
  position: absolute;
  left: 0.75rem;
  display: inline-flex;
  color: var(--md-sys-color-on-surface-variant);
  pointer-events: none;
}
.filter-search-icon .icon { width: 24px; height: 24px; }

/* The search field: an M3 outlined text field with a leading search icon —
   white, 1dp outline, extra-small corners, 48dp (form density). Not M3's
   grey pill search bar: grey read as disabled, and a white outlined pill is
   what an outlined button looks like. It inherits .filter-input's fill,
   outline, hover and focus. */
.filter-input--search {
  flex: 1;
  height: 48px;
  min-height: 48px;
  padding: 0 1rem 0 3rem;
  min-width: 0;
  font: var(--md-sys-typescale-body-large);
  letter-spacing: var(--md-sys-typescale-body-large-tracking);
}

/* A dropdown in the chips row is an M3 filter chip that opens a menu: 32dp,
   small (8dp) corners, label-large, a trailing 18dp arrow. The native
   <select> stays — the whole chip opens the menu (M3 asks for that on compact
   screens) and the platform picker stays accessible. Selects inside a chip's
   menu stay ordinary fields.

   Every chip here is outlined in `outline`, not M3's default outline-variant:
   M3's chip accessibility guidance asks for a 3:1 outline (or a label before
   the group) so a chip reads as interactive. The chip sets do both. */
.filter-bar-primary .filter-select:not(.filter-more-panel *) {
  flex: none;
  /* As wide as the chosen option's label, not the longest option's. */
  field-sizing: content;
  width: auto;
  min-width: 0;
  max-width: 16rem;
  height: 32px;
  min-height: 32px;
  padding: 0 2rem 0 1rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-small);
  background-color: transparent;
  background-position: right 0.5rem center;
  background-size: 18px;
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  text-overflow: ellipsis;
  cursor: pointer;
}
.filter-bar-primary .filter-select:not(.filter-more-panel *):hover:not(:disabled) {
  border-color: var(--md-sys-color-outline);
  background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 8%, transparent);
}
.filter-bar-primary .filter-select:not(.filter-more-panel *):focus-visible {
  border-color: var(--md-sys-color-outline);
  box-shadow: none;
  outline: var(--md-focus-ring);
  outline-offset: 2px;
}

/* Selected: a select with an "any" option whose pick is something else is
   an active filter — secondary-container fill, no outline, a leading check.
   A select with no "any" option (a required range end) is never "off", so it
   stays an unselected chip showing its value. */
.filter-bar-primary .filter-select:not(.filter-more-panel *):has(option[value=""]):has(option:checked:not([value=""])) {
  border-color: transparent;
  padding-left: 2.125rem;
  background-color: var(--md-sys-color-secondary-container);
  background-image: var(--chip-check), var(--dropdown-arrow);
  background-position: left 0.5rem center, right 0.5rem center;
  background-size: 18px, 18px;
  color: var(--md-sys-color-on-secondary-container);
}
.filter-bar-primary .filter-select:not(.filter-more-panel *):has(option[value=""]):has(option:checked:not([value=""])):hover {
  background-color: color-mix(in srgb, var(--md-sys-color-secondary-container), var(--md-sys-color-on-secondary-container) 8%);
}

/* Disabled chip: outline and label at M3's disabled opacities. */
.filter-bar-primary .filter-select:not(.filter-more-panel *):disabled {
  border-color: color-mix(in srgb, var(--md-sys-color-on-surface) 12%, transparent);
  color: color-mix(in srgb, var(--md-sys-color-on-surface) 38%, transparent);
  cursor: not-allowed;
}

/* A text input that shares the chips row (vendors' Tax ID) matches the
   chips' height so the row keeps one line. */
.filter-chip-set > .filter-input {
  flex: 0 1 12rem;
  height: 32px;
  min-height: 32px;
  border-radius: var(--md-sys-shape-corner-small);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
}

.filter-toggles {
  display: flex;
  gap: 0.5rem; /* the chip set's own spacing, so a nested group reads as one set */
  align-items: center;
}

/* M3 filter chip: 32px, small corners, outline border (see the 3:1 note
   above); selected fills with secondary-container and gains a leading check. */
.toggle-pill {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  height: 32px;
  padding: 0 1rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-small);
  background-color: transparent;
  color: var(--md-sys-color-on-surface-variant);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  cursor: pointer;
  user-select: none;
}

/* The chip is the hidden checkbox's containing block, so in a sideways-
   scrolling chip set the checkbox scrolls (and clips) with its chip instead
   of widening the page. */
.toggle-pill { position: relative; }

.toggle-pill input {
  position: absolute;
  opacity: 0;
  pointer-events: none;
}

/* Selected follows the live checkbox as well as the server's .is-active, so
   a chip that never submits ("Show all") still shows its state. */
.toggle-pill.is-active,
.toggle-pill:has(input:checked) {
  background-color: var(--md-sys-color-secondary-container);
  border-color: transparent;
  color: var(--md-sys-color-on-secondary-container);
  padding-left: 0.5rem;
}

.toggle-pill.is-active::before,
.toggle-pill:has(input:checked)::before {
  content: "";
  width: 18px;
  height: 18px;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M378-246 154-470l43-43 181 181 384-384 43 43-427 427Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M378-246 154-470l43-43 181 181 384-384 43 43-427 427Z'/%3E%3C/svg%3E") center / contain no-repeat;
}

.filter-more {
  position: relative;
}

/* An M3 filter chip that opens a menu ("More filters", Management's period):
   same 32dp chip as the dropdowns beside it. It shows selected — tonal fill —
   while its menu is open or while it carries active filters (a badge, or the
   period chip's chosen range). */
.filter-more-trigger {
  list-style: none;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 0.5rem 0 1rem;
  border: 1px solid var(--md-sys-color-outline);
  border-radius: var(--md-sys-shape-corner-small);
  background-color: transparent;
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  color: var(--md-sys-color-on-surface-variant);
  user-select: none;
  white-space: nowrap;
}
.filter-more-trigger:hover {
  background-color: color-mix(in srgb, var(--md-sys-color-on-surface-variant) 8%, transparent);
}
.filter-more-trigger:focus-visible {
  outline: var(--md-focus-ring);
  outline-offset: 2px;
}

.filter-more-trigger::-webkit-details-marker { display: none; }
.filter-more-trigger::after {
  content: "";
  width: 18px;
  height: 18px;
  margin-left: 0.5rem;
  background-color: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M480-360 280-560h400L480-360Z'/%3E%3C/svg%3E") center / contain no-repeat;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 -960 960 960'%3E%3Cpath d='M480-360 280-560h400L480-360Z'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform var(--md-sys-motion-duration-short4) var(--md-sys-motion-easing-standard);
}

.filter-more[open] .filter-more-trigger,
.filter-more-trigger:has(.filter-more-badge),
.filter-more-trigger.is-active {
  background-color: var(--md-sys-color-secondary-container);
  border-color: transparent;
  color: var(--md-sys-color-on-secondary-container);
}

.filter-more[open] .filter-more-trigger::after { transform: rotate(180deg); }

/* A chip holding a chosen value (the period chip's range) leads with the
   selected filter chip's check, like the dropdown chips. */
.filter-more-trigger.is-active { padding-left: 0.5rem; }
.filter-more-trigger.is-active::before {
  content: "";
  width: 18px;
  height: 18px;
  margin-right: 0.5rem;
  background-color: currentColor;
  -webkit-mask: var(--md-icon-check) center / contain no-repeat;
  mask: var(--md-icon-check) center / contain no-repeat;
}

.filter-more-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  height: 16px;
  padding: 0 0.25rem;
  margin-left: 0.375rem;
  /* M3 large badge: error container colours, label-small. */
  background: var(--md-sys-color-error);
  color: var(--md-sys-color-on-error);
  border-radius: var(--md-sys-shape-corner-full);
  font: var(--md-sys-typescale-label-small);
  letter-spacing: var(--md-sys-typescale-label-small-tracking);
}

.filter-more-panel {
  position: absolute;
  left: 0;
  top: calc(100% + 0.4rem);
  z-index: 20;
  /* M3 menu surface, remapped to white like the dialogs (modals.css says
     why): on the default surface-container grey, the controls inside read
     as inactive. */
  background: var(--md-sys-color-surface-container-lowest);
  border: none;
  border-radius: var(--md-sys-shape-corner-large);
  box-shadow: var(--md-sys-elevation-level2);
  padding: 1rem;
  min-width: 320px;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.filter-field {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  font: var(--md-sys-typescale-body-small);
  letter-spacing: var(--md-sys-typescale-body-small-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

.filter-field > span {
  font-weight: 500;
}

/* The control's own type and colour come from the base .filter-select rule. */
.filter-field .filter-select {
  min-width: 0;
  width: 100%;
}

/* Narrow screens: a chip that opens a menu takes its own row and its menu
   opens in the flow beneath it, full width — anchored mid-row, a 320dp menu
   would run off the screen. */
@media (max-width: 760px) {
  .filter-bar-primary > .filter-more { flex-basis: 100%; }
  .filter-more-panel { position: static; width: auto; min-width: 0; margin-top: 0.5rem; }
}

/* The filter chips, on their own row under the search field, led by a
   "Filter" label — M3's chip accessibility guidance names a label before the
   group as one way to show the chips are interactive. Wraps on wide screens. */
.filter-chip-set {
  flex: 1 1 100%;
  min-width: 0; /* a flex item otherwise grows to its chips' full width */
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.filter-chip-set-label {
  margin-right: 0.25rem;
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  color: var(--md-sys-color-on-surface-variant);
}

/* "Show all": M3's reflow method for a chip row too long for a phone. The
   set scrolls sideways in one row; this leading filter chip, when selected,
   reflows it to wrap so every chip shows at once. A nameless checkbox, so it
   never reaches the form's params; CSS-only via :has(). Only sets that carry
   one scroll — short sets just wrap. Hidden where the set wraps anyway. */
.filter-show-all { display: none; }

@media (max-width: 600px) {
  .filter-show-all { display: inline-flex; }

  .filter-chip-set:has(> .filter-show-all) {
    flex-wrap: nowrap;
    overflow-x: auto;
    padding-block: 4px; /* keeps the chips' focus rings inside the scroller */
    scrollbar-width: none;
  }
  .filter-chip-set:has(> .filter-show-all) > * { flex: none; }

  /* Reflowed by "Show all" — or while a chip's menu is open, which a
     sideways scroller would clip. */
  .filter-chip-set:has(> .filter-show-all input:checked),
  .filter-chip-set:has(> .filter-more[open]) {
    flex-wrap: wrap;
    overflow-x: visible;
  }
}

/* Narrow screens: an open menu chip inside a chip set takes the full row, so
   its in-flow menu (see .filter-more-panel above) has room. */
@media (max-width: 760px) {
  .filter-chip-set > .filter-more[open] { flex-basis: 100%; }
}

/* Set by filter_bar_controller when the menu would run off the screen. */
.filter-more-panel.opens-left { left: auto; right: 0; }

/* A chip menu's actions (a dismissive text button, then Apply) at the
   trailing edge. */
.filter-menu-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.5rem;
}

/* Clear all: a text button at the end of the chips. */
.filter-chip-clear-all {
  display: inline-flex;
  align-items: center;
  height: 32px;
  padding: 0 0.75rem;
  border-radius: var(--md-sys-shape-corner-full);
  color: var(--md-sys-color-primary);
  font: var(--md-sys-typescale-label-large);
  letter-spacing: var(--md-sys-typescale-label-large-tracking);
  text-decoration: none;
}

.filter-chip-clear-all:hover { background: color-mix(in srgb, var(--md-sys-color-primary) 8%, transparent); }

/* Inline "pick one and submit" row built on .filter-select. Shared by the
   vendor, expert and ToR link pickers — hence the components
   layer, not a feature file. */
.vendor-expert-link-form {
  display: flex;
  gap: 0.6rem;
  margin-top: 1rem;
}

.vendor-expert-link-form .filter-select {
  flex: 1;
  min-width: 0;
}

/* Linked state: the record's name beside its Unlink button. No wrap — in a
   narrow cell the name wraps internally and the button stays on its row, so
   stacked pairings (an expert's vendor list) keep each button beside its
   name. */
.vendor-expert-linked {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.vendor-expert-linked a {
  min-width: 0;
  overflow-wrap: anywhere;
}

.vendor-expert-linked + .vendor-expert-linked {
  margin-top: 0.4rem;
}

/* Type-ahead results under a .vendor-expert-link-form input. */
.vendor-search-results {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}
.vendor-search-result {
  background-color: transparent;
  border: none;
  border-radius: var(--md-sys-shape-corner-extra-small);
  min-height: 40px;
  padding: 0 0.75rem;
  text-align: left;
  cursor: pointer;
  font: var(--md-sys-typescale-body-large);
  letter-spacing: var(--md-sys-typescale-body-large-tracking);
  color: var(--md-sys-color-on-surface);
}
