/* Inventory page - B60 OS. Tokens only (--ds-*). */

.inventory-page {
    padding: 0;
}

/*
 * The tab strip used to sit inside a full-width .ds-card of its own. Measured
 * at 1520x730: that card ran from y=102 to y=222 -- 120px of the 730px screen
 * spent on a 46px control and two rules of empty white either side of it. The
 * strip is already a self-contained pill group (.ds-tabs draws its own inset
 * surface), so the card was a box around a box. Without it the same strip
 * costs 62px and Stock Overview shows two more rows of stock.
 */
.inventory-tabs {
    align-self: flex-start;
    flex: 0 0 auto;
}

/*
 * The page is spaced twice. .ds-page-stack is a column flex with a 16px gap,
 * and components.css adds `margin-top: var(--space-6)` to every sibling under
 * .inventory-page for the document rhythm it was written for. Measured: 40px
 * between the tab strip and the tab body where the stack asks for 16. The gap
 * is the one that belongs to this layout, so the margin stands down -- worth
 * half a row of stock on a 730px screen.
 */
.page-content .inventory-page.ds-page-stack > * + * {
    margin-top: 0;
}

/*
 * auto-FIT, not auto-fill. Measured at 1520x730: the row is 1394px wide, which
 * auto-fill divides into six 219px tracks whether or not there are six cards.
 * Overview has four and History has three, so the cards stopped at x=1018 and
 * x=786 with 376px and 608px of empty grid to their right -- a stat row that
 * quits two-thirds of the way across the page. auto-fit collapses the empty
 * tracks so the cards there actually stretch to the full width.
 */
.inventory-stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--ds-space-4);
    margin-block-end: var(--ds-space-4);
}

/*
 * And the figure scales instead of clipping. Measured on the same screen:
 * "1,862,200.00 USD" needs 247px and the value box is 185px, so Inventory
 * Value and Stock IN value both read "1,862,200.00 US" -- the card's entire
 * reason for existing, cut mid-word. Same fix the Accounting stat row got.
 */
.inventory-stat-grid .ds-stat-card { min-width: 0; }

.inventory-stat-grid .ds-stat-card-value {
    font-size: clamp(1rem, 1.7vw, var(--ds-text-2xl));
    display: block;
    min-width: 0;
    overflow-wrap: anywhere;
}

.inventory-stat-grid .ds-stat-card-top {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: var(--ds-space-3);
}

.inventory-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--ds-space-3);
    min-height: 40px;
}

.inventory-toolbar .page-search {
    flex: 1 1 220px;
    min-width: 180px;
    position: relative;
}

.inventory-toolbar .page-search svg {
    position: absolute;
    inset-inline-start: var(--ds-space-3);
    top: 50%;
    transform: translateY(-50%);
    width: 16px;
    height: 16px;
    color: var(--ds-text-tertiary);
    pointer-events: none;
}

.inventory-toolbar .page-search .ds-input {
    width: 100%;
    min-height: 40px;
    height: 40px;
    padding-inline-start: calc(var(--ds-space-3) + 20px);
}

.inventory-toolbar .ds-select,
.inventory-toolbar .ds-btn {
    width: auto;
    min-height: 40px;
    height: 40px;
    min-width: 140px;
    flex: 0 1 auto;
}

.inventory-toolbar .ds-btn {
    min-width: 0;
}

@media (max-width: 900px) {
    .inventory-toolbar .ds-select,
    .inventory-toolbar .ds-btn,
    .inventory-toolbar .page-search {
        flex: 1 1 100%;
        width: 100%;
        max-width: none;
        min-width: 0;
    }
}

.inventory-toolbar .ds-select,
.inventory-toolbar .ds-btn {
    min-height: 44px;
}

.inventory-thumb-well {
    width: 40px;
    height: 40px;
    margin-inline: auto;
    border-radius: var(--ds-radius-md);
    background: var(--ds-surface-alt);
    box-shadow: inset 0 0 0 1px var(--ds-border);
    display: flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}

