/* ==========================================================================
   MDU Warehouse Inventory System — design system
   MDU Printing Machine and Supplies

   Layered on top of Bootstrap 5. Everything here is either a brand token or a
   component Bootstrap does not ship. No utility classes are redefined.
   ========================================================================== */

:root {
    /*
     | Brand
     |
     | Both values are sampled straight from the MDU Printing logo artwork, so
     | the interface and the mark are literally the same colour rather than an
     | approximation of it. The tints below are that crimson mixed with white —
     | 7% for surfaces, 25% for borders — which is what keeps the whole palette
     | reading as one colour instead of several reds that nearly match.
     |
     | White on the crimson measures 7.4:1, comfortably past WCAG AA and into
     | AAA, so sidebar labels and button text are properly legible.
     */
    --mdu-red: #A71C21;         /* logo crimson */
    --mdu-red-hover: #8B171B;
    --mdu-red-light: #FAEEEF;
    --mdu-red-accent: #E9C6C7;
    --mdu-red-deep: #6B1216;    /* gradient anchor */

    /* The logo's second colour. Available for anything that should read as
       brand without competing with the crimson. */
    --mdu-charcoal: #3E3E40;

    /* Surfaces ---------------------------------------------------------- */
    --mdu-bg: #F8F9FA;
    --mdu-card: #FFFFFF;
    --mdu-border: #E5E7EB;

    /* Type -------------------------------------------------------------- */
    --mdu-text: #212121;
    --mdu-text-muted: #616161;

    /* Semantic ---------------------------------------------------------- */
    --mdu-success: #4CAF50;
    --mdu-warning: #FB8C00;
    --mdu-danger: #F44336;

    /* The danger red's own tint pair, mirroring red-light/red-hover for the
       crimson. Destructive controls tint in these rather than the brand
       colour, so "removes something" never reads as "is selected". The deep
       shade is the one that stays readable on the tint (5.5:1). */
    --mdu-danger-light: #FDECEA;
    --mdu-danger-deep: #C62828;

    /* Geometry ---------------------------------------------------------- */
    --mdu-radius: 12px;
    --mdu-radius-sm: 8px;
    --mdu-shadow: 0 1px 2px rgba(16, 24, 40, .04), 0 4px 16px rgba(16, 24, 40, .06);
    --mdu-shadow-lg: 0 8px 28px rgba(16, 24, 40, .12);
    --mdu-sidebar-width: 268px;
    --mdu-sidebar-rail: 72px;   /* width when collapsed to icons */
    --mdu-topbar-height: 68px;

    --mdu-transition: 160ms cubic-bezier(.4, 0, .2, 1);

    /* Bootstrap overrides ------------------------------------------------ */
    --bs-primary: var(--mdu-red);
    --bs-primary-rgb: 167, 28, 33;
    --bs-link-color: var(--mdu-red);
    --bs-link-hover-color: var(--mdu-red-hover);
    --bs-body-bg: var(--mdu-bg);
    --bs-body-color: var(--mdu-text);
    --bs-border-color: var(--mdu-border);
    --bs-focus-ring-color: rgba(167, 28, 33, .22);
}

/* ==========================================================================
   Base
   ========================================================================== */

html {
    -webkit-text-size-adjust: 100%;
}

body {
    background-color: var(--mdu-bg);
    color: var(--mdu-text);
    font-family: "Inter", "Segoe UI", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif;
    font-size: .9375rem;
    line-height: 1.55;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4, h5, h6 {
    color: var(--mdu-text);
    font-weight: 650;
    letter-spacing: -.011em;
}

.text-muted-2 {
    color: var(--mdu-text-muted) !important;
}

.fw-600 {
    font-weight: 600;
}

.fw-650 {
    font-weight: 650;
}

.min-w-0 {
    min-width: 0;
}

.tabular {
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
}

a {
    text-decoration: none;
}

a:hover {
    text-decoration: none;
}

::selection {
    background: var(--mdu-red-accent);
    color: var(--mdu-text);
}

:focus-visible {
    outline: 2px solid var(--mdu-red);
    outline-offset: 2px;
}

/* ==========================================================================
   Scrollbars

   The default OS scrollbar is a grey slab that sits badly on the crimson
   sidebar. These tint it to whatever surface it is on: the track disappears
   entirely, and the thumb is the surface colour lightened — so it reads as part
   of the panel rather than a widget bolted onto it.

   Deliberately not invisible. A thumb you cannot find is worse than an ugly
   one: it is the only cue that there is more content below, and it has to stay
   grabbable. `thin` rather than `none`, and the thumb keeps clear contrast
   against its track in both themes below.

   Two mechanisms on purpose. scrollbar-color/-width is the standard and is what
   Firefox and current Chrome honour; ::-webkit-scrollbar covers older WebKit,
   which ignores the standard properties. Browsers that support neither fall
   back to the OS scrollbar, which still works.
   ========================================================================== */

/* --- Light surfaces: the page, tables, panels ---------------------------- */

* {
    scrollbar-width: thin;
    scrollbar-color: rgba(16, 24, 40, .22) transparent;
}

/*
 * background: transparent is load-bearing on all four of these. Styling only
 * the thumb leaves the container, the track, the track-piece and — on Windows —
 * the arrow buttons painting their default near-white, which is the pale
 * channel that shows down the side of a coloured panel.
 */
*::-webkit-scrollbar {
    width: 10px;
    height: 10px;
    background: transparent;
}

*::-webkit-scrollbar-track,
*::-webkit-scrollbar-track-piece {
    background: transparent;
    border: 0;
    box-shadow: none;
}

/*
 * The arrow buttons only exist on Windows, are a solid pale block at each end,
 * and cannot be made to blend — there is no way to tint their glyph. Removing
 * them matches every overlay scrollbar (macOS, iOS, Android, Chrome's own
 * overlay mode), and the thumb still shows position and stays draggable.
 */
*::-webkit-scrollbar-button {
    display: none;
    width: 0;
    height: 0;
}

*::-webkit-scrollbar-thumb {
    background-color: rgba(16, 24, 40, .22);
    border-radius: 999px;

    /* A transparent border inset by background-clip leaves the thumb looking
       slim while the scrollbar keeps a comfortable 10px hit area. */
    border: 3px solid transparent;
    background-clip: content-box;
    transition: background-color var(--mdu-transition);
}

*::-webkit-scrollbar-thumb:hover {
    background-color: rgba(16, 24, 40, .38);
}

*::-webkit-scrollbar-corner {
    background: transparent;
}

/* --- The crimson sidebar --------------------------------------------------
   White at 38% over #A71C21 lands around rgb(200, 114, 117) — the same colour
   family as the panel, several shades lighter, so it tints rather than
   interrupts.

   38% rather than something fainter because this sidebar only scrolls on short
   screens: the scrollbar is not always there, so nobody is looking for it, and
   a bar you have to hunt for fails the one job it has. Hover lifts it to 58% so
   grabbing it gives feedback. */

.sidebar,
.sidebar__nav {
    scrollbar-color: rgba(255, 255, 255, .38) transparent;
}

.sidebar ::-webkit-scrollbar-thumb,
.sidebar__nav::-webkit-scrollbar-thumb {
    background-color: rgba(255, 255, 255, .38);
}

.sidebar ::-webkit-scrollbar-thumb:hover,
.sidebar__nav::-webkit-scrollbar-thumb:hover {
    background-color: rgba(255, 255, 255, .58);
}

/* Same reasoning on the login panel, which shares the crimson. */
.auth-aside {
    scrollbar-color: rgba(255, 255, 255, .38) transparent;
}

/* ==========================================================================
   App shell
   ========================================================================== */

.app-shell {
    min-height: 100vh;
}

/* --- Sidebar -------------------------------------------------------------- */

.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    width: var(--mdu-sidebar-width);
    background: linear-gradient(178deg, var(--mdu-red) 0%, var(--mdu-red-hover) 100%);
    color: #fff;
    display: flex;
    flex-direction: column;
    z-index: 1045;
    transition: transform var(--mdu-transition);
    box-shadow: 2px 0 18px rgba(16, 24, 40, .08);
}

.sidebar__brand {
    display: flex;
    align-items: center;
    gap: .75rem;
    height: var(--mdu-topbar-height);
    padding: 0 1.25rem;
    border-bottom: 1px solid rgba(255, 255, 255, .16);
    flex-shrink: 0;
}

/* The logo doubles as the collapse control. Keeping it as the single toggle —
   rather than adding a separate chevron to the header — means the rail has no
   extra chrome to make room for when it is only 72px wide. */
.sidebar__brand-toggle {
    position: relative;
    width: 38px;
    height: 38px;
    padding: 0;
    border: 0;
    background: transparent;
    border-radius: 10px;
    flex-shrink: 0;
    cursor: pointer;
    transition: transform var(--mdu-transition);
}

.sidebar__brand-toggle:hover {
    transform: scale(1.05);
}

.sidebar__brand-toggle:active {
    transform: scale(.97);
}

/* The mark is crimson-on-transparent, so on the crimson sidebar it needs a
   white plate to sit on — otherwise half the logo vanishes into the panel. */
.sidebar__logo {
    width: 38px;
    height: 38px;
    border-radius: 10px;
    background: #fff;
    display: grid;
    place-items: center;
    padding: 6px;
    flex-shrink: 0;
    box-shadow: 0 1px 3px rgba(16, 24, 40, .18);
}

.sidebar__logo img {
    width: 100%;
    height: 100%;
    display: block;
}

/* Sits on top of the logo and fades in on hover, so the control is discovered
   exactly where the eye already is. */
.sidebar__brand-reveal {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    border-radius: 10px;
    background: #fff;
    color: var(--mdu-red);
    font-size: 1.0625rem;
    opacity: 0;
    transition: opacity var(--mdu-transition);
    box-shadow: 0 1px 3px rgba(16, 24, 40, .18);
}

.sidebar__brand-toggle:hover .sidebar__brand-reveal,
.sidebar__brand-toggle:focus-visible .sidebar__brand-reveal {
    opacity: 1;
}

/* Points left to collapse; the collapsed state below flips it to point right.
   display:block is load-bearing — transforms are ignored on inline elements,
   and Bootstrap Icons renders <i> inline, so without this the chevron would
   quietly never rotate. */
.sidebar__brand-reveal i {
    display: block;
    transform: rotate(180deg);
    transition: transform var(--mdu-transition);
}

.sidebar__brand-text {
    min-width: 0;
    line-height: 1.15;
}

.sidebar__brand-name {
    font-weight: 700;
    font-size: .9375rem;
    color: #fff;
}

.sidebar__brand-sub {
    font-size: .6875rem;
    color: rgba(255, 255, 255, .75);
    text-transform: uppercase;
    letter-spacing: .06em;
}

.sidebar__nav {
    flex: 1 1 auto;
    overflow-y: auto;
    padding: 1rem .75rem 1.5rem;
}

.sidebar__section {
    font-size: .6875rem;
    text-transform: uppercase;
    letter-spacing: .08em;
    color: rgba(255, 255, 255, .6);
    padding: .875rem .75rem .375rem;
    font-weight: 600;
}

.sidebar__link {
    display: flex;
    align-items: center;
    gap: .75rem;
    padding: .625rem .75rem;
    margin-bottom: .125rem;
    border-radius: var(--mdu-radius-sm);
    color: rgba(255, 255, 255, .88);
    font-weight: 500;
    border-left: 3px solid transparent;
    transition: background-color var(--mdu-transition), color var(--mdu-transition),
                border-color var(--mdu-transition), transform var(--mdu-transition);
}

