/* ═══════════════════════════════════════════════════════════
   COMPONENTS — Ledger.

   New markup uses the new names (.btn-primary, .input, .panel, .chip,
   .os, .table …). The prototype's names (.btn-r, .inp, .card, .badge …)
   are kept as aliases on the same rules because JS and tests use them
   and the screens not yet rewritten still carry them.
   ═══════════════════════════════════════════════════════════ */

/* ── BUTTONS ──────────────────────────────────────────────────
   .btn + .btn-primary | .btn-secondary | .btn-ghost | .btn-danger
   sizes: .btn-sm (24px) · default (30px) · .btn-lg (36px) · .btn-block
   legacy: .btn-r = primary, .btn-o = secondary, .btn-g = primary */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    height: var(--control-h);
    padding: 0 12px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-base);
    font-weight: var(--weight-medium);
    line-height: 1;
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    transition: background-color var(--duration), border-color var(--duration), color var(--duration);
}

.btn svg { color: var(--text-2); }
.btn:hover { background: var(--surface-hover); color: var(--text); }

.btn-primary, .btn-r, .btn-g {
    background: var(--accent);
    border-color: var(--accent);
    color: var(--on-accent);
}

.btn-primary svg, .btn-r svg, .btn-g svg { color: currentColor; }

.btn-primary:hover, .btn-r:hover, .btn-g:hover {
    background: var(--accent-hover);
    border-color: var(--accent-hover);
    color: var(--on-accent);
}

.btn-secondary, .btn-o { background: var(--surface); }

.btn-ghost {
    border-color: transparent;
    background: transparent;
    color: var(--text-2);
}

.btn-ghost:hover { background: rgba(27, 26, 23, .05); }

.btn-danger {
    background: var(--danger);
    border-color: var(--danger);
    color: #FFFFFF;
}

.btn-danger svg { color: currentColor; }
.btn-danger:hover { background: var(--danger-hover); border-color: var(--danger-hover); color: #FFFFFF; }

/* A quiet destructive action (text + border in the danger colour). */
.btn-danger-quiet { color: var(--danger); border-color: var(--danger-line); }
.btn-danger-quiet:hover { background: var(--danger-bg); color: var(--danger-text); }

.btn-sm { height: var(--control-h-sm); padding: 0 9px; font-size: var(--text-sm); }
.btn-lg { height: var(--control-h-lg); padding: 0 16px; }
.btn-block { display: flex; width: 100%; }

.btn:disabled, .btn[aria-disabled="true"] {
    opacity: .55;
    cursor: not-allowed;
    pointer-events: none;
}

.btn[aria-busy="true"] { cursor: progress; }

/* Square icon-only button (close, copy, prev/next): 28px, 44px on touch screens. */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex: none;
    padding: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-2);
    text-decoration: none;
    cursor: pointer;
}

.icon-btn:hover { background: rgba(27, 26, 23, .06); color: var(--text); }
.icon-btn:disabled { color: var(--text-disabled); background: transparent; cursor: default; }

/* ── TOP-BAR BUTTONS (Import CSV / Export CSV / Add Unit) ── */

.tbtn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 30px;
    padding: 0 10px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-base);
    font-weight: var(--weight-medium);
    white-space: nowrap;
    text-decoration: none;
    cursor: pointer;
    flex: none;
}

.tbtn svg { color: var(--text-2); }
.tbtn:hover { background: var(--surface-hover); color: var(--text); }

.tbtn-primary {
    padding: 0 12px 0 10px;
    border-color: var(--accent);
    background: var(--accent);
    color: var(--on-accent);
}

.tbtn-primary svg { color: currentColor; }
.tbtn-primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); color: var(--on-accent); }

/* The exports (app.js): "Exporting…" while the file is on its way, and "Export shown (0)" switched
   off — nothing is listed, so there is nothing to export (a click says so). */
.tbtn[aria-busy="true"], .sbi[aria-busy="true"] { cursor: progress; }
.tbtn[aria-disabled="true"], .sbi[aria-disabled="true"] { color: var(--text-disabled); cursor: not-allowed; }
.tbtn[aria-disabled="true"] svg, .sbi[aria-disabled="true"] svg { color: var(--text-disabled); }
.tbtn[aria-disabled="true"]:hover { background: var(--surface); color: var(--text-disabled); }

/* ── FORMS ────────────────────────────────────────────────────
   .field > .field-label + .input|select.input + .field-hint + .field-error
   legacy: .fg > label|.fg-lbl + .inp */

