/* Grid toolbar: the Export and Columns menus, and the multi-select filter.
 *
 * A separate file, `menu-drop-` / `multi-` prefixed, so nothing here can
 * disturb an existing selector. Grid *density* is not here — that edits
 * `.data-table` in echopms.css directly, because overriding a rule from
 * another stylesheet would leave two places to look.
 *
 * Colours come from the tokens in echopms.css.
 */

/* ---------------------------------------------------------------------
   Shared dropdown — used by Export and Columns
   ------------------------------------------------------------------ */

.menu-drop { position: relative; display: inline-block; }

.menu-drop__trigger {
    display: inline-flex; align-items: center; gap: 0.4rem;
    cursor: pointer; list-style: none; white-space: nowrap;
}
/* Safari draws its own marker on <summary>. */
.menu-drop__trigger::-webkit-details-marker { display: none; }

.menu-drop__caret {
    width: 0.4rem; height: 0.4rem; margin-left: 0.1rem;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg) translate(-1px, -1px);
    transition: transform var(--transition-fast);
}
.menu-drop[open] .menu-drop__caret { transform: rotate(-135deg) translate(-2px, -2px); }

.menu-drop__count {
    background: var(--color-accent-2); color: #fff;
    border-radius: var(--radius-full);
    font-size: var(--fs-xs); font-weight: 600;
    padding: 0.05rem 0.4rem; line-height: 1.4;
}

.menu-drop__panel {
    position: absolute; z-index: 100; right: 0; top: calc(100% + 0.35rem);
    min-width: 15rem;
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-2);
}

.menu-drop__heading {
    margin: 0 0 0.3rem; padding: 0 var(--sp-2);
    font-size: var(--fs-xs); font-weight: 700;
    text-transform: uppercase; letter-spacing: 0.04em;
    color: var(--color-text-subtle);
}

.menu-drop__item {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 0.4rem var(--sp-2); border-radius: var(--radius);
    font-size: var(--fs-sm); color: var(--color-text); text-decoration: none;
}
.menu-drop__item:hover { background: var(--color-section); }
.menu-drop__item[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }

.menu-drop__tag {
    flex: none; width: 3rem;
    font-size: var(--fs-xs); font-weight: 700; letter-spacing: 0.02em;
    color: var(--color-accent-2);
}

.menu-drop__list { max-height: 18rem; overflow-y: auto; }

.menu-drop__check {
    display: flex; align-items: center; gap: var(--sp-2);
    padding: 0.3rem var(--sp-2); border-radius: var(--radius);
    font-size: var(--fs-sm); cursor: pointer;
}
.menu-drop__check:hover { background: var(--color-section); }
.menu-drop__check input { margin: 0; }

.menu-drop__actions {
    display: flex; gap: var(--sp-3); justify-content: space-between;
    padding: var(--sp-2) var(--sp-2) 0.2rem;
    margin-top: 0.3rem; border-top: 1px solid var(--color-border);
}
.menu-drop__foot {
    margin: 0.35rem 0 0; padding: 0.3rem var(--sp-2) 0;
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
}

/* ---------------------------------------------------------------------
   Export status — announced politely, never a blocking dialog
   ------------------------------------------------------------------ */

.export-status {
    display: inline-flex; align-items: center; gap: 0.4rem;
    font-size: var(--fs-sm); padding: 0.2rem 0.5rem;
    border-radius: var(--radius);
}
.export-status:empty { display: none; }
.export-status.is-busy { color: var(--color-text-muted); }
.export-status.is-ok { color: var(--color-success); background: var(--color-success-soft); }
.export-status.is-error { color: var(--color-danger); background: var(--color-danger-soft); }

.export-status__spinner {
    width: 0.7rem; height: 0.7rem; border-radius: var(--radius-full);
    border: 2px solid var(--color-border-strong);
    border-top-color: var(--color-accent-2);
    animation: export-spin 0.7s linear infinite;
}
@keyframes export-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
    .export-status__spinner { animation: none; }
}

/* ---------------------------------------------------------------------
   Multi-select filter
   ------------------------------------------------------------------ */

.multi-select { position: relative; display: inline-block; min-width: 13rem; }

.multi-select__trigger {
    display: flex; align-items: center; gap: 0.4rem; width: 100%;
    padding: 0.4rem 0.6rem; font: inherit; text-align: left;
    background: var(--color-bg); color: var(--color-text);
    border: 1px solid var(--color-border); border-radius: var(--radius);
    cursor: pointer;
}
.multi-select__trigger:hover { border-color: var(--color-border-strong); }
.multi-select__trigger:focus-visible { outline: none; box-shadow: var(--shadow-focus); }
.multi-select__trigger.is-empty { color: var(--color-text-muted); }
.multi-select__summary { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.multi-select__panel {
    position: absolute; z-index: 100; left: 0; top: calc(100% + 0.3rem);
    width: max(100%, 17rem);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-lg);
    padding: var(--sp-2);
}
.multi-select__panel[hidden] { display: none; }