.sidebar__link i {
    font-size: 1.0625rem;
    width: 1.25rem;
    text-align: center;
    flex-shrink: 0;
}

.sidebar__link:hover {
    background-color: rgba(255, 255, 255, .12);
    color: #fff;
    transform: translateX(2px);
}

.sidebar__link.is-active {
    background-color: var(--mdu-red-light);
    color: var(--mdu-red-hover);
    border-left-color: #fff;
    font-weight: 650;
    box-shadow: 0 1px 6px rgba(16, 24, 40, .12);
}

.sidebar__link.is-active:hover {
    transform: none;
    background-color: var(--mdu-red-light);
}

.sidebar__badge {
    margin-left: auto;
    background: rgba(255, 255, 255, .22);
    color: #fff;
    font-size: .6875rem;
    font-weight: 700;
    padding: .0625rem .4375rem;
    border-radius: 999px;
    line-height: 1.5;
}

.sidebar__link.is-active .sidebar__badge {
    background: var(--mdu-red);
    color: #fff;
}

.sidebar__backdrop {
    display: none;
    position: fixed;
    inset: 0;
    background: rgba(16, 24, 40, .45);
    z-index: 1040;
}

.sidebar__backdrop.is-visible {
    display: block;
}

/* --- Sidebar: collapsed rail ----------------------------------------------
   Desktop only. Below 992px the sidebar is already a slide-over drawer, and a
   drawer that opens at 72px wide would be useless — so none of this applies
   there.

   Everything keys off --mdu-sidebar-width, which .app-main also uses for its
   left margin, so redefining that one variable moves the sidebar and the page
   content together.

   The class lives on <html> rather than the sidebar, because it is set by an
   inline script before first paint to stop a collapsed rail flashing open on
   every page load. This is a server-rendered app: without that, every single
   navigation would show the expand-then-collapse jump. */

@media (min-width: 992px) {

    .sidebar-collapsed {
        --mdu-sidebar-width: var(--mdu-sidebar-rail);
    }

    .sidebar-collapsed .sidebar {
        transition: width 220ms cubic-bezier(.4, 0, .2, 1);
    }

    /* --- Brand row --- */

    .sidebar-collapsed .sidebar__brand {
        padding: 0;
        justify-content: center;
    }

    .sidebar-collapsed .sidebar__brand-text {
        display: none;
    }

    .sidebar-collapsed .sidebar__brand-reveal i {
        transform: none;   /* point right — this expands */
    }

    /* --- Links become icons --- */

    .sidebar-collapsed .sidebar__nav {
        padding: 1rem .75rem 1.5rem;

        /* Tooltips escape the sidebar, so this cannot clip. The nav is short
           enough (at most nine items) that losing scroll is not a trade. */
        overflow: visible;
    }

    .sidebar-collapsed .sidebar__link {
        position: relative;
        justify-content: center;
        padding: .6875rem 0;
        gap: 0;
    }

    /*
     * Clipped rather than display:none, so the label stays in the accessibility
     * tree. A screen reader still announces "Dashboard"; only sighted users
     * lose the text, and they get the tooltip instead.
     */
    .sidebar-collapsed .sidebar__link > span {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border: 0;
    }

    .sidebar-collapsed .sidebar__link:hover {
        transform: none;   /* no nudge — there is nowhere to nudge to */
    }

    /* --- Tooltip --- */

    .sidebar-collapsed .sidebar__link::after {
        content: attr(data-label);
        position: absolute;
        left: calc(100% + 12px);
        top: 50%;
        transform: translateY(-50%) translateX(-4px);
        z-index: 1060;
        background: var(--mdu-charcoal);
        color: #fff;
        font-size: .75rem;
        font-weight: 600;
        letter-spacing: .01em;
        padding: .3125rem .5625rem;
        border-radius: 6px;
        white-space: nowrap;
        pointer-events: none;
        opacity: 0;
        box-shadow: var(--mdu-shadow-lg);
        transition: opacity var(--mdu-transition), transform var(--mdu-transition);
    }

    .sidebar-collapsed .sidebar__link:hover::after,
    .sidebar-collapsed .sidebar__link:focus-visible::after {
        opacity: 1;
        transform: translateY(-50%) translateX(0);
    }

    /* --- Section headings become dividers --- */

    .sidebar-collapsed .sidebar__section {
        font-size: 0;              /* hidden visually, still read aloud */
        padding: .875rem .5rem .625rem;
    }

    .sidebar-collapsed .sidebar__section::before {
        content: "";
        display: block;
        height: 1px;
        background: rgba(255, 255, 255, .2);
    }

}

/* The drawer is opened by the topbar hamburger on small screens, so the logo
   is just a logo there. */
@media (max-width: 991.98px) {
    .sidebar__brand-toggle {
        pointer-events: none;
        cursor: default;
    }

    .sidebar__brand-reveal {
        display: none;
    }
}

/* --- Main column ---------------------------------------------------------- */

.app-main {
    margin-left: var(--mdu-sidebar-width);
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}

.topbar {
    position: sticky;
    top: 0;
    z-index: 1030;
    height: var(--mdu-topbar-height);
    background: rgba(255, 255, 255, .88);
    backdrop-filter: saturate(180%) blur(10px);
    border-bottom: 1px solid var(--mdu-border);
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0 1.5rem;
}

.topbar__title {
    font-size: 1.0625rem;
    font-weight: 650;
    margin: 0;
    line-height: 1.2;
}

.topbar__subtitle {
    font-size: .75rem;
    color: var(--mdu-text-muted);
}

.topbar__meta {
    display: flex;
    align-items: center;
    gap: .5rem;
    font-size: .8125rem;
    color: var(--mdu-text-muted);
    padding: .375rem .75rem;
    border-radius: 999px;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
    white-space: nowrap;
}

.topbar__toggle {
    display: none;
    border: 1px solid var(--mdu-border);
    background: #fff;
    border-radius: var(--mdu-radius-sm);
    width: 40px;
    height: 40px;
    color: var(--mdu-text);
    font-size: 1.125rem;
}

.app-content {
    flex: 1 1 auto;
    padding: 1.75rem 1.5rem 3rem;
}

/* --- User dropdown -------------------------------------------------------- */

.user-menu {
    display: flex;
    align-items: center;
    gap: .625rem;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    padding: .25rem .625rem .25rem .25rem;
    transition: background-color var(--mdu-transition), border-color var(--mdu-transition);
}

.user-menu:hover,
.user-menu[aria-expanded="true"] {
    background: var(--mdu-red-light);
    border-color: var(--mdu-red-accent);
}

.avatar {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    background: var(--mdu-red);
    color: #fff;
    display: grid;
    place-items: center;
    font-weight: 700;
    font-size: .8125rem;
    flex-shrink: 0;
}

.user-menu__name {
    font-size: .8125rem;
    font-weight: 600;
    line-height: 1.15;
    text-align: left;
}

.user-menu__role {
    font-size: .6875rem;
    color: var(--mdu-text-muted);
    line-height: 1.15;
}

.dropdown-menu {
    /*
     * Bootstrap compiled its hover and active colours into these variables
     * as literals — grey hover, #0d6efd active — so the --bs-primary
     * override in :root never reaches them. Re-pointed at the palette:
     * hover is a brand-tinted pill, pressed is the full crimson.
     */
    --bs-dropdown-link-hover-color: var(--mdu-red-hover);
    --bs-dropdown-link-hover-bg: var(--mdu-red-light);
    --bs-dropdown-link-active-color: #fff;
    --bs-dropdown-link-active-bg: var(--mdu-red);

    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius);
    box-shadow: var(--mdu-shadow-lg);
    padding: .375rem;
    font-size: .875rem;
}

.dropdown-item {
    border-radius: var(--mdu-radius-sm);
    padding: .5rem .75rem;
    display: flex;
    align-items: center;
    gap: .625rem;
    transition: background-color var(--mdu-transition), color var(--mdu-transition);
}

/*
 * Destructive entries — sign out is the resident example — tint in the
 * warning red rather than the brand crimson, so "leaves or removes
 * something" reads differently from "is selected". The !important matches
 * the one Bootstrap puts on .text-danger itself.
 */
.dropdown-item.text-danger:hover,
.dropdown-item.text-danger:focus {
    background-color: var(--mdu-danger-light);
    color: var(--mdu-danger-deep) !important;
}

.dropdown-item.text-danger:active {
    background-color: var(--mdu-danger);
    color: #fff !important;
}

/* ==========================================================================
   Cards
   ========================================================================== */

.card {
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius);
    box-shadow: var(--mdu-shadow);
}

.card-header {
    background: transparent;
    border-bottom: 1px solid var(--mdu-border);
    padding: 1rem 1.25rem;
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

.card-header h2,
.card-header h3 {
    font-size: .9375rem;
    font-weight: 650;
    margin: 0;
}

.card-header .card-subtitle {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    margin: .125rem 0 0;
}

.card-body {
    padding: 1.25rem;
}

.card-footer {
    background: transparent;
    border-top: 1px solid var(--mdu-border);
    padding: .875rem 1.25rem;
}

/* --- Stat card ------------------------------------------------------------ */

.stat-card {
    position: relative;
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius);
    box-shadow: var(--mdu-shadow);
    padding: 1.25rem;
    height: 100%;
    overflow: hidden;
    transition: transform var(--mdu-transition), box-shadow var(--mdu-transition);
}

.stat-card::before {
    content: "";
    position: absolute;
    inset: 0 0 auto 0;
    height: 4px;
    background: var(--stat-color, var(--mdu-red));
}

.stat-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--mdu-shadow-lg);
}

/* A card that is also a filter button (the logs page). The link resets its
   own text styling so the card inside looks identical either way. */
.stat-card-link {
    display: block;
    color: inherit;
    text-decoration: none;
}

.stat-card-link:hover {
    color: inherit;
}

.stat-card-link:focus-visible {
    outline: none;
}

.stat-card-link:focus-visible .stat-card {
    box-shadow: 0 0 0 3.5px rgba(167, 28, 33, .14), var(--mdu-shadow);
}

/* The applied filter wears a ring in its own accent — each card already
   carries its colour as --stat-color, so one rule rings all three. */
.stat-card--active {
    box-shadow: 0 0 0 2px var(--stat-color), var(--mdu-shadow);
    border-color: transparent;
}

.stat-card__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: .75rem;
    margin-bottom: .625rem;
}

.stat-card__label {
    font-size: .75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--mdu-text-muted);
}

.stat-card__icon {
    width: 40px;
    height: 40px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    font-size: 1.125rem;
    background: var(--stat-tint, var(--mdu-red-light));
    color: var(--stat-color, var(--mdu-red));
    flex-shrink: 0;
}

.stat-card__value {
    font-size: 1.875rem;
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.stat-card__description {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    margin-top: .25rem;
}

.stat-card__link {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--stat-color, var(--mdu-red));
    margin-top: .625rem;
}

.stat-card__link:hover {
    gap: .4375rem;
}

/* ==========================================================================
   Tables
   ========================================================================== */

.table-card {
    overflow: hidden;
}

.table-scroll {
    max-height: var(--table-max-height, none);
    overflow: auto;
}

.table {
    --bs-table-bg: transparent;
    margin-bottom: 0;
    font-size: .875rem;
}

.table > thead {
    position: sticky;
    top: 0;
    z-index: 2;
}

.table > thead th {
    background: #FAFBFC;
    border-bottom: 1px solid var(--mdu-border);
    color: var(--mdu-text-muted);
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    padding: .75rem 1rem;
    white-space: nowrap;
}

.table > tbody td {
    padding: .8125rem 1rem;
    border-bottom: 1px solid var(--mdu-border);
    vertical-align: middle;
}

