/*--------------------------------------------------------------
# components.css: the site's shared building blocks (docs/archive/UI_MODERNIZATION_PLAN.md, Phase 1).
#
# Loaded by _Layout right after site.css, so where the two meet, this file decides. Sizes and
# colours come from tokens.css.
#
#   1. Form fields: floating fields and select2, one size and one look everywhere
#   2. A field with its own button beside it (.field-action, .btn-field)
#   3. Buttons in the site's colours (.btn-alma, .btn-alma-secondary, .btn-outline-alma, .btn-outline-serenity)
#   4. The page header (.page-header)
#   5. The grid toolbar (.grid-toolbar), its search box (.grid-search, Views/Shared/_GridSearch.cshtml)
#      and the filter panel (.filter-offcanvas)
#   6. Grid cards: the grid below md (.grid-cards, .grid-card)
#   7. Form pages: the card, its sections and its actions (.form-card, .form-section, .form-actions)
#   8. Details pages: the record card and its sections (.detail-card, .detail-section)
--------------------------------------------------------------*/


/*--------------------------------------------------------------
# 1. Form fields
#
# Every floating field (.form-floating: the label inside the box, over the value) is --field-h
# tall (52px) with a 12px label over a 15px value, whether it is an input, a date, a native
# select, a textarea or a select2. The label and the value start at the same inset
# (--field-px), the value is centred in the space under the label, and the label always sits at
# the top: there is no "label as placeholder" state for some fields and not others.
#
# Why about 50px: Bootstrap's floating field is 58px. Dense business forms in the common design
# systems use 32-40px controls with the label above them (IBM Carbon 32/40px, Atlassian 32/40px,
# Ant Design 32px, Salesforce 32px), which with the label comes to about 52-60px a field. A
# floating field of 48-52px fits the same label and value in no more height, and stays above the
# 44px touch target the forms need on the warehouse's phones. 48px was tried first; 52px was
# chosen for a little more room.
--------------------------------------------------------------*/

/* The box. The padding is repeated for every state Bootstrap gives its own (focused, filled,
   autofilled), which it writes with higher specificity than the plain selector. */
.form-floating > .form-control,
.form-floating > .form-select {
    height: var(--field-h);
    min-height: var(--field-h);
    font-size: var(--field-font);
    line-height: 1.25;
}

.form-floating > .form-control,
.form-floating > .form-control:focus,
.form-floating > .form-control:not(:placeholder-shown),
.form-floating > .form-control:-webkit-autofill,
.form-floating > .form-select {
    padding: var(--field-value-top) var(--field-px) var(--field-value-bottom);
}

/* Firefox's name for :placeholder-shown, in a rule of its own: an unknown selector in a list
   would drop the whole list in other browsers. */
.form-floating > .form-control:not(:-moz-placeholder-shown) {
    padding: var(--field-value-top) var(--field-px) var(--field-value-bottom);
}

.form-floating > .form-select {
    padding-right: 2.25rem;
    background-position: right var(--field-px) center;
}

/* A textarea starts one field high (it lines up with the fields beside it) and can be dragged
   taller. */
.form-floating > textarea.form-control {
    resize: vertical;
}

    /* An input centres its value in the space under the label, so the value sits a few pixels
       below the label; a textarea's text starts at the top of that space, touching the label. Its
       first line starts where an input's value does (the space's height less one line, halved). */
    .form-floating > textarea.form-control,
    .form-floating > textarea.form-control:focus,
    .form-floating > textarea.form-control:not(:placeholder-shown) {
        padding-top: calc(var(--field-value-top) + (var(--field-h) - 2px - var(--field-value-top) - var(--field-value-bottom) - 1.25em) / 2);
    }

/* A field that can't be changed here (a derived total, a date set by a filed invoice), floating
   or not: read-only and disabled look the same. Bootstrap 5.2 greys only :disabled; 5.1, which the
   pages also loaded until 10a77a4, greyed [readonly] too, and the forms rely on that. */
.form-control[readonly],
.form-control:disabled,
.form-select:disabled {
    background-color: var(--field-readonly-bg);
}

/* Bootstrap 5.2 squares the corners of any floating field with a sibling after or before it; the
   rule was meant for input groups only (5.3 scopes it to them). Rounded everywhere else. */
.form-floating:not(:last-child) > .form-control,
.form-floating:not(:last-child) > .form-select,
.form-floating:not(:first-child) > .form-control,
.form-floating:not(:first-child) > .form-select {
    border-radius: var(--bs-border-radius);
}

.input-group > .form-floating:not(:last-child) > .form-control,
.input-group > .form-floating:not(:last-child) > .form-select {
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
}

.input-group > .form-floating:not(:first-child) > .form-control,
.input-group > .form-floating:not(:first-child) > .form-select {
    border-top-left-radius: 0;
    border-bottom-left-radius: 0;
}

/* In an input group the field's wrapper is exactly the field (site.css pads every .form-floating
   below; here that would stretch the group's other parts taller than the field), and the group
   keeps that 10px under it instead. */
.input-group > .form-floating {
    padding-bottom: 0;
}

.input-group:has(> .form-floating) {
    margin-bottom: 10px;
}

/* The label's box: from the wrapper's top-left corner, as wide as the wrapper. (Kept apart from
   the rule below, so the two column rules further down can move it.) */
.form-floating > label {
    top: 0;
    left: 0;
    right: 0;
    width: auto;
    height: auto;
}

/* The label: always at the top, over the value, in one size and weight whatever class the view
   gave it (control-label, form-label, small-bold-text). Colour utilities (text-success on Date In,
   text-danger on Date Out) still apply, and fw-bold still wins. Every state Bootstrap floats the
   label in is listed so this wins over its transform. */
.form-floating > label,
.form-floating > .form-control:focus ~ label,
.form-floating > .form-control:not(:placeholder-shown) ~ label,
.form-floating > .form-control:-webkit-autofill ~ label,
.form-floating > .form-select ~ label {
    padding: var(--field-label-top) var(--field-px) 0;
    font-size: var(--field-label-font);
    font-weight: 500;
    line-height: 1.25;
    color: var(--field-label-color);
    opacity: 1;
    transform: none;
}

.form-floating > .form-control:not(:-moz-placeholder-shown) ~ label {
    opacity: 1;
    transform: none;
}

/* A floating field that is also its grid column (class="col-md-4 form-floating"): the control
   sits inside the column's padding, but the label is placed from the column's edge. Moving the
   label in by the same padding lines it up with the value; the gutter variable resolves on the
   label exactly as it does on its column. */
.row > .form-floating > label {
    left: calc(var(--bs-gutter-x) * .5);
    right: calc(var(--bs-gutter-x) * .5);
}

/* The same for a wrapper padded with p-1 (the Orders forms): 4px on every side, the top too. */
.form-floating.p-1 > label {
    top: .25rem;
    left: .25rem;
    right: .25rem;
}

/*---------------------------------------------------------- select2: every select2 on the site
   One look with the native .form-select: the same border, radius, chevron and focus colour.
   The clear button (×) and the chevron share the box's middle; open, the list joins the box
   with no gap. */
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple {
    border: 1px solid var(--field-border);
    border-radius: var(--bs-border-radius);
    background-color: #fff;
}

.select2-container--default .select2-selection--single {
    height: calc(1.5em + .75rem + 2px);        /* a .form-select's 38px */
    background: #fff var(--field-chevron) no-repeat right .75rem center / 16px 12px;
}

    .select2-container--default .select2-selection--single .select2-selection__rendered {
        padding: .375rem 2.25rem .375rem .75rem;
        line-height: 1.5;
        text-align: left;
    }

    .select2-container--default .select2-selection--single .select2-selection__placeholder {
        color: #212529;
    }

    /* The chevron is the box's background, as on a native select. */
    .select2-container--default .select2-selection--single .select2-selection__arrow {
        display: none;
    }

    /* The clear button: in the middle of the box, left of the chevron. */
    .select2-container--default .select2-selection--single .select2-selection__clear {
        position: absolute;
        top: 50%;
        right: 2.25rem;
        z-index: 1;
        float: none;
        height: auto;
        margin: 0;
        padding: 0 .25rem;
        color: #6c757d;
        font-size: 1.1rem;
        font-weight: 400;
        line-height: 1;
        transform: translateY(-50%);
    }

        .select2-container--default .select2-selection--single .select2-selection__clear:hover {
            color: #212529;
        }

    .select2-container--default .select2-selection--single.select2-selection--clearable .select2-selection__rendered {
        padding-right: 3.75rem;
    }

.select2-container--default.select2-container--focus .select2-selection--single,
.select2-container--default.select2-container--focus .select2-selection--multiple,
.select2-container--default.select2-container--open .select2-selection--single,
.select2-container--default.select2-container--open .select2-selection--multiple {
    border-color: var(--field-focus);
    outline: 0;
}

.select2-container--default.select2-container--disabled .select2-selection--single,
.select2-container--default.select2-container--disabled .select2-selection--multiple {
    background-color: #e9ecef;
}

/* Open: the list and the box share one border, joined without a seam (select2 squares the
   touching corners; a rounded corner left there is what showed the gap). */
.select2-container--default.select2-container--open.select2-container--below .select2-selection--single,
.select2-container--default.select2-container--open.select2-container--below .select2-selection--multiple {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
}

.select2-container--default.select2-container--open.select2-container--above .select2-selection--single,
.select2-container--default.select2-container--open.select2-container--above .select2-selection--multiple {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
}

.select2-dropdown {
    border-color: var(--field-focus);
    border-radius: var(--bs-border-radius);
    font-size: var(--field-font);
    overflow: hidden;
}

.select2-search--dropdown {
    padding: .375rem;
}

.select2-container--default .select2-search--dropdown .select2-search__field {
    padding: .25rem .5rem;
    border: 1px solid var(--field-border);
    border-radius: calc(var(--bs-border-radius) - 2px);
    font-size: var(--field-font);
    outline: 0;
}

    .select2-container--default .select2-search--dropdown .select2-search__field:focus {
        border-color: var(--field-focus);
    }

.select2-results__option {
    padding: .375rem var(--field-px);
}

.select2-container--default .select2-results__option--highlighted.select2-results__option--selectable {
    background-color: var(--alma-blue);
}

.select2-container--default .select2-results__option--selected {
    background-color: #e9ecef;
}

/* Several values (select2 multiple): chips in the site's quiet style. */
.select2-container--default .select2-selection--multiple .select2-selection__choice {
    border-radius: calc(var(--bs-border-radius) - 2px);
}

/* Width: a select2 fills its field (select2 sizes itself from the <select> otherwise). */
.select2-container,
.select2-container--default .select2-selection--single,
.select2-container--default .select2-selection--multiple,
.select2-container--default .select2-selection {
    width: 100% !important;
    max-width: 100% !important;
    box-sizing: border-box !important;
    min-width: 0 !important;
}

/*---------------------------------------------------------- select2 as a floating field
   The same box, label and value inset as the inputs beside it. */
.form-floating > .select2-container .select2-selection--single {
    height: var(--field-h);
}

    /* An input centres its value in the space under the label; select2's text is ordinary block
       text, so it is given a line as tall as that space, which centres it the same way at any
       --field-h (the 2px are the box's top and bottom borders). */
    .form-floating > .select2-container .select2-selection--single .select2-selection__rendered {
        padding: var(--field-value-top) 2.25rem var(--field-value-bottom) var(--field-px);
        font-size: var(--field-font);
        line-height: calc(var(--field-h) - 2px - var(--field-value-top) - var(--field-value-bottom));
    }

    .form-floating > .select2-container .select2-selection--single.select2-selection--clearable .select2-selection__rendered {
        padding-right: 3.75rem;
    }

.form-floating > .select2-container .select2-selection--multiple {
    min-height: var(--field-h);
    padding: var(--field-value-top) 2rem var(--field-value-bottom) calc(var(--field-px) - 5px);
    font-size: var(--field-font);
}