.field, .fg { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.fg { margin-bottom: 12px; }

.field-label, .fg > label, .fg .fg-lbl {
    display: block;
    font-size: var(--text-sm);
    line-height: 16px;
    font-weight: var(--weight-medium);
    color: var(--text-2);
}

.field-label .req { color: var(--warn); }

/* A label with its required mark beside it: <span class="field-label-row"><label class="field-label">…</label><span class="req">*</span></span>. */
.field-label-row { display: flex; align-items: baseline; gap: 4px; line-height: 16px; }
.field-label-row .req { color: var(--warn); font-size: var(--text-sm); }
.field-hint { font-size: var(--text-sm); line-height: 16px; color: var(--text-3); }

.input, .inp {
    width: 100%;
    height: var(--control-h);
    padding: 0 10px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-base);
    outline: none;
    transition: border-color var(--duration), box-shadow var(--duration);
}

textarea.input, textarea.inp { height: auto; min-height: 72px; padding: 6px 10px; line-height: var(--leading-base); resize: vertical; }

select.input, select.inp {
    appearance: none;
    -webkit-appearance: none;
    padding-right: 28px;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 16 16' fill='none' stroke='%234A463E' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 10px center;
    background-size: 12px 12px;
    cursor: pointer;
}

.input:hover, .inp:hover { border-color: var(--text-2); }

.input:focus, .inp:focus,
.input:focus-visible, .inp:focus-visible {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px var(--accent-ring);
    outline: none;
}

.input:disabled, .inp:disabled {
    background: var(--bg);
    border-color: var(--line-strong);
    color: var(--text-2);
    opacity: 1;
}

.input-code { font-family: var(--font-mono); font-variant-numeric: normal; }

/* A read-only value shown like a field (the fixed warehouse / branch). */
.inp-static {
    display: flex;
    align-items: center;
    gap: 6px;
    border-style: dashed;
    border-color: var(--line-strong);
    background: transparent;
    color: var(--text);
    font-weight: var(--weight-medium);
}

/* A field the server refused: warning border, message under it. */
.input.input-validation-error, .inp.input-validation-error,
.input[aria-invalid="true"], .inp[aria-invalid="true"] {
    border-color: var(--warn);
}

/* Refused and focused (the sign-in field that takes focus after a refusal): the warning border
   stays, with a halo in the warning family instead of the accent's, so it still reads invalid. */
.input.input-validation-error:focus, .inp.input-validation-error:focus,
.input[aria-invalid="true"]:focus, .inp[aria-invalid="true"]:focus {
    border-color: var(--warn);
    box-shadow: 0 0 0 3px var(--warn-line);
}

/* A password field with its show-password toggle inside the right end (Sign in, A-Login):
   <div class="input-reveal"><input class="input"><button class="input-reveal-btn"></div>.
   js/password-reveal.js unhides the button and swaps the eye for the struck-out eye. */
.input-reveal { position: relative; display: flex; }
.input-reveal > .input { flex: 1; min-width: 0; padding-right: 40px; }

.input-reveal-btn {
    position: absolute;
    top: 50%;
    right: 4px;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0;
    border: 0;
    border-radius: var(--radius-xs);
    background: transparent;
    color: var(--text-2);
    cursor: pointer;
}

.input-reveal-btn:hover { background: rgba(27, 26, 23, .06); color: var(--text); }
.input-reveal-btn .reveal-hide,
.input-reveal-btn[aria-pressed="true"] .reveal-show { display: none; }
.input-reveal-btn[aria-pressed="true"] .reveal-hide { display: block; }

/* One feedback family per field: the message is in the warning colour of the field's border
   ([aria-invalid] above), never a second (danger) red under an amber box. */
.field-error {
    display: block;
    font-size: var(--text-sm);
    line-height: 16px;
    font-weight: var(--weight-medium);
    color: var(--warn);
}

.field-error:empty, .field-validation-valid { display: none; }

input[type="checkbox"], input[type="radio"] {
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
}

.check {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 24px;
    cursor: pointer;
}

/* Search box with a leading icon (top bar, alert columns). */
.tsearch { position: relative; display: flex; align-items: center; margin: 0; }

.tsearch svg {
    position: absolute;
    left: 10px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-3);
    pointer-events: none;
}

.tsearch input {
    width: 100%;
    height: var(--control-h);
    padding: 0 30px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-base);
    outline: none;
}

.tsearch input:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-ring); }
/* The browser's own clear control (a blue ✕ in Chrome and Safari) drawn as the Ledger's: a 12px
   ✕ in --text-3, --text on hover. */
.tsearch input::-webkit-search-cancel-button {
    -webkit-appearance: none;
    appearance: none;
    width: 14px;
    height: 14px;
    margin: 0 -4px 0 4px;
    background-color: var(--text-3);
    -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M4 4l8 8M12 4l-8 8'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
    mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='1.8' stroke-linecap='round'%3E%3Cpath d='M4 4l8 8M12 4l-8 8'/%3E%3C/svg%3E") no-repeat center / 12px 12px;
    cursor: pointer;
}