.multi-select__search {
    width: 100%; padding: 0.35rem 0.5rem; font: inherit;
    border: 1px solid var(--color-border); border-radius: var(--radius);
    background: var(--color-section); margin-bottom: 0.35rem;
}
.multi-select__search:focus {
    outline: none; background: var(--color-bg);
    border-color: var(--color-accent-2);
}

.multi-select__list { max-height: 15rem; overflow-y: auto; }
.multi-select__option {
    display: flex; align-items: flex-start; gap: var(--sp-2);
    padding: 0.3rem var(--sp-2); border-radius: var(--radius);
    font-size: var(--fs-sm); cursor: pointer;
}
.multi-select__option:hover,
.multi-select__option.is-active { background: var(--color-section); }
.multi-select__option input { margin: 0.2rem 0 0; }
.multi-select__sub {
    display: block; font-size: var(--fs-xs); color: var(--color-text-muted);
}
.multi-select__empty,
.multi-select__loading {
    padding: 0.5rem var(--sp-2); font-size: var(--fs-sm);
    color: var(--color-text-muted);
}

.multi-select__actions {
    display: flex; gap: var(--sp-3); justify-content: space-between;
    padding: var(--sp-2) var(--sp-2) 0.2rem;
    margin-top: 0.3rem; border-top: 1px solid var(--color-border);
}

/* The chosen values, shown under the control so the selection is visible
   without opening it. */
.multi-select__chips {
    display: flex; flex-wrap: wrap; gap: 0.25rem; margin-top: 0.3rem;
}
.multi-select__chips:empty { display: none; }
.multi-select__chip {
    display: inline-flex; align-items: center; gap: 0.3rem;
    padding: 0.1rem 0.4rem; font-size: var(--fs-xs);
    background: var(--color-accent-soft); color: var(--color-text-strong);
    border-radius: var(--radius-full);
}
.multi-select__chip button {
    border: none; background: none; cursor: pointer; padding: 0;
    font-size: 0.9rem; line-height: 1; color: var(--color-text-muted);
}
.multi-select__chip button:hover { color: var(--color-danger); }

/* ---------------------------------------------------------------------
   Toolbar layout
   ------------------------------------------------------------------ */

.filters .menu-drop { margin-left: 0.2rem; }

/* Push the menus to the right of the filter bar so every list page puts
   them in the same place. */
.filters__spacer { flex: 1 1 auto; }

@media (max-width: 720px) {
    .menu-drop__panel { right: auto; left: 0; min-width: 13rem; }
    .multi-select { min-width: 100%; }
    .filters__spacer { display: none; }
}

@media print {
    .menu-drop, .export-status, .multi-select { display: none !important; }
}

/* Reset sits beside Apply as a quieter action — clearing filters should
   not compete with running them. */
.filters__reset {
    color: var(--color-text-muted);
    text-decoration: none;
    padding: 0.35rem 0.5rem;
}
.filters__reset:hover { color: var(--color-danger); text-decoration: underline; }

/* ---------------------------------------------------------------------
   Status marks and icon-only actions
   ------------------------------------------------------------------ */

/* Text that only a screen reader reads. Used to give an icon-only
   control a name — without it, a button containing just an SVG is
   announced as "button" and nothing else. */
.visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    margin: -1px; padding: 0; border: 0;
    clip: rect(0 0 0 0); clip-path: inset(50%);
    overflow: hidden; white-space: nowrap;
}

/* Record status: a tick for active, a cross for inactive.
   Colour alone never carries the meaning — the word is in the tooltip
   and in the hidden label, so it survives colour blindness and reaches
   a screen reader. */
.status-mark {
    display: inline-flex; align-items: center; justify-content: center;
    width: 1.5rem; height: 1.5rem; border-radius: var(--radius-full);
    vertical-align: middle;
}
.status-mark--on { color: var(--color-success); background: var(--color-success-soft); }
.status-mark--off { color: var(--color-danger); background: var(--color-danger-soft); }

/* A destructive row action shown as a cross. It keeps the button it was
   always in, so the confirm and the POST are unchanged. */
.icon-x { display: block; }

button .icon-x,
a .icon-x { pointer-events: none; }

.btn-link-danger .icon-x { color: var(--color-danger); }

/* Icon-only buttons need a hit area a finger can find. */
.btn-sm:has(> .icon-x),
.btn-link:has(> .icon-x) {
    padding: 0.28rem 0.45rem;
    line-height: 1;
}

@media print {
    .status-mark { background: none; }
}