/*--------------------------------------------------------------
# 2. A field with its own button beside it
#
# .field-action: an export's order or package with its Remove button, a note with Add Package.
# The field and the button are separate controls with a gap between them, each with its own
# rounded corners. (An .input-group joins its children into one control and squares the corners
# where they meet, which is wrong for a button set apart.)
#
#   <div class="field-action mb-2"><input class="form-control" …><button class="btn …">…</button></div>
#
# A child can itself be an .input-group (fields that are joined), and .field-fixed keeps a child
# to a quarter of the row, between 3.5rem and 10rem (a package's type beside its measurements).
#
# .btn-field: a button as tall as the floating field in the column next to it (Expenses' New
# Type / New Vendor).
--------------------------------------------------------------*/
.field-action {
    display: flex;
    align-items: center;
    gap: .5rem;
}

    .field-action > .form-control,
    .field-action > .form-select,
    .field-action > .input-group {
        flex: 1 1 0;
        width: auto;
        min-width: 0;
    }

    .field-action > .btn {
        flex: none;
        margin: 0;
    }

    .field-action > .field-fixed {
        flex: 0 0 25%;
        min-width: 3.5rem;
        max-width: 10rem;
    }

    /* A floating field in the row (a package's type and notes) sizes like a plain one. */
    .field-action > .form-floating {
        flex: 1 1 0;
        min-width: 0;
    }

    .field-action > .form-floating.field-fixed {
        flex: 0 0 25%;
    }

/* Joined floating measurements (a package's length, width, height, weight): narrow boxes, so
   their label and value sit closer to the edge; both still fit, the label over the value. */
.field-action > .input-group > .form-floating {
    --field-px: .5rem;
}

/* The row spaces its fields; the 10px §1 puts under an input group of floating fields would
   lift the group off the row's line. */
.field-action > .input-group:has(> .form-floating) {
    margin-bottom: 0;
}

/* A package, saved or being entered, is a small bordered box of its own. */
.form-item {
    margin-bottom: .5rem;
    padding: .5rem;
    border: 1px solid var(--field-border);
    border-radius: var(--alma-radius);
    background-color: #fff;
}

    .form-item.is-new {
        border-style: dashed;
    }

/* A choice in a list (an in-stock order): its checkbox and text in a small bordered tile, the
   whole tile clickable through its label. */
.form-option {
    margin: 0 0 .375rem;
    padding: .375rem .625rem .375rem 2.125rem;
    border: 1px solid var(--field-border);
    border-radius: var(--alma-radius);
    background-color: #fff;
}

    .form-option:last-child {
        margin-bottom: 0;
    }

    /* Ticked: pale green with a green tick (the orders card around it is pale blue). */
    .form-option:has(.form-check-input:checked) {
        border-color: var(--field-chosen-border);
        background-color: var(--field-chosen-bg);
    }

        .form-option .form-check-input:checked {
            border-color: var(--field-chosen-check);
            background-color: var(--field-chosen-check);
        }

    /* The fields' value size, not the page's 16px. */
    .form-option .form-check-label {
        display: block;
        font-size: var(--field-font);
        cursor: pointer;
    }

/* An item already chosen (an order on the export, in Edit): the ticked tile's pale green. */
.form-control.is-chosen,
.form-control.is-chosen[readonly] {
    border-color: var(--field-chosen-border);
    background-color: var(--field-chosen-bg);
}

/* On a phone a package being entered has its type (a select, whose chevron takes room) and its
   measurements on a row each: side by side, neither has room for its text. A saved package's
   read-only type box fits beside its values and stays on one row. */
@media (max-width: 575.98px) {
    .field-action:has(> .field-fixed > select) {
        flex-wrap: wrap;
    }

        .field-action > .form-floating.field-fixed:has(> select),
        .field-action > .form-floating.field-fixed:has(> select) + .input-group {
            flex: 1 1 100%;
            max-width: none;
        }

    /* The measurements' labels in short (L / W / H / KG) from data-short: at a phone's width four
       full names don't fit their boxes. The full name stays for screen readers. */
    .field-action > .input-group > .form-floating > label[data-short] {
        font-size: 0;
    }

        .field-action > .input-group > .form-floating > label[data-short]::after {
            content: attr(data-short);
            font-size: var(--field-label-font);
        }
}
.btn.btn-field {
    height: var(--field-h);
    margin: 0;
}

/* Remove (×) beside a field: a small square in the middle of the room a full-height button took
   (its margins keep that width), so the field beside it keeps its size.
     <button class="btn btn-outline-danger btn-remove" aria-label="Remove"><i class="bi bi-x-lg"></i></button> */
.btn.btn-remove {
    --bs-btn-padding-x: 0;
    --bs-btn-padding-y: 0;
    --bs-btn-font-size: .875rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.875rem;
    height: 1.875rem;
    margin: 0 .375rem;
    line-height: 1;
}

/* A button in a row of plain (38px) controls, at the small button's size but the row's height
   (Edit's Add beside the orders list). */
.field-action > .btn.btn-sm {
    align-self: stretch;
}


/*--------------------------------------------------------------
# 3. Buttons in the site's colours
#
# Built on Bootstrap 5.2's button variables, so the site's colours come with Bootstrap's own
# hover, pressed, focus and disabled states, and work at every size (btn-sm, btn-lg).
# The colours are the role tokens in tokens.css (--btn-{role}-*); each role class below only
# maps them onto --bs-btn-*. A theme changes the tokens, never these blocks.
#
#   Role          Class                 For
#   primary       btn-alma              Add New, Save, Edit, Apply, record actions
#                                       (btn-primary / btn-outline-primary / btn-outline-secondary render the same)
#   filter        btn-alma-filter       Filters, the column picker
#   neutral       btn-alma-light        switches, utilities, cross-links, Reset, counts
#   menu          btn-alma-menu         Menu (the neutral tokens unless a style sets --btn-menu-*)
#   cancel        btn-secondary         Cancel, Close in a classic modal
#   danger        btn-danger            Delete, a row's remove (×), Withdraw, Credit note
#   danger-soft   btn-outline-danger    the single PDF download
#   success       btn-success           Open Job, Approve, Submit to myDATA
#   success-soft  btn-outline-success   Create Job, Excel
#   warning       btn-warning           AES
--------------------------------------------------------------*/
/* Keyboard focus on a button (Phase 3 of docs/archive/UI_MODERNIZATION_PLAN.md): a brand-blue ring, 2px, offset 2px, on
   :focus-visible only, so a mouse click shows nothing. site.css used to switch every button's focus off
   (outline: none; box-shadow: none); the modern components (.mm-btn, .mm-close, the grid search...) have
   their own ring in the same blue. */
.btn:focus-visible {
    outline: 2px solid var(--alma-accent);
    outline-offset: 2px;
    box-shadow: none;
}

/* The role blocks. Each border falls back to the theme's --btn-rim (the night sets one) and then to the fill,
   so a solid button needs no border token and a soft one sets its own. */
.btn-alma,
.btn-primary,
.btn-outline-primary,
.btn-outline-secondary:not(.grid-pager-size .btn-outline-secondary) {
    --bs-btn-color: var(--btn-primary-fg);
    --bs-btn-bg: var(--btn-primary-bg);
    --bs-btn-border-color: var(--btn-primary-bd, var(--btn-rim, var(--btn-primary-bg)));
    --bs-btn-hover-color: var(--btn-primary-fg-h, var(--btn-primary-fg));
    --bs-btn-hover-bg: var(--btn-primary-bg-h);
    --bs-btn-hover-border-color: var(--btn-primary-bd-h, var(--btn-rim, var(--btn-primary-bg-h)));
    --bs-btn-active-color: var(--btn-primary-fg-h, var(--btn-primary-fg));
    --bs-btn-active-bg: var(--btn-primary-bg-a);
    --bs-btn-active-border-color: var(--btn-primary-bd-a, var(--btn-rim, var(--btn-primary-bg-a)));
    --bs-btn-disabled-color: var(--btn-primary-fg);
    --bs-btn-disabled-bg: var(--btn-primary-bg);
    --bs-btn-disabled-border-color: var(--btn-primary-bd, var(--btn-rim, var(--btn-primary-bg)));
}

.btn-alma-filter {
    --bs-btn-color: var(--btn-filter-fg);
    --bs-btn-bg: var(--btn-filter-bg);
    --bs-btn-border-color: var(--btn-filter-bd, var(--btn-rim, var(--btn-filter-bg)));
    --bs-btn-hover-color: var(--btn-filter-fg-h, var(--btn-filter-fg));
    --bs-btn-hover-bg: var(--btn-filter-bg-h);
    --bs-btn-hover-border-color: var(--btn-filter-bd-h, var(--btn-rim, var(--btn-filter-bg-h)));
    --bs-btn-active-color: var(--btn-filter-fg-h, var(--btn-filter-fg));
    --bs-btn-active-bg: var(--btn-filter-bg-a);
    --bs-btn-active-border-color: var(--btn-filter-bd-a, var(--btn-rim, var(--btn-filter-bg-a)));
    --bs-btn-disabled-color: var(--btn-filter-fg);
    --bs-btn-disabled-bg: var(--btn-filter-bg);
    --bs-btn-disabled-border-color: var(--btn-filter-bd, var(--btn-rim, var(--btn-filter-bg)));
}

.btn-alma-light {
    --bs-btn-color: var(--btn-neutral-fg);
    --bs-btn-bg: var(--btn-neutral-bg);
    --bs-btn-border-color: var(--btn-neutral-bd, var(--btn-rim, var(--btn-neutral-bg)));
    --bs-btn-hover-color: var(--btn-neutral-fg-h, var(--btn-neutral-fg));
    --bs-btn-hover-bg: var(--btn-neutral-bg-h);
    --bs-btn-hover-border-color: var(--btn-neutral-bd-h, var(--btn-rim, var(--btn-neutral-bg-h)));
    --bs-btn-active-color: var(--btn-neutral-fg-h, var(--btn-neutral-fg));
    --bs-btn-active-bg: var(--btn-neutral-bg-a);
    --bs-btn-active-border-color: var(--btn-neutral-bd-a, var(--btn-rim, var(--btn-neutral-bg-a)));
    --bs-btn-disabled-color: var(--btn-neutral-fg);
    --bs-btn-disabled-bg: var(--btn-neutral-bg);
    --bs-btn-disabled-border-color: var(--btn-neutral-bd, var(--btn-rim, var(--btn-neutral-bg)));
}

/* Menu (a grid toolbar's, beside Add New, and a Details header's phone Menu): its own tokens, --btn-menu-*, which fall
   back to the menu tier's, so a style that sets none (style A) draws it as btn-alma-light. */
.btn-alma-menu {
    --bs-btn-color: var(--btn-menu-fg, var(--btn-neutral-fg));
    --bs-btn-bg: var(--btn-menu-bg, var(--btn-neutral-bg));
    --bs-btn-border-color: var(--btn-menu-bd, var(--btn-neutral-bd, var(--btn-rim, var(--btn-neutral-bg))));
    --bs-btn-hover-color: var(--btn-menu-fg-h, var(--btn-neutral-fg-h, var(--btn-neutral-fg)));
    --bs-btn-hover-bg: var(--btn-menu-bg-h, var(--btn-neutral-bg-h));
    --bs-btn-hover-border-color: var(--btn-menu-bd-h, var(--btn-neutral-bd-h, var(--btn-rim, var(--btn-neutral-bg-h))));
    --bs-btn-active-color: var(--btn-menu-fg-h, var(--btn-neutral-fg-h, var(--btn-neutral-fg)));
    --bs-btn-active-bg: var(--btn-menu-bg-a, var(--btn-neutral-bg-a));
    --bs-btn-active-border-color: var(--btn-menu-bd-a, var(--btn-neutral-bd-a, var(--btn-rim, var(--btn-neutral-bg-a))));
    --bs-btn-disabled-color: var(--btn-menu-fg, var(--btn-neutral-fg));
    --bs-btn-disabled-bg: var(--btn-menu-bg, var(--btn-neutral-bg));
    --bs-btn-disabled-border-color: var(--btn-menu-bd, var(--btn-neutral-bd, var(--btn-rim, var(--btn-neutral-bg))));
}

