/* ==========================================================================
   BRAND LAYER

   Loaded after the Bootstrap 5.3.3 CDN link in base2.html, which is what lets
   these overrides win without !important.

   THE TRAP: Bootstrap compiles its hex values into each component's own
   variables at build time -- .btn-primary is literally `--bs-btn-bg:#0d6efd`,
   not `var(--bs-primary)`. So redefining --bs-primary recolours .text-primary
   and .bg-primary and reaches NO button, pager, form focus ring or checkbox.
   Anything Bootstrap hardcodes gets its own block further down; only the
   :root hooks in the second group below actually cascade.
   ========================================================================== */

/* Self-hosted rather than Google Fonts: the help-screenshot capture drives a
   real browser against a live server and must not depend on an external host
   being reachable, and a same-origin font keeps a third-party request off every
   authenticated page. The landing page stays on Google Fonts -- its CSP already
   names fonts.gstatic.com and it deploys separately. Subsets and unicode-ranges
   mirror Google's own split, so latin-ext is only fetched when it is needed. */
@font-face {
    font-family: 'Archivo';
    font-style: normal;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    font-display: swap;
    src: url("fonts/archivo-latin-ext.589f7bc0fac4.woff2") format('woff2');
    unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
    font-family: 'Archivo';
    font-style: normal;
    font-weight: 100 900;
    font-stretch: 62% 125%;
    font-display: swap;
    src: url("fonts/archivo-latin.de2f1fe81758.woff2") format('woff2');
    unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

:root {
    /* --- Brand palette -------------------------------------------------
       The app's single source of truth. site/styles.css carries a hand-kept
       mirror: the landing page is a separate Render static site with its own
       CSP and cannot share a stylesheet with Django. Change one, change both.

       Orange is a FILL, never small text on white -- it measures 2.6:1 there.
       --ba-orange carries navy text at 4.74:1; --ba-orange-ink is the only
       orange allowed to read against white (5.18:1). */
    --ba-navy: #1E335C;
    --ba-navy-700: #192C51;
    --ba-navy-800: #12203F;
    --ba-navy-lift: #2C4675;
    --ba-orange: #FA7C22;
    --ba-orange-hover: #FB8A3C;
    --ba-orange-active: #E96D14;
    --ba-orange-ink: #C2410C;
    --ba-surface-1: #F2F4F8;
    --ba-surface-2: #E4E9F1;
    --ba-rule: #D5DCE6;
    --ba-steel: #5B6B86;

    /* --- Bootstrap hooks that really do resolve from :root -------------- */
    --bs-dark-rgb: 30, 51, 92;
    --bs-primary: #1E335C;
    --bs-primary-rgb: 30, 51, 92;
    --bs-primary-text-emphasis: #12203F;
    /* Pale navy, not the logo's near-white box face: this is what a subtle
       badge fills with, and #F2F4F8 left it looking like an outlined button
       next to the soft chips of the other four variants. Nothing else in the
       app consumes it (.bg-primary-subtle/.alert-primary/.table-primary/
       .accordion are all unused). */
    --bs-primary-bg-subtle: #DDE3EE;
    --bs-primary-border-subtle: #9FB0CC;
    /* `a` reads rgba(var(--bs-link-color-rgb)), and a:hover swaps in
       --bs-link-hover-color-rgb -- the non-rgb pair alone changes nothing. */
    --bs-link-color: #1E335C;
    --bs-link-color-rgb: 30, 51, 92;
    --bs-link-hover-color: #12203F;
    --bs-link-hover-color-rgb: 18, 32, 63;
    /* Orange focus ring: it has to stay visible against navy chrome, which a
       navy ring would not. */
    --bs-focus-ring-color: rgba(194, 65, 12, 0.3);
    --bs-body-font-family: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
}

/* --- Buttons -----------------------------------------------------------
   Navy is the primary action; orange stays the accent so it does not crowd
   the red/amber/green the PO and WO status workflows need. */
.btn-primary {
    --bs-btn-bg: var(--ba-navy);
    --bs-btn-border-color: var(--ba-navy);
    --bs-btn-hover-bg: var(--ba-navy-700);
    --bs-btn-hover-border-color: var(--ba-navy-700);
    --bs-btn-active-bg: var(--ba-navy-800);
    --bs-btn-active-border-color: var(--ba-navy-800);
    --bs-btn-disabled-bg: var(--ba-navy);
    --bs-btn-disabled-border-color: var(--ba-navy);
    --bs-btn-focus-shadow-rgb: 194, 65, 12;
}

.btn-outline-primary {
    --bs-btn-color: var(--ba-navy);
    --bs-btn-border-color: var(--ba-navy);
    --bs-btn-hover-bg: var(--ba-navy);
    --bs-btn-hover-border-color: var(--ba-navy);
    --bs-btn-active-bg: var(--ba-navy-700);
    --bs-btn-active-border-color: var(--ba-navy-700);
    --bs-btn-disabled-color: var(--ba-navy);
    --bs-btn-disabled-border-color: var(--ba-navy);
    --bs-btn-focus-shadow-rgb: 194, 65, 12;
}

/* --- Form controls -----------------------------------------------------
   Bootstrap writes this focus shadow as a literal rgba(13,110,253,.25), NOT
   as var(--bs-focus-ring-color), so overriding the ring variable alone leaves
   every field in the app ringed in blue. */
.form-control:focus,
.form-select:focus {
    border-color: var(--ba-navy-lift);
    box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
}

.form-check-input:checked {
    background-color: var(--ba-navy);
    border-color: var(--ba-navy);
}

.form-check-input:focus {
    border-color: var(--ba-navy-lift);
    box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
}

/* --- Pager -------------------------------------------------------------
   django-tables2 renders this from its own bootstrap5.html template, so it
   appears nowhere in sim_app/templates -- and ships on all seven list pages. */
.pagination {
    --bs-pagination-color: var(--ba-navy);
    --bs-pagination-hover-color: var(--ba-navy-800);
    --bs-pagination-focus-color: var(--ba-navy-800);
    --bs-pagination-focus-box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
    --bs-pagination-active-bg: var(--ba-navy);
    --bs-pagination-active-border-color: var(--ba-navy);
}

/* The help sidebar is the only list-group in the app. */
.list-group {
    --bs-list-group-active-bg: var(--ba-navy);
    --bs-list-group-active-border-color: var(--ba-navy);
}

.dropdown-menu {
    --bs-dropdown-link-active-bg: var(--ba-navy);
}

/* django-autocomplete-light ships its own select2.css with a hardcoded blue
   highlight on the focused dropdown option (`--select2-highlighted-bg:#5897fb`).
   It renders in no app template, so nothing above reaches it -- same trap as
   .pagination. Six DAL pickers across the part, BOM, PO, WO and inventory pages
   would otherwise flash Bootstrap-era blue on every keyboard selection. */
:root {
    --select2-highlighted-bg: var(--ba-navy);
    --select2-highlighted-fg: #FFFFFF;
}

/* Bootstrap's .navbar-dark hardcodes rgba(255,255,255,.55) for nav links.
   That measured 5.67:1 on the old near-black bar but only 4.92:1 on the
   lighter brand navy -- still AA, but visibly washed out. .80 gives 8.7:1
   and keeps the links clearly secondary to the solid-white brand. */
.navbar-dark {
    --bs-navbar-color: rgba(255, 255, 255, 0.80);
    --bs-navbar-hover-color: #FFFFFF;
}

/* The action bar's `?`. It was btn-sm, which made it 24px against the 38px of
   the buttons beside it; it now takes the default .btn size so the bar reads as
   one row of controls.

   bootstrap-icons gives every glyph `vertical-align:-.125em` to sit on a text
   baseline, and the question-mark's ink sits high in its em box, so in an
   icon-only button it lands above centre. Redistributing .btn's vertical
   padding -- .45rem over .3rem, still .75rem in total -- drops it to dead
   centre without changing the button's height.

   Measure this against the real page, not a mock: the anchor's line box comes
   from the page font's metrics, so the same split lands differently once
   Archivo is loaded. A mock without it said .6rem/.15rem, which is 6px low. */
.help-link {
    padding-top: 0.45rem;
    padding-bottom: 0.3rem;
}

/* --- Status badges -----------------------------------------------------
   PO and WO status, rendered by sim_app/_status_badge.html. Subtle rather
   than solid: 7-10:1 contrast against 4.5:1, and calm enough to sit on every
   row of a long list. Colour groups states into categories (see
   PO_STATUS_VARIANT in models.py); the label always says which state, so
   colour is never the only signal.
 */
.status-badge {
    font-weight: 600;
}

/* --- Brand chrome ------------------------------------------------------ */
.navbar-brand .brand-mark {
    height: 30px;
    width: auto;
    display: block;
}

.navbar-brand .brand-word {
    font-weight: 700;
    letter-spacing: -0.01em;
}

button.bom-delete,
button.quant-edit,
button.inv-transfer,
button.inv-cycle,
th.inv_new_loc,
th.inv_new_quan,
button.row-edit,
button.lineitem-delete,
button.lineitem-edit,
button.lineitem-button {
    visibility: hidden;
}

/* :focus-within alongside every :hover -- visibility:hidden also drops a
   button from the tab order, so hover-only reveals were unreachable from the
   keyboard (tabbing into the row's inputs now reveals its buttons). */
tr.bom-row:hover button.bom-delete,
tr.bom-row:focus-within button.bom-delete,
tr.bom-row:hover button.quant-edit,
tr.bom-row:focus-within button.quant-edit,
tr.inv-row:hover button.inv-transfer,
tr.inv-row:focus-within button.inv-transfer,
tr.inv-row:hover button.inv-cycle,
tr.inv-row:focus-within button.inv-cycle,
[data-edit-group]:hover button.row-edit,
[data-edit-group]:focus-within button.row-edit,
tr.po-row:hover button.lineitem-delete,
tr.po-row:focus-within button.lineitem-delete,
tr.po-row:hover button.lineitem-edit,
tr.po-row:focus-within button.lineitem-edit,
tr.po-row:hover button.lineitem-button,
tr.po-row:focus-within button.lineitem-button {
    visibility: visible;
}

tr.dragover-up {
    border-top: 3px solid black;
}

tr.dragover-down {
    border-bottom: 3px solid black;
}

button.quant-cancel,
button.quant-save,
button.inv-cancel,
button.inv-save,
td.inv_new_loc>select,
td.inv_new_quan>input,
tr.po-add button,
button.lineitem-cancel,
button.lineitem-save {
    display: none;
}

div#letterhead>img {
    float: left;
    margin-right: 1em;
}