.inventory-thumb-well img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.inventory-thumb-fallback {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 100%;
    font-size: var(--ds-text-xs);
    font-weight: var(--ds-fw-semibold);
    color: var(--ds-text-secondary);
}

/*
 * Stock Overview and Movement History scroll with the page.
 *
 * They used to scroll inside the table. Measured at 1520x730: the card sat at
 * x=96..1492 and the table's own scrollbar landed at x=1470 -- seventeen
 * pixels inside the card, with white either side of it and the thumb starting
 * level with the column headings. A short bar floating in the middle of the
 * layout, pointing at nothing, while the window's own scrollbar stayed empty
 * because the page could not scroll at all.
 *
 * So the whole height chain is released for these two tabs: the stack, the
 * tab body, the list card and the table wrap all take their natural height,
 * .page-content gets a scroll range, and the one scrollbar is the window's.
 * The column headings still stay put -- thead is sticky, and sticky needs
 * every ancestor up to the scroller to have visible overflow, which is why
 * the card's clip is lifted here too.
 *
 * Receive, Adjust and Recipes keep the opposite treatment (fill the height,
 * scroll their own middles): they are panels with a pinned action, not lists.
 */
.page-content > .inventory-page:has(> #invTabBody.is-list),
.page-content > .inventory-page:has(> #invTabBody > .ds-list-card) {
    flex: 0 0 auto;
}

.inventory-page > #invTabBody.is-list > .ds-list-card,
.inventory-page > #invTabBody > .ds-list-card {
    flex: 0 0 auto;
    overflow: visible;
}

/* Specific enough to beat `.ds-list-card > .inventory-table-wrap`, which is
   what makes the table its own scrollport for the other list pages. */
.inventory-page > #invTabBody > .ds-list-card > .inventory-table-wrap {
    flex: 0 0 auto;
    min-height: 0;
    overflow: visible;
}

/* On a phone the table is wider than the screen and there is no room to be
   precious about sticky headings: give the wrap its horizontal scroll back. */
@media (max-width: 768px) {
    .inventory-page > #invTabBody > .ds-list-card > .inventory-table-wrap {
        overflow-x: auto;
    }
}

/* The page scrolls and the column headings stay. Stock Overview lists every
   product now, so without this there is nothing on screen by the sixth row
   saying which number is stock, which is unit cost and which is value --
   three columns of bare figures. Movement History is worse, being all numbers
   and dates.

   A background is not decoration here: without one the rows show straight
   through a sticky header.

   The negative offset matches .page-content's 10px top padding. Content
   scrolls through a scrollport's padding box, so at top:0 the heading parks
   10px down and rows flash past in the strip above it. Pulled up by the same
   amount, the heading sits flush against the top of the scrollport and there
   is no strip. */
.inventory-table-wrap .ds-table thead th {
    position: sticky;
    top: -10px;
    z-index: 1;
    background: var(--ds-surface-alt);
}

.inventory-table-wrap .ds-table tbody tr {
    height: 56px;
}

.inventory-table-wrap .ds-table {
    width: 100%;
    margin: 0;
}

.inventory-table-wrap .ds-table .num {
    text-align: end;
    font-variant-numeric: tabular-nums;
}

.inventory-table-wrap .ds-table tr.is-low td:first-child {
    box-shadow: inset 3px 0 0 var(--ds-warning);
}

.inventory-table-wrap .ds-table tr.is-out td:first-child {
    box-shadow: inset 3px 0 0 var(--ds-danger);
}

.inventory-table-wrap .ds-table tr.is-low td,
.inventory-table-wrap .ds-table tr.is-out td {
    background: transparent;
}

.inventory-stock-qty {
    font-size: var(--ds-text-lg);
    font-weight: var(--ds-fw-bold);
    font-variant-numeric: tabular-nums;
}

.inventory-stock-qty.is-low {
    color: var(--ds-warning);
}

.inventory-stock-qty.is-out {
    color: var(--ds-danger);
}

.inventory-stock-qty.is-ok {
    color: var(--ds-success);
}