.btn-secondary {
    --bs-btn-color: var(--btn-cancel-fg);
    --bs-btn-bg: var(--btn-cancel-bg);
    --bs-btn-border-color: var(--btn-cancel-bd, var(--btn-rim, var(--btn-cancel-bg)));
    --bs-btn-hover-color: var(--btn-cancel-fg-h, var(--btn-cancel-fg));
    --bs-btn-hover-bg: var(--btn-cancel-bg-h);
    --bs-btn-hover-border-color: var(--btn-cancel-bd-h, var(--btn-rim, var(--btn-cancel-bg-h)));
    --bs-btn-active-color: var(--btn-cancel-fg-h, var(--btn-cancel-fg));
    --bs-btn-active-bg: var(--btn-cancel-bg-a);
    --bs-btn-active-border-color: var(--btn-cancel-bd-a, var(--btn-rim, var(--btn-cancel-bg-a)));
    --bs-btn-disabled-color: var(--btn-cancel-fg);
    --bs-btn-disabled-bg: var(--btn-cancel-bg);
    --bs-btn-disabled-border-color: var(--btn-cancel-bd, var(--btn-rim, var(--btn-cancel-bg)));
}

/* Admin-only actions (Orders' "Set Date Created" and the like): a muted purple, the same in every area. */
.btn-admin {
    --bs-btn-color: var(--btn-admin-fg);
    --bs-btn-bg: var(--btn-admin-bg);
    --bs-btn-border-color: var(--btn-admin-bd, var(--btn-rim, var(--btn-admin-bg)));
    --bs-btn-hover-color: var(--btn-admin-fg-h, var(--btn-admin-fg));
    --bs-btn-hover-bg: var(--btn-admin-bg-h);
    --bs-btn-hover-border-color: var(--btn-admin-bd-h, var(--btn-rim, var(--btn-admin-bg-h)));
    --bs-btn-active-color: var(--btn-admin-fg-h, var(--btn-admin-fg));
    --bs-btn-active-bg: var(--btn-admin-bg-a);
    --bs-btn-active-border-color: var(--btn-admin-bd-a, var(--btn-rim, var(--btn-admin-bg-a)));
    --bs-btn-disabled-color: var(--btn-admin-fg);
    --bs-btn-disabled-bg: var(--btn-admin-bg);
    --bs-btn-disabled-border-color: var(--btn-admin-bd, var(--btn-rim, var(--btn-admin-bg)));
}

.btn-danger {
    --bs-btn-color: var(--btn-danger-fg);
    --bs-btn-bg: var(--btn-danger-bg);
    --bs-btn-border-color: var(--btn-danger-bd, var(--btn-rim, var(--btn-danger-bg)));
    --bs-btn-hover-color: var(--btn-danger-fg-h, var(--btn-danger-fg));
    --bs-btn-hover-bg: var(--btn-danger-bg-h);
    --bs-btn-hover-border-color: var(--btn-danger-bd-h, var(--btn-rim, var(--btn-danger-bg-h)));
    --bs-btn-active-color: var(--btn-danger-fg-h, var(--btn-danger-fg));
    --bs-btn-active-bg: var(--btn-danger-bg-a);
    --bs-btn-active-border-color: var(--btn-danger-bd-a, var(--btn-rim, var(--btn-danger-bg-a)));
    --bs-btn-disabled-color: var(--btn-danger-fg);
    --bs-btn-disabled-bg: var(--btn-danger-bg);
    --bs-btn-disabled-border-color: var(--btn-danger-bd, var(--btn-rim, var(--btn-danger-bg)));
}

.btn-outline-danger {
    --bs-btn-color: var(--btn-danger-soft-fg);
    --bs-btn-bg: var(--btn-danger-soft-bg);
    --bs-btn-border-color: var(--btn-danger-soft-bd, var(--btn-rim, var(--btn-danger-soft-bg)));
    --bs-btn-hover-color: var(--btn-danger-soft-fg-h, var(--btn-danger-soft-fg));
    --bs-btn-hover-bg: var(--btn-danger-soft-bg-h);
    --bs-btn-hover-border-color: var(--btn-danger-soft-bd-h, var(--btn-rim, var(--btn-danger-soft-bg-h)));
    --bs-btn-active-color: var(--btn-danger-soft-fg-h, var(--btn-danger-soft-fg));
    --bs-btn-active-bg: var(--btn-danger-soft-bg-a);
    --bs-btn-active-border-color: var(--btn-danger-soft-bd-a, var(--btn-rim, var(--btn-danger-soft-bg-a)));
    --bs-btn-disabled-color: var(--btn-danger-soft-fg);
    --bs-btn-disabled-bg: var(--btn-danger-soft-bg);
    --bs-btn-disabled-border-color: var(--btn-danger-soft-bd, var(--btn-rim, var(--btn-danger-soft-bg)));
}

.btn-success {
    --bs-btn-color: var(--btn-success-fg);
    --bs-btn-bg: var(--btn-success-bg);
    --bs-btn-border-color: var(--btn-success-bd, var(--btn-rim, var(--btn-success-bg)));
    --bs-btn-hover-color: var(--btn-success-fg-h, var(--btn-success-fg));
    --bs-btn-hover-bg: var(--btn-success-bg-h);
    --bs-btn-hover-border-color: var(--btn-success-bd-h, var(--btn-rim, var(--btn-success-bg-h)));
    --bs-btn-active-color: var(--btn-success-fg-h, var(--btn-success-fg));
    --bs-btn-active-bg: var(--btn-success-bg-a);
    --bs-btn-active-border-color: var(--btn-success-bd-a, var(--btn-rim, var(--btn-success-bg-a)));
    --bs-btn-disabled-color: var(--btn-success-fg);
    --bs-btn-disabled-bg: var(--btn-success-bg);
    --bs-btn-disabled-border-color: var(--btn-success-bd, var(--btn-rim, var(--btn-success-bg)));
}

.btn-outline-success {
    --bs-btn-color: var(--btn-success-soft-fg);
    --bs-btn-bg: var(--btn-success-soft-bg);
    --bs-btn-border-color: var(--btn-success-soft-bd, var(--btn-rim, var(--btn-success-soft-bg)));
    --bs-btn-hover-color: var(--btn-success-soft-fg-h, var(--btn-success-soft-fg));
    --bs-btn-hover-bg: var(--btn-success-soft-bg-h);
    --bs-btn-hover-border-color: var(--btn-success-soft-bd-h, var(--btn-rim, var(--btn-success-soft-bg-h)));
    --bs-btn-active-color: var(--btn-success-soft-fg-h, var(--btn-success-soft-fg));
    --bs-btn-active-bg: var(--btn-success-soft-bg-a);
    --bs-btn-active-border-color: var(--btn-success-soft-bd-a, var(--btn-rim, var(--btn-success-soft-bg-a)));
    --bs-btn-disabled-color: var(--btn-success-soft-fg);
    --bs-btn-disabled-bg: var(--btn-success-soft-bg);
    --bs-btn-disabled-border-color: var(--btn-success-soft-bd, var(--btn-rim, var(--btn-success-soft-bg)));
}

.btn-warning {
    --bs-btn-color: var(--btn-warning-fg);
    --bs-btn-bg: var(--btn-warning-bg);
    --bs-btn-border-color: var(--btn-warning-bd, var(--btn-rim, var(--btn-warning-bg)));
    --bs-btn-hover-color: var(--btn-warning-fg-h, var(--btn-warning-fg));
    --bs-btn-hover-bg: var(--btn-warning-bg-h);
    --bs-btn-hover-border-color: var(--btn-warning-bd-h, var(--btn-rim, var(--btn-warning-bg-h)));
    --bs-btn-active-color: var(--btn-warning-fg-h, var(--btn-warning-fg));
    --bs-btn-active-bg: var(--btn-warning-bg-a);
    --bs-btn-active-border-color: var(--btn-warning-bd-a, var(--btn-rim, var(--btn-warning-bg-a)));
    --bs-btn-disabled-color: var(--btn-warning-fg);
    --bs-btn-disabled-bg: var(--btn-warning-bg);
    --bs-btn-disabled-border-color: var(--btn-warning-bd, var(--btn-rim, var(--btn-warning-bg)));
}

.btn-light {
    --bs-btn-color: var(--btn-light-fg);
    --bs-btn-bg: var(--btn-light-bg);
    --bs-btn-border-color: var(--btn-light-bd, var(--btn-rim, var(--btn-light-bg)));
    --bs-btn-hover-color: var(--btn-light-fg-h, var(--btn-light-fg));
    --bs-btn-hover-bg: var(--btn-light-bg-h);
    --bs-btn-hover-border-color: var(--btn-light-bd-h, var(--btn-rim, var(--btn-light-bg-h)));
    --bs-btn-active-color: var(--btn-light-fg-h, var(--btn-light-fg));
    --bs-btn-active-bg: var(--btn-light-bg-a);
    --bs-btn-active-border-color: var(--btn-light-bd-a, var(--btn-rim, var(--btn-light-bg-a)));
    --bs-btn-disabled-color: var(--btn-light-fg);
    --bs-btn-disabled-bg: var(--btn-light-bg);
    --bs-btn-disabled-border-color: var(--btn-light-bd, var(--btn-rim, var(--btn-light-bg)));
}

.btn-alma-secondary {
    --bs-btn-color: #fff;
    --bs-btn-bg: var(--alma-steel);
    --bs-btn-border-color: var(--alma-steel);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #878d93;
    --bs-btn-hover-border-color: #878d93;
    --bs-btn-focus-shadow-rgb: 139, 158, 176;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #767c82;
    --bs-btn-active-border-color: #767c82;
    --bs-btn-disabled-color: #fff;
    --bs-btn-disabled-bg: var(--alma-steel);
    --bs-btn-disabled-border-color: var(--alma-steel);
}

.btn-outline-alma {
    --bs-btn-color: var(--alma-blue);
    --bs-btn-border-color: var(--alma-blue);
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: var(--alma-blue);
    --bs-btn-hover-border-color: var(--alma-blue);
    --bs-btn-focus-shadow-rgb: 48, 79, 127;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #29446d;
    --bs-btn-active-border-color: #29446d;
    --bs-btn-disabled-color: var(--alma-blue);
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: var(--alma-blue);
}

/* Serenity blue (#306AC0): the 1804 index's bulk Sent-date button. */
.btn-outline-serenity {
    --bs-btn-color: #306ac0;
    --bs-btn-border-color: #306ac0;
    --bs-btn-hover-color: #fff;
    --bs-btn-hover-bg: #306ac0;
    --bs-btn-hover-border-color: #306ac0;
    --bs-btn-focus-shadow-rgb: 48, 106, 192;
    --bs-btn-active-color: #fff;
    --bs-btn-active-bg: #24508f;
    --bs-btn-active-border-color: #24508f;
    --bs-btn-disabled-color: #306ac0;
    --bs-btn-disabled-bg: transparent;
    --bs-btn-disabled-border-color: #306ac0;
}

/* A button whose request is under way (.is-busy, with aria-busy): a spinner in its middle, in the
   button's own colour, its text and icon hidden so the button keeps its size, and no second click. */
.btn.is-busy {
    position: relative;
    color: transparent !important;
    pointer-events: none;
    transition: none;   /* at once: Bootstrap's 0.15s colour fade would show the text under the spinner */
}

    .btn.is-busy::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 50%;
        width: 1rem;
        height: 1rem;
        margin: -.5rem 0 0 -.5rem;
        border: .15rem solid var(--bs-btn-color);
        border-right-color: transparent;
        border-radius: 50%;
        animation: spinner-border .75s linear infinite;
    }

    .btn.btn-remove.is-busy::after {
        width: .875rem;
        height: .875rem;
        margin: -.4375rem 0 0 -.4375rem;
        border-width: .125rem;
    }