/*
 * Dashboard tables. They are read at a glance, not worked in, so rows pack
 * tighter and more of the morning fits above the fold.
 */
.table--tight > thead th {
    padding: .5625rem 1rem;
}

.table--tight > tbody td {
    padding: .5rem 1rem;
}

.table > tbody tr:last-child td {
    border-bottom: 0;
}

.table > tbody tr {
    transition: background-color var(--mdu-transition);
}

.table > tbody tr:hover {
    background-color: var(--mdu-red-light);
}

.table-plain > tbody tr:hover {
    background-color: #FAFBFC;
}

/* Sortable column headers */
.th-sort {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    color: inherit;
    white-space: nowrap;
}

.th-sort:hover {
    color: var(--mdu-red);
}

.th-sort i {
    font-size: .75rem;
    opacity: .45;
}

.th-sort.is-sorted {
    color: var(--mdu-red);
}

.th-sort.is-sorted i {
    opacity: 1;
}

/* ==========================================================================
   Product cell
   ========================================================================== */

.product-cell {
    display: flex;
    align-items: center;
    gap: .75rem;
    min-width: 0;
}

.product-thumb {
    width: 44px;
    height: 44px;
    border-radius: var(--mdu-radius-sm);
    object-fit: cover;
    border: 1px solid var(--mdu-border);
    background: var(--mdu-bg);
    flex-shrink: 0;
    transition: transform var(--mdu-transition), box-shadow var(--mdu-transition);
}

.product-thumb--button {
    padding: 0;
    display: block;
    cursor: zoom-in;
}

.product-thumb--button:hover {
    transform: scale(1.06);
    box-shadow: var(--mdu-shadow);
}

.product-thumb--placeholder {
    display: grid;
    place-items: center;
    color: #B0B7C3;
    font-size: 1.125rem;
}

.product-thumb--lg {
    width: 100%;
    height: auto;
    aspect-ratio: 1;
    border-radius: var(--mdu-radius);
}

.product-cell__name {
    font-weight: 600;
    line-height: 1.3;
    overflow: hidden;
    text-overflow: ellipsis;
}

.product-cell__meta {
    font-size: .75rem;
    color: var(--mdu-text-muted);
}

/* --- Variation ------------------------------------------------------------
   Each variation is its own listing with its own stock, so it needs to read as
   a distinct value rather than as a grey afterthought next to the product name.
   Kept neutral on purpose — the red accent belongs to actions, not to data. */

.variation-chip {
    display: inline-block;
    font-size: .75rem;
    font-weight: 650;
    background: #EEF1F5;
    border: 1px solid #DDE2E9;
    border-radius: 6px;
    padding: .125rem .4375rem;
    color: #35404E;
    white-space: nowrap;
}

.variation-chip--none {
    background: transparent;
    border-style: dashed;
    border-color: var(--mdu-border);
    color: #9AA2AD;
    font-weight: 500;
}

/* --- Expandable product rows ---------------------------------------------
   One row per item; its variations live in a nested panel that opens beneath.
   The nested rows are indented and set on a tinted background so it is always
   obvious which item you are inside. */

.row-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 26px;
    height: 26px;
    border-radius: 7px;
    border: 1px solid var(--mdu-border);
    background: #fff;
    color: var(--mdu-text-muted);
    flex-shrink: 0;
    transition: background-color var(--mdu-transition), border-color var(--mdu-transition),
                color var(--mdu-transition), transform var(--mdu-transition);
}

.row-toggle:hover {
    border-color: var(--mdu-red-accent);
    background: var(--mdu-red-light);
    color: var(--mdu-red-hover);
}

.row-toggle i {
    font-size: .875rem;
    transition: transform var(--mdu-transition);
}

.row-toggle[aria-expanded="true"] i {
    transform: rotate(90deg);
}

.variant-panel > td {
    padding: 0 !important;
    background: #FAFBFC;
    border-bottom: 1px solid var(--mdu-border);
}

.variant-table {
    width: 100%;
    margin: 0;
    font-size: .8125rem;
}

.variant-table th {
    font-size: .625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    color: var(--mdu-text-muted);
    padding: .5rem 1rem;
    background: transparent;
    border-bottom: 1px solid var(--mdu-border);
    white-space: nowrap;
}

.variant-table td {
    padding: .625rem 1rem;
    border-bottom: 1px solid #EDF0F3;
    vertical-align: middle;
}

.variant-table tr:last-child td {
    border-bottom: 0;
}

.variant-table tr:hover td {
    background: var(--mdu-red-light);
}

/* The indent that signals "these belong to the row above". */
.variant-table th:first-child,
.variant-table td:first-child {
    padding-left: 3.25rem;
}

/* A remove button that is locked because the row still holds stock. Not
   `disabled` — a dead button explains nothing, and this one still answers when
   clicked. */
.btn-locked {
    background: #fff;
    border: 1px dashed var(--mdu-border);
    color: #A9B0BA;
    cursor: not-allowed;
}

.btn-locked:hover {
    background: var(--mdu-red-light);
    border-color: var(--mdu-red-accent);
    color: var(--mdu-red-hover);
}

/* Draws the eye back to the row that refused, so the explanation is not the
   only thing the operator has to notice. */
@keyframes row-refuse {
    0%, 100% { background-color: transparent; }
    15%, 60% { background-color: var(--mdu-red-light); }
}

.row-refused > td {
    animation: row-refuse 1.2s ease;
}

.variant-count {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--mdu-text-muted);
    white-space: nowrap;
}

/* --- Selected-variation strip (stock movement forms) ---------------------- */

/*
 * Reads back the variation the form is about to move, on one line across the
 * full width of the card. It replaced a tall panel in a side column: the same
 * four facts, none of the space.
 *
 * Hidden until a variation is chosen (mdu.js toggles .d-none), because there
 * is nothing truthful to put in it before then.
 */
.variant-strip {
    display: flex;
    align-items: center;
    gap: .875rem 1.5rem;
    flex-wrap: wrap;
    padding: .875rem 1.125rem;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
}

.variant-strip__identity {
    flex: 1 1 12rem;
    min-width: 0;
}

.variant-strip__product {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    line-height: 1.35;
}

.variant-strip__variation {
    font-size: 1.0625rem;
    font-weight: 700;
    letter-spacing: -.015em;
    line-height: 1.3;
}

.variant-strip__tags {
    display: flex;
    align-items: center;
    gap: .5rem;
    flex-wrap: wrap;
}

.variant-strip__figures {
    display: flex;
    gap: 1.75rem;
    margin-left: auto;
}

.variant-strip__figure {
    display: flex;
    flex-direction: column;
    text-align: right;
}

.variant-strip__value {
    font-size: 1.25rem;
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: -.02em;
}

.variant-strip__label {
    font-size: .6875rem;
    color: var(--mdu-text-muted);
}

/* Nothing is pushed to the right once the strip has stacked. */
@media (max-width: 575.98px) {
    .variant-strip__figures {
        margin-left: 0;
        gap: 1.5rem;
    }

    .variant-strip__figure {
        text-align: left;
    }
}

/* --- Info hint ------------------------------------------------------------ */

/*
 * The "i" in a card header. For orientation copy only — what the screen does,
 * what it commits you to. Anything needed in order to fill in a particular
 * field stays visible next to that field, because help behind an icon is help
 * most people never open.
 *
 * Hover and keyboard focus are handled here; mdu.js adds tap-to-open for touch
 * screens, which have no hover to offer.
 */
.info-hint {
    position: relative;
    display: inline-flex;
    flex: 0 0 auto;
}

.info-hint__trigger {
    display: grid;
    place-items: center;
    width: 30px;
    height: 30px;
    padding: 0;
    border: 0;
    border-radius: 50%;
    background: transparent;
    color: var(--mdu-text-muted);
    font-size: 1rem;
    line-height: 1;
    transition: color var(--mdu-transition), background-color var(--mdu-transition);
}

.info-hint:hover .info-hint__trigger,
.info-hint__trigger:focus-visible,
.info-hint.is-open .info-hint__trigger {
    color: var(--mdu-red);
    background: var(--mdu-red-light);
}

.info-hint__bubble {
    position: absolute;
    top: calc(100% + 10px);
    right: 0;
    z-index: 1070;
    width: 21rem;
    max-width: calc(100vw - 2.5rem);
    padding: .875rem 1rem;
    background: var(--mdu-charcoal);
    color: rgba(255, 255, 255, .88);
    font-size: .8125rem;
    font-weight: 400;
    line-height: 1.5;
    text-align: left;
    border-radius: var(--mdu-radius-sm);
    box-shadow: var(--mdu-shadow-lg);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-4px);
    transition: opacity var(--mdu-transition), transform var(--mdu-transition), visibility var(--mdu-transition);
}

/* Bridges the gap under the icon, so the bubble survives the trip to it. */
.info-hint__bubble::before {
    content: "";
    position: absolute;
    inset: -10px 0 auto 0;
    height: 10px;
}

.info-hint__bubble::after {
    content: "";
    position: absolute;
    top: -4px;
    right: 11px;
    width: 10px;
    height: 10px;
    background: inherit;
    border-radius: 2px;
    transform: rotate(45deg);
}

.info-hint:hover .info-hint__bubble,
.info-hint__trigger:focus-visible + .info-hint__bubble,
.info-hint.is-open .info-hint__bubble {
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transform: translateY(0);
}

/*
 * Escape, for someone who reached the hint by Tab. Focus alone keeps the
 * bubble open, so this has to override the rules above — same specificity,
 * later in the file — until focus or the pointer leaves.
 */
.info-hint.is-dismissed .info-hint__bubble {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transform: translateY(-4px);
}

.info-hint__title {
    display: block;
    color: #fff;
    font-size: .8125rem;
    font-weight: 650;
    margin-bottom: .375rem;
}

.info-hint__bubble p {
    margin: 0 0 .625rem;
}

.info-hint__bubble p:last-child {
    margin-bottom: 0;
}

.sku-chip {
    display: inline-block;
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .75rem;
    font-weight: 600;
    letter-spacing: .01em;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
    border-radius: 6px;
    padding: .125rem .4375rem;
    color: var(--mdu-text-muted);
    white-space: nowrap;
}

/* ==========================================================================
   Badges
   ========================================================================== */

.badge-stock,
.badge-txn,
.badge-status {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .6875rem;
    font-weight: 650;
    padding: .25rem .5625rem;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
    line-height: 1.45;
}

.badge-stock i,
.badge-txn i {
    font-size: .75rem;
}

.badge-stock--in {
    background: #E8F5E9;
    color: #2E7D32;
    border-color: #C8E6C9;
}

.badge-stock--low {
    background: #FFF3E0;
    color: #E65100;
    border-color: #FFE0B2;
}

.badge-stock--out {
    background: var(--mdu-red-light);
    color: #C62828;
    border-color: var(--mdu-red-accent);
}

.badge-txn--in {
    background: #E8F5E9;
    color: #2E7D32;
    border-color: #C8E6C9;
}

.badge-txn--out {
    background: #E3F2FD;
    color: #1565C0;
    border-color: #BBDEFB;
}

.badge-txn--return {
    background: #F3E5F5;
    color: #6A1B9A;
    border-color: #E1BEE7;
}

.badge-status--active {
    background: #E8F5E9;
    color: #2E7D32;
    border-color: #C8E6C9;
}

.badge-status--inactive {
    background: #ECEFF1;
    color: #546E7A;
    border-color: #CFD8DC;
}