.tsearch input::-webkit-search-cancel-button:hover { background-color: var(--text); }

.tsearch-kbd { position: absolute; right: 7px; top: 50%; transform: translateY(-50%); pointer-events: none; }
.tsearch:focus-within .tsearch-kbd { display: none; }

/* ── KBD HINT ─────────────────────────────────────────────── */

.kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-xs);
    background: var(--surface-kbd);
    color: var(--text-2);
    font-family: var(--font-mono);
    font-size: var(--text-xs);
    line-height: 16px;
}

/* ── ALERTS ───────────────────────────────────────────────────
   .alert + .alert-warn | .alert-danger | .alert-ok | .alert-info | .alert-note
   An icon (svg, currentColor) then the text. legacy: .ab .ab-a/.ab-r/.ab-g */

.alert, .ab {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface-chip);
    color: var(--text-2);
    font-size: var(--text-base);
    line-height: var(--leading-base);
}

.ab { margin-bottom: 12px; }
.alert svg, .ab svg { flex: none; margin-top: 1px; }
.alert > div, .ab > div { min-width: 0; }

.alert-warn, .ab-a { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-text); }
.alert-danger, .ab-r { background: var(--danger-bg); border-color: var(--danger-line); color: var(--danger-text); }
.alert-ok, .ab-g { background: var(--ok-bg); border-color: var(--ok-line); color: var(--ok-text); }
.alert-info { background: var(--info-bg); border-color: var(--info-line); color: var(--info-text); }
.alert-note { background: var(--surface-chip); border-color: var(--line); color: var(--text-2); font-size: 12.5px; line-height: 17px; padding: 8px 10px; }

.alert ul, .ab ul { list-style: none; }

/* asp-validation-summary renders an empty box when there is nothing to say. */
.validation-summary-valid { display: none !important; }

/* ── TOAST ─────────────────────────────────────────────────── */

#toast {
    position: fixed;
    right: 20px;
    bottom: 20px;
    z-index: 400;
    display: flex;
    align-items: center;
    gap: 10px;
    max-width: 360px;
    padding: 10px 14px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-lg);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-base);
    box-shadow: var(--shadow-overlay);
    transform: translateY(12px);
    opacity: 0;
    pointer-events: none;
    transition: transform .2s var(--ease), opacity .2s var(--ease);
}

#toast.sh { transform: none; opacity: 1; }

/* Master Inventory (desktop): the list's footer is pinned to the bottom of the screen — the pager
   and "Show deleted" — so a toast (an export, a delete, a restore) stands above it, over the list's
   last rows, rather than on those controls for its 3.2 s. With the pane at full width it stands
   above the pane's footer the same way (the footer's actions line up with the content column,
   to the toast's left).
   A unit pane is open (pane.js puts .pane-open on <html>): a save's toast must not sit on the
   pane's footer (Edit details, Delete unit and its note) either. Docked or overlaid, it moves over
   the list beside the pane (above its pager). On a phone the pane is the whole screen: the toast
   drops in under its header instead of covering the activity entry the save just scrolled into view. */
@media (min-width: 900px) {
    body.page-inventory #toast { bottom: 56px; }

    html.pane-open:not(.pane-full) #toast {
        right: calc(var(--pane-w) + 20px);
        bottom: 56px;   /* above the list's own footer (the pager), over its last rows */
        max-width: min(360px, calc(100vw - var(--pane-w) - var(--sidebar-w) - 40px));
    }
}
.tdot { width: 8px; height: 8px; border-radius: 50%; flex: none; }

/* ── PANELS ───────────────────────────────────────────────────
   .panel > .panel-hd (.panel-t + .panel-sub + .panel-link) + .panel-body
   legacy: .card > .card-hd (.card-ht) + .card-p */

.panel, .card {
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
    min-width: 0;
}

.panel-hd {
    height: var(--panel-head-h);
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 14px;
    border-bottom: 1px solid var(--line);
}

.card-hd {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 8px;
    min-height: var(--panel-head-h);
    padding: 6px 14px;
    border-bottom: 1px solid var(--line);
}

.panel-t, .card-ht {
    font-size: var(--text-heading);
    line-height: 18px;
    font-weight: var(--weight-semibold);
    color: var(--text);
}

.panel-sub { font-size: var(--text-sm); color: var(--text-3); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

.panel-link {
    margin-left: auto;
    display: inline-flex;
    align-items: center;
    gap: 2px;
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--accent);
    text-decoration: none;
    white-space: nowrap;
}

.panel-link:hover { color: var(--accent-hover); text-decoration: underline; }

.panel-body { padding: 14px; }
.card-p { padding: 16px; }