.pre-line {
    white-space: pre-line;
}

.title {
    font-size: 1.25em;
    font-weight: bold;
    display: block;
}

.poheader {
    font-weight: bold;
    color: white;
    background-color: var(--ba-navy);
    display: block;
    text-transform: uppercase;
    padding: 0.25em 0.5em;
}

#poheader p {
    line-height: 1;
    font-size: 3em;
    font-weight: bold;
    text-transform: uppercase;
    color: var(--ba-navy);
    margin: 0;
    margin-bottom: 0.5em;
    padding: 0;
}

#poheader table {
    margin-top: 0.5em;
    justify-self: right;
    font-size: 1.25em;
}

#poheader td {
    padding: 0 0.5em;
    /* Part of the PO document, so it follows the document's navy rather than
       sitting at pure black beside it. The drag-drop indicators above stay
       black: they are transient UI, not part of the printed artefact. */
    border: 1px solid var(--ba-navy);
}

#poheader button,
#poheader a.btn {
    margin-top: 0.5em;
    margin-left: 0.5em;
    float: right;
    font-size: 1.25em;
}

div#vendor,
div#shipto,
div#terms,
div#lineitems {
    margin-top: 2em;
}

#terms table {
    width: 100%;
}

#terms th,
#lineitems th {
    font-weight: bold;
    color: white;
    background-color: var(--ba-navy);
    text-transform: uppercase;
    padding: 0.25em 0.5em;
    border: 2px solid var(--ba-navy);
}