/* A label beside the cross, used where there is room for words — the
   record-level action on a detail page. The hidden label inside the
   icon include is suppressed here so a screen reader does not hear the
   name twice. */
.btn-label {
    margin-left: 0.35rem;
}
button:has(> .btn-label) {
    display: inline-flex;
    align-items: center;
}
button:has(> .btn-label) .visually-hidden {
    display: none;
}

/* ---------------------------------------------------------------------
   Per-column grid filters — grid-filters.js / _includes/col_filter.html
   A second <tr class="grid-filter-row"> in <thead>, one box per column.
   ------------------------------------------------------------------ */

.grid-filter-row td {
    background: var(--color-section);
    padding: 0.35rem 0.5rem 0.5rem;
    border-bottom: 1px solid var(--color-border);
    vertical-align: middle;
}

.grid-filter__box { position: relative; }

.grid-filter-row input,
.grid-filter-row select {
    width: 100%;
    min-width: 5.5rem;
    box-sizing: border-box;
    height: 1.9rem;
    font: inherit;
    font-size: var(--fs-xs);
    font-weight: 500;
    text-transform: none;
    letter-spacing: normal;
    color: var(--color-text);
    background-color: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-full);
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast),
                background-color var(--transition-fast);
}
.grid-filter-row input[type="text"] {
    /* Magnifier on the left, room for the clear button on the right. */
    padding: 0 1.6rem 0 1.75rem;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.5' stroke-linecap='round'%3E%3Ccircle cx='11' cy='11' r='7'/%3E%3Cline x1='20' y1='20' x2='16.5' y2='16.5'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: 0.6rem center;
    background-size: 0.8rem;
}
.grid-filter-row input[type="date"] { padding: 0 0.6rem; }
.grid-filter-row select {
    padding: 0 1.6rem 0 0.75rem;
    appearance: none;
    -webkit-appearance: none;
    cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.55rem center;
    background-size: 0.75rem;
}
.grid-filter-row td.num input { text-align: right; }

.grid-filter-row input::placeholder {
    color: var(--color-text-subtle);
    font-weight: 400;
}
.grid-filter-row input:hover,
.grid-filter-row select:hover { border-color: var(--color-border-strong); }
.grid-filter-row input:focus,
.grid-filter-row select:focus {
    outline: none;
    border-color: var(--color-accent-2);
    box-shadow: var(--shadow-focus);
}

/* A box holding a value: teal outline and tint, so a reader sees at a
   glance which columns are narrowing the list. */
.grid-filter.is-active input,
.grid-filter.is-active select {
    border-color: var(--color-accent-2);
    background-color: var(--color-accent-soft);
    font-weight: 600;
}

.grid-filter__clear {
    position: absolute;
    top: 50%;
    right: 0.3rem;
    transform: translateY(-50%);
    width: 1.2rem;
    height: 1.2rem;
    padding: 0;
    border: 0;
    border-radius: var(--radius-full);
    background: var(--color-accent-2);
    color: #fff;
    font-size: 0.85rem;
    line-height: 1.2rem;
    text-align: center;
    cursor: pointer;
    opacity: 0.85;
    transition: opacity var(--transition-fast), transform var(--transition-fast);
}
.grid-filter__clear:hover { opacity: 1; transform: translateY(-50%) scale(1.08); }

/* Heading of a filtered column gets a teal dot. */
.data-table th.is-filtered { color: var(--color-accent-2); }
.data-table th.is-filtered::after {
    content: "";
    display: inline-block;
    width: 0.4rem;
    height: 0.4rem;
    margin-left: 0.35rem;
    border-radius: var(--radius-full);
    background: var(--color-accent-2);
    vertical-align: middle;
}