/* A heading + rule inside a pane or form. */
.section-t { font-size: var(--text-heading); font-weight: var(--weight-semibold); color: var(--text); }

/* Key facts in a hairline grid (unit pane, phone detail): <dl class="facts"><div><dt/><dd/></div>… */
.facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border: 1px solid var(--line);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.facts > div {
    padding: 7px 12px;
    border-bottom: 1px solid var(--line);
    min-width: 0;
}

.facts > div:nth-child(odd) { border-right: 1px solid var(--line); }
.facts > div:nth-last-child(-n + 2):nth-child(odd),
.facts > div:last-child { border-bottom: 0; }

.facts dt {
    font-size: var(--text-xs);
    line-height: 14px;
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    color: var(--text-3);
}

.facts dd { margin: 2px 0 0; line-height: 22px; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.facts dd.mono { font-size: 13px; }

/* ── AVATAR ─────────────────────────────────────────────────── */

.avatar {
    width: 28px;
    height: 28px;
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: var(--surface-avatar);
    color: var(--text);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
}

.avatar-xs { width: 17px; height: 17px; font-size: 9px; }

/* ── CHIPS, TAGS AND BADGES ───────────────────────────────────
   .chip              neutral 22px chip (category, status in a pane)
   .chip-warn         warning chip (Defect)
   .tag-new/.tag-po   category tag · .bp .bp-xx brand tag (class stored per brand)
   .os .os-<status>   order status: dot + label (.os-dot alone for just the dot)
   .count-pill        small count (alerts)
   .level-critical / .level-low   low-stock level
   legacy: .badge .b-g/.b-r/.b-a/.b-b/.b-p/.b-k/.b-grey, .cat-new, .cat-po, .br-hq, .cdot */

.chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 22px;
    padding: 0 8px;
    border: 1px solid var(--line-chip);
    border-radius: var(--radius-xs);
    background: var(--surface-chip);
    color: var(--text-2);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    white-space: nowrap;
}

.chip-warn { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-text); }

/* A wrapping row of chips / tags / order statuses. */
.chip-row { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }

.badge {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 20px;
    padding: 0 7px;
    border: 1px solid var(--line-chip);
    border-radius: var(--radius-xs);
    background: var(--surface-chip);
    color: var(--text-2);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    line-height: 1;
    white-space: nowrap;
}

.b-g    { background: var(--ok-bg);     color: var(--ok-text);     border-color: var(--ok-line); }
.b-r    { background: var(--danger-bg); color: var(--danger-text); border-color: var(--danger-line); }
.b-a    { background: var(--warn-bg);   color: var(--warn-text);   border-color: var(--warn-line); }
.b-b    { background: var(--info-bg);   color: var(--info-text);   border-color: var(--info-line); }
.b-p    { background: var(--pbg);       color: var(--cat-preowned-fg); border-color: var(--pbd); }
.b-k    { background: var(--text);      color: var(--surface);     border-color: var(--text); }
.b-grey { background: var(--surface-chip); color: var(--text-2);   border-color: var(--line-chip); }

/* Category tag */
.tag-new, .tag-po, .cat-new, .cat-po {
    display: inline-flex;
    align-items: center;
    height: 18px;
    padding: 0 6px;
    border-radius: var(--radius-xs);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    white-space: nowrap;
}

.tag-new, .cat-new { background: var(--cat-new-bg); color: var(--cat-new-fg); }
.tag-po, .cat-po { background: var(--cat-preowned-bg); color: var(--cat-preowned-fg); }

/* A category as a badge (the prototype's "25 NEW", "NEW MOTORCYCLES ONLY"): upper case, spaced
   like the Ledger's other capitals (column headers, group labels). */
.badge.cat-new, .badge.cat-po {
    height: 20px;
    border: 0;
    text-transform: uppercase;
    letter-spacing: var(--tracking-caps);
}

/* Branch (legacy inventory column) */
.br-hq {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 20px;
    padding: 0 7px;
    border: 1px solid var(--line-chip);
    border-radius: var(--radius-xs);
    background: var(--surface-chip);
    color: var(--text-2);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    white-space: nowrap;
}

/* Colour swatch (the view sets the background inline from UnitDisplay.SwatchHex). */
.cdot, .swatch {
    width: 10px;
    height: 10px;
    flex: none;
    border-radius: 2px;
    box-shadow: inset 0 0 0 1px rgba(27, 26, 23, .28);
}

/* A colour the palette does not name gets no guessed swatch: its place is kept empty, so the
   names line up (.swatch-gap in the table, Low Stock Alerts and the staged list). */
.swatch-gap { display: inline-block; width: 10px; height: 10px; flex: none; }