/* --- Approval workflow ----------------------------------------------------
   Deliberately neutral: pending is amber because it needs attention, approved
   green, rejected grey rather than red. Red is the brand colour here and is
   reserved for actions — a rejected row is not an error, it is a decision. */

.badge-approval {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .6875rem;
    font-weight: 650;
    padding: .25rem .5625rem;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
    line-height: 1.45;
}

.badge-approval i {
    font-size: .75rem;
}

.badge-approval--draft {
    background: #ECEFF1;
    color: #546E7A;
    border-color: #CFD8DC;
}

/* ==========================================================================
   Category badge

   What kind of item something is. Sits beside the stock and approval badges
   and must stay quieter than both: those two say something is wrong or waiting,
   this only says what the thing is. Hence tinted neutrals rather than the
   semantic palette — enough colour to scan a column by, not enough to read as
   a warning.
   ========================================================================== */

.badge-category {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    padding: .2rem .5rem;
    border-radius: 999px;
    border: 1px solid transparent;
    font-size: .6875rem;
    font-weight: 600;
    letter-spacing: .01em;
    white-space: nowrap;
    line-height: 1.45;
}

.badge-category i {
    font-size: .6875rem;
}

/*
 * Six muted tones, picked from the category's own id rather than configured —
 * these are records the warehouse creates, and nobody is going to choose a
 * colour for each one. Muted on purpose: the column should be scannable, not
 * a rainbow competing with the stock badges beside it.
 */