#terms td {
    padding: 0.25em 0.5em;
    border: 2px solid var(--ba-navy);
}

tr.po-row td {
    border-left: 2px solid var(--ba-navy);
    border-right: 2px solid var(--ba-navy);
}

#lineitems table.table>:not(:first-child) {
    border-top: none;
}

#lineitems tr:nth-last-child(1 of .po-row)>td {
    border-bottom: 2px solid var(--ba-navy);
}

tr.receiving-section:not(:first-child)>td {
    border-top: 2px solid var(--ba-navy);
}

#lineitems tr:nth-last-child(1 of .po-row)>td.lineitem-edit-cell {
    border-bottom: none;
}

#lineitems td.lineitem-edit-cell {
    border-top: none;
    border-right: none;
    border-bottom: none;
    box-shadow: none;
}

/* The row buttons live in the page margin beside the table, not in a column
   of their own: a 49px button column pushed the line tables past a 1280px
   viewport. Zero-width cell + absolutely positioned strip, the same trick the
   inline Ship To / terms editors use (span.inline-actions). */
#lineitems td.lineitem-edit-cell {
    position: relative;
    width: 0;
    padding: 0;
}

#lineitems .lineitem-actions {
    position: absolute;
    top: 0.25rem;
    left: 0.25rem;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
    z-index: 2;
}