/* Brand tag: .bp + the brand's stored pill class. */
.bp {
    display: inline-flex;
    align-items: center;
    height: 16px;
    padding: 0 5px;
    border-radius: var(--radius-xs);
    background: var(--brand-other-bg);
    color: var(--brand-other-fg);
    font-size: var(--text-2xs);
    font-weight: var(--weight-semibold);
    letter-spacing: .03em;
    white-space: nowrap;
    flex: none;
}

.bp-ya { background: var(--brand-yamaha-bg);   color: var(--brand-yamaha-fg); }
.bp-ho { background: var(--brand-honda-bg);    color: var(--brand-honda-fg); }
.bp-ka { background: var(--brand-kawasaki-bg); color: var(--brand-kawasaki-fg); }
.bp-su { background: var(--brand-suzuki-bg);   color: var(--brand-suzuki-fg); }
.bp-mo { background: var(--brand-modenas-bg);  color: var(--brand-modenas-fg); }
.bp-kt { background: var(--brand-ktm-bg);      color: var(--brand-ktm-fg); }
.bp-be { background: var(--brand-benelli-bg);  color: var(--brand-benelli-fg); }
.bp-sy { background: var(--brand-sym-bg);      color: var(--brand-sym-fg); }
.bp-av { background: var(--brand-aveta-bg);    color: var(--brand-aveta-fg); }
.bp-ko { background: var(--brand-kove-bg);     color: var(--brand-kove-fg); }
.bp-wm { background: var(--brand-wmoto-bg);    color: var(--brand-wmoto-fg); }
.bp-cf { background: var(--brand-cfmoto-bg);   color: var(--brand-cfmoto-fg); }
.bp-zn { background: var(--brand-zontes-bg);   color: var(--brand-zontes-fg); }
.bp-xx { background: var(--brand-other-bg);    color: var(--brand-other-fg); }

/* Order status: <span class="os os-cash"><span class="os-dot" aria-hidden="true"></span>Cash Buy</span>
   (Display.OrderStatusTag). Available is a ring; the others are filled. */
.os {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--text);
    white-space: nowrap;
}

.os-dot {
    display: inline-block;
    width: 8px;
    height: 8px;
    flex: none;
    border-radius: 50%;
    background: var(--os-available);
}

.os-dot-lg { width: 9px; height: 9px; }

.os-available .os-dot, .os-dot.os-available { background: transparent; border: 1.5px solid var(--os-available); }
.os-cash .os-dot, .os-dot.os-cash { background: var(--os-cash); }
.os-loan .os-dot, .os-dot.os-loan { background: var(--os-loan); }
.os-ready .os-dot, .os-dot.os-ready { background: var(--os-ready); }
.os-sold .os-dot, .os-dot.os-sold { background: var(--os-sold); }

/* Unit status: plain text; Defect in the warning colour with its icon. */
.status { display: inline-flex; align-items: center; gap: 4px; color: var(--text-2); white-space: nowrap; }
.status-defect { color: var(--warn); font-weight: var(--weight-semibold); }

/* Low-stock level */
.level-critical, .level-low {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 20px;
    padding: 0 7px;
    border-radius: var(--radius-xs);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
    letter-spacing: .02em;
    white-space: nowrap;
}

.level-critical { background: var(--warn); color: #FFFFFF; }
.level-low { background: var(--warn-bg); color: var(--warn); }

.count-pill {
    min-width: 22px;
    height: 18px;
    padding: 0 5px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 9px;
    background: var(--warn-bg);
    color: var(--warn);
    font-size: var(--text-xs);
    font-weight: var(--weight-semibold);
}

/* ── SEGMENTED CONTROL ────────────────────────────────────────
   <div class="seg" role="group" aria-label="…"><button class="sgi" aria-pressed="true">All <span class="sgi-n">40</span></button>…
   The pressed / current item is .act or [aria-pressed="true"] or [aria-current]. */

.seg {
    display: inline-flex;
    align-items: center;
    gap: 2px;
    height: var(--control-h);
    padding: 2px;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-md);
    background: var(--bg-sidebar);
}

