/* ============================================================
   AR UI Framework — List View ("search list")
   ------------------------------------------------------------
   The Odoo list-view shell: control panel, search box with
   facet chips and the Filters / Group By / Favorites panel,
   selection banner, sortable table with collapsible groups and
   an aggregate row, and the empty / no-results / loading states.

   Rendered by public/shared/components/list-view.php
   (app_list_view()) and driven by
   public/assets/js/components/list-view.js (window.ARListView).

   Source
   ------
   Generalised from the approved DeepSeek list-view mockup of
   2026-08-21 (archived at docs/design/mockups/), the same source
   and process as the 2026-08-11 SAP-blue table adoption and the
   module-form component.

   Framework rules this file follows
   ---------------------------------
   * No new palette. The mockup shipped 24 --app-list-view-*
     colour tokens; all but three carried values already in
     core/tokens.css (#005c9e, #e5f0fa, #d4e6f7, #107c41 ...).
     Every colour here resolves to a --tbl-* token, so the list
     view cannot drift away from the table it contains.
   * Sizing rides --ui-* so the list honours the 100/90/80
     UI-scale system in core/ui-scale.css. The mockup's fixed
     px sizing would have ignored it.
   * Buttons are NOT redefined app-wide: .app-list-view__btn is
     scoped to this component, for the compact 28px control-panel
     controls Odoo uses. Page-level buttons stay on the shared
     .btn family from components/buttons.css.
   * Every class is BEM-prefixed .app-list-view__*.
   * RTL comes from logical properties throughout. The mockup
     used `right: 0` on the dropdown and `left/right` in its
     media query, which would have pinned the panel to the wrong
     edge in Arabic.
   * Light-only, no prefers-color-scheme block.
   ============================================================ */

.app-list-view {
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-md, 8px);
    min-width: 0;
    font-size: var(--ui-font-size, 13px);
    line-height: var(--ui-line-height, 1.4);
    color: var(--tbl-text, #1a2026);
}

/* ============================================================
   Control panel
   ============================================================ */

/* Metrics match workspace/odoo-list-control-bar.css exactly -- 44px bar, white
   card, 4px radius, 34px controls, 8px control radius. Two list shells now run
   side by side in the app (25 pages on the older bar, this component on the
   migrated ones) and a control bar that is 10px taller with a 20px pill would
   read as a different product on every page that moved. Same numbers, one app. */
.app-list-view__control {
    display: flex;
    align-items: center;
    gap: var(--ui-space-md, 8px);
    flex-wrap: wrap;
    min-height: var(--odoo-list-control-h, 44px);
    max-height: var(--odoo-list-control-h, 44px);
    padding: 6px 12px;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
}

.app-list-view__control-start,
.app-list-view__control-end {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 6px);
    flex-shrink: 0;
}

.app-list-view__control-end { margin-inline-start: auto; }

.app-list-view__control-center {
    flex: 1 1 240px;
    min-width: 200px;
}

.app-list-view__title {
    margin: 0;
    font-size: var(--ui-font-size, 14px);
    font-weight: 600;
    color: var(--tbl-text, #1a2026);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: min(260px, 28vw);
}

/* Compact control-panel button. Scoped to this component on purpose --
   the shared .btn family is sized for page actions, not a 28px toolbar. */
.app-list-view__btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--ui-space-xs, 4px);
    height: 34px;
    padding-inline: var(--ui-space-md, 10px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: 8px;
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text-secondary, #3d4a5a);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: border-color .15s ease, color .15s ease, background .15s ease;
}