/*--------------------------------------------------------------
# 4. The page header
#
# The first thing on every Index / Details / Create / Edit page (docs/reference/V3_STYLE_REFERENCE.md §5a, the rule):
# the title on the left, no icon, 31px tall like the header's buttons; on the right a status line
# (Orders' "In Stock & Pending") or buttons. 14px to the first card (10px on a phone). A form's
# validation summary goes under it. .page-header-row keeps title and actions on one row at every
# width; a plain .page-header wraps (on a phone it stacks, on the left).
#
#   <div class="page-header page-header-row">
#       <h3 class="page-header-title">Title</h3>
#       <div class="page-header-aside">…</div>          (optional)
#   </div>
--------------------------------------------------------------*/
.page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: .25rem 1rem;
    /* The same space under the header as above it (v3-shell.css's container padding) and as a grid page's (v3-grid.js
       HEAD_GAP): 14px, 10px on a phone. */
    margin-bottom: 14px;
}

/* No taller than the header's buttons (btn-sm, 31px): 26px at line height 1.2 (the user, 2026-10-12); 22px on a phone,
   where a Details title and its Menu share one line. */
.page-header-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .25rem .5rem;
    margin: 0;
    font-size: 1.625rem;
    line-height: 1.2;
}

/* A title that is only its icon and its text keeps the icon on the text's first line: too long for the room beside a
   phone's Menu ("Supplier Invoice Details"), the text wraps by words next to the icon instead of dropping, whole,
   under it. Titles with badges keep wrapping, so a badge goes to the next line rather than squeezing the title. */
.page-header-title:not(:has(> :not(i))) {
    flex-wrap: nowrap;
}

.page-header-aside {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .375rem;
    margin-left: auto;
}

/* What an Index shows (its filter: Orders' "In Stock & Pending", 1804's "Pending Declarations"): a soft pill right of
   the title, inside the h3 (the user, 2026-10-12; it replaced the status line on the header's right). Neutral by
   default; .is-warning / .is-success / .is-info for a filter with a meaning. Night values in v3-night.css. */
/* Centred on the title's letters, not its line box: the box's middle sits above the lowercase letters the eye reads
   (and moves with each browser's font metrics), so the title aligns its text and the pill on their baselines, and the
   pill is lifted .26em (3.4px): its centre then sits on the middle of the title's lowercase letters, 6.9px over the
   baseline at 26px (measured in the harness; the user, 2026-10-12). */
.page-header-title:has(> .page-header-badge) {
    align-items: baseline;
}

.page-header-badge {
    position: relative;
    top: -.26em;
    display: inline-flex;
    align-items: center;
    padding: .25rem .625rem;
    border-radius: 999px;
    background-color: #e8eef7;
    color: #304f7f;
    font-size: .8125rem;
    font-weight: 500;
    line-height: 1.2;
    white-space: nowrap;
}

    .page-header-badge.is-warning {
        background-color: #fdf1dc;
        color: #8a5300;
    }

    .page-header-badge.is-success {
        background-color: #e3f3ea;
        color: #146c43;
    }

    .page-header-badge.is-info {
        background-color: #e1ecfb;
        color: #1f5fae;
    }

/* Under 400px the pill goes (the user, 2026-10-13). The title then centres its icon again, as one without a pill does. */
@media (max-width: 399.98px) {
    .page-header-badge {
        display: none;
    }

    .page-header-title:has(> .page-header-badge) {
        align-items: center;
    }
}

/* A form page's validation summary sits under the header (docs/archive/v2_STYLES_HOMOGENIZATION.md §5a). While it is empty
   (-valid; the unobtrusive script makes it -errors) its empty list's margin would push the form down. */
.page-header + .validation-summary-valid {
    display: none;
}

/* A narrow centred form (site.css .wms-centerdiv, 800px) whose header is its first child (H4): the header's own
   14px above (the container's padding) replaces the column's 20px. */
.wms-centerdiv.has-page-header {
    margin-top: 0;
}

    /* ... and the title centred over the form, as its actions are (the user, 2026-10-12). */
    .wms-centerdiv.has-page-header .page-header.page-header-row {
        justify-content: center;
        text-align: center;
    }

@media (max-width: 575.98px) {
    .page-header-title {
        font-size: 1.375rem;
    }
}

/* On a phone every header is on the left, the cards' edge, a centred form's too (the user, 2026-10-13: it had been
   centred below md); a plain .page-header puts its aside under the title. */
@media (max-width: 767.98px) {
    .page-header {
        margin-bottom: 10px;
        flex-direction: column;
        align-items: flex-start;
        justify-content: flex-start;
        text-align: left;
    }

    .page-header-aside {
        justify-content: flex-start;
        margin-left: 0;
    }

    .wms-centerdiv.has-page-header .page-header.page-header-row {
        justify-content: space-between;
        text-align: left;
    }
}


/*--------------------------------------------------------------
# 5. The grid toolbar and its search box
#
# Above a grid: the actions (Add New, Filters), the search box, and the tools (the column
# picker). One row at every width, one gap between them all, every control 31px high (a btn-sm).
# The buttons keep their size and the search box takes what is left.
#
# As the window narrows, first the buttons lose their labels (below 992px: icons only; the label
# is kept for screen readers and in the site tooltip), then the column picker goes where the
# grid becomes cards (below 768px: d-none d-md-flex on .grid-toolbar-tools). A button's text goes
# in <span class="btn-label">, and every button keeps an aria-label, since site.js turns titles
# into its own tooltips.
#
# A grid with more buttons than fit (Orders, 1804, Jobs) puts them in one "Menu" dropdown in
# .grid-toolbar-actions, so the row still fits; which buttons stay outside it is decided per grid.
#
#   <div class="grid-toolbar">
#       <div class="grid-toolbar-actions">…buttons…</div>
#       <partial name="_GridSearch" model="…" />         (renders .grid-toolbar-search)
#       <div class="grid-toolbar-tools d-none d-md-flex">…column picker…</div>
#   </div>
--------------------------------------------------------------*/
.grid-toolbar {
    display: flex;
    align-items: center;
    gap: .25rem;
    margin-bottom: .5rem;
}

    .grid-toolbar .btn {
        margin: 0;          /* site.css gives every .btn 5px under it */
        /* The search box's height, set rather than left to the line, padding and borders adding up to it: at a display
           scaling that is not a whole number Chromium rounds a 1px border down to whole device pixels (0.8px at 125%), so
           a button came out 30.6px against the box's 31px, its top 0.2px below the box's (the user, 2026-10-13). */
        height: var(--grid-control-h);
    }

    .grid-toolbar .btn > i + .btn-label,
    .grid-toolbar .btn > span > :is(i, .spinner-border) + .btn-label {
        margin-left: .35rem;
    }

.grid-toolbar-actions,
.grid-toolbar-tools {
    display: flex;
    flex: none;
    align-items: center;
    gap: .25rem;
}

.grid-toolbar-search {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    min-width: 0;
}

/* The Menu dropdown's items (Orders: Overview, Packing, Advanced Search, Excel, PDF): the icon
   beside the text, as in a Details page's Menu. */
.grid-toolbar .dropdown-item {
    display: flex;
    align-items: center;
    gap: .5rem;
}

@media (max-width: 991.98px) {
    .grid-toolbar .btn-label {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip: rect(0 0 0 0);
        white-space: nowrap;
    }
}

/* A segmented quick filter beside the toolbar's buttons (TaxInvoices'/Remittances' company switch):
   one control, the active segment filled with the site's blue. */
.grid-switch {
    display: inline-flex;
    flex: none;
    align-self: stretch;        /* as tall as the buttons beside it, whatever height the browser gives them */
    min-height: 31px;
    overflow: hidden;
}