/*
 * Receive is two panels that must both end at the bottom of the screen.
 *
 * They used to be `align-items: start` blocks of natural height inside a tab
 * body that is `overflow: hidden`. Measured at 1520x730: the sidebar came out
 * 772px tall in a 638px content column, so its last 264px -- Vendor, Payment
 * Method, Notes, the totals and the "Record Purchase" button -- were clipped
 * off the bottom of the screen. Nothing scrolled to reach them: the clip meant
 * .page-content never grew a scroll range either, so on the actual till a
 * delivery could be picked but not recorded.
 *
 * Now each panel is a column that fills the available height and scrolls its
 * own middle, with the action pinned where it can always be reached.
 */
.inventory-receive-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 460px;
    gap: var(--ds-space-5);
    align-items: stretch;
    flex: 1;
    min-height: 0;
}

.inventory-receive-layout > .ds-card {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

@media (max-width: 960px) {
    .inventory-receive-layout {
        grid-template-columns: 1fr;
    }
}

.inventory-product-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: var(--ds-space-2);
    align-content: start;
    flex: 1;
    min-height: 0;
    overflow-y: auto;
}

.inventory-picker-card {
    border: 2px solid var(--ds-border);
    cursor: pointer;
    text-align: start;
    padding: var(--ds-space-2);
    background: var(--ds-surface);
    border-radius: var(--ds-radius-md);
    transition: border-color var(--ds-motion-hover) var(--ds-ease-standard);
}

.inventory-picker-card.is-in-cart {
    border-color: var(--ds-primary);
    background: var(--ds-primary-tint);
}

/* `position: sticky` was decoration on a panel taller than the viewport it was
   sticking inside -- it never had anywhere to stick to. The panel now sizes
   itself to the screen instead, so there is nothing to pin. */
.inventory-receive-sidebar {
    position: static;
}

/* The middle of the sidebar -- picked lines and the purchase fields -- is the
   part that grows with the delivery, so it is the part that scrolls.

   min-height is the floor that keeps this honest. Without it, a short window
   shrinks this region toward zero (measured: 0px at a 502px viewport) and the
   lines you are checking become unreachable inside a panel that still looks
   fine. With it, the panel outgrows the tab body instead -- and the tab body
   scrolls, so everything stays reachable by the one gesture. */
.inventory-receive-scroll {
    flex: 1 1 auto;
    min-height: 96px;
    overflow-y: auto;
    display: grid;
    gap: var(--ds-space-3);
    align-content: start;
    padding-inline-end: var(--ds-space-1);
}

/* Totals and the button that commits the delivery never scroll away: pinned
   to the foot of the panel when it fits, and stuck to the bottom of the
   scroll viewport when it does not. */
.inventory-receive-footer {
    position: sticky;
    bottom: 0;
    z-index: 1;
    flex: 0 0 auto;
    display: grid;
    gap: var(--ds-space-3);
    padding-block-start: var(--ds-space-3);
    margin-block-start: var(--ds-space-3);
    border-block-start: 1px solid var(--ds-border);
    background: var(--ds-surface);
}

.inventory-receive-fields {
    display: grid;
    gap: var(--ds-space-3);
    padding-block-start: var(--ds-space-3);
    border-block-start: 1px solid var(--ds-border);
}

.inventory-mode-toggle {
    display: flex;
    gap: var(--ds-space-2);
    margin-block-end: var(--ds-space-4);
    padding: 3px;
    background: var(--ds-bg-inset);
    border-radius: var(--ds-radius-md);
}

.inventory-mode-toggle .ds-btn {
    flex: 1;
}

/* Two rows of label-over-figure cost 70px of a 518px panel; one row of
   label-beside-figure costs 44px, and the total is still the biggest thing
   in the footer. The 26px goes to the list of what is being received. */
.inventory-receive-totals {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--ds-space-3);
    padding: var(--ds-space-2) var(--ds-space-3);
    background: var(--ds-bg-inset);
    border-radius: var(--ds-radius-md);
}

.inventory-receive-totals > div {
    display: flex;
    align-items: baseline;
    gap: var(--ds-space-2);
    min-width: 0;
}