/* "Showing 12 of 40 rows · Clear filters" above the grid. */
.grid-filter-status {
    display: flex;
    align-items: center;
    gap: var(--sp-2);
    margin: 0 0 var(--sp-2);
    padding: 0.45rem var(--sp-3);
    font-size: var(--fs-sm);
    color: var(--color-text-strong);
    background: var(--color-accent-soft);
    border: 1px solid color-mix(in srgb, var(--color-accent-2) 30%, transparent);
    border-radius: var(--radius);
}
.grid-filter-status[hidden] { display: none; }
.grid-filter-status__icon {
    width: 0.95rem;
    height: 0.95rem;
    flex: none;
    background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230d9488' stroke-width='2.2' stroke-linejoin='round'%3E%3Cpolygon points='3 4 21 4 14 12.5 14 19 10 21 10 12.5 3 4'/%3E%3C/svg%3E") no-repeat center / contain;
}
.grid-filter-status__text { font-weight: 600; }
.grid-filter-status__clear {
    margin-left: auto;
    padding: 0.2rem 0.7rem;
    font: inherit;
    font-size: var(--fs-xs);
    font-weight: 600;
    color: var(--color-accent-2);
    background: var(--color-bg);
    border: 1px solid var(--color-accent-2);
    border-radius: var(--radius-full);
    cursor: pointer;
    transition: background var(--transition-fast), color var(--transition-fast);
}
.grid-filter-status__clear:hover { background: var(--color-accent-2); color: #fff; }

.grid-filter-empty td.empty { text-align: center; }

@media print {
    .grid-filter-row, .grid-filter-status { display: none !important; }
}

/* Licence page usage bars. Decoration only — the percentage beside each bar
   carries the meaning, so a bar that fails to paint loses nothing. */
.usage-bar {
    display: block;
    height: 0.5rem;
    width: 100%;
    max-width: 10rem;
    background: var(--color-border, #e2e8f0);
    border-radius: 999px;
    overflow: hidden;
}
.usage-bar__fill {
    display: block;
    height: 100%;
    background: var(--color-success, #0d9488);
    border-radius: 999px;
}
.usage-bar__fill--near { background: var(--color-warning, #d97706); }
.usage-bar__fill--over { background: var(--color-danger, #dc2626); }

/* An inline row of controls that performs an action rather than filtering a
   grid — assigning a licence, recording a payment. Same shape as `.filters`,
   but a distinct class on purpose: `.filters` means "filter bar" in this
   codebase and `test_grid_toolbar.py` keys off it to decide which grids need
   a Columns menu. Reusing it for an action form makes that guard fire on a
   page that has no grid to configure. */
.action-row {
    display: flex;
    gap: var(--sp-3);
    align-items: center;
    flex-wrap: wrap;
    margin-bottom: var(--sp-4);
}
.action-row input[type="text"],
.action-row input[type="number"],
.action-row select {
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    background: var(--color-bg);
    font-size: var(--fs-sm);
    font-family: inherit;
    color: var(--color-text-strong);
}

/* Plan picker on the registration screen. Radio cards: the whole card is the
   label, so the hit area is the card rather than the dot. */
.plan-note {
    font-size: var(--fs-sm);
    color: var(--color-text-muted);
    margin: 0 0 var(--sp-3);
}
.plan-grid {
    display: grid;
    gap: var(--sp-3);
    grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
    margin-bottom: var(--sp-4);
}
.plan {
    position: relative;
    display: block;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    padding: 0.85rem 0.9rem;
    cursor: pointer;
    min-width: 0;
    transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
.plan:hover { border-color: var(--color-primary); }
/* Selection has to read without colour alone, so the border thickens too. */
.plan:has(input:checked) {
    border-color: var(--color-primary);
    box-shadow: inset 0 0 0 1px var(--color-primary);
}
.plan:has(input:focus-visible) { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.plan input { position: absolute; top: 0.9rem; right: 0.9rem; }
.plan__body { display: block; padding-right: 1.4rem; }
.plan__name { display: block; font-weight: 700; }
.plan__price { display: block; margin-top: 0.2rem; font-size: var(--fs-sm); }
.plan__per { color: var(--color-text-muted); }
.plan__alt { display: block; color: var(--color-text-muted); font-size: var(--fs-xs); }
.plan__desc {
    display: block;
    margin-top: 0.4rem;
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
}
.plan__limits {
    display: block;
    margin-top: 0.55rem;
    padding-top: 0.5rem;
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
}
.plan__limits span { display: block; }

/* What the new customer chose, on the registration confirmation. */
.plan-summary {
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius);
    padding: 0.9rem 1rem;
    margin: var(--sp-4) 0;
}
.plan-summary__row {
    display: flex;
    justify-content: space-between;
    gap: var(--sp-3);
    padding: 0.3rem 0;
    font-size: var(--fs-sm);
}
.plan-summary__row span { color: var(--color-text-muted); }
.plan-summary__vat { color: var(--color-text-muted); font-size: var(--fs-xs); }
.plan-summary__note {
    margin: 0.6rem 0 0;
    padding-top: 0.6rem;
    border-top: 1px solid var(--color-border);
    font-size: var(--fs-xs);
    color: var(--color-text-muted);
}

/* A disabled input must read as "you cannot type here", not as an empty one
   you have failed to fill in. Used by the auto-coded ID box on the add
   screens, which shows "Auto" and is allocated on save.

   Tokens rather than literals so it follows the theme; the older
   `.address-field input:disabled` rule hardcodes greys and does not. */
input:disabled,
select:disabled,
textarea:disabled {
    background: var(--color-section, #f0f0f3);
    color: var(--color-text-muted, #777);
    cursor: not-allowed;
    /* Safari drops the colour on a disabled control without this. */
    -webkit-text-fill-color: var(--color-text-muted, #777);
    opacity: 1;
}