.grid-switch-btn {
    padding: 0 .75rem;
    /* The segments carry the switch's outline themselves (a border on .grid-switch would sit outside
       them and leave them 2px shorter than the buttons beside, the filled one visibly so). */
    border: 1px solid var(--alma-line, #ced4da);
    border-left-width: 0;
    background: none;
    color: var(--alma-blue);
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1;
}

    /* The end segments round with the strip: they carry its outline, which the strip's clip would otherwise shave off
       at its corners (the user, 2026-10-23: the corners looked cut). */
    .grid-switch-btn:first-child {
        border-left-width: 1px;
        border-top-left-radius: inherit;
        border-bottom-left-radius: inherit;
    }

    .grid-switch-btn:last-child {
        border-top-right-radius: inherit;
        border-bottom-right-radius: inherit;
    }

    .grid-switch-btn:hover {
        background-color: rgba(48, 79, 127, .08);
    }

    .grid-switch-btn.is-active {
        border-color: var(--alma-blue);
        background-color: var(--alma-blue);
        color: #fff;
    }

/* The search box: the active filters as pills (the search text is one of them), the search text,
   then apply / clear everything. The pills scroll sideways rather than squeeze the text, which
   always keeps 8rem. */
.grid-search {
    display: flex;
    flex: 1 1 auto;
    align-items: center;
    min-width: 0;
    height: var(--grid-control-h);
    border: 1px solid var(--grid-search-border, #6c757d);
    overflow: hidden;
}

.grid-search-pills {
    display: flex;
    flex: 0 1 auto;
    align-items: center;
    gap: .25rem;
    min-width: 0;
    padding-left: .3rem;
    overflow-x: auto;
    scrollbar-width: none;
}

    .grid-search-pills:empty {
        display: none;
    }

    .grid-search-pills::-webkit-scrollbar {
        display: none;
    }

    /* More pills than room: their right edge fades until the row is scrolled to its end
       (index-grid.js sets the class). */
    .grid-search-pills.is-overflowing {
        -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
        mask-image: linear-gradient(to right, #000 calc(100% - 1.5rem), transparent);
    }

.grid-search-pill {
    display: inline-flex;
    flex: none;
    align-items: center;
    gap: .25rem;
    padding: 1px 6px;
    border: 1px solid var(--alma-blue);
    border-radius: 5px;
    background-color: var(--alma-blue);
    font-size: .7rem;
    line-height: 1.6;
    white-space: nowrap;
}

    .grid-search-pill:hover,
    .grid-search-pill:focus-visible {
        border-color: #dee2e6;
        background-color: #dee2e6;
        color: var(--alma-accent);
    }

.grid-search-pill-value {
    max-width: 16ch;
    overflow: hidden;
    text-overflow: ellipsis;
}

.grid-search-input {
    flex: 1 1 auto;
    min-width: 8rem;       /* 6.5rem below 400px, below */
    height: 100%;
    padding: 0 .5rem;
    border: 0;
    font-size: .875rem;
    outline: 0;
}

.grid-search-btn {
    display: inline-flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 100%;
    padding: 0;
    border: 0;
    background: #f8f9fa;
    text-decoration: none;
}

    .grid-search-btn:hover,
    .grid-search-btn:focus-visible {
        background: #e2e6ea;
        color: #212529;
    }

    .grid-search-btn.is-reset {
        border-left: 1px solid #dee2e6;
    }

    /* The ✓ and the × drawn the same size. At one font size bi-check-lg's ink is 11×8px and
       bi-x-lg's 13×12px (measured at 16px), so the ✓ is set larger and the × smaller: about
       11×8 and 10×10 here, 13×9 and 12×11 at the touch size below. */
    .grid-search-btn {
        font-size: .875rem;
    }

        .grid-search-btn > i {
            line-height: 1;
        }

        .grid-search-btn > .bi-check-lg {
            font-size: 1.15em;
        }

        .grid-search-btn > .bi-x-lg {
            font-size: .9em;
        }

@media (max-width: 575.98px) {
    .grid-search-pill-value {
        max-width: 11ch;
    }
}

/* Touch: where the grid is cards (below 768px) the toolbar's controls are 40px, large enough to
   hit with a finger. The search text is 16px there, so phones don't zoom in when it is focused. */
@media (max-width: 767.98px) {
    .grid-toolbar {
        --grid-control-h: 40px;
    }

        .grid-toolbar .btn {
            min-width: var(--grid-control-h);
            height: var(--grid-control-h);
            display: inline-flex;
            align-items: center;
            justify-content: center;
            font-size: 1rem;
        }

    .grid-search-input {
        font-size: 1rem;
    }

    .grid-search-btn {
        width: 2.5rem;
        font-size: 1rem;
    }

    .grid-search-pill {
        padding: 3px 8px;
        font-size: .75rem;
    }
}

/* The narrowest phones (360-375px) with three buttons before the box (Orders: Add New, Filters,
   Menu): at 8rem the text pushed the box's clear-all × past its edge, where the box clips it. */
@media (max-width: 399.98px) {
    .grid-search-input {
        min-width: 6.5rem;
    }
}

/*---------------------------------------------------------- The filter panel (.filter-offcanvas)
   The toolbar's Filters button opens it. The same on every grid:

     <div class="offcanvas offcanvas-end filter-offcanvas" id="filtersOffcanvas" tabindex="-1" aria-labelledby="…Title">
         <div class="offcanvas-header">
             <h2 class="offcanvas-title" id="…Title"><i class="bi bi-funnel"></i>Filters</h2>
             <button class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
         </div>
         <div class="offcanvas-body">   one .form-floating select per filter  </div>
         <div class="offcanvas-footer"> <a class="btn btn-outline-secondary"><i class="bi bi-x-lg"></i>Reset All Filters</a> </div>
     </div>

   Reset is in the footer at the panel's foot, on the left. */
.filter-offcanvas .offcanvas-header {
    border-bottom: 1px solid var(--alma-line);
}

.filter-offcanvas .offcanvas-title {
    display: flex;
    align-items: center;
    gap: .5rem;
    margin: 0;
    color: var(--alma-blue);
    font-size: 1.1rem;
    font-weight: 700;
}

.filter-offcanvas .offcanvas-body {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

    /* The body spaces the fields; site.css's 10px under every floating field would double it. */
    .filter-offcanvas .offcanvas-body .form-floating {
        padding-bottom: 0;
    }

.filter-offcanvas .offcanvas-footer {
    display: flex;
    justify-content: flex-start;
    gap: .5rem;
    padding: .75rem 1rem;
    border-top: 1px solid var(--alma-line);
    background-color: var(--alma-surface);
}

    .filter-offcanvas .offcanvas-footer .btn {
        display: inline-flex;
        align-items: center;
        gap: .375rem;
        margin: 0;
    }

/*---------------------------------------------------------- The pager (Views/Shared/_GridPager.cshtml)
   Under a grid, one row: the small page links, 1rem later the page size, and at the right the page
   and record counts (LazZiya's badges), from lg up only. Below md the phone pager (centred, no
   counts) takes over.

   LazZiya renders its links and its counts in one wrapper (.pagination-sm > .col, .col-2); the
   wrapper is display:contents here so both become the row's items and the counts can go right.
   The page size is a split control in the links' look (LazZiya's .page-link):
   "Page Size" as the label on the left, the current size on the right opening the sizes.
     <div class="dropdown grid-pager-size" data-grid-page-size data-page data-page-size>
       <div class="btn-group btn-group-sm"><span class="btn grid-pager-size-label">Page Size</span>
         <button class="btn dropdown-toggle grid-pager-size-value" data-bs-toggle="dropdown">20</button>
         <ul class="dropdown-menu"><li><button class="dropdown-item" data-grid-page-size-value="50">50</button>…
*/
/* It wraps rather than run past the page if the links ever need more room (three-digit pages at
   768px): the page size then goes under them. */
.grid-pager {
    flex-wrap: wrap;
    align-items: center;
    gap: .5rem 1rem;
    margin-top: 6px;
}

    .grid-pager > .pagination-sm {
        display: contents;
    }

        .grid-pager > .pagination-sm > .col,
        .grid-pager > .pagination-sm > .col-2 {
            flex: none;
            width: auto;
            max-width: none;
            padding: 0;
        }

        .grid-pager > .pagination-sm > .col-2 {
            order: 2;
            margin-left: auto;
        }

/* The small pager (Bootstrap's .pagination-sm sizes: 31px, 14px, 4px corners). LazZiya puts
   .pagination-sm on its wrapper, but .pagination sets the sizes again on the list itself, so the
   wrapper's never reached the links; they are set on the list here. */
.grid-pager .pagination,
.grid-pager-mobile .pagination {
    --bs-pagination-padding-x: .5rem;
    --bs-pagination-padding-y: .25rem;
    --bs-pagination-font-size: .875rem;
    --bs-pagination-border-radius: var(--bs-border-radius-sm);
    flex-wrap: nowrap;
    margin: 0;
}

.grid-pager-size {
    flex: none;
    order: 1;
}

    /* The links' size (above). */
    .grid-pager-size .btn {
        --bs-btn-padding-y: .25rem;
        --bs-btn-padding-x: .5rem;
        --bs-btn-font-size: .875rem;
        --bs-btn-border-radius: var(--bs-border-radius-sm);
        --bs-btn-border-color: var(--bs-border-color);
        --bs-btn-bg: #fff;
        --bs-btn-color: var(--bs-link-color);
        --bs-btn-hover-bg: var(--bs-secondary-bg, #e9ecef);
        --bs-btn-hover-border-color: var(--bs-border-color);
        --bs-btn-hover-color: var(--bs-link-hover-color);
        --bs-btn-active-bg: var(--bs-secondary-bg, #e9ecef);
        --bs-btn-active-border-color: var(--bs-border-color);
        --bs-btn-active-color: var(--bs-link-hover-color);
        margin: 0;
    }

    /* The label is text, not a button: the pager's grey, no hover. */
    .grid-pager-size .grid-pager-size-label {
        --bs-btn-color: var(--bs-secondary-color, #6c757d);
        background-color: var(--bs-tertiary-bg, #f8f9fa);
        pointer-events: none;
        cursor: default;
    }

    .grid-pager-size .grid-pager-size-value {
        min-width: 3.25rem;
        font-weight: 600;
    }

    .grid-pager-size .dropdown-menu {
        --bs-dropdown-min-width: 0;
        --bs-dropdown-font-size: .875rem;
        --bs-dropdown-link-active-bg: var(--alma-blue);
    }

/* The pager's look: the page links and the page size are each one flat strip, a soft tint of the scene's colour like the
   menu tier's buttons (btn-alma-light), split by hairlines, and the open page is a solid fill of that colour with white
   text. No gradients, highlights or shadows (2026-10-13: the raised / pressed-in glass tried that day stood out against
   the app's flat buttons). The page size's value fills the same way while its sizes are open. LazZiya's "…" between the
   pages (an <li> with bare text, no link) is a cell of the strip like the others, muted and inert, instead of a gap that
   split the pager in two. The colours are tokens: v3-shell.css sets the sunset ones, v3-night.css the night ones. The cells
   keep Bootstrap's small sizes (31px high). */
.grid-pager,
.grid-pager-mobile {
    --pager-face: #eef3f9;
    --pager-face-label: #e2e9f3;
    --pager-edge: rgba(48, 79, 127, 0.2);
    --pager-divider: rgba(48, 79, 127, 0.14);
    --pager-ink: var(--alma-blue, #304f7f);
    --pager-muted: #5f6f86;
    --pager-hover: #dbe5f2;
    --pager-active-face: var(--alma-blue, #304f7f);
    --pager-active-ink: #fff;
    --pager-radius: 6px;
}

    /* The strips. */
    .grid-pager .pagination,
    .grid-pager-mobile .pagination,
    .grid-pager-size .btn-group {
        border: 1px solid var(--pager-edge);
        border-radius: var(--pager-radius);
        background: var(--pager-face);
    }

    /* The page links' strip clips its cells to its corners (it holds no menu; the page size's does, so its end cells
       round their own corners below). */
    .grid-pager .pagination,
    .grid-pager-mobile .pagination {
        overflow: hidden;
    }

    /* A cell: no box of its own (the strip is the box), a hairline on its left after the first. */
    .grid-pager .pagination > .page-item > .page-link,
    .grid-pager-mobile .pagination > .page-item > .page-link,
    .grid-pager .pagination > .page-item:not(:has(> .page-link)),
    .grid-pager-mobile .pagination > .page-item:not(:has(> .page-link)) {
        margin: 0;
        border: 0;
        border-radius: 0;
        background: transparent;
        color: var(--pager-ink);
        box-shadow: inset 1px 0 0 var(--pager-divider);
    }

    .grid-pager .pagination > .page-item:first-child > .page-link,
    .grid-pager-mobile .pagination > .page-item:first-child > .page-link {
        box-shadow: none;
    }

    /* The phone's narrowest width hides « and »: the first cell left is ‹, with no hairline before it. */
    @media (max-width: 399.98px) {
        .grid-pager-mobile .pagination > .page-item:nth-child(2) > .page-link {
            box-shadow: none;
        }
    }

    /* The "…": a cell like the page numbers, in the muted ink, not a link. */
    .grid-pager .pagination > .page-item:not(:has(> .page-link)),
    .grid-pager-mobile .pagination > .page-item:not(:has(> .page-link)) {
        display: flex;
        align-items: center;
        padding: var(--bs-pagination-padding-y) .35rem;
        color: var(--pager-muted);
        font-size: var(--bs-pagination-font-size);
        line-height: 1.5;
        letter-spacing: .05em;
        cursor: default;
        user-select: none;
    }

    .grid-pager .pagination > .page-item > .page-link:hover,
    .grid-pager-mobile .pagination > .page-item > .page-link:hover {
        background: var(--pager-hover);
        color: var(--pager-ink);
    }

    .grid-pager .pagination > .page-item > .page-link:focus-visible,
    .grid-pager-mobile .pagination > .page-item > .page-link:focus-visible {
        box-shadow: inset 0 0 0 2px rgba(48, 79, 127, 0.45);
    }

    /* The open page, filled. */
    .grid-pager .pagination > .page-item > .page-link.pagination-active-page,
    .grid-pager-mobile .pagination > .page-item > .page-link.pagination-active-page {
        background: var(--pager-active-face);
        color: var(--pager-active-ink);
        box-shadow: none;
        font-weight: 600;
    }

    /* The page size: the same cells. The label is the strip's quieter end; the value fills while the sizes are open. */
    .grid-pager-size .btn-group > .btn {
        border: 0;
        border-radius: 0;
        background: transparent;
        color: var(--pager-ink);
        box-shadow: none;
    }

        .grid-pager-size .btn-group > .grid-pager-size-label {
            border-radius: calc(var(--pager-radius) - 1px) 0 0 calc(var(--pager-radius) - 1px);
        }

        .grid-pager-size .btn-group > .grid-pager-size-value {
            border-radius: 0 calc(var(--pager-radius) - 1px) calc(var(--pager-radius) - 1px) 0;
        }

    .grid-pager-size .btn-group > .grid-pager-size-label {
        background: var(--pager-face-label);
        color: var(--pager-muted);
    }

    .grid-pager-size .btn-group > .grid-pager-size-value {
        box-shadow: inset 1px 0 0 var(--pager-divider);
    }

        .grid-pager-size .btn-group > .grid-pager-size-value:hover {
            background: var(--pager-hover);
            color: var(--pager-ink);
        }

        .grid-pager-size .btn-group > .grid-pager-size-value.show,
        .grid-pager-size .btn-group > .grid-pager-size-value:active {
            background: var(--pager-active-face);
            color: var(--pager-active-ink);
            box-shadow: none;
        }

        .grid-pager-size .btn-group > .grid-pager-size-value:focus-visible {
            box-shadow: inset 0 0 0 2px rgba(48, 79, 127, 0.45);
        }

    /* The sizes: a menu in the strip's tint, the size in use filled. */
    .grid-pager-size .dropdown-menu {
        --bs-dropdown-padding-y: 4px;
        --bs-dropdown-item-padding-y: .2rem;
        --bs-dropdown-link-color: var(--pager-ink);
        --bs-dropdown-link-hover-bg: var(--pager-hover);
        --bs-dropdown-link-hover-color: var(--pager-ink);
        border: 1px solid var(--pager-edge);
        border-radius: var(--pager-radius);
        text-align: center;
    }

        .grid-pager-size .dropdown-menu .dropdown-item.active {
            background: var(--pager-active-face);
            color: var(--pager-active-ink);
            font-weight: 600;
        }

.grid-pager-mobile {
    margin-top: 6px;
}

    /* LazZiya marks each arrow's screen-reader text with Bootstrap 4's .sr-only, which Bootstrap 5
       doesn't have, so it shows: the phone drew every arrow twice («« ‹‹) and ran past 360px, and
       the desktop reads «First ‹Previous. Hidden the way .visually-hidden hides: always on the
       phone, and on the desktop below lg, where ten three-digit pages with the words didn't fit
       768px (from lg the words stay). */
    .grid-pager-mobile .sr-only {
        position: absolute !important;
        width: 1px !important;
        height: 1px !important;
        padding: 0 !important;
        margin: -1px !important;
        overflow: hidden !important;
        clip: rect(0, 0, 0, 0) !important;
        white-space: nowrap !important;
        border: 0 !important;
    }

    /* The narrowest phones (below 400px): ‹ and › with the five pages, without « First / Last »,
       which with two-digit pages took the row past 360px. */
    @media (max-width: 991.98px) {
        .grid-pager .sr-only {
            position: absolute !important;
            width: 1px !important;
            height: 1px !important;
            padding: 0 !important;
            margin: -1px !important;
            overflow: hidden !important;
            clip: rect(0, 0, 0, 0) !important;
            white-space: nowrap !important;
            border: 0 !important;
        }
    }

    @media (max-width: 399.98px) {
        .grid-pager-mobile .pagination {
            --bs-pagination-padding-x: .3rem;   /* room for three-digit pages */
        }

        .grid-pager-mobile .pagination > .page-item:first-child,
        .grid-pager-mobile .pagination > .page-item:last-child {
            display: none;
        }
    }


/*--------------------------------------------------------------
# 6. Grid cards: the grid below md (768px), one card a record
#
# Three rows at most, each a main part on the left (truncated with … when it runs out of room)
# and an aside on the right (a date, a client, the chips). The first row's main part is the
# record's link to its Details.
#
#   <div class="grid-cards d-md-none">
#       <div class="grid-card">
#           <div class="grid-card-row">
#               <a class="grid-card-title" …>MRN</a><span class="grid-card-aside">date</span>
#           </div>
#           <div class="grid-card-row">
#               <span class="grid-card-main"><a class="grid-card-icon">…</a><a class="grid-card-text">…</a></span>
#               <span class="grid-card-chips"><button class="grid-card-chip is-primary">…</button></span>
#           </div>
#       </div>
#   </div>
#
# Not a Bootstrap .card: site.css stretches every .card to its container's height.
--------------------------------------------------------------*/
.grid-cards {
    display: flex;
    flex-direction: column;
    gap: .375rem;
    margin-bottom: .75rem;
}

.grid-card {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    padding: .4rem .6rem;
    border-left: 3px solid var(--alma-blue);
    background-color: #fff;
    font-size: .8rem;
    line-height: 1.35;
    -webkit-touch-callout: none;
}

.grid-card-empty {
    padding: 1rem;
    border-left-color: #dc3545;
    color: #dc3545;
    font-size: 1rem;
    font-weight: 600;
    text-align: center;
}

.grid-card-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    min-width: 0;
    min-height: 1.375rem;
}

.grid-card-title,
.grid-card-main,
.grid-card-text {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.grid-card-title {
    color: var(--alma-blue);
    font-size: .875rem;
    font-weight: 600;
    text-decoration: none;
}

.grid-card-main {
    display: flex;
    align-items: center;
    gap: .375rem;
}

.grid-card a.grid-card-text,
.grid-card a.grid-card-aside {
    color: var(--alma-blue);
    text-decoration: none;
}

/* A link in the card's own text colour (the client before its vessel); short of room, it gives
   way before the part after it. */
.grid-card a.grid-card-text.is-quiet {
    flex: 0 3 auto;
    color: #212529;
    font-weight: 400;
}

/* A middle dot between two parts of one line. */
.grid-card-sep {
    flex: none;
    color: var(--alma-muted);
}

.grid-card-aside {
    flex: none;
    max-width: 45%;
    overflow: hidden;
    color: var(--alma-muted);
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A reference number as the aside (an MRN): dark and semibold to read at a glance, a little smaller, so its 18 characters keep to the row. */
.grid-card-aside.is-code {
    max-width: none;
    color: #212529;
    font-size: .72rem;
    font-weight: 600;
}

.grid-card-text.is-small {
    font-size: .75rem;
}

.grid-card-label {
    color: var(--alma-muted);
    font-size: .7rem;
    font-weight: 600;
    text-transform: uppercase;
}

/* A three-part row (Clients: email, phone, Tax ID): email on the left and never truncated (it may
   wrap instead), phone centred regardless of how wide its neighbours are — which justify-content
   can't promise once they differ in width, a grid's middle column can — and Tax ID on the right,
   the one that gives way to an ellipsis if the row runs out of room. */
.grid-card-row.grid-card-row-contact {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: baseline;
}

.grid-card-contact-email {
    min-width: 0;
    overflow-wrap: anywhere;
}

.grid-card-contact-phone {
    justify-self: center;
    flex: none;
    white-space: nowrap;
}

.grid-card-contact-taxid {
    display: flex;
    align-items: baseline;
    gap: .3rem;
    justify-self: end;
    min-width: 0;
    max-width: 100%;
}

.grid-card-icon {
    display: inline-flex;
    flex: none;
    align-items: center;
    color: var(--alma-blue);
    font-size: 1rem;
    line-height: 1;
    text-decoration: none;
}

    .grid-card-icon .flag img,
    .grid-card-chip .flag img {
        width: 16px !important;     /* site.css sizes the flag 20px, with a 5px lift */
        height: 16px !important;
        margin: 0;
    }

.grid-card-chips {
    display: flex;
    flex: none;
    gap: .25rem;
}

.grid-card-chip {
    padding: 1px 7px;
    border: 1px solid #adb5bd;
    border-radius: 999px;
    background-color: #fff;
    color: #212529;
    font-size: .68rem;
    font-weight: 600;
    line-height: 1.5;
    white-space: nowrap;
}

    button.grid-card-chip:hover,
    button.grid-card-chip:focus-visible {
        border-color: var(--alma-blue);
        background-color: var(--alma-blue);
        color: #fff;
    }

    .grid-card-chip.is-primary {
        border-color: var(--alma-blue);
        color: var(--alma-blue);
    }

    .grid-card-chip.is-static {
        background-color: #f6f6f6;
        color: var(--alma-muted);
    }

    /* A record's state (an order's In Stock / Exported / In Progress / Pending): the quick
       views' chip colours (modal.css), filled, with no outline. */
    .grid-card-chip.is-success,
    .grid-card-chip.is-warning,
    .grid-card-chip.is-danger,
    .grid-card-chip.is-muted {
        border-color: transparent;
    }

    .grid-card-chip.is-success {
        background-color: rgba(25, 135, 84, .12);
        color: #146c43;
    }

    .grid-card-chip.is-warning {
        background-color: rgba(245, 158, 11, .16);
        color: #93370d;
    }

    .grid-card-chip.is-danger {
        background-color: rgba(180, 35, 24, .1);
        color: #b42318;
    }

    .grid-card-chip.is-muted {
        background-color: rgba(107, 118, 134, .12);
        color: var(--alma-muted);
    }

/* Orders' Status column (_OrderRow): every state's chip as wide as the widest label (In Progress, Greek Σε Απόθεμα), so
   the dates beside them line up. A link chip (Exported, opening its export) keeps its state's look. */
.order-status-cell .grid-card-chip {
    display: inline-block;
    min-width: 7em;
    text-align: center;
}

a.grid-card-chip {
    text-decoration: none;
}

/* A card's actions menu (Customs): three vertical dots at the end of the card's last row, opening a
   dropdown of the row's actions. The icon sits beside each item's text, as in a Menu. */
.grid-card-menu-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.75rem;
    height: 1.5rem;
    margin: -.125rem -.25rem -.125rem 0;
    padding: 0;
    border: 0;
    border-radius: var(--alma-radius);
    background: none;
    color: var(--alma-blue);
    font-size: 1.1rem;
    line-height: 1;
}

    .grid-card-menu-btn:hover,
    .grid-card-menu-btn[aria-expanded="true"] {
        background-color: rgba(48, 79, 127, .1);
    }

.grid-card-menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* A card's main part as a button (Clients' address, opening the map): the button chrome reset so
   it reads exactly like the plain span version beside it, and sizes to its content rather than the
   whole row, so the clickable area ends where the text does. */
button.grid-card-main {
    border: 0;
    padding: 0;
    background: none;
    text-align: left;
    cursor: pointer;
}

/* The table's row-number column (#): as narrow as its numbers. */
.grid-col-no {
    width: .5%;
}

/* Fixed column widths (2026-11-03, piloted on Declaration1804): a grid's table opts in with .grid-fixed and gives every
   heading its content's width as --w, in em of the table's font (so it shrinks with the font at tablet widths), sized
   from the live data's 95th percentile. The columns then no longer follow the page's content: switching pages left
   them up to 32px wider or narrower, and every other column moved with them. When the widths add up to less than the
   table, the rest is shared out in proportion to them. A longer value ends in an ellipsis. v3-grid.js (fixColumns) turns
   the shown headings' widths into percentages so the table never runs wider than the page: when they don't fit, the
   headings marked .grid-shrink (free text) give up the room and dates, numbers and codes keep theirs. */
.table_custom.grid-fixed {
    table-layout: fixed;
}

    .table_custom.grid-fixed > thead > tr > th {
        width: calc(var(--w, 6em) + .7em);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

    /* The "#" heading is font-size 0 (v3-shell.css), so its width is in rem: three digits, for a page of 200. */
    .table_custom.grid-fixed > thead > tr > th.grid-col-no {
        width: 1.6rem;
    }

    .table_custom.grid-fixed > tbody > tr > td {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

        /* A truncating link or span (site.css's .orders-table-truncate: 24ch, 12ch on a tablet) fills its column
           instead, so its own ellipsis falls at the column's edge; the cell would otherwise cut it off with none.
           After an icon (Orders' priority flame) it leaves the icon's room. */
        .table_custom.grid-fixed > tbody > tr > td .orders-table-truncate {
            max-width: 100%;
        }

        .table_custom.grid-fixed > tbody > tr > td > .bi + .orders-table-truncate {
            max-width: calc(100% - 1.4em);
        }

/* Every row-number cell in the app recedes (opacity, so it follows every scene's ink): index grids
   (.grid-col-no, or .v3-col-no where v3-grid.js finds a "#" column), the tables inside Details pages and
   windows (.mm-col-no), the job line rows (.row-index) and .row-no for the rest. The job number leads. */
td.grid-col-no,
td.v3-col-no,
td.mm-col-no,
td.row-index,
td.row-no {
    opacity: .45;
    font-size: .85em;
}

.grid-job-no {
    font-weight: 600;
}

/* A table cell's text that opens something (Orders' "Multiple" sizes): a real button, looking as
   the cell's link it replaces (not a .btn, whose margin and font size would change the row). */
.grid-link-button {
    padding: 0;
    border: 0;
    background: none;
    color: #106eea;             /* site.css's link colours */
    font: inherit;
}

    .grid-link-button:hover {
        color: #3b8af2;
    }

/* A table badge that opens something (Exports' Orders / Packages): a real button, looking as the
   block badge it replaces, the cell's width less its 2px margins. */
.grid-badge-button {
    display: block;
    width: calc(100% - 4px);
    cursor: pointer;
}

/* A grid's row menu (right-click / long-press, wwwroot/js/grid-row-menu.js; Sent Pre-Alerts): one
   dropdown for the page, placed at the pointer. Fixed, so the grid's scroller and pager never clip it
   (the two classes outrank .dropdown-menu's absolute). */
.dropdown-menu.grid-row-menu {
    position: fixed;
    z-index: 1040;
    min-width: 14rem;
}

    .grid-row-menu .dropdown-item {
        display: flex;
        align-items: center;
        gap: .5rem;
    }

[data-prealert-row] {
    -webkit-touch-callout: none;
}

/* An export's shipment status (_ShipmentStatusBadge): the icon before the word; for staff a button
   (the Delivered window), keeping the badge's own look. */
.shipment-status {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    white-space: nowrap;
}

button.shipment-status {
    cursor: pointer;
}

/* Nothing to go by yet: for staff a quiet dash that still opens the Delivered window. */
button.shipment-status.is-empty {
    min-width: 1.75rem;
    justify-content: center;
    padding: 0 .375rem;
    border: 0;
    background: none;
    color: inherit;
    opacity: .55;
}

    button.shipment-status.is-empty:is(:hover, :focus-visible) {
        opacity: 1;
    }

/* Arrived by the ETA alone: the Arrived colour with a dashed line, until Golden Cargo's arrival email
   makes it solid (v3 draws the badge's line; only its style changes). */
.badge.shipment-status.is-estimate {
    border-style: dashed !important;
}

/* The Exports grid's Status chips all as wide as the column (like Orders and Packages), so it reads as one. */
#exportsDesktopTable td[data-column-name="Status"] .grid-card-chip.shipment-status {
    display: flex;
    justify-content: center;
    width: calc(100% - 4px);
    margin-inline: auto;
}

.badge.customs-exit {
    white-space: nowrap;
}

/* Beside an exported order's Exported chip (_OrderStateMeta): the chips' size and shape. */
.mm-meta .badge.shipment-status,
.mm-meta .badge.customs-exit {
    padding: 2px 10px;
    border-radius: 999px;
    font-size: 0.7rem;
    line-height: 1.5;
    letter-spacing: 0.02em;
}

    .detail-head-chips .badge.shipment-status {
        padding: 4px 12px;
        font-size: .8rem;
    }

/* Their columns' headings and empty "-" centred over the cell-wide badges (the user, 2026-10-23); Status
   centred like them (the user, 2026-11-04) */
#exportsDesktopTable :is(th, td):is([data-column-name="Orders"], [data-column-name="Packages"], [data-column-name="Status"]) {
    text-align: center;
}

/* A state badge in a table cell (Jobs' paperwork, Paid / Open), its colour from the bg-* class
   beside it. The size is the one site.css's global .badge gives every badge, written out here so
   the rows keep their height when Phase 3 deletes that rule. */
.badge.grid-badge {
    margin: 2px;
    padding: 4px 8px;
    border-radius: 5px;
}


/*--------------------------------------------------------------
# 7. Form pages: the card, its sections and its actions
#
# A Create or Edit page is a .page-header, then one .form-card holding the fields and, last,
# the .form-actions: Save, then Cancel, then Delete where the page has one.
#
#   <div class="page-header"><h3 class="page-header-title"><i class="bi bi-…"></i>Title</h3></div>
#   <form …>
#       <div class="form-card">                          (.form-card-narrow: 800px, centred)
#           <div class="row g-3">
#               <div class="col-md-4">
#                   <div class="row g-2">                (the field grid: one 8px gap all round)
#                       <div class="col-sm-8 form-floating">…</div>
#                       <div class="col-12"><div class="form-section">…</div></div>
#                   </div>
#               </div>
#           </div>
#           <div class="form-actions">
#               <span class="form-actions-note">…</span>   (optional: why Save is disabled)
#               <button class="btn btn-alma">Save</button>
#               <a class="btn btn-secondary"><i class="bi bi-x-lg"></i>Cancel</a>
#           </div>
#       </div>
#   </form>
#
# A .form-section is a panel inside the form (Orders, Packages, Invoices): a quiet title over its
# content. It replaces Bootstrap .cards in forms, which site.css stretches to their column.
#
# The old wms-form-shadow / wms-centerdiv / boxshadowdiv keep working until the last form moves.
--------------------------------------------------------------*/
.form-card {
    padding: 1rem 1.25rem;
    border: 1px solid var(--alma-line);
    border-radius: var(--alma-radius-panel);
    background-color: #fff;
    box-shadow: 0 1px 3px rgba(23, 43, 69, .08);
}

    /* The field grid spaces the fields; site.css's 10px under every floating field would double it. */
    .form-card .form-floating {
        padding-bottom: 0;
    }

    .form-card .btn {
        margin-bottom: 0;   /* site.css gives every .btn 5px under it */
    }

/* A floating textarea several lines high (an agent's name and address). */
.form-floating > textarea.form-control.field-tall {
    height: 12.5rem;
}

/* A floating textarea of three lines (an order's notes in a quick edit): one field and two more
   lines of the value's height. */
.form-floating > textarea.form-control.field-3-lines {
    height: calc(var(--field-h) + 2.5em);
}

.form-section {
    padding: .625rem .75rem .75rem;
    border: 1px solid var(--alma-line);
    border-radius: var(--alma-radius);
    background-color: var(--alma-surface);
}

.form-section-title {
    margin: 0 0 .5rem;
    color: var(--alma-muted);
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
}

    .form-section > :last-child {
        margin-bottom: 0;
    }

/* A section's "nothing here" line, at the fields' value size. */
.form-section-empty {
    margin: 0 0 .5rem;
    color: var(--alma-muted);
    font-size: var(--field-font);
}

/* A choice's link (an invoice's number) at the text's weight, in the site's blue. */
.form-option .form-check-label a {
    font-weight: 500;
}

/* A row of small buttons under a field (the agent's Edit / Save / Cancel / Remove). */
.form-inline-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .375rem;
}

.form-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: .5rem;
    /* No rule above the buttons (the user, 2026-10-12: it adds nothing); the space alone sets them off. */
    margin-top: 1rem;
}

    /* Label and icon centred in the button whatever its height: a link (Cancel) does not centre its text the way a
       <button> (Save) does, which showed once the phone's 44px height applies. */
    .form-actions > .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
    }

.form-actions-note {
    margin-right: auto;
    color: #dc3545;
    font-size: .875rem;
}

/* A centred form's actions are centred too (the user, 2026-10-12); an admin-only one sits after them, or wraps. */
.wms-centerdiv .form-actions {
    justify-content: center;
}

/* Field groups (the user, 2026-10-12): 8px between the fields of a group (each group a row g-2), 12px between
   groups. The row's own margin is minus its gutter, so the 12px is reached from there. */
.form-field-group + .form-field-group {
    margin-top: calc(.75rem - var(--bs-gutter-y));
}

/* A wrapper inside a field grid that must not break it (Orders' package rows, which a script adds and removes): its
   columns count as the row's, so they take the gutter Bootstrap gives a row's direct children, and a floating
   field's label the same inset as there (.row > .form-floating > label, above). */
.row-contents {
    display: contents;
}

    :where(.row-contents) > * {
        flex-shrink: 0;
        max-width: 100%;
        padding-right: calc(var(--bs-gutter-x) * .5);
        padding-left: calc(var(--bs-gutter-x) * .5);
        margin-top: var(--bs-gutter-y);
    }

    .row-contents > .form-floating > label {
        left: calc(var(--bs-gutter-x) * .5);
        right: calc(var(--bs-gutter-x) * .5);
    }

@media (max-width: 575.98px) {
    .form-card {
        padding: .75rem;
    }

    /* On a phone the actions share the row, each wide enough to hit with a thumb. */
    .form-actions > .btn {
        flex: 1 1 0;
        min-height: 44px;
    }

    /* An admin-only action takes its own line under Save and Cancel. */
    .form-actions > .btn-admin {
        flex-basis: 100%;
    }

    .form-actions-note {
        flex-basis: 100%;
        margin-right: 0;
        text-align: center;
    }
}


/*--------------------------------------------------------------
# 8. Details pages: the record card and its sections
#
# A record's page reads as its quick view at page size, in the same pieces (modal.css:
# chips, facts, notes, tables, totals), under .mm-scope for their values:
#
#   <div class="page-header">…title…<div class="page-header-aside">Documents, Photos, Edit, Delete, Back</div></div>
#   <div class="mm-scope detail-page">
#       <div class="detail-card">
#           <div class="detail-head">
#               <div class="detail-head-main"><h2 class="detail-title">MRN</h2><span class="mm-title-aside">B/L …</span></div>
#               <div class="mm-meta detail-head-meta">chips, <span class="detail-date">date</span></div>
#           </div>
#           <div class="detail-body">                        (three panels of one width and height)
#               <div class="detail-block">the party, as addressed, <table class="detail-table">contact</table></div>
#               <div class="detail-block"><table class="detail-table">label | value rows</table></div>
#               <div class="detail-block"><table class="detail-table">…</table></div>
#           </div>
#           <p class="mm-note detail-note">…</p>
#       </div>
#       <div class="detail-section"><h3 class="mm-group-title">Orders</h3><table class="mm-table is-rows">…</table><div class="mm-totals">…</div></div>
#       <partial name="_AuditFooter" />   (.record-audit: id, created, modified; bottom-left, outside the cards)
#   </div>
#
# The header's buttons carry an icon and a .btn-label; below 576px only the icons show.
--------------------------------------------------------------*/
.page-header-aside .btn {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    margin: 0;
}

    .page-header-aside .btn .badge {
        margin: 0;
    }

/* Every label from xl up; below xl only the main action's (.btn-label.is-kept, Edit). */
@media (max-width: 1199.98px) {
    .page-header-aside .btn-label:not(.is-kept) {
        display: none;
    }
}

/* ... and from xl up too while the labels don't fit beside the title: site.js sets .is-compact on the header when its
   actions would drop to a second row (a page with many buttons, a long title, the Greek labels), so the page never
   jumps down by a row (the user, 2026-10-15). */
.page-header.is-compact .page-header-aside .btn-label:not(.is-kept) {
    display: none;
}

/* A label that shows from xl up and leaves its icon alone below (a button outside .page-header-aside,
   with an aria-label and a title to say what the icon is). */
@media (max-width: 1199.98px) {
    .btn-label-wide {
        display: none;
    }
}

/* .page-header-row: the title and the actions stay one row at every width (a plain .page-header
   stacks and centres them below md). Below sm the actions are one Menu dropdown
   (.page-header-menu), since the title and five buttons don't fit a phone's width. */
.page-header-row .page-header-title {
    min-width: 0;
}

.page-header-row .page-header-aside {
    flex-wrap: nowrap;
}

/* A header whose title is a long reference (Customs' LRN): it shrinks and wraps inside its own box
   rather than push the actions onto a second row. */
.page-header-row .page-header-ref {
    min-width: 0;
    overflow-wrap: anywhere;
}

.page-header-menu {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    margin: 0;
}

.page-header-row .dropdown-item {
    display: flex;
    align-items: center;
    gap: .5rem;
}

/* The title's first line centred on the buttons (the user, 2026-10-13). Above sm a line of title is the buttons' 31px
   (26px at 1.2); below it the title is smaller (22px, Imports' 19px), so it is padded back to a 31px line and the row is
   top-aligned: a one-line title is centred on the Menu, a title that wraps keeps its first line beside it. */
@media (max-width: 767.98px) {
    .page-header.page-header-row {
        flex-direction: row;
        flex-wrap: nowrap;
        align-items: flex-start;
        justify-content: space-between;
        text-align: left;
    }

        .page-header.page-header-row .page-header-title {
            padding-block: max(0px, calc((1.9375rem - 1.2em) / 2));
        }

        /* An aside that is less than a button high (Customs Create's Message Id) is centred on the same 31px line. */
        .page-header.page-header-row .page-header-aside {
            justify-content: flex-end;
            min-height: 1.9375rem;
            margin-left: auto;
        }
}

.detail-card,
.detail-section {
    padding: 1.25rem 1.5rem;
    background-color: #fff;
}

.detail-section {
    margin-top: 1rem;
}

/* A page's first card under the header, on a page converted to the page header standard
   (docs/archive/v2_STYLES_HOMOGENIZATION.md §5a, H6): the space under it is the header's own margin. In v2 it is drawn
   like the grid card, 14px outside the container on each side (v3-shell.css), so its content lines up with the title. */
.page-card {
    padding: 1rem;
}

/* A very small phone (the user, 2026-10-12): the page drops its side margins (the container's 90%) for 8px, and a
   Create / Edit form's card runs from screen edge to screen edge: it keeps its ground and its top and bottom edges,
   loses its sides and corners, and pads its fields by the same 8px. After .page-card, whose padding this overrides.
   Under the shell (v3-shell.css) the card goes altogether and the sea turns plain; only the container's 8px is used. */
@media (max-width: 399.98px) {
    .form-card,
    .form-card.page-card {
        margin-left: -8px;
        margin-right: -8px;
        padding: 12px 8px;
        border-left: 0;
        border-right: 0;
        border-radius: 0;
    }

    :root .container.container-responsive:has(.form-card) {
        max-width: 100%;
        padding-left: 8px;
        padding-right: 8px;
    }
}

/* One row: the record's reference large with its second one beside it (MRN, B/L) on the left; its
   chips and its date on the right, under them when the row runs out of room. No rule under it: the body's panels
   are their own boxes, so the head stands 16px over them, the panels' own gap (was 14px, a hairline, then 16px). */
.detail-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px 24px;
    margin-bottom: 1rem;
}

.detail-head-main {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 18px;
    min-width: 0;
}

/* Two classes: modal.css (loaded after this file) sets .mm-meta's margin. */
.detail-card .detail-head-meta {
    justify-content: flex-end;
    margin: 0;
}

/* From lg up the row has three parts: the MRN on the left, the waybill in the middle (its label as
   the panels' labels, its number as large as the MRN), the chips and the date on the right. Below
   lg the waybill is the small B/L beside the MRN. */
/* The label sits over the number, in the space between the card's top edge and the number (as far
   from the one as from the other), so the row is no taller than the MRN makes it. */
.detail-head-waybill {
    position: relative;
    min-width: 0;
}

    .detail-head-waybill > .detail-block-label {
        position: absolute;
        bottom: 100%;
        left: 50%;
        margin-bottom: var(--detail-waybill-label-gap, 2px);
        line-height: 1;
        white-space: nowrap;
        transform: translateX(-50%);
    }

.detail-waybill {
    color: var(--mm-ink);
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -.01em;
    white-space: nowrap;
}

@media (min-width: 992px) {
    .detail-head {
        display: grid;
        grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    }

        .detail-head > .detail-head-waybill {
            justify-self: center;
        }

    .detail-card .detail-head-meta {
        justify-self: end;
    }
}

/* The date as strong as the B/L beside the MRN. */
.detail-date {
    color: var(--mm-ink);
    font-size: .95rem;
    font-weight: 600;
    white-space: nowrap;
}

.detail-title {
    min-width: 0;
    margin: 0;
    color: var(--mm-ink);
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1.25;
    letter-spacing: -.01em;
    overflow-wrap: anywhere;
}

/* Three panels of one width and one height (the tallest sets it): the party as addressed, where it
   goes, the record's own details. Two equal columns between md and lg (the third under them,
   across), one below md. */
.detail-body {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1rem;
}

    .detail-body > .detail-block {
        margin: 0;
    }

.detail-block {
    padding: 14px 16px;
    border-radius: var(--alma-radius-panel);
    background: var(--alma-surface);
    color: var(--mm-ink);
    font-size: .86rem;
    line-height: 1.5;
}

.detail-block-label {
    margin: 0;
    color: var(--mm-muted);
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .03em;
    text-transform: uppercase;
}

.detail-block-name {
    margin: 1px 0 2px;
    font-size: .95rem;
    font-weight: 700;
}

.detail-strong {
    font-weight: 700;
}

/* A value over several lines as entered (an agent's name and address). */
.detail-table td.is-lines,
.mm-fact dd.is-lines {
    white-space: pre-line;
}

/* Labels and values as a borderless table (a party's contact, where it goes, the record's own
   details): the label column as wide as its longest label, the values wrapping in theirs, so a
   long label never runs into its value whatever the width; a value of several lines keeps its
   label at its top. */
.detail-table {
    width: 100%;
    border-collapse: collapse;
}

    .detail-table th {
        width: 1%;
        padding: 3px 16px 3px 0;
        color: var(--mm-muted);
        font-size: .68rem;
        font-weight: 600;
        letter-spacing: .03em;
        text-transform: uppercase;
        white-space: nowrap;
        vertical-align: baseline;
    }

    .detail-table td {
        padding: 3px 0;
        overflow-wrap: anywhere;
        vertical-align: baseline;
    }

.detail-block > .detail-table {
    margin-top: 8px;
}

    /* A panel that is only the table: its first row level with the other panels' labels. */
    .detail-block > .detail-table:first-child {
        margin-top: -3px;
    }

/* A party in a panel (an order's client, its vessel): the label, the full name, then what belongs
   to it (a count that filters a grid) on a line of its own. */
.detail-party + .detail-party {
    margin-top: 14px;
}

.detail-party > .detail-block-name {
    display: block;
}

/* An order's head: the state chip (larger) and the PO on the left, the supplier's short name on
   the right, as large as the PO, in the row's middle. The name shows only beside the POs: when
   they would reach it, the page's script hides it (the supplier panel is right under the head);
   below sm never. The POs never go under the chip. */
.detail-head.is-order {
    --detail-title-line: calc(1.6rem * 1.25);
}

    .detail-head.is-order > .detail-head-main {
        flex: 0 1 auto;
        flex-wrap: nowrap;
        align-items: flex-start;
        gap: 12px;
    }

/* The chips centred on the PO's first line (a box one title line high), however many lines the
   POs take. Two classes: modal.css (loaded after this file) gives .mm-meta a bottom margin,
   which lifted the chip off the PO's middle. */
.detail-head .detail-head-chips {
    flex: none;
    flex-wrap: nowrap;
    height: var(--detail-title-line);
    margin: 0;
}

    .detail-head-chips .mm-chip {
        padding: 4px 12px;
        font-size: .8rem;
    }

.detail-head-supplier {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: 1px;
    min-width: 0;
}

/* As large as the PO (a little lighter, so the PO stays the record's name). */
.detail-head-supplier-name {
    color: var(--mm-ink);
    font-size: 1.6rem;
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: -.01em;
    overflow-wrap: anywhere;
}

@media (max-width: 575.98px) {
    .detail-head.is-order {
        --detail-title-line: 1.25rem;
    }

    .detail-head.is-order > .detail-head-supplier {
        display: none;
    }
}

@media (min-width: 992px) {
    .detail-head.is-order {
        display: flex;
    }
}

/* Sections side by side (an order's Packing and Supplier Invoice), one under the other only when
   the row has no room for two of about 30rem. */
.detail-sections {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 30rem), 1fr));
    gap: 1rem;
    margin-top: 1rem;
}

    .detail-sections > .detail-section {
        margin-top: 0;
    }

/* A record beside its map (Clients, Suppliers, Vessels Details): two cards of one height from lg up, one under the
   other below. The map fills its card and is never shorter than --detail-map-h, so the three pages' maps match. */
.detail-pair {
    --detail-map-h: 400px;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
}

.detail-map-card {
    display: flex;
    flex-direction: column;
    padding: 8px;
}

    /* Two classes: site.css's .address-map sets a fixed 400px. */
    .detail-map-card > .address-map,
    .detail-map-card > .detail-map {
        flex: 1 0 var(--detail-map-h);
        height: auto;
        min-height: var(--detail-map-h);
        border-radius: calc(var(--alma-radius-panel) - 4px);
        overflow: hidden;
    }

/* A record's head with only its name (and maybe a chip): one row at every width, not the three-part grid of lg. */
@media (min-width: 992px) {
    .detail-head.is-plain {
        display: flex;
    }
}

/* The record card's facts: panels two to a row (.is-wide takes the row), one to a row on a phone. */
.detail-facts {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 12px;
}

    .detail-facts > .is-wide {
        grid-column: 1 / -1;
    }

/* A row of buttons in a record card, under its facts (Suppliers' Invoices / Orders, then the Admin's tools). */
.detail-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
}

    .detail-actions .btn,
    .detail-actions form {
        margin: 0;
    }

    .detail-actions .badge {
        margin: 0 0 0 .25rem;
        padding: 4px 8px;
    }

/* A section that opens under the cards (a Bootstrap .collapse): the gap above it is a box inside the collapse, so it
   opens and closes with the section instead of jumping. */
.detail-collapse::before {
    content: "";
    display: block;
    height: 1rem;
}

.detail-collapse > .detail-section {
    margin-top: 0;
}

/* A section title with a small action at its end (a client's Vessels with Manage). */
.detail-section-title-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    margin-bottom: .5rem;
}

    .detail-section-title-row > .mm-group-title {
        margin: 0;
    }