/* Let entry fields shrink to their column instead of forcing it to their
   intrinsic width (208px text inputs, a 320px Select2). */
#lineitems td > input:not([type="checkbox"]):not([type="hidden"]) {
    width: 100%;
    min-width: 3.5rem;
}

#lineitems td > input[type="date"] {
    min-width: 8.5rem;
}

#lineitems td .select2-container {
    width: 100% !important;
    min-width: 8rem;
}

/* tr#subtotal {
    border-top: 2px solid var(--ba-navy);
} */

#lineitems tr.po-sub td,
#lineitems tr.po-total td {
    box-shadow: none;
}

#lineitems tr.po-sub td:first-of-type,
#lineitems tr.po-total td {
    border: none;
}

#lineitems tr.po-total td:last-of-type,
#lineitems tr.po-total td:nth-last-of-type(2) {
    border-top: double var(--ba-navy);
    font-weight: bold;
}

tr.po-add span.select2-container {
    width: 100% !important;
}

/* The finished-goods picker in the work-order action bar (edit_wo.html).
   Select2 writes an inline style="width:…px" measured off the hidden <select>,
   which in the bar's flex row collapses to almost nothing — hence !important,
   same reason as the rule above. The dropdown itself is safe in the sticky bar:
   DAL passes no dropdownParent, so select2 attaches it to <body>, outside the
   .sticky-top stacking context. */
.action-bar span.select2-container {
    width: 16rem !important;
}

/* Select2 pickers sized to match Bootstrap 5 form controls.

   Keyed on .select2-bs5, which sim_app/widgets.py:select2_attrs() puts on the
   container via data-container-css-class. That attribute is also what stops
   DAL's `containerCssClass: ':all:'` copying Bootstrap's .form-select onto the
   container — which used to draw a second chevron over select2's own arrow and
   offset the text inside an oversized box.

   These have to out-specify select2.css rather than out-order it: main.css is in
   <head>, but {{ form.media }} is emitted in the page *body* on some templates
   (_list_toolbar.html, part.html), so select2.css can always land later. Chaining
   .select2-bs5 onto the container gives 0,3,0 against select2's 0,2,0, and scopes
   the sizing to pickers that opted in. Do not "simplify" these selectors.

   --bs-* resolve from :root; the literal fallbacks cover the print/PDF templates,
   which don't load Bootstrap. */