.sgi {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 100%;
    padding: 0 10px;
    border: 1px solid transparent;
    border-radius: var(--radius-xs);
    background: transparent;
    color: var(--text-2);
    font-size: 12.5px;
    font-weight: var(--weight-medium);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.sgi:hover { color: var(--text); }

.sgi.act, .sgi[aria-pressed="true"], .sgi[aria-current="page"], .sgi[aria-current="true"] {
    border-color: var(--line-strong);
    background: var(--surface);
    color: var(--text);
    font-weight: var(--weight-semibold);
}

.sgi-n { font-weight: var(--weight-regular); color: var(--text-2); font-variant-numeric: tabular-nums; }

/* ── FILTER PILL (legacy: dashboard breakdown, inventory brands) ── */

.fp {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 9px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-pill);
    background: var(--surface);
    color: var(--text-2);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.fp:hover { color: var(--text); border-color: var(--text-2); }
.fp.act, .fp[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

/* ── FILTER CHIP ──────────────────────────────────────────────
   <a class="fchip" data-chip="OrderStatus" href="…without this filter…">…label…<span class="fchip-x"><svg/></span></a>
   A filter that narrows the list, removable on its own (Master Inventory's active filters), and
   "Clear all" (.fchip-clear, also Low Stock Alerts' "Clear search & sort"). */

.fchip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 24px;
    padding: 0 4px 0 8px;
    border: 1px solid var(--line-chip);
    border-radius: var(--radius-xs);
    background: var(--surface-chip);
    color: var(--text);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    white-space: nowrap;
    text-decoration: none;
}

.fchip:hover { border-color: var(--line-control); background: var(--surface-hover); }
.fchip .os { gap: 6px; color: var(--text); }
.fchip > svg { color: var(--warn); }
.fchip-warn { border-color: var(--warn-line); background: var(--warn-bg); color: var(--warn-text); }
.fchip-warn:hover { border-color: var(--warn); background: var(--warn-bg); }

.fchip-x {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 16px;
    height: 16px;
    border-radius: var(--radius-xs);
    color: var(--text-2);
}

.fchip:hover .fchip-x { background: var(--line-chip); color: var(--text); }

/* A quiet text button with its ✕ (an inline SVG in the link), not a bare underlined link. */
.fchip-clear {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    height: 24px;
    padding: 0 6px;
    border-radius: var(--radius-xs);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    color: var(--text-2);
    text-decoration: none;
    white-space: nowrap;
}

.fchip-clear svg { flex: none; color: var(--text-3); }

.fchip-clear:hover { background: var(--surface-hover); color: var(--text); }
.fchip-clear:hover svg { color: currentColor; }

/* ── TABLES ───────────────────────────────────────────────────
   One-line rows (36px), uppercase column headers, hairline row dividers.
     .tw                   horizontal scroll wrapper (legacy)
     .table-wrap           scroll container; its thead sticks to the top
     .cell-mono / .td-serial   serials, codes, plates (IBM Plex Mono 12px)
     .cell-num / .td-price     right-aligned tabular numbers (prices)
     .row-selected / [aria-selected=true] / [aria-current]  the row open in the pane */

.tw, .table-wrap { overflow-x: auto; min-width: 0; }
.table-wrap { overflow: auto; min-height: 0; }

table { width: 100%; border-collapse: collapse; border-spacing: 0; }

th {
    height: var(--row-h-head);
    padding: 0 8px;
    border-bottom: 1px solid var(--line-strong);
    background: var(--surface-sunken);
    color: var(--text-3);
    font-size: var(--text-xs);
    font-weight: var(--weight-medium);
    letter-spacing: var(--tracking-caps);
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
    vertical-align: middle;
}

td {
    height: var(--row-h);
    padding: 0 8px;
    border-bottom: 1px solid var(--line-row);
    color: var(--text);
    font-size: var(--text-base);
    white-space: nowrap;
    vertical-align: middle;
}

th:first-child, td:first-child { padding-left: 20px; }
th:last-child, td:last-child { padding-right: 16px; }

.table-wrap thead th, .tw thead th { position: sticky; top: 0; z-index: 1; }

tbody tr { background: var(--surface); }
tbody tr:hover td { background: var(--surface-hover); }
tr:last-child td { border-bottom-color: var(--line-row); }

tbody tr.row-selected td, tbody tr[aria-selected="true"] td, tbody tr[aria-current="true"] td {
    background: var(--accent-tint);
}

.cell-mono, .td-serial {
    font-family: var(--font-mono);
    font-size: var(--text-sm);
    font-variant-numeric: normal;
    white-space: nowrap;
}

.cell-num, .td-price, th.cell-num { text-align: right; font-variant-numeric: tabular-nums; }
.cell-num .cur, .td-price .cur { font-weight: var(--weight-regular); color: var(--text-3); }
.cell-muted { color: var(--text-2); }

.empty-row, .empty {
    padding: 28px 16px;
    text-align: center;
    color: var(--text-3);
    white-space: normal;
}

td.empty-row { height: auto; }
/* An empty list's message is not a row to open: no hover fill (the pointer is often still there
   after the action that emptied it — a restore, a search). */
tbody tr:hover td.empty-row { background: transparent; }

/* ── ROW ACTIONS (legacy "Info" button) ── */

.ra { display: flex; gap: 4px; opacity: 0; transition: opacity var(--duration); }
tr:hover .ra { opacity: 1; }

/* Hover-only would hide "Info" — the only way into a unit — from keyboard users and from every
   touch screen, which has no hover at all. */
tr:focus-within .ra { opacity: 1; }

@media (hover: none), (pointer: coarse) {
    .ra { opacity: 1; }
}

.rb {
    display: inline-flex;
    align-items: center;
    height: 24px;
    padding: 0 9px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-size: var(--text-sm);
    font-weight: var(--weight-medium);
    cursor: pointer;
}

.rb:hover { background: var(--surface-hover); }
.rb.rr:hover { border-color: var(--danger-line); background: var(--danger-bg); color: var(--danger-text); }

/* ── PAGINATION ───────────────────────────────────────────────
   .pager (legacy bar) · .pagination > a|button.page-btn ([aria-current="page"] = current) */

.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    min-height: 40px;
    padding: 6px 20px;
    border-top: 1px solid var(--line-strong);
    background: var(--bg);
    font-size: 12.5px;
    color: var(--text-2);
}