.badge-category--1 { background: #FFF4E5; color: #8A5200; border-color: #F5DDBA; }
.badge-category--2 { background: #E8F1FB; color: #1B4F8A; border-color: #C6DCF2; }
.badge-category--3 { background: #EDE9F6; color: #4A3A86; border-color: #D6CEEB; }
.badge-category--4 { background: #E7F4EC; color: #1F6B41; border-color: #C4E3D1; }
.badge-category--5 { background: #FCEAF1; color: #8A2454; border-color: #F2CBDC; }
.badge-category--0 { background: #E9F3F5; color: #1F5A66; border-color: #C6E0E6; }

/* A SKU component being typed: uppercase, monospaced, so it reads as a code. */
.sku-code {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    text-transform: uppercase;
    letter-spacing: .02em;
}

/* The letters this category's SKUs begin with. */
.badge-category__abbrev {
    font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    font-size: .625rem;
    font-weight: 700;
    letter-spacing: .02em;
    opacity: .75;
}

/* Products that predate categorisation. Deliberately flat and grey — it is an
   absence, not a category, and should look like one without shouting. */
.badge-category--none {
    background: #F4F5F7;
    color: #8A9099;
    border-color: #E5E7EB;
    font-weight: 500;
}

.badge-approval--pending {
    background: #FFF3E0;
    color: #E65100;
    border-color: #FFE0B2;
}

.badge-approval--approved {
    background: #E8F5E9;
    color: #2E7D32;
    border-color: #C8E6C9;
}

/* Sent back to be fixed — amber like pending, because it is still in flight,
   but outlined so it reads as a different state at a glance. */
.badge-approval--changes {
    background: #FFF8E1;
    color: #B26A00;
    border-color: #FFE082;
}

.badge-approval--rejected {
    background: #F5F5F5;
    color: #5F6368;
    border-color: #E0E0E0;
}

.badge-approval--archived {
    background: #ECEFF1;
    color: #455A64;
    border-color: #CFD8DC;
}

/* --- Before / after diff --------------------------------------------------
   Two columns, not inline strikethrough: an admin reading a request needs to
   compare values, and stacked rows make that a straight vertical scan. */

.diff-row {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: .875rem;
    align-items: center;
    padding: .8125rem 0;
    border-bottom: 1px solid var(--mdu-border);
}

.diff-row:last-child {
    border-bottom: 0;
}

.diff-label {
    font-size: .6875rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--mdu-text-muted);
    margin-bottom: .3125rem;
}

.diff-value {
    font-size: .875rem;
    padding: .4375rem .625rem;
    border-radius: var(--mdu-radius-sm);
    word-break: break-word;
    /* A description or specification keeps its line breaks in the diff. */
    white-space: pre-line;
}

.diff-value--from {
    background: #F5F5F5;
    color: var(--mdu-text-muted);
    border: 1px solid #E5E7EB;
}

.diff-value--to {
    background: #E8F5E9;
    color: #1B5E20;
    border: 1px solid #C8E6C9;
    font-weight: 600;
}

.diff-arrow {
    color: #B0B7C3;
    font-size: 1.125rem;
}

.diff-state {
    font-size: .625rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .06em;
    padding: .125rem .4375rem;
    border-radius: 5px;
}

.diff-state--added   { background: #E8F5E9; color: #2E7D32; }
.diff-state--changed { background: #FFF3E0; color: #E65100; }
.diff-state--removed { background: #F5F5F5; color: #5F6368; }

@media (max-width: 575.98px) {
    .diff-row {
        grid-template-columns: 1fr;
    }

    .diff-arrow {
        transform: rotate(90deg);
        justify-self: start;
    }
}

/* --- Approval queue tabs --------------------------------------------------- */

/*
 * The active pill colour is a compiled literal (#0d6efd) — the :root
 * --bs-primary override never reaches it. The approval tabs below restyle
 * their pills entirely, so this exists for the next bare .nav-pills, which
 * would otherwise arrive Bootstrap-blue in a crimson interface.
 */
.nav-pills {
    --bs-nav-pills-link-active-color: #fff;
    --bs-nav-pills-link-active-bg: var(--mdu-red);
}

.approval-tabs {
    gap: .375rem;
}

.approval-tabs .nav-link {
    display: inline-flex;
    align-items: center;
    gap: .4375rem;
    background: #fff;
    border: 1px solid var(--mdu-border);
    color: var(--mdu-text-muted);
    font-size: .875rem;
    font-weight: 600;
    border-radius: var(--mdu-radius-sm);
    padding: .5rem .875rem;
    transition: background-color var(--mdu-transition), border-color var(--mdu-transition), color var(--mdu-transition);
}

.approval-tabs .nav-link:hover {
    border-color: var(--mdu-red-accent);
    background: var(--mdu-red-light);
    color: var(--mdu-red-hover);
}

.approval-tabs .nav-link.active {
    background: var(--mdu-red);
    border-color: var(--mdu-red);
    color: #fff;
}

/* The count is the reason to click, so it stays legible in both states. */
.approval-tabs__count {
    background: var(--mdu-warning);
    color: #fff;
    font-size: .6875rem;
    font-weight: 700;
    line-height: 1.5;
    padding: .0625rem .4375rem;
    border-radius: 999px;
}

.approval-tabs .nav-link.active .approval-tabs__count {
    background: rgba(255, 255, 255, .28);
}

/* --- Decision panel -------------------------------------------------------- */

.decision-panel {
    position: sticky;
    top: calc(var(--mdu-topbar-height) + 1.25rem);
}

.badge-archived {
    background: #ECEFF1;
    color: #546E7A;
    border: 1px solid #CFD8DC;
    font-size: .6875rem;
    font-weight: 650;
    padding: .125rem .4375rem;
    border-radius: 6px;
}

/* Quantity deltas in the ledger */
.qty-delta {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.qty-delta--up {
    color: #2E7D32;
}

.qty-delta--down {
    color: #1565C0;
}

/* ==========================================================================
   Forms
   ========================================================================== */

.form-label {
    font-size: .8125rem;
    font-weight: 600;
    margin-bottom: .375rem;
    color: var(--mdu-text);
}

.form-label .req {
    color: var(--mdu-red);
    margin-left: .125rem;
}

.form-control,
.form-select {
    border-radius: var(--mdu-radius-sm);
    border-color: var(--mdu-border);
    padding: .5625rem .75rem;
    font-size: .875rem;
    transition: border-color var(--mdu-transition), box-shadow var(--mdu-transition);
}

.form-control:focus,
.form-select:focus {
    border-color: var(--mdu-red);
    box-shadow: 0 0 0 3.5px rgba(167, 28, 33, .14);
}

.form-control::placeholder {
    color: #A0A6B0;
}

.form-control.is-invalid,
.form-select.is-invalid {
    border-color: var(--mdu-danger);
}

.form-control.is-invalid:focus,
.form-select.is-invalid:focus {
    box-shadow: 0 0 0 3.5px rgba(244, 67, 54, .16);
}

.form-text {
    font-size: .75rem;
    color: var(--mdu-text-muted);
}

/* Sign-in failure banner — form-level, because the error belongs to the
   credentials pair rather than either field. Broad and calm: soft red wash,
   a leading icon, a short bold title over the sentence. */

.auth-alert {
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .875rem 1rem;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-red-light);
    border: 1px solid var(--mdu-red-accent);
    color: var(--mdu-red-deep);
    font-size: .875rem;
    line-height: 1.45;
}

.auth-alert > i {
    font-size: 1.125rem;
    line-height: 1.3;
}

.auth-alert strong {
    display: block;
    font-size: .8125rem;
    text-transform: uppercase;
    letter-spacing: .02em;
    margin-bottom: .125rem;
}

/* Password visibility toggle — sits inside the field and inherits its
   background, so it reads as part of the input rather than a control
   bolted onto it. The icon uses the same grey as placeholder text. */

.password-field {
    position: relative;
}

.password-field .form-control {
    padding-right: 2.75rem;
}

/* Bootstrap paints its warning glyph in the same corner the toggle occupies;
   the red border and message carry the state on their own. */
.password-field .form-control.is-invalid {
    background-image: none;
    padding-right: 2.75rem;
}

/* Edge draws its own reveal eye, which would double up with ours. */
.password-field input::-ms-reveal {
    display: none;
}

.password-toggle {
    position: absolute;
    top: 1px;
    right: 1px;
    bottom: 1px;
    width: 2.5rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: transparent;
    border-radius: 0 var(--mdu-radius-sm) var(--mdu-radius-sm) 0;
    color: #A0A6B0;
    font-size: .9375rem;
    cursor: pointer;
    transition: color var(--mdu-transition);
}

.password-toggle:hover {
    color: var(--mdu-charcoal);
}

.password-toggle:focus-visible {
    outline: 2px solid var(--mdu-red);
    outline-offset: -2px;
}

.invalid-feedback {
    font-size: .75rem;
    font-weight: 500;
}

.input-group-text {
    background: var(--mdu-bg);
    border-color: var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
    font-size: .875rem;
    color: var(--mdu-text-muted);
}

.form-check-input:checked {
    background-color: var(--mdu-red);
    border-color: var(--mdu-red);
}

.form-check-input:focus {
    border-color: var(--mdu-red);
    box-shadow: 0 0 0 3.5px rgba(167, 28, 33, .14);
}

.form-section {
    border-top: 1px solid var(--mdu-border);
    margin-top: 1.5rem;
    padding-top: 1.5rem;
}

.form-section:first-child {
    border-top: 0;
    margin-top: 0;
    padding-top: 0;
}

.form-section__title {
    font-size: .8125rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    color: var(--mdu-text-muted);
    margin-bottom: 1rem;
}

/* --- Identity row ---------------------------------------------------------
   The product's name and its picture, side by side at the top of the form.
   The name is the first thing you read and the first thing you type, so it
   leads; the image is a compact tile beside it rather than a tall dropzone
   that pushes everything else below the fold. */

.identity-row {
    display: flex;
    gap: 1.25rem;
    align-items: flex-start;
}

.identity-row__fields {
    flex: 1 1 auto;
    min-width: 0;
}

.identity-row__name .form-control {
    font-size: 1.0625rem;
    font-weight: 600;
    padding: .6875rem .875rem;
}

@media (max-width: 575.98px) {
    .identity-row {
        flex-direction: column;
    }
}

/* --- Compact image upload -------------------------------------------------
   A labelled tile that opens the file picker. The caption and icon are always
   visible — hover only deepens them — because a control that exists solely on
   hover is invisible on touch and to anyone who never happens to point at it. */

.image-drop {
    position: relative;
    width: 108px;
    height: 108px;
    flex-shrink: 0;
    border-radius: var(--mdu-radius);
    border: 1px dashed var(--mdu-border);
    background: var(--mdu-bg);
    overflow: hidden;
    cursor: pointer;
    display: block;
    transition: border-color var(--mdu-transition), background-color var(--mdu-transition);
}

.image-drop:hover,
.image-drop:focus-within {
    border-color: var(--mdu-red-accent);
    background: var(--mdu-red-light);
}

.image-preview {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    color: #B0B7C3;
    font-size: 1.375rem;
}

.image-preview img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Sits over the tile. Translucent by default so the caption is always legible
   against a photo, opaque on hover. */
.image-drop__overlay {
    position: absolute;
    inset: auto 0 0 0;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: .3125rem;
    padding: .3125rem;
    font-size: .6875rem;
    font-weight: 650;
    color: #fff;
    background: rgba(16, 24, 40, .62);
    transition: background-color var(--mdu-transition), padding var(--mdu-transition);
}

.image-drop:hover .image-drop__overlay,
.image-drop:focus-within .image-drop__overlay {
    background: var(--mdu-red);
}

.image-drop__overlay i {
    font-size: .8125rem;
}

/* Clipped rather than hidden, so it can still take keyboard focus and the
   tile shows a focus ring through :focus-within. */
.image-drop input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    border: 0;
}

.image-drop:focus-within {
    outline: 2px solid var(--mdu-red);
    outline-offset: 2px;
}

.image-remove {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .75rem;
    font-weight: 600;
    color: var(--mdu-text-muted);
    background: none;
    border: 0;
    padding: .25rem 0 0;
}

.image-remove:hover {
    color: var(--mdu-red-hover);
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
    border-radius: var(--mdu-radius-sm);
    font-size: .875rem;
    font-weight: 600;
    padding: .5rem .875rem;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .4375rem;
    transition: transform var(--mdu-transition), box-shadow var(--mdu-transition),
                background-color var(--mdu-transition), border-color var(--mdu-transition), color var(--mdu-transition);
}

.btn:active {
    transform: translateY(1px);
}

.btn:disabled,
.btn.disabled {
    transform: none;
    opacity: .6;
}

.btn-primary {
    background-color: var(--mdu-red);
    border-color: var(--mdu-red);
    color: #fff;
}

.btn-primary:hover,
.btn-primary:focus {
    background-color: var(--mdu-red-hover);
    border-color: var(--mdu-red-hover);
    color: #fff;
    box-shadow: 0 4px 12px rgba(167, 28, 33, .28);
}

.btn-primary:disabled,
.btn-primary.disabled {
    background-color: var(--mdu-red);
    border-color: var(--mdu-red);
}

.btn-outline-primary {
    color: var(--mdu-red);
    border-color: var(--mdu-red-accent);
    background: #fff;
}

.btn-outline-primary:hover,
.btn-outline-primary:focus {
    background-color: var(--mdu-red-light);
    border-color: var(--mdu-red);
    color: var(--mdu-red-hover);
}

.btn-light-neutral {
    background: #fff;
    border: 1px solid var(--mdu-border);
    color: var(--mdu-text);
}

.btn-light-neutral:hover {
    background: var(--mdu-bg);
    border-color: #D5D9DF;
    color: var(--mdu-text);
}

/* The most final action on a screen, kept deliberately quiet so it is never
   the thing you click by momentum. */
.btn-quiet-danger {
    background: transparent;
    border: 1px solid transparent;
    color: var(--mdu-text-muted);
}

.btn-quiet-danger:hover,
.btn-quiet-danger:focus {
    background: var(--mdu-red-light);
    border-color: var(--mdu-red-accent);
    color: var(--mdu-red-hover);
}

.btn-sm {
    padding: .3125rem .625rem;
    font-size: .8125rem;
    border-radius: 7px;
}

.btn-icon {
    width: 32px;
    height: 32px;
    padding: 0;
    border-radius: 7px;
}

/* Row action buttons */
.row-actions {
    display: inline-flex;
    gap: .3125rem;
    white-space: nowrap;
}

.row-actions .btn {
    background: #fff;
    border: 1px solid var(--mdu-border);
    color: var(--mdu-text-muted);
    width: 32px;
    height: 32px;
    padding: 0;
    font-size: .9375rem;
}

.row-actions .btn:hover {
    border-color: var(--mdu-red-accent);
    background: var(--mdu-red-light);
    color: var(--mdu-red-hover);
}

.row-actions .btn--success:hover {
    border-color: #C8E6C9;
    background: #E8F5E9;
    color: #2E7D32;
}

.row-actions .btn--info:hover {
    border-color: #BBDEFB;
    background: #E3F2FD;
    color: #1565C0;
}

.row-actions .btn--purple:hover {
    border-color: #E1BEE7;
    background: #F3E5F5;
    color: #6A1B9A;
}

/* ==========================================================================
   Page header
   ========================================================================== */

.page-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.page-header__title {
    font-size: 1.375rem;
    font-weight: 700;
    letter-spacing: -.018em;
    margin: 0;
}

.page-header__lead {
    color: var(--mdu-text-muted);
    font-size: .875rem;
    margin: .1875rem 0 0;
}

.page-header__actions {
    display: flex;
    gap: .5rem;
    flex-wrap: wrap;
}

/* ==========================================================================
   Filter bar
   ========================================================================== */

.filter-bar {
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius);
    box-shadow: var(--mdu-shadow);
    padding: 1rem 1.25rem;
    margin-bottom: 1.25rem;
}

/* Two native date inputs reading as one range control. */
.date-range {
    display: flex;
    align-items: center;
    gap: .375rem;
}

.date-range .form-control {
    flex: 1 1 0;
    min-width: 0;
}

.date-range__dash {
    color: var(--mdu-text-muted);
    flex-shrink: 0;
}

/* Buttons sit beside inputs in the bar, so they take the inputs' height —
   .btn is otherwise 2px shorter, which reads as misalignment, not intent. */
.filter-bar__actions .btn {
    padding-top: .5625rem;
    padding-bottom: .5625rem;
}

.filter-chip {
    display: inline-flex;
    align-items: center;
    gap: .375rem;
    background: var(--mdu-red-light);
    border: 1px solid var(--mdu-red-accent);
    color: var(--mdu-red-hover);
    border-radius: 999px;
    padding: .1875rem .625rem;
    font-size: .75rem;
    font-weight: 600;
}

.filter-chip a {
    color: inherit;
    display: inline-flex;
    opacity: .7;
}

.filter-chip a:hover {
    opacity: 1;
}

/* ==========================================================================
   Empty state
   ========================================================================== */

.empty-state {
    text-align: center;
    padding: 3rem 1.5rem;
}

.empty-state__icon {
    width: 60px;
    height: 60px;
    border-radius: 16px;
    background: var(--mdu-red-light);
    color: var(--mdu-red);
    display: grid;
    place-items: center;
    font-size: 1.625rem;
    margin: 0 auto 1rem;
}

.empty-state__title {
    font-weight: 650;
    font-size: 1rem;
    margin-bottom: .25rem;
}

.empty-state__text {
    color: var(--mdu-text-muted);
    font-size: .875rem;
    max-width: 26rem;
    margin: 0 auto;
}

/* ==========================================================================
   Toasts
   ========================================================================== */

.toast-stack {
    position: fixed;
    top: calc(var(--mdu-topbar-height) + .75rem);
    right: 1.25rem;
    z-index: 1090;
    display: flex;
    flex-direction: column;
    gap: .625rem;
    max-width: min(26rem, calc(100vw - 2.5rem));
}

.toast {
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    border-left: 4px solid var(--toast-color, var(--mdu-red));
    border-radius: var(--mdu-radius-sm);
    box-shadow: var(--mdu-shadow-lg);
    display: flex;
    align-items: flex-start;
    gap: .75rem;
    padding: .875rem 1rem;
    font-size: .875rem;
    animation: toast-in 260ms cubic-bezier(.16, 1, .3, 1);
}

.toast.is-leaving {
    animation: toast-out 200ms ease forwards;
}

.toast__icon {
    color: var(--toast-color, var(--mdu-red));
    font-size: 1.125rem;
    line-height: 1.35;
    flex-shrink: 0;
}

.toast__body {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--mdu-text);
}

.toast--success { --toast-color: var(--mdu-success); }
.toast--error   { --toast-color: var(--mdu-danger); }
.toast--warning { --toast-color: var(--mdu-warning); }
.toast--info    { --toast-color: #1565C0; }

@keyframes toast-in {
    from { opacity: 0; transform: translateX(20px) scale(.98); }
    to   { opacity: 1; transform: none; }
}

@keyframes toast-out {
    to { opacity: 0; transform: translateX(20px) scale(.98); }
}

/* ==========================================================================
   Modals
   ========================================================================== */

.modal-content {
    border: 0;
    border-radius: var(--mdu-radius);
    box-shadow: var(--mdu-shadow-lg);
}

.modal-header {
    border-bottom: 1px solid var(--mdu-border);
    padding: 1rem 1.25rem;
}

.modal-title {
    font-size: 1rem;
    font-weight: 650;
}

.modal-body {
    padding: 1.25rem;
}

.modal-footer {
    border-top: 1px solid var(--mdu-border);
    padding: .875rem 1.25rem;
    gap: .5rem;
}

.confirm-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    font-size: 1.5rem;
    background: var(--mdu-red-light);
    color: var(--mdu-red);
    flex-shrink: 0;
}

/* Destructive dialogs: the same disc in the warning red rather than the
   brand crimson, so "this one bites" reads before a single word does. */
.confirm-icon--danger {
    background: var(--mdu-danger-light);
    color: var(--mdu-danger);
}

/* ==========================================================================
   Pagination
   ========================================================================== */

.pagination {
    /*
     * Same story as the dropdown: the focus ring and active page are
     * compiled literals (#0d6efd), so a keyboard user tabbing the pager got
     * a Bootstrap-blue halo in an otherwise crimson interface. The ring
     * matches the 3.5px one every input in the system focuses with.
     */
    --bs-pagination-focus-color: var(--mdu-red-hover);
    --bs-pagination-focus-bg: var(--mdu-red-light);
    --bs-pagination-focus-box-shadow: 0 0 0 3.5px rgba(167, 28, 33, .14);
    --bs-pagination-active-color: #fff;
    --bs-pagination-active-bg: var(--mdu-red);
    --bs-pagination-active-border-color: var(--mdu-red);

    margin: 0;
    gap: .25rem;
}

.page-link {
    border-radius: var(--mdu-radius-sm) !important;
    border-color: var(--mdu-border);
    color: var(--mdu-text);
    font-size: .8125rem;
    font-weight: 600;
    padding: .375rem .6875rem;
    transition: background-color var(--mdu-transition), color var(--mdu-transition), border-color var(--mdu-transition);
}

.page-link:hover {
    background: var(--mdu-red-light);
    border-color: var(--mdu-red-accent);
    color: var(--mdu-red-hover);
}

.page-item.active .page-link {
    background: var(--mdu-red);
    border-color: var(--mdu-red);
    color: #fff;
}

.page-item.disabled .page-link {
    color: #B0B7C3;
    background: transparent;
}

/* ==========================================================================
   Stock meter
   ========================================================================== */

.stock-meter {
    height: 5px;
    border-radius: 999px;
    background: #EEF0F3;
    overflow: hidden;
    margin-top: .3125rem;
    max-width: 120px;
}

.stock-meter__fill {
    height: 100%;
    border-radius: 999px;
    background: var(--mdu-success);
    transition: width 400ms var(--mdu-transition);
}

.stock-meter__fill--low { background: var(--mdu-warning); }
.stock-meter__fill--out { background: var(--mdu-danger); }

/* ==========================================================================
   Timeline (product movement history)
   ========================================================================== */

/*
 * Weight and dimensions inside one table cell. Three inputs read as one
 * measurement, so they share a heading and sit tight together rather than
 * claiming three columns of a table that is already wide enough.
 */
.measure-group {
    display: flex;
    align-items: center;
    gap: .25rem;
}

.measure-group .form-control {
    padding-left: .5rem;
    padding-right: .375rem;
    min-width: 0;
    flex: 1 1 0;
    text-align: right;
}

.measure-group__by,
.measure-group__unit {
    color: var(--mdu-text-muted);
    font-size: .75rem;
    flex-shrink: 0;
}

/* The unit belongs to the figure before it, so it sits tight against it. */
.measure-group__unit {
    margin-left: -.125rem;
    margin-right: .125rem;
}

/* ==========================================================================
   Reminder bell
   ========================================================================== */

.reminder-bell {
    position: relative;
    width: 40px;
    height: 40px;
    display: grid;
    place-items: center;
    border: 1px solid var(--mdu-border);
    background: #fff;
    border-radius: var(--mdu-radius-sm);
    color: var(--mdu-text-muted);
    font-size: 1.0625rem;
    flex-shrink: 0;
    transition: background-color var(--mdu-transition), border-color var(--mdu-transition), color var(--mdu-transition);
}

.reminder-bell:hover,
.reminder-bell[aria-expanded="true"] {
    background: var(--mdu-red-light);
    border-color: var(--mdu-red-accent);
    color: var(--mdu-red-hover);
}

/* Only ever shown with a number in it, so it never reads as decoration. */
.reminder-bell.has-items {
    color: var(--mdu-red);
}

.reminder-bell__count {
    position: absolute;
    top: -5px;
    right: -5px;
    min-width: 18px;
    height: 18px;
    padding: 0 5px;
    border-radius: 999px;
    background: var(--mdu-red);
    color: #fff;
    font-size: .6875rem;
    font-weight: 700;
    line-height: 18px;
    text-align: center;
    box-shadow: 0 0 0 2px #fff;
}

.reminder-menu {
    width: min(24rem, calc(100vw - 2rem));
    padding: 0;
    max-height: min(28rem, 70vh);
    overflow-y: auto;
}

.reminder-menu__head {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: .75rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--mdu-border);
    position: sticky;
    top: 0;
    background: var(--mdu-card);
    z-index: 1;
}

.reminder {
    display: flex;
    gap: .75rem;
    padding: .75rem 1rem;
    border-bottom: 1px solid var(--mdu-border);
    color: inherit;
    text-decoration: none;
    transition: background-color var(--mdu-transition);
}

.reminder:last-child {
    border-bottom: 0;
}

.reminder:hover {
    background: var(--mdu-bg);
    color: inherit;
}

.reminder__icon {
    width: 32px;
    height: 32px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    font-size: .875rem;
}

.reminder__body {
    display: flex;
    flex-direction: column;
    gap: .125rem;
    min-width: 0;
}

.reminder__title {
    font-size: .8125rem;
    font-weight: 650;
    line-height: 1.35;
}

.reminder__detail {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    line-height: 1.45;
}

/* Three tones, and only three: informational, worth acting on, and wrong. */
.reminder--info .reminder__icon { background: #E3F2FD; color: #1565C0; }
.reminder--attention .reminder__icon { background: #FFF3E0; color: #B26A00; }
.reminder--urgent .reminder__icon { background: var(--mdu-danger-light); color: var(--mdu-danger-deep); }

.reminder-menu__empty {
    display: flex;
    align-items: center;
    gap: .5rem;
    padding: 1.5rem 1rem;
    justify-content: center;
    color: var(--mdu-text-muted);
    font-size: .8125rem;
}

.reminder-menu__empty i {
    color: var(--mdu-success);
    font-size: 1rem;
}

/*
 * Where a release went. Two quiet tints rather than the brand crimson: this
 * is a category, not a state, and nothing here is wrong or urgent.
 */
.badge-dest {
    display: inline-flex;
    align-items: center;
    gap: .3125rem;
    font-size: .6875rem;
    font-weight: 700;
    padding: .1875rem .5rem;
    border-radius: 999px;
    white-space: nowrap;
}

.badge-dest--customer {
    background: #E3F2FD;
    color: #1565C0;
}

.badge-dest--shop {
    background: #EDE7F6;
    color: #5E35B1;
}

/* The same measurements read back — a quiet second line under the name. */
.variant-measure {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    margin-top: .125rem;
}

/*
 * A product's description, wherever it is read back. Prose rather than data,
 * so it gets a comfortable line height and is separated by space and a rule
 * instead of being squeezed into the figures list below it.
 */
.product-description {
    font-size: .875rem;
    line-height: 1.6;
    color: var(--mdu-text);
    padding-bottom: 1rem;
    margin-bottom: 1rem;
    border-bottom: 1px solid var(--mdu-border);
    overflow-wrap: anywhere;
}

/* The figures under a description. Line breaks are the warehouse's own —
   one rating per line — so they are kept as typed. */
.product-description > p + .product-spec {
    margin-top: .875rem;
}

.product-spec__body {
    white-space: pre-line;
    color: var(--mdu-text);
}

.detail-list {
    display: grid;
    gap: .875rem;
}

.detail-list__row {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
}

.detail-list__label {
    font-size: .8125rem;
    color: var(--mdu-text-muted);
    flex-shrink: 0;
}

.detail-list__value {
    font-size: .875rem;
    font-weight: 600;
    text-align: right;
    word-break: break-word;
}

/* ==========================================================================
   Auth
   ========================================================================== */

.auth-page {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 1fr;
}

@media (min-width: 992px) {
    .auth-page {
        grid-template-columns: 1.05fr .95fr;
    }
}

.auth-aside {
    display: none;
    background: linear-gradient(155deg, var(--mdu-red) 0%, var(--mdu-red-hover) 55%, var(--mdu-red-deep) 100%);
    color: #fff;
    padding: 3.5rem;
    position: relative;
    overflow: hidden;
    flex-direction: column;
    justify-content: space-between;
}

@media (min-width: 992px) {
    .auth-aside {
        display: flex;
    }
}

.auth-aside::after {
    content: "";
    position: absolute;
    width: 460px;
    height: 460px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .07);
    right: -150px;
    bottom: -170px;
}

.auth-aside::before {
    content: "";
    position: absolute;
    width: 260px;
    height: 260px;
    border-radius: 50%;
    background: rgba(255, 255, 255, .06);
    left: -90px;
    top: -70px;
}

.auth-aside__content {
    position: relative;
    z-index: 1;
    max-width: 30rem;
}

.auth-aside__title {
    font-size: 2rem;
    font-weight: 700;
    color: #fff;
    letter-spacing: -.02em;
    line-height: 1.2;
}

.auth-aside__lead {
    color: rgba(255, 255, 255, .85);
    margin-top: .875rem;
}

.auth-feature {
    display: flex;
    align-items: center;
    gap: .75rem;
    margin-top: 1rem;
    font-size: .9375rem;
    color: rgba(255, 255, 255, .92);
}

.auth-feature i {
    width: 34px;
    height: 34px;
    border-radius: 9px;
    background: rgba(255, 255, 255, .16);
    display: grid;
    place-items: center;
    flex-shrink: 0;
}

.auth-main {
    display: grid;
    place-items: center;
    padding: 2rem 1.5rem;
    background: var(--mdu-card);
}

.auth-card {
    width: 100%;
    max-width: 25rem;
}

.auth-logo {
    width: 58px;
    height: 58px;
    border-radius: 14px;
    background: #fff;
    border: 1px solid var(--mdu-border);
    display: grid;
    place-items: center;
    padding: 9px;
    margin-bottom: 1.25rem;
}

.auth-logo img {
    width: 100%;
    height: 100%;
    display: block;
}

/* Same reason as the sidebar: the crimson panel would swallow the crimson
   half of the mark. */
.auth-aside__logo {
    width: 68px;
    height: 68px;
    border-radius: 18px;
    background: #fff;
    display: grid;
    place-items: center;
    padding: 11px;
    margin-bottom: 1.75rem;
    box-shadow: 0 6px 20px rgba(16, 24, 40, .18);
}

.auth-aside__logo img {
    width: 100%;
    height: 100%;
    display: block;
}

/* ==========================================================================
   Utilities
   ========================================================================== */

.divider-y {
    border-left: 1px solid var(--mdu-border);
    align-self: stretch;
    margin: .25rem 0;
}

.skeleton-hidden {
    visibility: hidden;
}

/* ==========================================================================
   Responsive
   ========================================================================== */

@media (max-width: 991.98px) {
    .sidebar {
        transform: translateX(-100%);
    }

    .sidebar.is-open {
        transform: none;
    }

    .app-main {
        margin-left: 0;
    }

    .topbar__toggle {
        display: grid;
        place-items: center;
    }

    .topbar {
        padding: 0 1rem;
    }

    .app-content {
        padding: 1.25rem 1rem 2.5rem;
    }

    .topbar__meta--date {
        display: none;
    }
}

@media (max-width: 575.98px) {
    .user-menu__text {
        display: none;
    }

    .page-header__title {
        font-size: 1.1875rem;
    }

    .stat-card__value {
        font-size: 1.625rem;
    }

    .toast-stack {
        left: 1rem;
        right: 1rem;
        max-width: none;
    }
}

@media print {
    .sidebar,
    .topbar,
    .page-header__actions,
    .filter-bar,
    .row-actions,
    .toast-stack,
    .pagination {
        display: none !important;
    }

    .app-main {
        margin-left: 0;
    }

    .card {
        box-shadow: none;
        border-color: #ccc;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: .001ms !important;
        transition-duration: .001ms !important;
    }
}

/* ==========================================================================
   Stock forms — pick, then count
   The picker is a disclosure list folded by product, drawn over the page so
   opening it never pushes the working table down the screen.
   ========================================================================== */

.vpicker {
    position: relative;
    max-width: 560px;
}

.vpicker__trigger {
    text-align: left;
    background-color: var(--mdu-card);
    cursor: pointer;
}

.vpicker__control {
    position: relative;
}

.vpicker__panel {
    position: absolute;
    z-index: 1060;
    inset: 100% 0 auto 0;
    margin-top: 4px;
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
    box-shadow: var(--mdu-shadow-lg);
    overflow: hidden;
}

.vpicker__search {
    position: relative;
    padding: 8px;
    border-bottom: 1px solid var(--mdu-border);
}

.vpicker__search .bi {
    position: absolute;
    left: 20px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--mdu-text-muted);
    pointer-events: none;
}

.vpicker__search .form-control {
    padding-left: 34px;
}

.vpicker__list {
    max-height: 320px;
    overflow-y: auto;
    padding: 4px;
}

.vpicker__product,
.vpicker__option {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 8px 10px;
    border: 0;
    border-radius: 6px;
    background: transparent;
    text-align: left;
    color: var(--mdu-text);
    cursor: pointer;
}

.vpicker__product {
    font-weight: 600;
}

.vpicker__product:hover,
.vpicker__product:focus-visible,
.vpicker__option:hover,
.vpicker__option:focus-visible {
    background: var(--mdu-red-light);
    outline: none;
}

.vpicker__caret {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    transition: transform var(--mdu-transition);
}

.vpicker__product[aria-expanded="true"] .vpicker__caret {
    transform: rotate(90deg);
}

.vpicker__name {
    flex: 1 1 auto;
    min-width: 0;
}

.vpicker__count {
    font-size: .75rem;
    font-weight: 500;
    color: var(--mdu-text-muted);
    font-variant-numeric: tabular-nums;
}

.vpicker__option {
    justify-content: space-between;
    padding-left: 30px;
}

/* A product with no variations: one row, aligned with the product names
   above and below it, and weighted like them. */
.vpicker__option--standalone .vpicker__name {
    font-weight: 600;
}

.vpicker__meta {
    font-size: .75rem;
    color: var(--mdu-text-muted);
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
}

.vpicker__none {
    margin: 0;
    padding: 16px 12px;
    font-size: .875rem;
    color: var(--mdu-text-muted);
    text-align: center;
}

.selection-empty {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-top: 16px;
    padding: 16px;
    border: 1px dashed var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
    color: var(--mdu-text-muted);
    font-size: .875rem;
}

.selection-empty .bi {
    font-size: 1.25rem;
}

.selection-table {
    margin-top: 16px;
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
}

.selection-table__qty {
    width: 150px;
}

@media (max-width: 575.98px) {
    .selection-table__qty {
        width: 110px;
    }
}

.selection-table .qty-input {
    max-width: 130px;
    margin-left: auto;
}

.document-picked {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
    padding: 6px 8px 6px 12px;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-bg);
    font-size: .875rem;
}

.document-picked__name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.document-picked__size {
    color: var(--mdu-text-muted);
    font-variant-numeric: tabular-nums;
}

/* ==========================================================================
   Inventory log — one row per event
   The whole row opens its dialog: a target the width of the table is easier
   to hit than an icon at the end of it.
   ========================================================================== */

.event-row {
    cursor: pointer;
}

.event-row:focus-visible {
    outline: 2px solid var(--mdu-red);
    outline-offset: -2px;
}

.event-row__open {
    color: var(--mdu-text-muted);
}

.event-row:hover .event-row__open {
    color: var(--mdu-red);
}

.text-truncate-2 {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.event-header {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 12px 24px;
    margin: 0 0 16px;
}

.event-header dt {
    font-size: .75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--mdu-text-muted);
}

.event-header dd {
    margin: 2px 0 0;
    overflow-wrap: anywhere;
}

.event-document {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding: 12px;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-bg);
}

.event-document__label {
    flex-basis: 100%;
    font-size: .75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: .04em;
    color: var(--mdu-text-muted);
}

.event-document__thumb img {
    display: block;
    width: 96px;
    height: 96px;
    object-fit: cover;
    border-radius: var(--mdu-radius-sm);
    border: 1px solid var(--mdu-border);
}

/* ==========================================================================
   Item Movements — a product row that opens onto its variations
   ========================================================================== */

/* The same grey the inventory's nested variation rows use, and the same
   hover, so a nested row behaves like a nested row everywhere. */
.movement-table__variants > tr > td {
    background: #FAFBFC;
    padding-top: .5rem;
    padding-bottom: .5rem;
}

.movement-table__variants > tr:hover > td {
    background-color: var(--mdu-red-light);
}

.movement-figure--in {
    color: var(--mdu-text);
}

.movement-figure--out {
    color: var(--mdu-red);
}

/* ==========================================================================
   Description preview over a product name
   ========================================================================== */

[data-preview] {
    text-decoration: underline dotted var(--mdu-border);
    text-underline-offset: 3px;
}

.name-preview {
    position: fixed;
    z-index: 1080;
    width: 320px;
    max-height: 132px;
    overflow: hidden;
    padding: 10px 12px;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-charcoal);
    color: #fff;
    font-size: .8125rem;
    line-height: 1.5;
    white-space: pre-line;
    box-shadow: var(--mdu-shadow-lg);
    pointer-events: none;
    opacity: 0;
    transform: translateY(2px);
    transition: opacity 120ms ease, transform 120ms ease;
}

.name-preview[data-open] {
    opacity: 1;
    transform: none;
}

/* Overflow fades out rather than stopping mid-letter; the whole description
   is on the product's own page. */
.name-preview[data-clipped] {
    -webkit-mask-image: linear-gradient(to bottom, #000 70%, transparent);
    mask-image: linear-gradient(to bottom, #000 70%, transparent);
}

@media (prefers-reduced-motion: reduce) {
    .name-preview {
        transition: none;
    }
}

/* ==========================================================================
   Dashboard — stock movement chart, ranking and stock health
   Server-rendered SVG in the app's own tokens: no chart library, in the
   first paint, and it prints.
   ========================================================================== */

.chart {
    margin: 0;
}

.chart__svg {
    display: block;
    width: 100%;
    height: auto;
    overflow: visible;
}

.chart__bar--empty {
    fill: var(--mdu-border);
}

.chart__grid {
    stroke: var(--mdu-border);
    stroke-width: 1;
    stroke-dasharray: 2 4;
}

.chart__baseline {
    stroke: var(--mdu-border);
    stroke-width: 1;
}

.chart__axis {
    fill: var(--mdu-text-muted);
    font-size: 10px;
    font-variant-numeric: tabular-nums;
}

.chart-empty {
    margin: 0;
    padding: 2.5rem 1rem;
    text-align: center;
    color: var(--mdu-text-muted);
    font-size: 0.875rem;
}

/* The movement toggle. Same shape as the stock status chips on Inventory, so
   the two read as one family.

   Links, not radios: choosing a dataset is going to a different view of the
   dashboard, and as links each choice is bookmarkable, openable in a new tab,
   and works with no script at all. */

.chart-toggle {
    display: inline-flex;
    padding: 0.2rem;
    gap: 0.2rem;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
    border-radius: 999px;
}

.chart-toggle__option {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    padding: 0.4rem 0.9rem;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1;
    color: var(--mdu-text-muted);
    text-decoration: none;
    white-space: nowrap;
    transition: background-color 0.12s ease, color 0.12s ease;
}

/* :not, or hovering the active option would repaint its label dark on
   crimson — unreadable, and only while the pointer is over it. */
.chart-toggle__option:hover:not([aria-current="page"]) {
    background: var(--mdu-red-light);
    color: var(--mdu-red-hover);
}

.chart-toggle__option:focus-visible {
    outline: 2px solid var(--mdu-red);
    outline-offset: 2px;
}

/* Active reads the same way it does on the approval tabs: crimson fill,
   white label. One language for "you are here" across the system. */
.chart-toggle__option[aria-current="page"] {
    background: var(--mdu-red);
    color: #fff;
}

/* The bar above the chart: what period, and what it came to.

   Filter left, figures right, on one line wherever there is room for one. As
   two stacked rows this cost 40px of every dashboard to say something that
   fits comfortably beside the control that produced it. */

.panel-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem 2rem;
    margin-bottom: 1.5rem;
}

.panel-bar__filter {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.5rem;
}

/* Chart and ranking, side by side.

   They are two readings of one query, so they share a card. Separated by space
   rather than a rule: a border here would draw a line through a single thought.

   Side by side only once there is genuinely room — below that the ranking goes
   under the chart, which is the order they would be read in anyway. */

.panel-body {
    container-type: inline-size;
}

.panel-split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem;
}

/* Side by side once the card itself is wide enough — measured on the card, not
   the window, because the same panel is full width on two dashboards and in a
   narrower column on the third. Stacked is the fallback, so a browser without
   container queries gets the readable layout rather than a squeezed one.

   760px, not less: below that the ranking column falls under about 300px
   and every item name starts wrapping onto three lines, which costs more
   height than stacking it would have saved. */
@container (min-width: 760px) {
    .panel-split {
        grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
        gap: 2rem;
    }
}

.panel-split__main,
.panel-split__aside {
    min-width: 0;
}

.panel-split__title {
    margin: 0 0 0.35rem;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--mdu-text-muted);
}