@media (max-width: 991.98px) {
    .detail-pair {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 575.98px) {
    .detail-pair {
        --detail-map-h: 300px;
    }

    .detail-facts {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Two classes: modal.css (loaded after this file) gives .mm-facts and .mm-note their
   margins in a modal. */
.detail-card .detail-note {
    margin: 1rem 0 0;
}

.detail-section > .mm-group-title {
    margin-bottom: .5rem;
}

.detail-section > .mm-state {
    min-height: 80px;
}

/* A section's content as one line of text (the packing totals typed in, when no packages were). */
.detail-line {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
    margin: .25rem 0 0;
    color: var(--mm-ink);
    font-size: .9rem;
    font-weight: 600;
}

/* The audit line closing a Details or Edit page (Views/Shared/_AuditFooter.cshtml): bottom-left, outside every card. */
.record-audit {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 2px 0;
    margin: .75rem 0 0;
    color: var(--mm-muted, #6c757d);
    font-size: .72rem;
    font-variant-numeric: tabular-nums;
}

    .record-audit > span:not(:last-child)::after {
        content: "·";
        margin: 0 8px;
    }

/* Under a narrow centred form (.wms-centerdiv, .form-card-narrow): the same width, so the line meets the card's left edge. */
.record-audit-narrow {
    width: 100%;
    max-width: 800px;
    margin: 0 auto;
}

@media (max-width: 991.98px) {
    .detail-body {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

        .detail-body > .detail-export,
        .detail-body > .detail-own {
            grid-column: 1 / -1;
        }
}

@media (max-width: 767.98px) {
    .detail-body {
        grid-template-columns: minmax(0, 1fr);
    }

    .detail-card .detail-head-meta {
        justify-content: flex-start;
    }
}

@media (max-width: 575.98px) {
    .detail-card,
    .detail-section {
        padding: .875rem;
    }

    /* The MRN and the B/L share one line on a phone, as on the quick view. */
    .detail-title {
        font-size: 1rem;
    }

    .detail-head-main {
        flex-wrap: nowrap;
        gap: 10px;
    }

        .detail-head-main .mm-title-aside {
            flex: none;
            font-size: .8rem;
        }

    .detail-date {
        font-size: .8rem;
    }
}