.app-list-view__btn:hover {
    border-color: var(--tbl-brand, #005c9e);
    color: var(--tbl-brand, #005c9e);
}

.app-list-view__btn[disabled] {
    opacity: .5;
    cursor: default;
    border-color: var(--tbl-border, #bcc3cd);
    color: var(--tbl-text-muted, #6b7a8a);
}

.app-list-view__btn--primary {
    background: var(--tbl-brand, #005c9e);
    border-color: var(--tbl-brand, #005c9e);
    color: var(--tbl-head-text, #fff);
}

.app-list-view__btn--primary:hover {
    background: var(--tbl-brand-hover, #004b82);
    border-color: var(--tbl-brand-hover, #004b82);
    color: var(--tbl-head-text, #fff);
}

.app-list-view__btn--icon {
    min-width: var(--ui-control-height-sm, 28px);
    padding-inline: var(--ui-space-sm, 6px);
}

.app-list-view__btn--quiet {
    border-color: transparent;
    background: transparent;
}

.app-list-view__icon {
    width: var(--ui-icon-size, 14px);
    height: var(--ui-icon-size, 14px);
    flex-shrink: 0;
    fill: none;
    stroke: currentColor;
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.app-list-view__icon--filled { fill: currentColor; stroke: none; }

/* ---- Pager ---- */

.app-list-view__pager {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    font-size: var(--ui-small-font-size, 12px);
    color: var(--tbl-text-secondary, #3d4a5a);
}

.app-list-view__pager-range {
    padding: 2px var(--ui-space-sm, 6px);
    border: 1px solid transparent;
    border-radius: var(--tbl-radius-sm, 2px);
    background: transparent;
    color: inherit;
    font: inherit;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    cursor: pointer;
}

.app-list-view__pager-range:hover { background: var(--tbl-brand-light, #e5f0fa); }

.app-list-view__pager-input {
    width: 84px;
    padding: 2px var(--ui-space-sm, 6px);
    border: 1px solid var(--tbl-brand, #005c9e);
    border-radius: var(--tbl-radius-sm, 2px);
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.app-list-view__pager-range[hidden],
.app-list-view__pager-input[hidden] { display: none; }

/* ---- View switcher ---- */

.app-list-view__views {
    display: flex;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: 8px;
    overflow: hidden;
}

.app-list-view__view {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: var(--ui-control-height-sm, 28px);
    height: calc(var(--ui-control-height-sm, 28px) - 2px);
    padding-inline: var(--ui-space-sm, 6px);
    border: 0;
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text-muted, #6b7a8a);
    cursor: pointer;
}

.app-list-view__view + .app-list-view__view {
    border-inline-start: 1px solid var(--tbl-border, #bcc3cd);
}

.app-list-view__view:hover {
    background: var(--tbl-brand-light, #e5f0fa);
    color: var(--tbl-brand, #005c9e);
}

.app-list-view__view[aria-pressed="true"] {
    background: var(--tbl-brand, #005c9e);
    color: var(--tbl-head-text, #fff);
}

/* ============================================================
   Search box
   ============================================================ */

.app-list-view__search { position: relative; }

.app-list-view__search-box {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ui-space-2xs, 3px);
    min-height: 34px;
    max-height: 34px;
    padding: 3px var(--ui-space-sm, 6px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: 8px;
    background: var(--tbl-surface, #fff);
    cursor: text;
    transition: border-color .15s ease, box-shadow .15s ease;
}

.app-list-view__search-box:focus-within {
    border-color: var(--tbl-brand, #005c9e);
    box-shadow: 0 0 0 2px rgba(0, 92, 158, .08);
}

.app-list-view__search-icon {
    flex-shrink: 0;
    margin-inline-end: var(--ui-space-xs, 4px);
    color: var(--tbl-text-muted, #6b7a8a);
}

.app-list-view__search-input {
    flex: 1 1 90px;
    min-width: 80px;
    /* min-height:0 is load-bearing: core/ui-scale.css gives every control a
       34px min-height, which pushed the box to 42 and the bar to 56 -- ten past
       the 44 the rest of the app's list bars are. */
    height: 26px;
    min-height: 0;
    padding-inline: var(--ui-space-xs, 4px);
    border: 0;
    background: transparent;
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    outline: none;
}

.app-list-view__search-input::placeholder { color: var(--tbl-text-muted, #6b7a8a); }

.app-list-view__search-caret {
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--tbl-text-muted, #6b7a8a);
    cursor: pointer;
    transition: transform .15s ease, color .15s ease;
}

.app-list-view__search-caret:hover { color: var(--tbl-brand, #005c9e); }
.app-list-view__search-caret[aria-expanded="true"] { transform: rotate(180deg); }

/* ---- Facet chips, inside the box ---- */

.app-list-view__facet {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-2xs, 3px);
    max-width: 100%;
    margin-block: 1px;
    padding: 1px 2px 1px var(--ui-space-xs, 4px);
    border: 1px solid transparent;
    border-radius: 12px;
    background: var(--tbl-brand-light, #e5f0fa);
    color: var(--tbl-brand, #005c9e);
    font-size: var(--ui-small-font-size, 11px);
    font-weight: 500;
    white-space: nowrap;
}

.app-list-view__facet:hover { border-color: var(--tbl-brand, #005c9e); }

.app-list-view__facet-label { opacity: .7; }

.app-list-view__facet-value {
    font-weight: 600;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* Odoo joins several values inside one facet with "or". */
.app-list-view__facet-or {
    opacity: .7;
    font-weight: 400;
    padding-inline: 2px;
}

.app-list-view__facet-remove {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: inherit;
    cursor: pointer;
    line-height: 1;
}

.app-list-view__facet-remove:hover { background: rgba(0, 92, 158, .12); }

/* ============================================================
   Search panel — Filters / Group By / Favorites
   ============================================================ */

.app-list-view__panel {
    position: absolute;
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    z-index: 60;
    display: flex;
    gap: var(--ui-space-xl, 24px);
    align-items: flex-start;
    min-width: min(560px, 100%);
    max-width: 680px;
    padding: var(--ui-space-lg, 14px) var(--ui-space-xl, 18px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .08);
}

.app-list-view__panel[hidden] { display: none; }

.app-list-view__panel-col {
    flex: 1 1 0;
    min-width: 170px;
    max-width: 240px;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.app-list-view__panel-heading {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    flex-shrink: 0;
    margin-block-end: var(--ui-space-sm, 6px);
    padding-block-end: var(--ui-space-xs, 4px);
    border-block-end: 1px solid var(--tbl-border, #bcc3cd);
    font-size: var(--ui-small-font-size, 10px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--tbl-text-muted, #6b7a8a);
}

.app-list-view__panel-heading .app-list-view__icon { width: 12px; height: 12px; }

/* Search-within-a-column. Not an Odoo feature -- added because a
   Collectors or Customers filter list here runs to dozens of entries. */
.app-list-view__panel-search {
    position: relative;
    flex-shrink: 0;
    margin-block-end: var(--ui-space-sm, 6px);
}

.app-list-view__panel-search input {
    width: 100%;
    height: 26px;
    padding-block: 3px;
    padding-inline: 26px var(--ui-space-md, 8px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius-sm, 2px);
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: var(--ui-small-font-size, 11px);
    outline: none;
}

.app-list-view__panel-search input:focus {
    border-color: var(--tbl-brand, #005c9e);
    box-shadow: 0 0 0 2px rgba(0, 92, 158, .06);
}

.app-list-view__panel-search .app-list-view__icon {
    position: absolute;
    inset-inline-start: 6px;
    inset-block-start: 50%;
    transform: translateY(-50%);
    width: 12px;
    height: 12px;
    color: var(--tbl-text-muted, #6b7a8a);
    pointer-events: none;
}

.app-list-view__panel-items {
    flex: 1 1 auto;
    overflow-y: auto;
    max-height: 220px;
    margin-inline-end: -4px;
    padding-inline-end: 4px;
}

.app-list-view__panel-items::-webkit-scrollbar { width: 4px; }
.app-list-view__panel-items::-webkit-scrollbar-track { background: var(--tbl-control-bg, #f0f2f5); border-radius: 100px; }
.app-list-view__panel-items::-webkit-scrollbar-thumb { background: var(--tbl-border-strong, #8f9aa8); border-radius: 100px; }
.app-list-view__panel-items::-webkit-scrollbar-thumb:hover { background: var(--tbl-brand, #005c9e); }

.app-list-view__panel-item {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 6px);
    width: 100%;
    padding: 3px var(--ui-space-sm, 6px);
    border: 0;
    border-radius: var(--tbl-radius-sm, 2px);
    background: transparent;
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    text-align: start;
    cursor: pointer;
}

.app-list-view__panel-item:hover { background: var(--tbl-brand-light, #e5f0fa); }
.app-list-view__panel-item[hidden] { display: none; }

.app-list-view__panel-item input[type="checkbox"] {
    width: 14px;
    height: 14px;
    flex-shrink: 0;
    accent-color: var(--tbl-brand, #005c9e);
    cursor: pointer;
}

.app-list-view__panel-item-text {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
}

.app-list-view__panel-count {
    flex-shrink: 0;
    margin-inline-start: auto;
    padding-inline: var(--ui-space-sm, 6px);
    border-radius: 100px;
    background: var(--tbl-control-bg, #f0f2f5);
    color: var(--tbl-text-muted, #6b7a8a);
    font-size: var(--ui-small-font-size, 10px);
    font-variant-numeric: tabular-nums;
}

.app-list-view__panel-sep {
    flex-shrink: 0;
    height: 1px;
    margin-block: 3px;
    background: var(--tbl-border, #bcc3cd);
}

.app-list-view__panel-item--action {
    flex-shrink: 0;
    color: var(--tbl-brand, #005c9e);
    font-weight: 500;
}

.app-list-view__panel-meter {
    flex-shrink: 0;
    margin-block-start: var(--ui-space-xs, 4px);
    padding-block-start: var(--ui-space-xs, 4px);
    border-block-start: 1px solid var(--tbl-border, #bcc3cd);
    color: var(--tbl-text-muted, #6b7a8a);
    font-size: var(--ui-small-font-size, 10px);
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* Save-current-search, expanding inline under the Favorites column. */
.app-list-view__panel-form {
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    gap: var(--ui-space-xs, 4px);
    padding: var(--ui-space-sm, 6px);
}

.app-list-view__panel-form[hidden] { display: none; }

.app-list-view__panel-form input[type="text"] {
    height: 26px;
    padding-inline: var(--ui-space-sm, 6px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius-sm, 2px);
    font: inherit;
    font-size: var(--ui-small-font-size, 11px);
    outline: none;
}

.app-list-view__panel-form input[type="text"]:focus { border-color: var(--tbl-brand, #005c9e); }

.app-list-view__panel-form label {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    font-size: var(--ui-small-font-size, 11px);
    color: var(--tbl-text-secondary, #3d4a5a);
}

/* ============================================================
   Popup menus (gear, optional columns)
   ============================================================ */

.app-list-view__menu-wrap { position: relative; display: inline-flex; }

.app-list-view__menu {
    position: absolute;
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    z-index: 60;
    min-width: 180px;
    padding: var(--ui-space-xs, 4px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .08);
}

.app-list-view__menu--end { inset-inline-start: auto; inset-inline-end: 0; }
.app-list-view__menu[hidden] { display: none; }

.app-list-view__menu-item {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 6px);
    width: 100%;
    padding: var(--ui-space-xs, 5px) var(--ui-space-md, 8px);
    border: 0;
    border-radius: var(--tbl-radius-sm, 2px);
    background: transparent;
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    text-align: start;
    cursor: pointer;
}

.app-list-view__menu-item:hover { background: var(--tbl-brand-light, #e5f0fa); }
.app-list-view__menu-item--danger { color: var(--tbl-danger, #b1302a); }
.app-list-view__menu-item--danger:hover { background: var(--tbl-danger-bg, #f7e8e7); }

.app-list-view__menu-item input[type="checkbox"] {
    width: 14px; height: 14px; accent-color: var(--tbl-brand, #005c9e); cursor: pointer;
}

.app-list-view__menu-sep { height: 1px; margin-block: 3px; background: var(--tbl-border, #bcc3cd); }

/* ============================================================
   Selection banner
   ============================================================ */

/*
 * The selected-count line. A LINE, not a panel, and its space is always reserved.
 *
 * It used to be a bordered blue box that appeared on the first tick: measured on
 * /contracts/all, ticking one row pushed the table down by 64px. A list jumping
 * under the cursor at the moment you click it is the worst possible time to move
 * it -- the next row you meant to tick is no longer where you aimed.
 *
 * So it keeps its place whether or not anything is selected: `visibility` instead
 * of `display`, the way the invoice review screen's own select-all line does. Same
 * proportions as that line -- 18px, 11px type, no box -- because all it has to say
 * is a number.
 */
.app-list-view__selection {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--ui-space-sm, 6px) var(--ui-space-md, 10px);
    min-height: 18px;
    margin-block-end: 3px;
    padding: 0 2px;
    color: var(--app-text-muted, #6b7280);
    font-size: 11px;
    font-weight: 600;
}

/*
 * Reserved, not removed: the row stays laid out and only its ink goes, which is
 * what keeps the table still. `visibility: hidden` also takes it out of the
 * accessibility tree, so nothing is announced while nothing is selected.
 *
 * `display` needs !important here and there is no way around it: core/reset.css
 * declares `[hidden] { display: none !important }` globally, so an ordinary
 * author rule loses and the line collapses anyway. Measured before this line was
 * added -- the table still jumped 49px with `visibility: hidden` set and nothing
 * else changed.
 */
.app-list-view__selection[hidden] {
    display: flex !important;
    visibility: hidden;
}

/*
 * The line's height must not change with its contents either, or the table moves
 * by the difference. The count, the "select all N" link and the clear button are
 * all sized to sit inside one 22px line.
 */
.app-list-view__selection { min-height: 22px; }
.app-list-view__selection .app-list-view__btn {
    min-height: 0;
    padding: 0 6px;
    font-size: 11px;
    line-height: 18px;
}
.app-list-view__selection .app-list-view__btn--icon {
    width: 18px;
    height: 18px;
    padding: 0;
    line-height: 1;
}
.app-list-view__selection .app-list-view__btn--icon svg {
    width: 12px;
    height: 12px;
}
.app-list-view__selection-count { font-weight: 700; font-variant-numeric: tabular-nums; }

.app-list-view__selection-all {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--tbl-brand, #005c9e);
    font: inherit;
    font-weight: 600;
    text-decoration: underline;
    cursor: pointer;
}

.app-list-view__selection-actions {
    display: flex;
    align-items: center;
    gap: var(--ui-space-sm, 6px);
    margin-inline-start: auto;
}

/* ============================================================
   Table
   ============================================================ */

.app-list-view__table-wrap {
    position: relative;
    overflow: auto;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
}

.app-list-view__table {
    width: 100%;
    border-collapse: separate;
    border-spacing: 0;
    font-size: var(--ui-table-font-size, 12px);
}

.app-list-view__table thead th {
    position: sticky;
    inset-block-start: 0;
    z-index: 2;
    padding: 0;
    background: var(--tbl-head-bg, #005c9e);
    color: var(--tbl-head-text, #fff);
    border-block-end: 1px solid var(--tbl-head-rule, #003f6e);
    white-space: nowrap;
    /* The browser's own default for <th> is `text-align: center`, and nothing here had
       overridden it: the component's own headers put their label in
       .app-list-view__th-inner, a flex box, where the th's text-align never applies. It
       applies on the tables that borrow this class and hand-build their head -- the four
       the portal receipts screens centred every header over start-aligned values, eight
       columns of it on open-po, purely from the UA sheet. Harmless to the component's own
       columns for the same reason it was invisible: a flex container ignores text-align,
       so end/centre there is still decided by justify-content on the inner. */
    text-align: start;
}

.app-list-view__th-inner {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    width: 100%;
    min-height: var(--ui-table-row-height, 32px);
    padding: var(--ui-table-cell-padding-y, 6px) var(--ui-table-cell-padding-x, 10px);
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-size: var(--ui-small-font-size, 11px);
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .03em;
    text-align: start;
}

/* Sortable headers are real buttons. The mockup put the click on the
   <th> itself, which is unreachable by keyboard. */
button.app-list-view__th-inner { cursor: pointer; }
button.app-list-view__th-inner:hover { background: var(--tbl-brand-hover, #004b82); }

.app-list-view__table th[aria-sort="ascending"],
.app-list-view__table th[aria-sort="descending"] { background: var(--tbl-head-sort-bg, #004b82); }

.app-list-view__sort {
    margin-inline-start: auto;
    opacity: .55;
    width: 10px;
    height: 10px;
}

.app-list-view__table th[aria-sort="ascending"] .app-list-view__sort,
.app-list-view__table th[aria-sort="descending"] .app-list-view__sort { opacity: 1; }
.app-list-view__table th[aria-sort="descending"] .app-list-view__sort { transform: rotate(180deg); }

.app-list-view__table td {
    height: var(--ui-table-row-height, 32px);
    padding: var(--ui-table-cell-padding-y, 6px) var(--ui-table-cell-padding-x, 10px);
    border-block-end: 1px solid var(--tbl-row-line, #d8dde4);
    vertical-align: middle;
}

.app-list-view__table tbody tr:last-child td { border-block-end: 0; }
.app-list-view__table tbody tr:hover td { background: var(--tbl-brand-light, #e5f0fa); }

.app-list-view__table tbody tr.is-selected td { background: var(--tbl-brand-selected, #d4e6f7); }
.app-list-view__table tbody tr.is-selected td:first-child {
    box-shadow: inset 3px 0 0 var(--tbl-brand, #005c9e);
}
html[dir="rtl"] .app-list-view__table tbody tr.is-selected td:first-child {
    box-shadow: inset -3px 0 0 var(--tbl-brand, #005c9e);
}

.app-list-view__tools-col { width: 1%; white-space: nowrap; }

/*
 * The tick column, at the width the invoice review screen proved: 34px, centred.
 *
 * `width: 1%` alone is not narrow, and the padding that makes it wide is not on
 * the cell. Measured on /contracts/all with selection on, the column came out at
 * 41px: the cell's own inline padding is already 0, but the header cell wraps its
 * content in `.app-list-view__th-inner`, which carries the table's 10px inline
 * padding on each side, and the checkbox itself adds 4px/3px of margin --
 * 10 + 4 + 14 + 3 + 10 = 41 exactly. Zeroing the cell padding alone changes
 * nothing, which is why this targets the inner wrapper and the checkbox's margins.
 *
 * Framework-level on purpose: every list in the app that turns selection on gets
 * the same narrow column, rather than each page discovering this and fixing it
 * its own way.
 */
.app-list-view__select-col {
    width: 34px;
    min-width: 34px;
    white-space: nowrap;
    text-align: center;
}
.app-list-view__table th.app-list-view__select-col,
.app-list-view__table td.app-list-view__select-col {
    padding-inline: 0;
}
.app-list-view__select-col .app-list-view__th-inner {
    padding-inline: 0;
    justify-content: center;
}
.app-list-view__select-col .app-list-view__checkbox {
    margin: 0;
}

.app-list-view__checkbox {
    width: 14px;
    height: 14px;
    accent-color: var(--tbl-brand, #005c9e);
    cursor: pointer;
}

.app-list-view__table thead .app-list-view__checkbox { accent-color: var(--tbl-head-text, #fff); }

.app-list-view__cell--end { text-align: end; }
.app-list-view__cell--center { text-align: center; }

/* The same two modifiers land on a <td>, which is block-ish and honours text-align, and
   on .app-list-view__th-inner, which is display:flex and does not -- text-align has no
   effect on the position of a flex item. So an end-aligned column had its values sitting
   right and its header label sitting left, offset by the width of the column. */
.app-list-view__th-inner.app-list-view__cell--end { justify-content: flex-end; }
.app-list-view__th-inner.app-list-view__cell--center { justify-content: center; }

.app-list-view__money {
    font-variant-numeric: tabular-nums;
    font-weight: 500;
    unicode-bidi: plaintext;
}

.app-list-view__money--positive { color: var(--tbl-success, #107c41); }
.app-list-view__money--negative { color: var(--tbl-danger, #b1302a); }

.app-list-view__link {
    color: var(--tbl-brand, #005c9e);
    font-weight: 500;
    text-decoration: none;
}

.app-list-view__link:hover { text-decoration: underline; }

.app-list-view__badge {
    display: inline-block;
    padding: 1px var(--ui-space-md, 8px);
    border-radius: 100px;
    font-size: var(--ui-small-font-size, 11px);
    font-weight: 500;
    white-space: nowrap;
}

.app-list-view__badge--success { background: var(--tbl-success-bg, #e6f2ea); color: var(--tbl-success, #107c41); }
.app-list-view__badge--warning { background: var(--tbl-warning-bg, #fcf0e0); color: var(--tbl-warning, #b25900); }
.app-list-view__badge--danger { background: var(--tbl-danger-bg, #f7e8e7); color: var(--tbl-danger, #b1302a); }
.app-list-view__badge--info { background: var(--tbl-info-bg, #e3edf5); color: var(--tbl-info, #1a5c8a); }
.app-list-view__badge--neutral { background: var(--tbl-muted-bg, #eef1f4); color: var(--tbl-muted, #5a6a7a); }

/* Row actions stay out of the way until the row is touched. */
.app-list-view__row-actions {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-2xs, 3px);
    opacity: 0;
    transition: opacity .12s ease;
}

.app-list-view__table tbody tr:hover .app-list-view__row-actions,
.app-list-view__table tbody tr:focus-within .app-list-view__row-actions,
.app-list-view__table tbody tr.is-selected .app-list-view__row-actions { opacity: 1; }

@media (hover: none) {
    .app-list-view__row-actions { opacity: 1; }
}

/* ---- Group rows ---- */

.app-list-view__group > td {
    background: var(--tbl-group-bg, #e6e9ed);
    font-weight: 700;
    border-block-end: 1px solid var(--tbl-border-strong, #8f9aa8);
    border-block-start: 1px solid var(--tbl-border, #bcc3cd);
}

.app-list-view__group-toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    font: inherit;
    font-weight: 700;
    cursor: pointer;
}

.app-list-view__group-chevron { transition: transform .15s ease; width: 12px; height: 12px; }
.app-list-view__group-toggle[aria-expanded="false"] .app-list-view__group-chevron { transform: rotate(-90deg); }
html[dir="rtl"] .app-list-view__group-toggle[aria-expanded="false"] .app-list-view__group-chevron { transform: rotate(90deg); }

.app-list-view__group-count { font-weight: 400; color: var(--tbl-text-muted, #6b7a8a); }

/* Second-level groups indent from the leading edge. */
.app-list-view__group--depth-1 .app-list-view__group-toggle { padding-inline-start: var(--ui-space-lg, 16px); }
.app-list-view__row--depth-1 td:first-child { padding-inline-start: calc(var(--ui-table-cell-padding-x, 10px) + var(--ui-space-lg, 16px)); }

.app-list-view__table tbody tr[hidden] { display: none; }

/* ---- Aggregate row ---- */

.app-list-view__table tfoot td {
    background: var(--tbl-foot-bg, #d4e2f0);
    color: var(--tbl-foot-text, #002b4f);
    font-weight: 700;
    border-block-start: 2px solid var(--tbl-foot-rule, #005c9e);
    border-block-end: 0;
    position: sticky;
    inset-block-end: 0;
}

/* ============================================================
   States
   ============================================================ */

.app-list-view__state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--ui-space-xs, 4px);
    padding: 48px var(--ui-space-xl, 20px);
    text-align: center;
    color: var(--tbl-text-muted, #6b7a8a);
}

.app-list-view__state[hidden] { display: none; }

.app-list-view__state-icon { width: 36px; height: 36px; opacity: .45; margin-block-end: var(--ui-space-xs, 4px); }
.app-list-view__state-title { font-size: var(--ui-font-size, 15px); font-weight: 600; color: var(--tbl-text, #1a2026); }
.app-list-view__state-action { margin-block-start: var(--ui-space-md, 10px); }

/* ---- Loading skeleton ---- */

.app-list-view__skeleton-bar {
    height: 10px;
    border-radius: 100px;
    background: linear-gradient(90deg,
        var(--tbl-control-bg, #f0f2f5) 25%,
        var(--tbl-row-line, #d8dde4) 37%,
        var(--tbl-control-bg, #f0f2f5) 63%);
    background-size: 400% 100%;
    animation: app-list-view-shimmer 1.4s ease infinite;
}

@keyframes app-list-view-shimmer {
    from { background-position: 100% 50%; }
    to { background-position: 0 50%; }
}

@media (prefers-reduced-motion: reduce) {
    .app-list-view__skeleton-bar { animation: none; }
}

/* ============================================================
   Focus + responsive
   ============================================================ */

.app-list-view :focus-visible {
    outline: 2px solid var(--tbl-brand, #005c9e);
    outline-offset: 1px;
}

.app-list-view__table thead :focus-visible {
    outline-color: var(--tbl-head-text, #fff);
    outline-offset: -2px;
}

@media (max-width: 900px) {
    .app-list-view__panel {
        inset-inline: 0;
        min-width: 0;
        max-width: none;
        flex-direction: column;
        gap: var(--ui-space-lg, 14px);
    }
    .app-list-view__panel-col { max-width: none; min-width: 0; }
    .app-list-view__panel-items { max-height: 140px; }
}

@media (max-width: 768px) {
    .app-list-view__control { align-items: stretch; }
    .app-list-view__control-center { flex-basis: 100%; order: 3; }
    .app-list-view__control-end { margin-inline-start: 0; justify-content: space-between; flex: 1 1 auto; }
    .app-list-view__search-box { border-radius: var(--tbl-radius, 4px); }
    .app-list-view__table { min-width: 680px; }
}


/* ============================================================
   Panel as three menus (panel_style: menus)
   ------------------------------------------------------------
   The shape the app standardised on: separate Filters / Group By /
   Favorites buttons rather than one caret opening a three-column
   panel. Matches ar-odoo-search-panel--split so a migrated page is
   indistinguishable from one still on the older bar.
   ============================================================ */

.app-list-view__menus {
    display: flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    flex-shrink: 0;
}

.app-list-view__menu-btn {
    display: inline-flex;
    align-items: center;
    gap: var(--ui-space-xs, 4px);
    height: 34px;
    padding-inline: var(--ui-space-md, 8px);
    border: 1px solid transparent;
    border-radius: 8px;
    background: transparent;
    color: var(--tbl-text-secondary, #3d4a5a);
    font: inherit;
    font-size: var(--ui-small-font-size, 12px);
    white-space: nowrap;
    cursor: pointer;
}

.app-list-view__menu-btn:hover,
.app-list-view__menu-btn[aria-expanded="true"] {
    background: var(--tbl-brand-light, #e5f0fa);
    color: var(--tbl-brand, #005c9e);
}

.app-list-view__menu-btn .app-list-view__icon { width: 12px; height: 12px; }

.app-list-view__menu-panel {
    position: absolute;
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    z-index: 60;
    min-width: 220px;
    max-width: 320px;
    max-height: 460px;
    overflow-y: auto;
    padding: var(--ui-space-sm, 6px);
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
    box-shadow: 0 4px 16px rgba(0, 0, 0, .08);
}

.app-list-view__menu-panel[hidden] { display: none; }

/* In menus mode the search box holds only the icon, chips and input. */
.app-list-view__search--menus { display: flex; align-items: center; gap: var(--ui-space-xs, 4px); }
.app-list-view__search--menus .app-list-view__search-box { flex: 1 1 auto; min-width: 0; }


/* ============================================================
   Legacy cell classes
   ------------------------------------------------------------
   A migrated page keeps its own row rendering, and that JS emits
   the older table's cell classes. The component's own td rules are
   descendant selectors so padding, borders and hover already apply;
   these four map the alignment helpers, which tables.css scopes to
   .app-table and therefore does not reach inside this table. With
   them a page moves onto app_list_view() without touching a line
   of its JavaScript.
   ============================================================ */

.app-list-view__table .text-end { text-align: end; }
.app-list-view__table .text-center { text-align: center; }

.app-list-view__table .num,
.app-list-view__table .amount {
    text-align: end;
    font-family: var(--font-numeric);
    font-variant-numeric: tabular-nums;
}

.app-list-view__table .app-table__actions {
    width: 1%;
    white-space: nowrap;
    text-align: center;
}

.app-list-view__table .app-amount-pos { color: var(--tbl-success, #107c41); font-weight: 700; }
.app-list-view__table .app-amount-neg { color: var(--tbl-danger, #b1302a); font-weight: 700; }

/* Group rows produced by ARWorkspaceGroupTreeRenderer. */
.app-list-view__table tr[data-ar-group-toggle] > td,
.app-list-view__table .ar-group-row > td {
    background: var(--tbl-group-bg, #e6e9ed);
    font-weight: 700;
    border-block-end: 1px solid var(--tbl-border-strong, #8f9aa8);
}


/* ============================================================
   Filter bar  (search.style: bar)
   ------------------------------------------------------------
   The design language of /financial/invoice-review, adopted as the
   app's one list-filter look on 2026-08-22 after the Odoo hidden
   panel was rejected. Everything is on screen at once: labelled
   controls in a wrapping row, no caret, no mega dropdown, no facet
   chips to decode. Numbers are that page's, not new ones --
   11px bold muted label over a 34px control, 150px wide, 10px gap,
   the search growing to fill the rest and capped at 320px.
   ============================================================ */

/* Two rows: the search and its controls always visible, the filter controls
   collapsed under a toggle. Before this every filter a page declared sat inline
   beside the search, so a six-filter page wrapped the bar onto three lines before
   a single row of data appeared.

   Collapsing is only safe because the toggle carries an ACTIVE count and the row
   opens itself when anything is set -- a hidden filter quietly narrowing the list
   is the one outcome this must not produce. See data-lv-filters-toggle in
   components/list-view.js.

   Widths here stay in px on purpose. A `rem` inside a @media condition resolves
   against the browser's initial 16px, NOT the 14px this app sets on :root, so a
   rem breakpoint fires ~14% wider than its arithmetic suggests. */
.app-list-view__filters {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 10px;
    width: 100%;
    margin-block-end: 10px;
}

/* The column direction belongs to the TWO-ROW bar, not to this class.
   Three contracts pages (monthly-rebate, marketing-fees, profitability) render
   .app-list-view__filters by hand with flat children -- no __filters-main, no
   __filters-more -- because they draw the bar outside an .app-list-view shell.
   Turning the shared class into a column put every one of their controls on its
   own line: marketing-fees became 7 controls on 7 lines. So the stacking hangs
   off the modifier the component emits, plus :has() for any consumer that writes
   the two rows by hand. A browser without :has() still gets the wrap row, which
   is the layout this class had before the two-row bar existed. */
.app-list-view__filters--rows,
.app-list-view__filters:has(> .app-list-view__filters-main) {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 8px;
}

/* The two-row bar as a standalone class, for pages not yet on app_list_view().
   They each name their filter container differently -- .inv-review-filters,
   .pos-cash-filters, .commission-reps-toolbar -- so the layout cannot hang off any
   of those without either four copies of it or redefining a class its other users
   share. Redefining is what stacked held-invoices' seven filters one per line, 637px
   tall, because it also uses .inv-review-filters and has flat children. A page opts
   in by adding this class and the two row wrappers; nothing it already owns changes
   meaning. */
.app-filter-bar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 8px;
    width: 100%;
}

/* Each row spans the bar. Stated on the ROW rather than left to the bar's align-items,
   because three pages set `align-items: flex-end` on their own filter container -- written
   when that container WAS the single row and the declaration aligned controls on their
   baseline. On a column container the same declaration stops the rows stretching, so the row
   fell back to fit-content and wrapped inside itself while 500px of the bar sat empty beside
   it: measured on /financial/held-invoices at an 860px viewport, a 299px row inside an 813px
   bar, Filters and Clear on a second line. Those pages load after this file, so out-specifying
   their align-items would be a fight; width does not need one. */
.app-list-view__filters-main,
.app-list-view__filters-more {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    align-items: flex-end;
    width: 100%;
}

/* The row is toggled by the `hidden` ATTRIBUTE rather than style.display, because
   core/reset.css declares `[hidden] { display: none !important }` -- an inline
   display would lose to it. */
.app-list-view__filters-more[hidden] { display: none; }

/* Row one carries no visible label line. The search input states its purpose in its
   own placeholder and the two buttons are labelled by their text, so the "Search"
   caption above them was 20px of vertical space -- a 16px line plus the 4px gap
   under it -- between the page header and the first control someone actually uses.
   Measured on financial/invoice-review: header to input was 30px, of which 20 was
   this.

   The <span> is hidden visually and kept for assistive tech; it is the input's
   accessible name and a placeholder is not a substitute for one. The `&nbsp;`
   spacers on the button fields exist only to align with that caption, so they go
   with it. Row two keeps its labels -- there the controls are bare selects and
   dates with nothing else to identify them. */
.app-list-view__filters-main .app-list-view__field > span:first-child,
.app-list-view__filters-main .app-label > span:first-child,
/* Some pages write the caption as a standalone <label for=...> rather than a <span>, so the
   two selectors above miss it and the row keeps the caption line they are meant to remove.
   The :not() is load-bearing: elsewhere the .app-label IS the wrapper around the control
   (<label class="app-label"><span>..</span><input></label>), and hiding that label would take
   the input with it. Only a label that holds no control is a caption. */
.app-list-view__filters-main .app-list-view__field > label.app-label:first-child:not(:has(input, select, textarea)) {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
}

.app-list-view__filters-more {
    padding-block-start: 8px;
    border-block-start: 1px dashed var(--tbl-border, #bcc3cd);
}

.app-list-view__filters-toggle {
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.app-list-view__filters-toggle[aria-expanded="true"] {
    background: var(--tbl-brand-light, #e5f0fa);
    border-color: var(--tbl-brand, #005c9e);
    color: var(--tbl-brand, #005c9e);
}

/* Count of filters currently narrowing the list. Shown only when non-zero, so an
   untouched bar carries no noise. */
.app-list-view__filters-count {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 16px;
    height: 16px;
    padding: 0 4px;
    border-radius: 8px;
    background: var(--tbl-brand, #005c9e);
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.app-list-view__filters-count[hidden] { display: none; }

.app-list-view__field {
    display: flex;
    flex-direction: column;
    gap: 4px;
    font-size: 11px;
    font-weight: 700;
    color: var(--app-text-muted, #6b7280);
}

/* Pages that predate the component label their fields with <label for>, not the
   <span> the component emits. Both are the field's label; style them the same
   rather than leaving those pages a size and colour adrift. */
.app-list-view__field > .app-label {
    font-size: inherit;
    font-weight: inherit;
    color: inherit;
    margin: 0;
}

.app-list-view__field > select,
.app-list-view__field > input,
.app-list-view__field > .app-input {
    width: 150px;
    height: 34px;
    padding-inline: 8px;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: 12px;
    font-weight: 400;
}

.app-list-view__field > select:focus,
.app-list-view__field > input:focus,
.app-list-view__field > .app-input:focus {
    outline: none;
    border-color: var(--tbl-brand, #005c9e);
    box-shadow: 0 0 0 2px rgba(0, 92, 158, .08);
}

/* `flex: 1 1 220px` made sense when the search shared one row with every filter --
   it took the slack so the selects kept their natural widths. Alone on row one it
   takes ALL the slack: measured 763px of a 929px row, 82%, while the input inside
   stays capped at 320px. The visible result is a search box at one end and the
   Filters/Clear buttons flung to the other with a void between them.

   In the two-row bar it sizes to its own input instead, so the buttons sit beside
   it. The single-row rule is kept for any consumer still laying the bar out flat. */
/* The field sizes to its own input rather than growing. Growing left the input
   capped at its 320px max-width inside a field stretched to the full row -- on
   /contracts/marketing-fees a 320px box in a 1464px field, so the next control
   sat 1100px away with nothing in between. The __filters-main rule repeats the
   value at higher specificity on purpose: it keeps the <=900px `flex-basis:100%`
   below from taking the two-row bar's first row and dropping Filters/Clear onto
   a line of their own. On a flat bar that mobile behaviour is still wanted. */
/* Positioned on purpose: this 320px field is the anchor a search dropdown must hang
   from. The slot around it, .app-list-view__search, is ALSO position:relative and spans
   the whole control bar, so a menu appended one level too high stretches to the full
   width of the screen -- which is exactly what the outstanding, SOA and worklist pickers
   did. Anchoring here is what keeps a dropdown the width of the box it belongs to.
   FinancialPageUtils.searchDropdownAnchor() returns this element; see the note there. */
.app-list-view__field--search { flex: 0 1 320px; position: relative; }

.app-list-view__filters-main .app-list-view__field--search { flex: 0 1 320px; }
.app-list-view__field--search > input,
.app-list-view__field--search > .app-input { width: 100%; max-width: 320px; }

/* Group By stacks, so it is a checkable menu rather than a select --
   and the items stay <button data-group-by> so the existing controller
   keeps driving them. Same shape as the reference page's tag filter. */
.app-list-view__pick { position: relative; }

.app-list-view__pick-btn {
    display: inline-flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    width: 170px;
    height: 34px;
    padding-inline: 8px;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: var(--tbl-radius, 4px);
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-align: start;
    cursor: pointer;
}

.app-list-view__pick-btn:hover { border-color: var(--tbl-brand, #005c9e); }
.app-list-view__pick-caret { font-size: 10px; opacity: .85; }

.app-list-view__pick-menu {
    position: absolute;
    z-index: 1500;
    inset-block-start: calc(100% + 4px);
    inset-inline-start: 0;
    min-width: 220px;
    max-width: 300px;
    max-height: 280px;
    overflow: auto;
    padding: 5px;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: 6px;
    background: var(--tbl-surface, #fff);
    box-shadow: 0 8px 24px rgba(15, 23, 42, .12);
}

.app-list-view__pick-menu[hidden] { display: none; }

.app-list-view__pick-menu [data-group-by],
.app-list-view__pick-opt {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 5px 8px;
    border: 0;
    border-radius: 5px;
    background: transparent;
    color: var(--tbl-text, #1a2026);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    text-align: start;
    cursor: pointer;
}

.app-list-view__pick-menu [data-group-by]:hover,
.app-list-view__pick-opt:hover { background: var(--app-surface-muted, #f6f8fb); }
.app-list-view__pick-menu [data-group-by].is-active { color: var(--tbl-brand, #005c9e); }

.app-list-view__field--action { justify-content: flex-end; }
.app-list-view__field--action > span { visibility: hidden; }

@media (max-width: 900px) {
    .app-list-view__field > select,
    .app-list-view__field > input,
    .app-list-view__field > .app-input { width: 140px; }
    .app-list-view__field--search { flex-basis: 100%; }
}

/* A one-option filter group renders as a toggle rather than a select. */
.app-list-view__toggle-filter {
    height: 34px;
    padding-inline: 12px;
    border: 1px solid var(--tbl-border, #bcc3cd);
    border-radius: 999px;
    background: var(--tbl-surface, #fff);
    color: var(--tbl-text-secondary, #3d4a5a);
    font: inherit;
    font-size: 12px;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.app-list-view__toggle-filter:hover { border-color: var(--tbl-brand, #005c9e); }

.app-list-view__toggle-filter.is-active {
    border-color: var(--tbl-brand, #005c9e);
    background: var(--tbl-brand-light, #e5f0fa);
    color: var(--tbl-brand, #005c9e);
}

/* ---------------------------------------------------------------------------
   "More filters" -- see components/list-view-more-filters.js
   ---------------------------------------------------------------------------
   Holds filter groups whose options only arrive after load, which the
   server-built bar cannot know about. Reuses the pick dropdown so it is the
   same object as Group By, and sits next to it on the bar.
   --------------------------------------------------------------------------- */
.app-list-view__more-title {
    padding: 6px 8px 2px;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--app-text-muted, #6b7280);
}

.app-list-view__more-title:first-child { padding-block-start: 2px; }

/* A tick in the gutter, so a chosen value reads as chosen rather than hovered. */
.app-list-view__pick-menu .app-list-view__pick-opt {
    position: relative;
    padding-inline-start: 22px;
}

.app-list-view__pick-opt.is-active { color: var(--tbl-brand, #005c9e); }

.app-list-view__pick-opt.is-active::before {
    content: "\2713";
    position: absolute;
    inset-inline-start: 7px;
    font-weight: 700;
}

/* Carry the "something is filtered in here" signal on the closed button too. */
.app-list-view__more.is-active .app-list-view__pick-btn {
    border-color: var(--tbl-brand, #005c9e);
    color: var(--tbl-brand, #005c9e);
    font-weight: 600;
}

/* The label can read "More filters (2) · Group By: Customer" -- wider than the
   button. Truncate rather than stretch the row. */
.app-list-view__more .app-list-view__pick-btn { max-width: 210px; }

.app-list-view__more [data-lv-more-label] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Group By, once adopted into the menu: same buttons, same controller, it just
   stops looking like a floating menu of its own. */
.app-list-view__more-group {
    position: static;
    z-index: auto;
    min-width: 0;
    max-width: none;
    max-height: none;
    overflow: visible;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    box-shadow: none;
}

/* ── Card view ────────────────────────────────────────────────────────────
   The table/cards pair. Only one is ever visible; the component sets
   data-view on the wrapper and toggles `hidden`, so these rules style the
   grid rather than drive the switching. */
.app-list-view__cards{display:grid;gap:12px;padding:12px;grid-template-columns:repeat(auto-fill,minmax(260px,1fr))}
.app-list-view__cards[hidden]{display:none}

.app-list-view__card{position:relative;display:flex;gap:12px;padding:12px;border:1px solid var(--color-border,#d9e1ea);border-radius:var(--radius-lg,10px);background:#fff;min-width:0}
.app-list-view__card:hover{border-color:var(--tbl-link,#005c9e);box-shadow:0 1px 6px rgba(16,24,40,.08)}
/* A card whose title is a link is clickable across its whole surface (see the card
   click handler in list-view.js). :has() scopes the cursor to exactly those cards, so a
   card with no link keeps the default pointer instead of promising a click it has not got. */
.app-list-view__card:has(.app-list-view__card-title a[href]){cursor:pointer}
.app-list-view__card:has(.app-list-view__card-title a[href]) a,
.app-list-view__card:has(.app-list-view__card-title a[href]) button{cursor:pointer}

.app-list-view__card-select{position:absolute;inset-inline-start:8px;inset-block-start:8px;margin:0;cursor:pointer}
.app-list-view__card-select input{cursor:pointer;margin:0}

/* Fixed square so a grid of mixed logo shapes still lines up. */
.app-list-view__card-media{flex:0 0 56px;width:56px;height:56px;border-radius:8px;overflow:hidden;background:var(--color-surface-2,#f2f4f7);display:flex;align-items:center;justify-content:center}
.app-list-view__card-img{width:100%;height:100%;object-fit:contain}
.app-list-view__card-initials{font-size:1.125rem;font-weight:800;color:var(--color-muted,#667085)}

.app-list-view__card-body{flex:1 1 auto;min-width:0}
.app-list-view__card-title{margin:0;font-size:.875rem;font-weight:700;line-height:1.3;overflow-wrap:anywhere}
.app-list-view__card-title a{color:var(--tbl-link,#005c9e);text-decoration:none}
.app-list-view__card-title a:hover{text-decoration:underline}
.app-list-view__card-subtitle{margin:2px 0 0;font-size:.75rem;color:var(--color-muted,#667085)}
.app-list-view__card-badges{display:flex;flex-wrap:wrap;gap:4px;margin-top:6px}

.app-list-view__card-meta{margin-top:8px;display:grid;gap:2px}
.app-list-view__card-meta-row{display:flex;gap:6px;font-size:.75rem;min-width:0}
.app-list-view__card-meta-label{flex:0 0 auto;color:var(--color-muted,#667085)}
.app-list-view__card-meta-value{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

.app-list-view__card-actions{flex:0 0 auto;display:flex;align-items:flex-start}

/* The view toggle only makes sense while rows are showing. */
.app-list-view[data-state="empty"] .app-list-view__views,
.app-list-view[data-state="no_results"] .app-list-view__views{opacity:.5;pointer-events:none}

@media (max-width:600px){
  .app-list-view__cards{grid-template-columns:1fr;padding:8px;gap:8px}
}

/* ── Card view: the tile variant ──────────────────────────────────────────
   Same card, laid out picture-first. The default card is a contact card --
   a 56px avatar beside the text -- which is right for customers and wrong
   for a catalogue, where the photograph is the row rather than a decoration.
   Only the layout changes: the markup, the JS and the switching are the
   component's existing ones, so a page still gets its cards from
   ARListView.renderCards() and never writes card markup of its own. */
.app-list-view__cards--tile{grid-template-columns:repeat(auto-fill,minmax(190px,1fr))}
.app-list-view__cards--tile .app-list-view__card{flex-direction:column;gap:0;padding:0;overflow:hidden}
/* Square, full width, and the SAME box whether or not there is a picture, so a
   catalogue that is mostly placeholders still lines up. */
.app-list-view__cards--tile .app-list-view__card-media{flex:0 0 auto;width:100%;height:auto;aspect-ratio:1/1;border-radius:0;border-bottom:1px solid var(--color-border,#d9e1ea)}
.app-list-view__cards--tile .app-list-view__card-initials{font-size:1.5rem}
.app-list-view__cards--tile .app-list-view__card-body{padding:8px 10px 10px}
/* Two lines, then ellipsis: product names here run past 60 characters, and a card
   that grows to fit one breaks the alignment of every card in its row. */
.app-list-view__cards--tile .app-list-view__card-title{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}
.app-list-view__cards--tile .app-list-view__card-select{background:#fff;border-radius:4px;padding:2px}

@media (max-width:600px){
  .app-list-view__cards--tile{grid-template-columns:repeat(auto-fill,minmax(150px,1fr))}
}