.pager-info { color: var(--text-2); }
.pager-btns, .pagination { display: flex; align-items: center; gap: 4px; }

.page-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    padding: 0 6px;
    border: 1px solid var(--line-control);
    border-radius: var(--radius-sm);
    background: var(--surface);
    color: var(--text);
    font-variant-numeric: tabular-nums;
    text-decoration: none;
    cursor: pointer;
}

.page-btn[aria-current="page"] { border-color: var(--text); font-weight: var(--weight-semibold); }
.page-btn:disabled, .page-btn[aria-disabled="true"] { border-color: var(--line); background: transparent; color: var(--text-disabled); cursor: default; }

/* ── MODALS (legacy overlay; the unit detail moves to the split pane) ── */

.ov {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: none;
    align-items: center;
    justify-content: center;
    padding: 12px;
    background: var(--scrim);
}

.ov.opn { display: flex; }

.modal {
    display: flex;
    flex-direction: column;
    width: 540px;
    max-width: calc(100vw - 24px);
    max-height: 88vh;
    max-height: 88dvh;
    border: 1px solid var(--line-strong);
    border-radius: var(--radius-lg);
    background: var(--surface);
    box-shadow: var(--shadow-overlay);
    animation: modal-in .16s var(--ease);
}

.modal:focus { outline: none; }
.modal-sm { width: 420px; }
.modal-lg { width: 720px; }
.modal-xl { width: 860px; }

@keyframes modal-in {
    from { opacity: 0; transform: translateY(6px); }
    to   { opacity: 1; transform: none; }
}

.mhd {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-shrink: 0;
    min-height: 48px;
    padding: 10px 12px 10px 18px;
    border-bottom: 1px solid var(--line);
}

.mhd > :first-child { min-width: 0; overflow-wrap: anywhere; }
.mhtitle { font-size: var(--text-title); line-height: 20px; font-weight: var(--weight-semibold); color: var(--text); }

.mhclose {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    flex-shrink: 0;
    border: 0;
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-2);
    font-size: 13px;
    cursor: pointer;
}

.mhclose:hover { background: rgba(27, 26, 23, .06); color: var(--text); }

.mbody { flex: 1; overflow-y: auto; padding: 16px 18px; scrollbar-width: thin; }

/* Ledger dialogs (Ec.ask, Ec.confirmDialog — the app's prompt() and confirm()): the question,
   then Cancel · the action at the right, as the unit pane's own confirmations. */
.ask-dialog .mfoot { justify-content: flex-end; }
.ask-dialog .ask-text { display: flex; flex-direction: column; gap: 8px; overflow-wrap: anywhere; }