.select2-container--default.select2-bs5 .select2-selection--single {
    height: calc(1.5em + 0.75rem + 2px);
    border: var(--bs-border-width, 1px) solid var(--bs-border-color, #dee2e6);
    border-radius: var(--bs-border-radius, 0.375rem);
    background-color: var(--bs-body-bg, #fff);
}

.select2-container--default.select2-bs5 .select2-selection--single .select2-selection__rendered {
    /* Height minus the two borders, so the text centres. */
    line-height: calc(1.5em + 0.75rem);
    padding-left: 0.75rem;
    /* Room for the arrow. */
    padding-right: 2.25rem;
    color: var(--bs-body-color, #212529);
}

.select2-container--default.select2-bs5 .select2-selection--single .select2-selection__arrow {
    height: calc(1.5em + 0.75rem);
    right: 0.25rem;
}

/* Compact variant, matching .form-select-sm — table rows and filter panels. */
.select2-container--default.select2-bs5-sm .select2-selection--single {
    height: calc(1.5em + 0.5rem + 2px);
    border-radius: var(--bs-border-radius-sm, 0.25rem);
    font-size: 0.875rem;
}

.select2-container--default.select2-bs5-sm .select2-selection--single .select2-selection__rendered {
    line-height: calc(1.5em + 0.5rem);
    padding-left: 0.5rem;
    padding-right: 1.75rem;
}

.select2-container--default.select2-bs5-sm .select2-selection--single .select2-selection__arrow {
    height: calc(1.5em + 0.5rem);
}

/* Invalid state. Bootstrap paints the error border via .form-select.is-invalid on
   the <select>, which select2 hides — and since we deliberately stopped copying
   classes onto the container, that border no longer reaches anything visible. The
   container is inserted immediately after the <select> ($container.insertAfter in
   select2.full.js), so an adjacent-sibling selector recovers it without JS. */
select.is-invalid + .select2-container--default.select2-bs5 .select2-selection--single {
    border-color: var(--bs-form-invalid-border-color, #dc3545);
}

select.is-invalid + .select2-container--default.select2-bs5.select2-container--open .select2-selection--single,
select.is-invalid + .select2-container--default.select2-bs5 .select2-selection--single:focus {
    box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
}

/* Focus ring, matching Bootstrap's — select2 puts :focus on the inner element. */
.select2-container--default.select2-bs5 .select2-selection--single:focus,
.select2-container--default.select2-bs5.select2-container--open .select2-selection--single {
    /* --ba-navy-lift, not --bs-primary-border-subtle: this focus ring wants a
       darker navy than the pale one Bootstrap's *-subtle family is for. */
    border-color: var(--ba-navy-lift, #2C4675);
    outline: 0;
    box-shadow: 0 0 0 0.25rem var(--bs-focus-ring-color);
}

/* tr.po-row>td.lineitem-edit-cell { */
/* position: relative; */
/* border-color: transparent; */
/* padding: 0;
    width: 0; */
/* } */

/* td.lineitem-edit-cell::after {
    content: "";
    position: absolute;
    top: 0;
    left: 0;
    width: 2.5em;
    height: 100%;
} */

/* button.lineitem-edit {
    position: absolute;
    top: 0.25em;
    left: 0.5em;
    z-index: 10;
} */

input.po-input {
    width: 100%;
}

input.integer-field {
    width: 5em;
}

i.pre-icon {
    left: -1.5em;
    top: 0.25em;
}

textarea.po-input {
    field-sizing: content;
}

/* Inline field editors (Ship To, and the PO terms row). The buttons are
   lifted OUT of the layout flow and pinned to the field's right edge, so the
   field itself runs the full width of its column and lines up with the
   read-only PO page and the line-items table. Sitting them beside the field
   is what used to hold this content short of the right margin.

   Visibility is driven by the `editing` class alone -- added by main.js on
   click, and rendered by the server when a save fails validation -- so there
   is one source of truth rather than inline styles racing these rules. */
[data-edit-group] {
    position: relative;
}

span.inline-actions {
    position: absolute;
    /* Beside the field, not on it: left:100% puts the strip just past the
       group's right edge, in the page margin, so it never covers content. */
    left: 100%;
    margin-left: 0.5rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    gap: 0.25rem;
    z-index: 2;
}

/* The address row's field is multi-line and grows, so its buttons anchor to
   the top rather than drifting to the middle of a tall box. */
span.inline-actions-top {
    top: 0.25rem;
    transform: none;
}

button.row-cancel,
button.row-save {
    display: none;
}

[data-edit-group].editing button.row-edit {
    display: none;
}

[data-edit-group].editing button.row-cancel,
[data-edit-group].editing button.row-save {
    display: inline-flex;
}

/* The terms buttons hang off #terms itself, below the table's last row. */
#terms > span.inline-actions {
    top: auto;
    bottom: 0.25rem;
    transform: none;
    /* #terms is a Bootstrap .row child, so it carries half a gutter of padding,
       and left:100% resolves against the PADDING box -- half a gutter right of
       the table's real edge. Ship To's group has no such padding, so without
       this correction the two strips sit in different columns. */
    margin-left: calc(0.5rem - var(--bs-gutter-x, 1.5rem) / 2);
}

/* Reserve the strip's column inside the container rather than letting it hang
   into the page margin. That margin is a function of the viewport and the
   container's breakpoint, and collapses to ~30-40px just above the 1200px and
   1400px breakpoints -- not enough for two buttons, so the save button would be
   clipped off the page. Every block on the page loses the same width, so they
   all stay flush with each other, which is the whole point. */
.po-edit-gutter {
    padding-right: 5.5rem;
}

img.part-image {
    width: 640px;
    max-width: 100%;
}

/* django-tables2 sort indicators: a faint up/down on every sortable header,
   a solid arrow showing direction on the active column. (asc/desc rules follow
   the base rule so they win at equal specificity.) */
th.orderable>a {
    text-decoration: none;
    white-space: nowrap;
}

th.orderable>a::after {
    content: "\2195";
    /* ↕ sortable, inactive */
    margin-left: 0.4em;
    font-size: 0.8em;
    opacity: 0.3;
}

th.asc>a::after {
    content: "\25B2";
    /* ▲ ascending */
    opacity: 1;
}

th.desc>a::after {
    content: "\25BC";
    /* ▼ descending */
    opacity: 1;
}

/* Price-break expand caret: point right when collapsed, down when open. */
button.caret-toggle .bi-caret-right-fill {
    /* inline-block is required — transform is ignored on inline elements. */
    display: inline-block;
    transition: transform 0.15s ease-in-out;
}

button.caret-toggle:not(.collapsed) .bi-caret-right-fill {
    transform: rotate(90deg);
}

/* In-app help pages. */
.help-nav { position: sticky; top: 7rem; }
.help-toc a { text-decoration: none; }
.help-body { max-width: 52rem; line-height: 1.6; }
.help-body h2 { margin-top: 2.5rem; padding-top: 0.5rem; border-top: 1px solid var(--bs-border-color); }
.help-body h3 { margin-top: 1.75rem; }
/* Headings are anchor targets under a sticky navbar + action bar. */
.help-body :is(h2, h3) { scroll-margin-top: 7rem; }
.help-body img.help-shot { max-width: 100%; height: auto; border: 1px solid var(--bs-border-color); border-radius: 0.375rem; box-shadow: 0 0.125rem 0.5rem rgba(0, 0, 0, 0.08); margin: 0.5rem 0 1rem; }
.help-body table { width: 100%; margin-bottom: 1rem; }
.help-body th, .help-body td { padding: 0.35rem 0.6rem; border-bottom: 1px solid var(--bs-border-color); vertical-align: top; }
.help-body .admonition { border-left: 4px solid var(--bs-info); background: var(--bs-light); padding: 0.75rem 1rem; margin: 1rem 0; border-radius: 0.25rem; }
.help-body .admonition.warning { border-left-color: var(--bs-warning); }
.help-body .admonition-title { font-weight: 600; margin-bottom: 0.25rem; }
.help-body .admonition p:last-child { margin-bottom: 0; }

/* Signup honeypot (sim_app/_honeypot.html): off-screen, not display:none, which
   naive bots skip. The wrapper is also inert, which keeps autofill out. */
.ba-hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