.panel-split__title span {
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
}

/* Movement scoreboard: the three figures the chart is a picture of. They lead,
   because they are the answer and the chart is the working — and because on a
   phone the bars are too thin to read while these stay legible. */

.movement-score {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.75rem;
    margin: 0;
}

.movement-score > div {
    min-width: 0;
}

/* A field that has to line up with the date range beside it. */
.panel-bar__field {
    display: flex;
    flex-direction: column;
}

.panel-bar__field .form-select {
    min-width: 11rem;
}

/* What the figure above is a figure of, when it is not all of them. */
.movement-score__scope {
    display: inline-block;
    margin-left: 0.3rem;
    padding: 0.05rem 0.4rem;
    border-radius: 999px;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
    color: var(--mdu-text);
    font-size: 0.625rem;
    font-weight: 600;
    letter-spacing: 0;
    text-transform: none;
    vertical-align: middle;
}

.movement-score dt {
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--mdu-text-muted);
    margin-bottom: 0.15rem;
}

.movement-score dd {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 700;
    line-height: 1.1;
    font-variant-numeric: tabular-nums;
}

.movement-score__note {
    display: block;
    font-size: 0.75rem;
    font-weight: 500;
    color: var(--mdu-text-muted);
}

/* Category legend. Shares the chart accent so the slice of colour under a
   name reads as part of the same drawing. */