.mfoot {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
    padding: 12px 18px;
    border-top: 1px solid var(--line);
    background: var(--bg);
    border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

/* ── DROP ZONE (CSV import, DO scan) ── */

.drop-zone {
    position: relative;   /* anchors the visually-hidden file input inside it */
    padding: 28px 20px;
    border: 1px dashed var(--line-control);
    border-radius: var(--radius-lg);
    background: var(--bg);
    text-align: center;
    cursor: pointer;
    transition: border-color var(--duration), background-color var(--duration);
}

.drop-zone:hover, .drop-zone.drag { border-color: var(--accent); background: var(--accent-tint); }

/* The file input inside is focusable (visually hidden, not display:none), so Tab reaches the zone
   and Enter/Space opens the picker; show that focus on the zone itself. */
.drop-zone:focus-within {
    border-color: var(--accent);
    background: var(--accent-tint);
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

.drop-icon  { font-size: 24px; line-height: 1; margin-bottom: 10px; color: var(--text-3); }
.drop-icon svg { margin: 0 auto; }
.drop-title { font-size: var(--text-base); font-weight: var(--weight-semibold); color: var(--text); margin-bottom: 4px; }
.drop-sub   { font-size: var(--text-sm); color: var(--text-3); }

/* ── CSV PREVIEW (import modal) ── */

.csv-preview {
    max-height: 240px;
    overflow: auto;
    border: 1px solid var(--line);
    border-radius: var(--radius-sm);
    background: var(--surface);
}

.csv-preview th { height: 28px; }
.csv-preview td { height: 30px; font-size: var(--text-sm); }
.csv-preview th:first-child, .csv-preview td:first-child { padding-left: 10px; }

/* A row the server rejected. */
.row-bad td { background: var(--danger-bg) !important; }
.row-bad-msg { color: var(--danger-text); font-size: var(--text-sm); font-weight: var(--weight-semibold); white-space: normal; }

/* ── SPINNER ── */

.spinner, .scan-spinner {
    width: 28px;
    height: 28px;
    border: 2px solid var(--line);
    border-top-color: var(--accent);
    border-radius: 50%;
    animation: spin .8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

/* ═══════════════════════════════════════════════════════════
   RESPONSIVE (the shell's breakpoints are in layouts.css)
   ═══════════════════════════════════════════════════════════ */

@media (max-width: 899.98px) {
    /* Icon-only top-bar actions, 44px touch targets. */
    .tbtn {
        width: var(--touch);
        height: var(--touch);
        padding: 0;
        justify-content: center;
        border-color: transparent;
        background: transparent;
    }

    .tbtn svg { width: 20px; height: 20px; color: var(--text-2); }

    .tbtn-l {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
    }

    .tbtn-primary { border-color: transparent; background: transparent; color: var(--accent); }
    .tbtn-primary svg { width: 18px; height: 18px; padding: 2px; border-radius: var(--radius-sm); background: var(--accent); color: var(--on-accent); box-sizing: content-box; }
    .tbtn-primary:hover { background: transparent; }

    .tsearch input { height: var(--touch); padding: 0 12px 0 40px; border-radius: var(--radius-lg); font-size: 16px; }
    .tsearch svg { left: 13px; width: 18px; height: 18px; }
    .tsearch-kbd { display: none; }

    .icon-btn { width: var(--touch); height: var(--touch); }

    /* 16px stops iOS Safari zooming the page on every field focus. */
    .input, .inp { font-size: 16px; border-radius: var(--radius-lg); }
    .btn { border-radius: var(--radius-lg); }

    /* The table scrolls sideways inside its wrapper, so each row stays on one line… */
    .tw .td-serial { max-width: none; }

    /* …and the row's "Info" action stays pinned to the right edge, reachable without scrolling. */
    .tw td:has(> .ra) {
        position: sticky;
        right: 0;
        background: var(--surface);
        box-shadow: -8px 0 10px -8px rgba(27, 26, 23, .18);
    }

    tbody tr:hover td:has(> .ra) { background: var(--surface-hover); }

    .ra { opacity: 1; }

    .mhclose { width: var(--touch); height: var(--touch); }
}

@media (max-width: 640px) {
    .card-p { padding: 14px; }
    .pager { padding: 8px 12px; }

    .modal-sm, .modal-lg, .modal-xl { width: 100%; }
    .mbody { padding: 14px; }
    .mfoot { padding: 12px 14px; flex-wrap: wrap; }

    #toast { left: 12px; right: 12px; bottom: calc(var(--tabbar-h) + 12px + env(safe-area-inset-bottom)); max-width: none; }
}

@media (max-width: 899.98px) {
    html.pane-fullscreen #toast {
        top: calc(56px + 8px + env(safe-area-inset-top));
        bottom: auto;
        left: 12px;
        right: 12px;
        max-width: none;
        transform: translateY(-12px);
    }

    html.pane-fullscreen #toast.sh { transform: none; }
}

/* ── Touch screens ──
   A tap leaves :hover on what was tapped until the next tap elsewhere, so a hover fill would stay
   on a button that has already done its job (the pane's copy button, the More sheet's rows). Hover
   fills are for pointers that hover; a touch screen keeps the resting look (and :active). */
@media (hover: none) {
    .icon-btn:not([aria-pressed="true"]):hover,
    .btn-ghost:not([aria-pressed="true"]):hover,
    .fchip-clear:hover,
    .input-reveal-btn:hover { background: transparent; }

    .btn:not(.btn-primary):not(.btn-danger):not(.btn-ghost):not(.btn-danger-quiet):not(:disabled):hover { background: var(--surface); }
}

@media (hover: none) and (min-width: 900px) {
    .tbtn:not(.tbtn-primary):hover { background: var(--surface); }
}

@media (hover: none) and (max-width: 899.98px) {
    .tbtn:hover { background: transparent; }
}