/*
 * The initials badge that used to open each line was 32px of a 428px panel
 * spent repeating the name printed beside it -- and it pushed "= 900.00 USD"
 * onto a third row, so four picked items filled the list twice over. Name and
 * its numbers, nothing else.
 */
.inventory-receive-line {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    gap: var(--ds-space-2);
    padding: var(--ds-space-2);
    border-block-end: 1px solid var(--ds-border);
    align-items: center;
}

/*
 * Adjust was a 640px form centred in 1394px of empty page, with the product's
 * current figures squeezed into a three-across strip inside the form and the
 * Apply button at the bottom of it. The width was doing no work and the
 * numbers you are correcting against were the smallest thing on screen.
 *
 * Same shape as Receive now: what you fill in on the left, what it will do on
 * the right, and the button that commits it beside the numbers it changes.
 */
.inventory-adjust-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    gap: var(--ds-space-5);
    align-items: start;
    max-width: 1040px;
    margin-inline: auto;
    width: 100%;
}

@media (max-width: 900px) {
    .inventory-adjust-layout {
        grid-template-columns: 1fr;
    }
}

.inventory-adjust-summary {
    display: grid;
    gap: var(--ds-space-4);
    align-content: start;
}

/* before -> after, at the size of a figure you are about to commit */
.inventory-adjust-preview {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    gap: var(--ds-space-3);
    padding: var(--ds-space-4);
    background: var(--ds-bg-inset);
    border-radius: var(--ds-radius-md);
    text-align: center;
}

.inventory-adjust-preview-arrow {
    color: var(--ds-text-tertiary);
    font-size: var(--ds-text-lg);
}

.inventory-adjust-preview-new {
    color: var(--ds-primary);
}

.inventory-adjust-preview-new.is-down {
    color: var(--ds-danger);
}

.inventory-adjust-facts {
    display: grid;
    gap: var(--ds-space-2);
    padding: var(--ds-space-3) var(--ds-space-4);
    background: var(--ds-bg-inset);
    border-radius: var(--ds-radius-md);
}

.inventory-adjust-fact {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--ds-space-3);
    min-width: 0;
}

.inventory-adjust-fact > .ds-tabular {
    font-weight: var(--ds-fw-semibold);
    text-align: end;
}

/* Still used by Receive's picked-line totals. */
.inventory-adjust-stats {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--ds-space-3);
    text-align: center;
    padding: var(--ds-space-4);
    background: var(--ds-bg-inset);
    border-radius: var(--ds-radius-md);
}

.inventory-adjust-stats-value {
    font-size: var(--ds-text-2xl);
    font-weight: var(--ds-fw-bold);
    font-variant-numeric: tabular-nums;
}

/*
 * The movement type filter used to be a second full-width .ds-card stacked
 * under the stat row, so Movement History spent 64px on a card holding five
 * pills and another 16px on the gap below it. With the tab strip's own card
 * above that, 300px of a 730px screen was gone before the first movement --
 * three rows visible out of 31. The pills belong in the table's own head row,
 * next to the count they filter.
 */
.inventory-history-filters {
    flex-wrap: wrap;
    gap: var(--ds-space-3);
}

.inventory-history-filters .ds-tabs {
    flex-wrap: wrap;
}

.inventory-cat-chips {
    display: flex;
    gap: var(--ds-space-2);
    flex-wrap: wrap;
    margin-block-end: var(--ds-space-4);
}

.inventory-info-banner {
    font-size: var(--ds-text-xs);
    color: var(--ds-text-secondary);
    background: var(--ds-bg-inset);
    padding: var(--ds-space-2) var(--ds-space-3);
    border-radius: var(--ds-radius-md);
    margin-block-end: var(--ds-space-4);
}

/* Count of Made-to-Order products deliberately left out of the stock table
   (next-up.md #40), so their absence reads as a decision, not a bug. */
.inventory-made-note {
    font-size: var(--ds-text-xs);
    color: var(--ds-text-tertiary);
    margin-inline-start: var(--ds-space-3);
}