.category-key {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}

.category-key li {
    display: inline-flex;
    align-items: baseline;
    gap: 0.4rem;
    padding: 0.3rem 0.7rem;
    border: 1px solid var(--mdu-border);
    border-radius: 999px;
    font-size: 0.8125rem;
    background: var(--mdu-card);
}

/* The band's colour, beside the name it belongs to. Small and square: a chip
   this size is a key, not a second chart. */
.category-key__swatch {
    width: 0.625rem;
    height: 0.625rem;
    border-radius: 3px;
    flex-shrink: 0;
    align-self: center;
}

.category-key__units {
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.category-key__share {
    color: var(--mdu-text-muted);
    font-size: 0.75rem;
}

/* Stock health ring ---------------------------------------------------- */

.health {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1.25rem;
    flex-wrap: wrap;
}

.health__ring {
    width: 132px;
    height: 132px;
    flex-shrink: 0;
    transform: rotate(-90deg);
}

.health__track {
    fill: none;
    stroke: var(--mdu-bg);
    stroke-width: 16;
}

.health__segment {
    fill: none;
    stroke-width: 16;
    transition: stroke-dasharray 0.2s ease;
}

/* The ring is rotated so the first segment starts at the top; the text inside
   it has to be turned back or it reads sideways. */
.health__total,
.health__caption {
    transform: rotate(90deg);
    transform-origin: 70px 70px;
    fill: var(--mdu-text);
}

.health__total {
    font-size: 26px;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.health__caption {
    font-size: 10px;
    fill: var(--mdu-text-muted);
    letter-spacing: 0.04em;
}

/* A vertical legend beside the ring: label on the left, count and share on
   the right. In a narrow card the ring wraps above it and the legend takes the
   full width, which is the same reading in one column instead of two. */

.health__key {
    display: grid;
    gap: 0.35rem;
    margin: 0;
    flex: 1 1 11rem;
    min-width: 0;
}

.health__stat {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.4rem 0.65rem;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-bg);
    color: inherit;
    text-decoration: none;
    /* The status colour, on the edge rather than as a dot. It is the same three
       the summary cards use, and it is the only colour in the block. */
    border-left: 3px solid var(--stat-colour);
    transition: background-color 0.12s ease, transform 0.12s ease;
}

a.health__stat:hover {
    background: var(--mdu-card);
    box-shadow: var(--mdu-shadow);
    transform: translateY(-1px);
}

a.health__stat:focus-visible {
    outline: 2px solid var(--mdu-red);
    outline-offset: 2px;
}

.health__stat-label {
    font-size: 0.8125rem;
    font-weight: 600;
}

.health__stat-value {
    display: flex;
    align-items: baseline;
    gap: 0.4rem;
    white-space: nowrap;
}

.health__stat strong {
    font-size: 1.0625rem;
    font-weight: 700;
    line-height: 1.2;
    font-variant-numeric: tabular-nums;
}

.health__share {
    color: var(--mdu-text-muted);
    font-weight: 500;
    font-size: 0.8125rem;
}

/* Ranked inks ---------------------------------------------------------- */

.item-rank {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 0.125rem;
    counter-reset: rank;
}

.item-rank__row {
    display: grid;
    grid-template-columns: 1.25rem minmax(0, 1fr) auto;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0.2rem;
    border-radius: var(--mdu-radius-sm);
}

.item-rank__row:hover {
    background: var(--mdu-bg);
}

.item-rank__place {
    font-size: 0.8125rem;
    font-weight: 700;
    color: var(--mdu-text-muted);
    font-variant-numeric: tabular-nums;
    text-align: right;
}

/* The proportional bar is the row's own background, so the ranking reads as a
   chart without a second drawing beside it. */
.item-rank__bar {
    position: relative;
    display: grid;
    gap: 0.1rem;
    min-width: 0;
    padding: 0.15rem 0.5rem;
    border-radius: var(--mdu-radius-sm);
    background: linear-gradient(
        to right,
        var(--rank-tint, var(--mdu-red-light)) var(--rank-share, 0%),
        transparent var(--rank-share, 0%)
    );
}

.item-rank__name {
    font-weight: 600;
    font-size: 0.875rem;
    line-height: 1.3;
    overflow-wrap: anywhere;
}

.item-rank__variation {
    font-weight: 500;
    color: var(--mdu-text-muted);
}

.item-rank__variation::before {
    content: "— ";
}

.item-rank__meta {
    font-size: 0.75rem;
    color: var(--mdu-text-muted);
}

.item-rank__figure {
    text-align: right;
    display: grid;
    gap: 0.05rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.item-rank__figure strong {
    font-size: 1rem;
}

.item-rank__unit {
    font-size: 0.75rem;
    color: var(--mdu-text-muted);
    margin-left: 0.15rem;
}

.item-rank__movements {
    font-size: 0.6875rem;
    color: var(--mdu-text-muted);
}


/* ==========================================================================
   Paperwork attached to a movement
   Above the figures it explains, in the event dialog. A photograph shows
   itself; anything else gets an icon and its own name.
   ========================================================================== */

.document-attached {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 16px;
    padding: 10px 12px;
    border: 1px solid var(--mdu-border);
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-bg);
    color: var(--mdu-text);
    text-decoration: none;
    transition: border-color var(--mdu-transition), background-color var(--mdu-transition);
}

.document-attached:hover,
.document-attached:focus-visible {
    border-color: var(--mdu-red-accent);
    background: var(--mdu-red-light);
    color: var(--mdu-text);
}

.document-attached__thumb {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--mdu-radius-sm);
    border: 1px solid var(--mdu-border);
    flex-shrink: 0;
}

.document-attached__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border-radius: var(--mdu-radius-sm);
    background: var(--mdu-card);
    border: 1px solid var(--mdu-border);
    color: var(--mdu-red);
    font-size: 1.25rem;
    flex-shrink: 0;
}

.document-attached__name {
    display: flex;
    flex-direction: column;
    font-weight: 600;
    min-width: 0;
    overflow-wrap: anywhere;
}

.document-attached__hint {
    font-size: .75rem;
    font-weight: 500;
    color: var(--mdu-text-muted);
}

/* ==========================================================================
   Account photo
   The same circle the initials use, so a row with a photo and a row without
   line up exactly.
   ========================================================================== */

.avatar--photo {
    object-fit: cover;
    background: var(--mdu-bg);
    border: 1px solid var(--mdu-border);
}

/* ==========================================================================
   Motion
   Only where something changes state: it appeared, it was added, it is
   leaving, it needs a look. 120–250ms, eased out on the way in and in on the
   way out; nothing on page load except the dashboard's own figures, which
   are what that page is opened to read. Transform and opacity only, so no
   animation ever moves the layout around it.

   The reduced-motion rule further up collapses every one of these to an
   instant change, and mdu.js skips its timed steps under the same setting.
   ========================================================================== */

:root {
    --mdu-ease-out: cubic-bezier(.16, 1, .3, 1);
    --mdu-ease-in: cubic-bezier(.4, 0, 1, 1);
    --mdu-enter: 180ms;
    --mdu-leave: 140ms;
}

@keyframes mdu-drop-in {
    from { opacity: 0; translate: 0 -4px; }
    to   { opacity: 1; translate: none; }
}

@keyframes mdu-fade-in {
    from { opacity: 0; }
    to   { opacity: 1; }
}

@keyframes mdu-leave {
    to { opacity: 0; translate: 8px 0; }
}

@keyframes mdu-pop {
    0%   { scale: .6; opacity: 0; }
    70%  { scale: 1.12; opacity: 1; }
    100% { scale: 1; }
}

/* Menus and the stock picker drop from where they were opened. */
.dropdown-menu.show,
.vpicker__panel:not([hidden]) {
    animation: mdu-drop-in var(--mdu-enter) var(--mdu-ease-out);
}

/* A product's variations settle into place when its row is opened. The
   animation restarts on its own each time the panel stops being hidden. */
.variant-panel:not(.d-none) > td > * {
    animation: mdu-drop-in var(--mdu-enter) var(--mdu-ease-out);
}

/* A line added to a stock form or a variation added to a product arrives
   with a brief tint, so the eye finds where it went. */
@keyframes mdu-arrive {
    from { background-color: var(--mdu-red-light); }
    to   { background-color: transparent; }
}

.is-arriving > td {
    animation: mdu-arrive 900ms ease-out;
}

/* ...and one being removed slides out before it goes. mdu.js disables its
   inputs first, so nothing it held is submitted during the exit. */
.is-leaving {
    animation: mdu-leave var(--mdu-leave) var(--mdu-ease-in) forwards;
    pointer-events: none;
}

/* A field the server refused gets one small shake on arrival, beside its
   message — the page reloads at the top, and the error may be far below. */
@keyframes mdu-nudge {
    0%, 100% { translate: none; }
    25%      { translate: -4px 0; }
    75%      { translate: 4px 0; }
}

.is-nudged {
    animation: mdu-nudge 260ms ease-in-out 2;
}

.invalid-feedback.d-block {
    animation: mdu-fade-in var(--mdu-enter) ease-out;
}

/* A count that has gone up since the last page pops once (mdu.js decides). */
.is-popping {
    animation: mdu-pop 320ms var(--mdu-ease-out) both;
}

/* The bell rings only when it has more to say than on the last page. */
@keyframes mdu-ring {
    0%, 100% { rotate: 0deg; }
    20%      { rotate: 14deg; }
    40%      { rotate: -12deg; }
    60%      { rotate: 8deg; }
    80%      { rotate: -4deg; }
}

.reminder-bell.is-ringing > .bi {
    display: inline-block;
    transform-origin: 50% 0;
    animation: mdu-ring 700ms ease-in-out;
}

/* Arrows in links and buttons lean the way they point. */
a .bi-arrow-right,
.btn .bi-arrow-right {
    display: inline-block;
    transition: transform var(--mdu-transition);
}

a:not(.stat-card__link):hover .bi-arrow-right,
a:not(.stat-card__link):focus-visible .bi-arrow-right,
.btn:hover .bi-arrow-right {
    transform: translateX(3px);
}

/* While a form is sending, the spinner takes the icon's place rather than
   sitting beside it. */
[data-submit-spinner]:not(.d-none) + .bi {
    display: none;
}

/* A newly chosen picture fades in instead of snapping over the old one. */
.image-preview img,
[data-photo-preview] img {
    animation: mdu-fade-in 220ms ease-out;
}

/* Dashboard charts: each column grows from the baseline, the ring draws
   round. Once, on first paint — the numbers are the page's whole point. */
@keyframes mdu-grow-up {
    from { scale: 1 0; }
    to   { scale: 1; }
}

.chart__col {
    transform-box: fill-box;
    transform-origin: 50% 100%;
    animation: mdu-grow-up 520ms var(--mdu-ease-out) both;
    /* A slight left-to-right sweep, capped so a 30-day chart is not still
       drawing its last column half a second later. */
    animation-delay: min(calc(var(--i, 0) * 14ms), 280ms);
}

@keyframes mdu-draw {
    from { stroke-dasharray: 0 400; }
}

.health__segment {
    animation: mdu-draw 700ms var(--mdu-ease-out) both;
}

/* ==========================================================================
   Phone fixes (found in the 2026-09-25 audit)
   ========================================================================== */

/* A dropdown's text must stop short of its chevron. The shared field padding
   above reset Bootstrap's right padding, so a long choice ran under the arrow. */
.form-select {
    padding-right: 2.25rem;
}

/* A table wider than its card keeps its action column in view: the thing you
   came to tap should not be 500px to the right. mdu.js adds .is-scrollable
   only while the table actually overflows, so wide screens are unchanged. */
.is-scrollable :is(.table, .variant-table) > :is(thead, tbody) > tr:not(.variant-panel) > .col-sticky {
    position: sticky;
    right: 0;
    z-index: 1;
    background-color: var(--mdu-card);
    box-shadow: -1px 0 0 var(--mdu-border), -8px 0 12px -10px rgba(16, 24, 40, .35);
}

.is-scrollable .table > thead > tr > .col-sticky {
    background-color: #FAFBFC;
    z-index: 3;
}

.is-scrollable .table > tbody > tr:hover > .col-sticky {
    background-color: var(--mdu-red-light);
}

.is-scrollable .variant-table > :is(thead, tbody) > tr > .col-sticky {
    background-color: #FAFBFC;
}

@media (max-width: 767.98px) {
    /* iPhones zoom into any field under 16px when it is tapped, and stay
       zoomed after leaving it. 16px on phones keeps the page still. */
    .form-control,
    .form-select,
    .vpicker__search input,
    textarea,
    input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="range"]) {
        font-size: 16px;
    }
}

@media (max-width: 575.98px) {
    /* The notification list keeps the page's 16px gutter. The positioning
       library would otherwise clamp it flush against the screen's edge. */
    .reminder-menu.show {
        position: fixed !important;
        inset: calc(var(--mdu-topbar-height) - 4px) 1rem auto 1rem !important;
        transform: none !important;
        width: auto;
    }

    /* An info bubble keeps a margin from the screen edge too. */
    .info-hint__bubble {
        max-width: calc(100vw - 3.5rem);
    }

    /* Summary cards stay one per row, but shorter: five of them used to take
       two whole screens before the data they summarise. */
    .stat-card {
        padding: .875rem 1rem;
    }

    .stat-card__head {
        margin-bottom: .25rem;
    }

    .stat-card__icon {
        width: 32px;
        height: 32px;
        font-size: 1rem;
        border-radius: 8px;
    }

    .stat-card__value {
        font-size: 1.5rem;
    }

    .stat-card__link {
        margin-top: .375rem;
    }

    /* A product without a photo does not spend a whole screen saying so. */
    .product-thumb--lg.product-thumb--placeholder {
        aspect-ratio: auto;
        height: 120px;
    }
}
