/* ==========================================================================
   RaceX Portál — global stylesheet
   Sections: 1. Tokens  2. Reset  3. Header/Nav  4. User menu  5. Layout
             6. Page toolbar  7. Buttons & controls  8. Table  9. Progress
             10. Shipments  11. Login  12. Empty state  13. Responsive
   ========================================================================== */

/* 1. Design tokens ------------------------------------------------------- */
:root {
    --bg: #f4f5f7;
    --surface: #ffffff;
    --border: #e7e9ee;
    --border-strong: #dcdfe6;

    --text: #232833;
    --text-muted: #8b919d;
    --text-soft: #aab0bb;

    --green: #a4cf4d;
    --green-mid: #c3de88;
    --green-track: #eaedf1;
    /* The band between two expedition-date groups in the ordered-parts table. */
    --date-seam: #ebf4fd;
    --green-text: #74a53a;
    --success-subtle: #dcfe98;
    --success-bold: #a2ef1d;
    --success-primary: #41670d;
    --success-secondary: #68ab05;

    --blue-avatar-bg: #dbe8f6;
    --blue-avatar-text: #5b81ac;

    --brand-orange: #e8712a;
    --brand-primary: #1c2c4f;
    --brand-secondary: #71829f;
    --brand-sky: #deecfb;
    --brand-highlight: #428ee6;
    --topbar-bg: #0f172a;

    --dot-purple: #b06ef0;
    --dot-green: #7ec13f;
    --dot-yellow: #f0c33f;
    --dot-red: #f0685a;
    --dot-blue: #5aa9f0;

    --radius: 10px;
    --radius-sm: 8px;
    --shadow: 0 1px 3px rgba(23, 28, 40, .06), 0 1px 2px rgba(23, 28, 40, .04);
    --shadow-pop: 0 8px 28px rgba(23, 28, 40, .14);

    --topbar-h: 41px;
    --header-h: 68px;
    /* The toolbar wraps, so its height is not a constant — app.js measures it
       onto each .card. This is the one-row desktop height, used until it does
       and if scripts never run at all. */
    --toolbar-h: 80px;
    --font: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
}

/* 2. Reset --------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

/* `min-height` on the body, not `height`: a sticky element can only stick
   inside its containing block, and the header's is the body's content box. With
   a fixed `height: 100%` that box is exactly one screen tall, so the sticky
   header and top bar were carried off the moment you scrolled past the first
   screenful — on a long table that looks like the menu vanishing at random.
   `min-height` keeps the body as tall as the page, and the two bars stay put
   all the way down. `html` keeps its height so the percentage resolves. */
html { height: 100%; }
body { min-height: 100%; }

body.app-body {
    margin: 0;
    font-family: var(--font);
    font-size: 14px;
    line-height: 1.45;
    color: var(--text);
    background: var(--bg);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}

a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; }
img { max-width: 100%; display: block; }

.icon { width: 18px; height: 18px; flex: 0 0 auto; }
.icon--chevron { width: 16px; height: 16px; }

/* 3. Header & navigation ------------------------------------------------- */
/* Thin dark RaceX brand strip above the customer header. */
/* Sticks above the customer header, which then sticks below it — the two are
   one block, so the RaceX strip must not scroll out from under it. Its height
   is a token because .app-header's `top` has to be exactly this. */
.topbar {
    position: sticky;
    top: 0;
    z-index: 60;
    background: var(--topbar-bg);
    color: #fff;
}
.topbar__inner {
    display: flex;
    align-items: center;
    height: var(--topbar-h);
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 28px;
}
.topbar__brand { display: inline-flex; align-items: center; gap: 10px; }
/* Full-colour horizontal wordmark (500×147). */
.topbar__logo { height: 29px; width: auto; }
.topbar__sub {
    font-size: 10px;
    font-weight: 700;
    line-height: 16px;
    letter-spacing: 0;
    text-transform: uppercase;
    color: #fff;
}

.app-header {
    position: sticky;
    top: var(--topbar-h);
    z-index: 50;
    background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.app-header__inner {
    display: flex;
    align-items: center;
    gap: 24px;
    height: var(--header-h);
    max-width: 1400px;
    margin: 0 auto;
    padding: 0 28px;
}

.brand {
    display: flex;
    align-items: center;
    flex: 0 0 auto;
    line-height: 1;
}
.brand__company { height: 35px; width: auto; }
.brand__fallback { font-size: 16px; font-weight: 700; color: var(--text); }

.main-nav {
    display: flex;
    align-items: center;
    gap: 34px;
    margin: 0 auto;
}
.main-nav__link {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    height: var(--header-h);
    font-size: 16px;
    font-weight: 500;
    line-height: 22px;
    letter-spacing: 0;
    color: var(--text-muted);
    border-bottom: 2px solid transparent;
    transition: color .15s ease;
}
.main-nav__link .icon { width: 27px; height: 27px; }
.main-nav__link:hover { color: var(--text); }
.main-nav__link.is-active {
    color: var(--text);
}
.main-nav__link.is-active span {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-underline-offset: 6px;
}

/* 4. Header tools + user menu ------------------------------------------- */
.header-tools {
    position: relative; /* anchors the notification panel to the header's right edge */
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 0 0 auto;
}
.icon-btn {
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: none;
    border-radius: 50%;
    background: transparent;
    color: var(--text-muted);
    transition: background .15s ease, color .15s ease;
}
.icon-btn:hover { background: #f1f2f5; color: var(--text); }
.notif__badge {
    position: absolute;
    top: 3px;
    right: 3px;
    min-width: 17px;
    height: 17px;
    padding: 0 4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    font-weight: 700;
    line-height: 1;
    color: #fff;
    background: #f0503a;
    border: 2px solid var(--surface);
    border-radius: 999px;
}
/* The badge's own display would otherwise beat the UA [hidden] rule. */
.notif__badge[hidden] { display: none; }

.avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    font-size: 12px;
    font-weight: 600;
    flex: 0 0 auto;
    letter-spacing: .02em;
}
.avatar--blue { background: var(--blue-avatar-bg); color: var(--blue-avatar-text); }
.avatar--sm { width: 26px; height: 26px; font-size: 10px; }

.user-menu { position: relative; }
.user-menu__trigger {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 5px 8px 5px 5px;
    border: none;
    background: transparent;
    border-radius: 999px;
    color: var(--text);
    transition: background .15s ease;
}
.user-menu__trigger:hover { background: #f1f2f5; }
.user-menu__meta { display: flex; flex-direction: column; line-height: 1.2; text-align: left; }
.user-menu__name { font-size: 14px; font-weight: 500; line-height: 20px; letter-spacing: 0; }
.user-menu__company { font-size: 14px; font-weight: 400; line-height: 20px; letter-spacing: 0; color: var(--text-muted); }
.user-menu__trigger .icon { color: var(--text-soft); transition: transform .2s ease; }
.user-menu.is-open .user-menu__trigger .icon { transform: rotate(180deg); }

.user-menu__dropdown {
    position: absolute;
    top: calc(100% + 8px);
    right: 0;
    min-width: 190px;
    padding: 6px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-pop);
}
.user-menu__dropdown[hidden] { display: none; }
.user-menu__item {
    display: block;
    padding: 9px 12px;
    font-size: 13px;
    border-radius: 6px;
    color: var(--text);
}
.user-menu__item:hover { background: #f4f5f7; }
.user-menu__item--danger { color: #d84a3b; }
.user-menu__sep { height: 1px; margin: 6px 4px; background: var(--border); }

/* Notification bell dropdown. Right-aligned to the header tools; the caret is
   nudged under the bell by notifications.js. */
.notif-panel {
    position: absolute;
    top: calc(100% + 12px);
    right: 0;
    z-index: 40;
    width: 440px;
    max-width: calc(100vw - 32px);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    box-shadow: var(--shadow-pop);
}
.notif-panel[hidden] { display: none; }
.notif-panel__caret {
    position: absolute;
    top: -7px;
    left: 50%;
    margin-left: -6px;
    width: 12px;
    height: 12px;
    background: var(--surface);
    border-left: 1px solid var(--border);
    border-top: 1px solid var(--border);
    border-radius: 3px 0 0 0;
    transform: rotate(45deg);
}
.notif-panel__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 16px 20px 14px;
}
.notif-panel__title { font-size: 15px; font-weight: 700; color: var(--text); }
.notif-panel__mark {
    padding: 0;
    border: none;
    background: transparent;
    font-size: 14px;
    font-weight: 500;
    color: var(--brand-highlight);
}
.notif-panel__mark:hover { text-decoration: underline; }
.notif-panel__body {
    max-height: 440px;
    overflow-y: auto;
    border-top: 1px solid var(--border);
    border-radius: 0 0 12px 12px;
}

.notif-item {
    display: block;
    padding: 14px 20px 16px;
    color: var(--text);
    border-bottom: 1px solid var(--border);
    transition: background .15s ease;
}
.notif-item:last-child { border-bottom: none; }
.notif-item.is-unread { background: #f5f7fa; }
.notif-item:hover { background: #eaeef5; }
.notif-item__cat {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    color: var(--brand-primary);
}
.notif-item__cat .icon { width: 17px; height: 17px; }
.notif-item__cat-label { font-size: 14px; font-weight: 600; }
.notif-item__pill {
    padding: 2px 10px;
    font-size: 12px;
    font-weight: 500;
    color: var(--brand-primary);
    background: var(--brand-sky);
    border-radius: 999px;
}
.notif-item__text { display: block; font-size: 14px; line-height: 20px; }
.notif-item__text strong { font-weight: 700; }
/* Already-read items stay legible but visibly recede. */
.notif-item.is-read .notif-item__cat,
.notif-item.is-read .notif-item__text { color: var(--text-muted); }
.notif-item.is-read .notif-item__text strong { font-weight: 500; color: var(--text); }
.notif-item__time { display: block; margin-top: 6px; font-size: 12px; color: var(--text-soft); }

.notif-empty { padding: 26px 20px; font-size: 14px; color: var(--text-muted); text-align: center; }

/* Placeholder rows while the panel is fetched. */
.notif-skeleton {
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 16px 20px 18px;
    border-bottom: 1px solid var(--border);
}
.notif-skeleton:last-of-type { border-bottom: none; }
.skeleton {
    display: block;
    height: 12px;
    border-radius: 6px;
    background: linear-gradient(90deg, #eef0f4 25%, #e2e5ea 50%, #eef0f4 75%);
    background-size: 240px 100%;
    animation: skeleton-shimmer 1.3s linear infinite;
}
.skeleton--cat { width: 34%; height: 14px; }
.skeleton--text { width: 88%; }
.skeleton--time { width: 22%; height: 10px; }
@keyframes skeleton-shimmer {
    from { background-position: -120px 0; }
    to { background-position: 240px 0; }
}

/* 4b. Page loading indicator -------------------------------------------- */
.page-loader {
    position: fixed;
    inset: 0;
    z-index: 200;
    pointer-events: none;
}
.page-loader[hidden] { display: none; }
/* Only the card blocks interaction — the bar alone should not swallow clicks. */
.page-loader.is-blocking {
    pointer-events: auto;
    background: rgba(244, 245, 247, .5);
}
.page-loader__bar {
    width: 0;
    height: 3px;
    background: var(--brand-highlight);
    box-shadow: 0 0 8px rgba(66, 142, 230, .5);
}
/* Creeps towards — never reaches — the end: the real duration is unknown. */
.page-loader.is-active .page-loader__bar { animation: page-loader-bar 10s ease-out forwards; }
@keyframes page-loader-bar {
    0%   { width: 0; }
    35%  { width: 55%; }
    70%  { width: 82%; }
    100% { width: 96%; }
}
.page-loader__card {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 16px 22px;
    font-size: 14px;
    font-weight: 500;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
}
.page-loader__card[hidden] { display: none; }
.spinner {
    width: 18px;
    height: 18px;
    border: 2px solid var(--border-strong);
    border-top-color: var(--brand-highlight);
    border-radius: 50%;
    animation: spinner-rotate .7s linear infinite;
}
@keyframes spinner-rotate { to { transform: rotate(360deg); } }

/* Screen-reader-only status text. */
.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

@media (prefers-reduced-motion: reduce) {
    .skeleton, .spinner, .page-loader.is-active .page-loader__bar { animation: none; }
    .page-loader.is-active .page-loader__bar { width: 96%; }
}

/* 5. Layout -------------------------------------------------------------- */
.app-main {
    max-width: 1400px;
    margin: 0 auto;
    padding: 26px 28px 48px;
}
.card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    /* Both lines on purpose. `hidden` clips the table to the rounded corners
       but makes the card a scroll container, which would trap the sticky table
       header inside a box that never scrolls; `clip` clips exactly the same way
       without becoming one, so the header can pin to the viewport. Browsers too
       old for `clip` ignore the second line and keep the old behaviour. */
    overflow: hidden;
    overflow: clip;
}

/* Company banner (logo strip above the table) */
.company-banner {
    display: flex;
    align-items: center;
    gap: 18px;
    padding: 4px 0 20px;
}
.company-banner--center { justify-content: center; padding: 22px 0 26px; }
.company-banner__logo { height: 46px; width: auto; }

/* 6. Page toolbar -------------------------------------------------------- */
.page-toolbar {
    display: flex;
    align-items: center;
    gap: 16px;
    flex-wrap: wrap;
    padding: 20px 22px;
    /* Rides down the page with the table, directly under the site header, with
       the column names pinned under it in turn. Its own background, or the rows
       would scroll through it; z-index above the header row (20) and below
       .app-header (50). */
    position: sticky;
    top: calc(var(--topbar-h) + var(--header-h));
    z-index: 30;
    background: var(--surface);
}
.page-title {
    margin: 0;
    font-size: 24px;
    font-weight: 600;
    line-height: 36px;
    letter-spacing: 0;
    color: var(--brand-primary);
}
.toolbar-spacer { flex: 1 1 auto; }

.search {
    position: relative;
    display: flex;
    align-items: center;
    min-width: 300px;
}
/* Direct child only: this is the magnifier sitting inside the field. The clear
   button's own icon is a grandchild and must stay where the button puts it. */
.search > .icon {
    position: absolute;
    left: 12px;
    color: var(--text-soft);
    pointer-events: none;
}
.search__input {
    /* Grows to fill the row; .search__clear is attached on its right. */
    flex: 1 1 auto;
    min-width: 0;
    height: 40px;
    padding: 0 14px 0 40px;
    font-size: 13.5px;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    /* Square on the right, where the clear button carries on. */
    border-right: 0;
    border-radius: var(--radius-sm) 0 0 var(--radius-sm);
    outline: none;
    transition: border-color .15s ease;
}
.search__input::placeholder { color: var(--text-soft); }
/* Chrome and Safari draw their own × inside input[type="search"]; Firefox draws
   none at all. Rather than live with the difference, the native one is switched
   off and .search__clear below is the one every browser gets — same place, same
   size, and it can carry a tooltip and an aria-label. */
.search__input::-webkit-search-cancel-button,
.search__input::-webkit-search-decoration {
    -webkit-appearance: none;
    appearance: none;
}
/* Attached to the field rather than floating inside it: same height, shared
   border, rounded only on the outer edge, so the two read as one control. */
.search__clear {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 40px;
    padding: 0;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
    color: var(--text-soft);
    cursor: pointer;
}
.search__clear .icon { width: 13px; height: 13px; }
.search__clear:hover { color: var(--text); background: var(--brand-sky); }
.search__clear:focus-visible { outline: 2px solid var(--dot-blue); outline-offset: -2px; }
/* The focus ring belongs to the pair, not to the field — half a ring around
   half a control is what a split border looks like otherwise. */
.search:focus-within {
    border-radius: var(--radius-sm);
    box-shadow: 0 0 0 3px rgba(90, 129, 172, .12);
}
.search:focus-within .search__input,
.search:focus-within .search__clear { border-color: #b9c6d6; }

/* 7. Buttons & controls -------------------------------------------------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    padding: 0 14px;
    font-size: 13px;
    font-weight: 600;
    color: #4a5160;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    transition: background .15s ease, border-color .15s ease, color .15s ease;
}
.btn:hover { background: #f7f8fa; border-color: #cfd4dd; }
.btn .icon { width: 16px; height: 16px; }
.btn--link {
    border: none;
    background: transparent;
    color: var(--brand-highlight);
    padding: 0 6px;
}
.btn--link:hover { background: transparent; color: #2f7bd0; text-decoration: underline; }

/* Segmented toggle (Shipping dates / Parts) */
.toggle-group {
    display: inline-flex;
    padding: 3px;
    background: #eef0f3;
    border-radius: var(--radius-sm);
}
.toggle-group__btn {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    height: 32px;
    padding: 0 14px;
    font-size: 13px;
    font-weight: 600;
    color: var(--text-muted);
    background: transparent;
    border: none;
    border-radius: 6px;
}
.toggle-group__btn.is-active {
    color: var(--text);
    background: var(--surface);
    box-shadow: var(--shadow);
}

/* Date-range picker (period the table is limited to) */
.daterange {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    height: 40px;
    padding: 0 8px 0 12px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
}
.daterange__label {
    font-size: 12px;
    font-weight: 600;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: .3px;
    white-space: nowrap;
}
.daterange__input {
    width: 124px;
    height: 28px;
    padding: 0 6px;
    font: inherit;
    font-size: 13px;
    color: var(--text);
    background: transparent;
    border: 1px solid transparent;
    border-radius: 6px;
    outline: none;
}
.daterange__input:hover { border-color: var(--border); }
.daterange__input:focus {
    border-color: #b9c6d6;
    box-shadow: 0 0 0 3px rgba(90, 129, 172, .12);
}
.daterange__sep { color: var(--text-soft); }
.daterange__clear {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    color: var(--text-soft);
    background: transparent;
    border: none;
    border-radius: 50%;
}
.daterange__clear:hover { color: var(--text); background: #eef0f3; }
.daterange__clear .icon { width: 13px; height: 13px; }
.daterange__clear[hidden] { display: none; }

/* Checkbox control */
.check {
    display: inline-flex;
    align-items: center;
    gap: 9px;
    font-size: 13.5px;
    color: var(--text);
    user-select: none;
    cursor: pointer;
}
.check input { width: 16px; height: 16px; accent-color: var(--green); }

/* 8. Table --------------------------------------------------------------- */
/* No `overflow-x` here on wide screens, deliberately: an element that scrolls
   on either axis becomes the containing block for `position: sticky` inside it,
   and this wrapper is exactly as tall as its table — so a sticky header would
   pin itself to a box that never scrolls and never move. The horizontal scroll
   is switched on at 960px in the responsive section, where the tables stop
   fitting and a pinned header matters less than reaching the last column. */
.table-wrap { width: 100%; }
.data-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 13.5px;
}
/* Child combinators, not a descendant selector: the expandable detail rows hold
   nested tables (RFQ parts, material movements) whose own <thead> sits inside
   this tbody. A plain `.data-table thead th` reached those too and made them
   sticky — an opaque header with a 190px offset and z-index 20 parks itself on
   top of the rows underneath, so an expanded panel came out looking empty. */
.data-table > thead > tr > th {
    padding: 11px 16px;
    text-align: left;
    font-size: 12px;
    font-weight: 700;
    line-height: 18px;
    letter-spacing: 0;
    text-transform: uppercase;
    color: var(--brand-secondary);
    background: var(--brand-sky);
    white-space: nowrap;
    /* Pinned under the two bars that are already sticky, so the column names
       stay readable down a long table. z-index sits above the rows but below
       .app-header (50) and .topbar (60), which must still cover it. */
    position: sticky;
    top: calc(var(--topbar-h) + var(--header-h) + var(--toolbar-h));
    z-index: 20;
    /* Hairlines as insets rather than borders: with `border-collapse: collapse`
       the borders belong to the table grid, not to the cell, so they stay
       behind while a sticky cell moves and the header loses its edges. */
    box-shadow: inset 0 1px 0 var(--border), inset 0 -1px 0 var(--border);
}
.data-table th.sortable { cursor: pointer; }
.data-table th.sortable .sort-caret {
    display: inline-block;
    margin-left: 5px;
    color: var(--text-muted);
    font-size: 9px;
    vertical-align: middle;
}
/* No caret, no gap after the label — keeps a right-aligned header flush with
   the numbers it sits above. */
.data-table th.sortable .sort-caret:empty { margin-left: 0; }
.data-table tbody td {
    padding: 14px 16px;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}
.data-table tbody tr:hover { background: #fafbfc; }
.data-table tbody tr.is-hidden { display: none; }
/* Expedition-date grouping (ordered parts, shipping-dates layout): rows sharing
   a date sit together and a 12px band opens where the date changes. The band is
   a collapsed top border, so it takes the place of that row's divider line
   rather than adding to it — the gap is the separator.
   Its own colour rather than the card's white: white on white is a gap you have
   to go looking for, and a tinted band reads as the table being cut through.
   A fixed colour and not transparent, so hovering the row below it does not
   tint the band along with the row. */
.data-table tbody tr.is-date-group-start > td { border-top: 12px solid var(--date-seam); }

/* Click a value to search for it. A plain button so the row's own click
   handler skips it (it ignores a, button, input, label) and so it is reachable
   by keyboard — the cell has to stay a value, not become a link to somewhere. */
.cell-search {
    appearance: none;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: inherit;
    cursor: pointer;
    display: inline-block;
    max-width: 100%;
}
/* The underline is the "this is clickable" hint and it appears at once — no
   transition anywhere on these, on purpose. */
.cell-search:hover,
.cell-search:focus-visible {
    color: var(--brand-primary);
    text-decoration: underline;
    text-underline-offset: 2px;
}
.cell-search:focus-visible { outline: 2px solid var(--dot-blue); outline-offset: 2px; border-radius: 2px; }

/* The avatar version: an underline under a circle looks like a mistake, so it
   lifts and picks up a ring instead. */
.avatar-search {
    appearance: none;
    padding: 0;
    border: 0;
    background: none;
    cursor: pointer;
    line-height: 0;
    border-radius: 999px;
}
.avatar-search:hover .avatar,
.avatar-search:focus-visible .avatar {
    box-shadow: 0 0 0 2px var(--brand-sky), 0 0 0 3px var(--dot-blue);
}
.avatar-search:focus-visible { outline: none; }

.cell-date { font-weight: 600; color: var(--text); white-space: nowrap; }
.cell-muted { color: var(--text-muted); white-space: nowrap; }
.cell-order {
    font-size: 14px;
    font-weight: 400;
    line-height: 20px;
    letter-spacing: 0;
    color: var(--brand-primary);
    font-variant-numeric: tabular-nums;
}

.part-name {
    font-size: 14px;
    font-weight: 600;
    line-height: 20px;
    letter-spacing: 0;
    color: var(--brand-primary);
}
.part-name .ver { color: var(--text-muted); font-weight: 500; }
.part-meta {
    margin-top: 2px;
    font-size: 12px;
    font-weight: 400;
    line-height: 18px;
    letter-spacing: 0;
    color: var(--brand-secondary);
}
.part-meta .sep { margin: 0 8px; color: var(--border-strong); }

/* Category status dot */
.dot {
    display: inline-block;
    width: 11px;
    height: 11px;
    border-radius: 50%;
    background: var(--text-soft);
}
.dot--purple { background: var(--dot-purple); }
.dot--green  { background: var(--dot-green); }
.dot--yellow { background: var(--dot-yellow); }
.dot--red    { background: var(--dot-red); }
.dot--blue   { background: var(--dot-blue); }

/* Current shipment mini columns */
.ship-cols { display: flex; align-items: center; gap: 22px; }
.ship-col { display: flex; flex-direction: column; align-items: center; gap: 2px; min-width: 34px; }
.ship-col__label { font-size: 10px; letter-spacing: .04em; text-transform: uppercase; color: var(--text-soft); }
.ship-col__value { font-size: 14px; font-weight: 600; color: var(--text); }
.ship-col__value--ready { color: var(--green-text); }
.ship-col__value--muted { color: var(--text-soft); }

/* Ready pill (production page) */
.ready-pill {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    padding: 5px 12px;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    line-height: 1.15;
}
.ready-pill__label { font-size: 10px; letter-spacing: .03em; color: var(--text-muted); }
.ready-pill__value { font-size: 14px; font-weight: 700; color: var(--text); }

/* 9. Progress bar -------------------------------------------------------- */
.progress { display: flex; align-items: center; gap: 10px; }
.progress__bar {
    display: flex;
    align-items: stretch;
    height: 18px;
    min-width: 190px;
    flex: 1 1 auto;
    border-radius: 3px;
    /* No overflow clipping: the QC marker box + its caret pop out of the bar. */
    background: var(--green-track);
}
.progress__seg {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    font-weight: 700;
    color: #fff;
    min-width: 14px;
}
.progress__seg--done { background: var(--green); border-radius: 3px 0 0 3px; }
.progress__seg--rest { background: transparent; color: var(--text-muted); border-radius: 0 3px 3px 0; }

/* QC / in-progress segment — a raised white marker box with a pointer caret. */
.progress__seg--qc {
    position: relative;
    z-index: 1;
    height: 22px;
    margin: -2px 0;
    color: var(--text);
    background: #fff;
    border: 1px solid var(--border-strong);
    border-radius: 4px;
    box-shadow: 0 1px 2px rgba(23, 28, 40, .12);
}
.progress__seg--qc::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 4px solid transparent;
    border-right: 4px solid transparent;
    border-top: 5px solid #b9bfc9;
}
.progress__total { font-size: 13px; font-weight: 700; color: var(--text); font-variant-numeric: tabular-nums; }
.progress__caption { margin-top: 5px; font-size: 10.5px; letter-spacing: .04em; color: var(--text-soft); text-transform: uppercase; }

/* 10. Expandable shipments (production) ---------------------------------- */
.row-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    border: none;
    background: transparent;
    color: var(--text-muted);
    border-radius: 6px;
}
.row-toggle:hover { background: #eef0f3; color: var(--text); }
.row-toggle .icon { transition: transform .2s ease; }
.row-toggle.is-open .icon { transform: rotate(180deg); }

.ship-detail-row > td { padding: 0; background: #f7f9fb; border-bottom: 1px solid var(--border); }
.ship-detail-row.is-hidden { display: none; }
.ship-detail {
    display: flex;
    align-items: stretch;
    gap: 16px;
    padding: 18px 22px 22px 60px;
}
.ship-total {
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    padding-right: 14px;
}
.ship-total__label { font-size: 10px; letter-spacing: .05em; text-transform: uppercase; color: var(--text-soft); }
.ship-total__value { font-size: 22px; font-weight: 700; }

.ship-group {
    flex: 1 1 0;
    max-width: 260px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding: 12px 14px;
}
.ship-group--current { border-color: #b9c6d6; box-shadow: 0 0 0 3px rgba(90, 129, 172, .10); }
.ship-group__title {
    display: flex;
    align-items: center;
    gap: 7px;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin-bottom: 10px;
}
.ship-group__title .icon { width: 14px; height: 14px; color: var(--text-soft); }
.ship-line {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 6px 0;
    font-size: 13px;
    border-top: 1px solid var(--border);
}
.ship-line:first-of-type { border-top: none; }
.ship-line__qty { display: inline-flex; align-items: center; gap: 6px; color: var(--blue-avatar-text); font-weight: 600; }
.ship-line__qty .icon { width: 14px; height: 14px; }
.ship-line__date { color: var(--text-muted); }
.ship-group--empty { display: flex; align-items: center; justify-content: center; color: var(--text-soft); }

/* 11. Login -------------------------------------------------------------- */
body.login-body {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    background: radial-gradient(1200px 600px at 50% -10%, #eef1f5 0%, var(--bg) 60%);
}
.login-card {
    width: 100%;
    max-width: 400px;
    margin: 24px;
    padding: 36px 34px 34px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    box-shadow: var(--shadow-pop);
}
.login-brand { display: flex; flex-direction: column; align-items: center; margin-bottom: 26px; }
.login-brand img { height: 40px; }
.login-brand span {
    margin-top: 6px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .18em;
    text-transform: uppercase;
    color: var(--text);
}
.login-title { text-align: center; font-size: 18px; font-weight: 700; margin: 0 0 22px; }
.form-field { margin-bottom: 16px; }
.form-field label { display: block; font-size: 12.5px; font-weight: 600; color: var(--text-muted); margin-bottom: 7px; }
.form-control {
    width: 100%;
    height: 44px;
    padding: 0 14px;
    font-size: 14px;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
    outline: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.form-control:focus {
    border-color: #b9c6d6;
    box-shadow: 0 0 0 3px rgba(90, 129, 172, .12);
}
.form-row-between { display: flex; align-items: center; justify-content: space-between; margin: 4px 0 20px; }
.btn-primary {
    width: 100%;
    height: 46px;
    font-size: 14.5px;
    font-weight: 700;
    color: #fff;
    background: var(--brand-orange);
    border: none;
    border-radius: var(--radius-sm);
    transition: background .15s ease, transform .05s ease;
}
.btn-primary:hover { background: #d5641f; }
.btn-primary:active { transform: translateY(1px); }
.alert {
    padding: 11px 14px;
    margin-bottom: 18px;
    font-size: 13px;
    border-radius: var(--radius-sm);
    background: #fdecea;
    border: 1px solid #f5c6c0;
    color: #b03a2e;
}
.login-hint {
    margin-top: 20px;
    padding-top: 16px;
    border-top: 1px solid var(--border);
    font-size: 12px;
    color: var(--text-muted);
    text-align: center;
    line-height: 1.6;
}

/* 12. Empty state -------------------------------------------------------- */
.empty-state {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    text-align: center;
    padding: 90px 24px;
    color: var(--text-muted);
}
.empty-state .icon { width: 44px; height: 44px; color: var(--text-soft); margin-bottom: 16px; }
.empty-state h2 { font-size: 18px; color: var(--text); margin: 0 0 6px; }
.empty-state p { margin: 0; max-width: 380px; }
.no-results { padding: 48px; text-align: center; color: var(--text-muted); }

/* "Load more" footer of a paged table. */
.table-more {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    padding: 18px 20px 22px;
    border-top: 1px solid var(--border);
}
.table-more__count { font-size: 13px; color: var(--text-muted); }
.table-more__count:empty { display: none; }
.table-more [hidden] { display: none; }
.table-more__loading {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: 13px;
    color: var(--text-muted);
}
/* Rows being replaced stay visible but clearly stale. */
.data-table.is-reloading tbody { opacity: .45; pointer-events: none; }

/* 13. Responsive ---------------------------------------------------------
   Four steps, each dropping what stops fitting rather than shrinking
   everything: 960 gives the toolbars room, 720 turns the header into icons and
   the toolbar into stacked rows, 560 makes the wide controls full-width, 480
   drops the customer logo. The tables themselves are never squeezed — they scroll
   inside .table-wrap, because a shipment bar or a six-column row reflowed into
   a phone width stops being readable long before it stops fitting. */
@media (max-width: 960px) {
    .topbar__inner,
    .app-header__inner { padding: 0 20px; }
    .app-main { padding: 22px 20px 40px; }
    .main-nav { gap: 20px; }
    .user-menu__meta { display: none; }
    .search { min-width: 200px; }
    .daterange__label { display: none; }
    .daterange__input { width: 116px; }

    /* Below this width the tables stop fitting, so the wrapper takes over the
       horizontal scroll — which also makes it the sticky containing block, and
       the header stops pinning. Reaching the last column wins here. */
    .table-wrap { overflow-x: auto; }

    /* Ten columns stop being readable well before the screen runs out — a card
       narrower than its own date says nothing. Below this the block fits as
       many whole cards as it can instead. */
    .op-detail__ships { grid-template-columns: repeat(auto-fill, minmax(84px, 1fr)); }
}
@media (max-width: 720px) {
    .topbar__inner { padding: 0 14px; }
    .app-header__inner { gap: 12px; padding: 0 14px; }
    .app-main { padding: 16px 12px 32px; }

    /* A customer logo is any shape at all, so cap both dimensions. */
    .brand__company { height: 26px; max-width: 96px; object-fit: contain; }

    /* Labels off, icons only. min-width:0 lets the nav shrink instead of
       pushing the tools off the edge, and it scrolls if even that is too
       tight — the page itself must never scroll sideways. */
    .main-nav {
        gap: 16px;
        min-width: 0;
        overflow-x: auto;
        scrollbar-width: none;
    }
    .main-nav::-webkit-scrollbar { display: none; }
    .main-nav__link span { display: none; }
    .main-nav__link .icon { width: 24px; height: 24px; }
    /* The active tab is normally marked by underlining its label, which is now
       hidden — without this there is no telling which page you are on. */
    .main-nav__link.is-active { border-bottom-color: var(--green); }

    /* The avatar is already the obvious thing to tap, so its chevron goes. */
    .header-tools { gap: 6px; }
    .user-menu__trigger { gap: 0; padding: 5px; }
    .user-menu__trigger .icon--chevron { display: none; }

    .page-title { font-size: 20px; line-height: 28px; }
    .page-toolbar { gap: 10px; padding: 16px; }
    /* Its own full row, so what is left of the toolbar keeps a sane width. */
    .search { flex: 1 1 100%; min-width: 0; }

    /* Tighter rows fit more of a table into one screenful of scrolling. */
    .data-table { font-size: 13px; }
    .data-table thead th { padding: 9px 12px; }
    .data-table tbody td { padding: 11px 12px; }
    .ship-status { min-width: 230px; }
    .table-more { gap: 10px; padding: 14px 16px 18px; }

    /* Total above the shipment cards instead of beside them. */
    .op-detail { flex-direction: column; gap: 12px; padding: 14px 16px 18px; }
    .op-detail__total { min-width: 0; padding: 10px 16px; }
    .mat-detail { padding: 12px 16px 16px; }

    .card-head { padding: 16px; }
    .card-body { padding: 16px; }
    .company-banner { padding: 2px 0 14px; }
    .company-banner__logo { height: 36px; }
}
@media (max-width: 560px) {
    /* Controls that cannot usefully be narrowed take a row of their own. */
    .toggle-group { flex: 1 1 100%; }
    .toggle-group__btn { flex: 1 1 0; justify-content: center; }
    .daterange { flex: 1 1 100%; justify-content: space-between; }
    .daterange__input { flex: 1 1 0; width: auto; min-width: 0; }
    .viewing-as { flex-direction: column; gap: 8px; text-align: center; }
}
@media (max-width: 480px) {
    .app-header__inner { gap: 8px; }
    /* Last thing to go, and the only one that carries no information: they know
       whose portal they are on, and the RaceX strip above says the rest. */
    .brand { display: none; }
    .main-nav { gap: 10px; }
    .topbar__logo { height: 24px; }
    .page-toolbar { padding: 14px 12px; }
}

/* 14. Auth pages (login / request access / reset) ------------------------ */
:root {
    --auth-blue: #3b6fd4;
    --auth-blue-hover: #315fbb;
    --auth-heading: #1f2b3d;
    --auth-text: #5b6474;
    --auth-muted: #8b93a1;
    --auth-input-border: #dbe0e8;
    --auth-lime: #a4d420;
}
body.auth-body {
    margin: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 100vh;
    padding: 40px 20px;
    font-family: var(--font);
    color: var(--auth-heading);
    background: var(--surface);
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}
.auth-shell { width: 100%; max-width: 470px; }
.auth-brand { display: flex; justify-content: center; margin-bottom: 22px; }
.auth-brand img { display: block; height: 58px; width: auto; }
.auth-card {
    padding: 34px 36px 30px;
    background: #f6f7f9;
    border: 1px solid #ebedf1;
    border-radius: 16px;
    box-shadow: 0 10px 30px rgba(23, 28, 40, .06);
}
.auth-title { font-size: 26px; font-weight: 700; color: var(--auth-heading); margin: 0 0 8px; }
.auth-subtitle { font-size: 15px; color: var(--auth-text); margin: 0 0 26px; line-height: 1.5; }

/* Back link */
.auth-back {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    margin-bottom: 22px;
    font-size: 14px;
    font-weight: 500;
    color: var(--auth-muted);
    transition: color .15s ease;
}
.auth-back:hover { color: var(--auth-heading); }
.auth-back .bi { font-size: 16px; line-height: 1; }

/* Fields */
.auth-field { margin-bottom: 18px; }
.auth-field label { display: block; font-size: 13.5px; font-weight: 600; color: var(--auth-heading); margin-bottom: 8px; }
.auth-input {
    width: 100%;
    height: 50px;
    padding: 0 15px;
    font-size: 15px;
    font-family: inherit;
    color: var(--auth-heading);
    background: var(--surface);
    border: 1px solid var(--auth-input-border);
    border-radius: 10px;
    outline: none;
    transition: border-color .15s ease, box-shadow .15s ease;
}
.auth-input::placeholder { color: #a9b0bc; }
.auth-input:focus {
    border-color: var(--auth-blue);
    box-shadow: 0 0 0 3px rgba(59, 111, 212, .14);
}

/* Password field with SHOW/HIDE toggle */
.auth-password { position: relative; }
.auth-password .auth-input { padding-right: 64px; }
.auth-toggle {
    position: absolute;
    top: 0;
    right: 14px;
    height: 50px;
    padding: 0;
    background: none;
    border: none;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .08em;
    color: var(--auth-muted);
    cursor: pointer;
    transition: color .15s ease;
}
.auth-toggle:hover { color: var(--auth-heading); }

/* Forgot password (right aligned under password) */
.auth-forgot { text-align: right; margin: 10px 0 22px; }
.auth-forgot a { font-size: 13.5px; font-weight: 600; color: var(--auth-heading); }
.auth-forgot a:hover { text-decoration: underline; }

/* Buttons */
.auth-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    height: 52px;
    font-size: 15px;
    font-family: inherit;
    font-weight: 700;
    color: #fff;
    background: var(--auth-blue);
    border: none;
    border-radius: 10px;
    cursor: pointer;
    transition: background .15s ease, transform .05s ease;
}
.auth-btn:hover { background: var(--auth-blue-hover); }
.auth-btn:active { transform: translateY(1px); }
.auth-btn--ghost {
    color: var(--auth-heading);
    background: var(--surface);
    border: 1px solid #d7dce4;
}
.auth-btn--ghost:hover { background: #eceef2; }

/* Divider "NEW TO THE PORTAL?" */
.auth-divider {
    display: flex;
    align-items: center;
    gap: 16px;
    margin: 28px 0 18px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .12em;
    text-transform: uppercase;
    color: var(--auth-muted);
}
.auth-divider::before,
.auth-divider::after { content: ""; flex: 1; height: 1px; background: #e2e5ea; }

/* Info box (portal permission notice) */
.auth-note {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin: 4px 0 22px;
    padding: 12px 14px;
    font-size: 13px;
    line-height: 1.45;
    color: #46536b;
    background: #eef4fb;
    border: 1px solid #d6e4f5;
    border-radius: 10px;
}
.auth-note .bi { flex: none; font-size: 18px; line-height: 1; margin-top: 1px; color: var(--blue-avatar-text); }

/* Inbox confirmation icon */
.auth-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 56px;
    height: 56px;
    margin-bottom: 24px;
    background: var(--auth-lime);
    border-radius: 50%;
}
.auth-icon .bi { font-size: 26px; line-height: 1; color: var(--auth-heading); }

/* Footer / helper line */
.auth-foot { margin-top: 22px; font-size: 14px; color: var(--auth-muted); }
.auth-foot--center { text-align: center; }
.auth-foot--top { margin-top: 28px; padding-top: 20px; border-top: 1px solid #e6e8ec; }
.auth-foot a { font-weight: 700; color: var(--auth-heading); }
.auth-foot a:hover { text-decoration: underline; }

.auth-message { font-size: 15px; color: var(--auth-text); line-height: 1.55; margin: 0 0 26px; }
.auth-message strong { color: var(--auth-heading); }

.auth-alert {
    padding: 11px 14px;
    margin-bottom: 18px;
    font-size: 13.5px;
    border-radius: 10px;
    background: #fdecea;
    border: 1px solid #f5c6c0;
    color: #b03a2e;
}
.auth-alert--ok {
    background: #eef7e6;
    border-color: #cfe6b3;
    color: #5a7d2e;
}

.auth-help { margin: 8px 0 0; font-size: 12.5px; color: var(--auth-muted); line-height: 1.5; }

/* Read-only Helios details shown while activating an account */
.auth-summary {
    margin-bottom: 22px;
    padding: 14px 16px;
    background: #f6f8fa;
    border: 1px solid var(--auth-input-border);
    border-radius: 10px;
}
.auth-summary__row {
    display: flex;
    justify-content: space-between;
    gap: 16px;
    font-size: 13.5px;
    line-height: 1.9;
}
.auth-summary__label { color: var(--auth-muted); }
.auth-summary__value { color: var(--auth-heading); font-weight: 600; text-align: right; }

@media (max-width: 520px) {
    .auth-card { padding: 26px 22px 24px; }
    .auth-title { font-size: 23px; }
}

/* 15. Account / profile pages -------------------------------------------- */
.page-head { margin-bottom: 18px; }
.stack { display: flex; flex-direction: column; gap: 20px; }

.card-head { padding: 20px 22px; border-bottom: 1px solid var(--border); }
.card-head h2 { margin: 0; font-size: 16px; font-weight: 700; color: var(--text); }
.card-head p { margin: 5px 0 0; font-size: 13px; color: var(--text-muted); }
.card-body { padding: 22px; }

.field-row { display: flex; gap: 18px; }
.field-row .form-field { flex: 1 1 0; min-width: 0; }

.form-static {
    display: flex;
    align-items: center;
    height: 44px;
    padding: 0 14px;
    font-size: 14px;
    color: var(--text-muted);
    background: #f4f5f7;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}

.field-help { margin: -4px 0 16px; font-size: 12.5px; color: var(--text-muted); }
.form-actions { margin-top: 4px; }

.btn-primary--inline { width: auto; height: 44px; padding: 0 24px; }

.alert--ok { background: #eef7e6; border-color: #cfe6b3; color: #5a7d2e; }

@media (max-width: 560px) {
    .field-row { flex-direction: column; gap: 0; }
}

/* 16. Tooling page ------------------------------------------------------- */
.cell-id {
    max-width: 130px;
    font-size: 12px;
    color: var(--text-muted);
    line-height: 1.35;
    word-break: break-word;
}
.tool-name-cell { display: flex; align-items: center; gap: 12px; }
/* Name over ID, beside the thumbnail. `min-width: 0` so a long tooling name
   wraps inside the cell instead of stretching the flex row. */
.tool-name-block { min-width: 0; }
.tool-name { font-weight: 500; color: var(--text); }
.thumb {
    width: 46px;
    height: 36px;
    border-radius: 6px;
    object-fit: cover;
    border: 1px solid var(--border);
    background: #f1f2f5;
    flex: 0 0 auto;
}
.thumb--empty { display: grid; place-items: center; color: var(--text-soft); }
.thumb--empty .icon { width: 20px; height: 20px; }
/* A thumbnail that opens the full photo. Button, not an image with a handler,
   so it is reachable by keyboard and the row's own click skips it. */
.thumb-btn {
    padding: 0;
    border: 0;
    background: none;
    line-height: 0;
    border-radius: 6px;
    cursor: zoom-in;
}
.thumb-btn:hover .thumb { border-color: var(--dot-blue); }
.thumb-btn:focus-visible { outline: 2px solid var(--dot-blue); outline-offset: 2px; }

/* Full-size photo overlay (markup in partials/_lightbox.html.twig). */
.lightbox {
    position: fixed;
    inset: 0;
    z-index: 300;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 32px;
    background: rgba(17, 24, 39, .72);
}
.lightbox[hidden] { display: none; }
/* The page behind must not scroll while the overlay is up. */
body.has-lightbox { overflow: hidden; }
.lightbox__frame {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    max-width: 100%;
    max-height: 100%;
}
.lightbox__img {
    max-width: 100%;
    /* Room for the caption under it. */
    max-height: calc(100vh - 120px);
    width: auto;
    height: auto;
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: 0 18px 50px rgba(0, 0, 0, .45);
}
.lightbox__caption {
    font-size: 13px;
    font-weight: 600;
    color: #fff;
    text-align: center;
}
.lightbox__loading,
.lightbox__error {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 0;
    padding: 20px 26px;
    font-size: 13px;
    color: #fff;
}
.lightbox__loading[hidden],
.lightbox__error[hidden] { display: none; }
.lightbox__close {
    position: absolute;
    top: -14px;
    right: -14px;
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: 999px;
    cursor: pointer;
}
.lightbox__close .icon { width: 14px; height: 14px; }
.lightbox__close:hover { background: var(--brand-sky); }
.lightbox__close:focus-visible { outline: 2px solid var(--dot-blue); outline-offset: 2px; }
@media (max-width: 720px) {
    .lightbox { padding: 16px; }
    /* Inside the frame on a small screen — outside it there is no room. */
    .lightbox__close { top: 8px; right: 8px; }
}

/* Condition ring gauge */
.condition-cell { display: flex; align-items: center; gap: 12px; }
.gauge {
    --val: 0;
    --gcolor: var(--dot-green);
    position: relative;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    background: conic-gradient(var(--gcolor) calc(var(--val) * 1%), var(--green-track) 0);
    display: grid;
    place-items: center;
    flex: 0 0 auto;
}
.gauge::before {
    content: "";
    position: absolute;
    inset: 5px;
    background: var(--surface);
    border-radius: 50%;
}
.gauge__num { position: relative; font-size: 11px; font-weight: 700; color: var(--text); }
/* Four digits and a percent sign in a 36px inner circle. */
.gauge__num--tight { font-size: 9px; letter-spacing: -.02em; }
/* Over its designed life: the ring is full, so the excess laps it a second
   time in a darker shade — 120 % is one full turn plus a fifth. The full turn
   underneath is the base colour, which at this point is always red. */
.gauge--over {
    --over: 0;
    background:
        conic-gradient(var(--gover) calc(var(--over) * 1%), var(--gcolor) 0);
}
.gauge--green  { --gcolor: var(--dot-green); }
.gauge--yellow { --gcolor: var(--dot-yellow); }
.gauge--red    { --gcolor: var(--dot-red); --gover: #8f1d12; }
.gauge--na     { --gcolor: var(--border-strong); }
.gauge--na .gauge__num { color: var(--text-soft); }
.gauge-scale { font-size: 13px; color: var(--text-muted); font-variant-numeric: tabular-nums; }

/* 17. RFQ page ----------------------------------------------------------- */
.cell-subject { font-weight: 600; color: var(--text); }
.cell-rfqnum { color: var(--text-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }

/* Status badges */
.badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    height: 28px;
    padding: 0 13px;
    font-size: 12.5px;
    font-weight: 600;
    border-radius: 999px;
    border: 1px solid transparent;
    white-space: nowrap;
}
.badge .icon { width: 14px; height: 14px; }
/* The green deepens as the RFQ advances: the quotation going out is the soft
   outline, and the solid fill is saved for the customer's own approval — the
   furthest an RFQ gets. (These two were the other way round until 2026-09-16.) */
.badge--sent      { background: var(--surface); border-color: #bcdf8e; color: var(--green-text); }
.badge--confirmed { background: #52a83f; color: #fff; }
.badge--rejected { background: var(--surface); border-color: #f3b6ae; color: #d84a3b; }
.badge--received { background: var(--surface); border-color: var(--border-strong); color: var(--text-muted); }
/* Still being worked on, not yet sent — blue, so it reads as "in motion"
   rather than as the muted "waiting on you" of received. */
.badge--progress { background: var(--surface); border-color: var(--dot-blue); color: var(--blue-avatar-text); }

/* Row actions (download + expand) */
.cell-actions { white-space: nowrap; text-align: right; }
.icon-btn-sm {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border: 1px solid var(--border-strong);
    border-radius: 7px;
    /* The download is the one thing on the row you can act on, so it reads as
       near-black on a light grey plate rather than as muted grey on white,
       where it disappeared into the row. */
    color: var(--text);
    background: var(--bg);
    vertical-align: middle;
    transition: background .15s ease, color .15s ease, border-color .15s ease;
}
.icon-btn-sm:hover { background: #e6e8ec; color: #000; border-color: #cfd4dd; }
.icon-btn-sm .icon { width: 16px; height: 16px; }
.icon-btn-sm.is-disabled { opacity: .45; pointer-events: none; }
/* Holds an icon button's place when the button is not drawn, so a column of
   them stays a column. Same box as .icon-btn-sm, nothing visible. */
.icon-btn-spacer { display: inline-block; width: 30px; height: 30px; vertical-align: middle; }

/* Approve / decline and their confirmation, switched off 2026-09-02: the
   decision is made over email. Kept commented so it can come back — see the
   note in templates/rfq/_rows.html.twig for the other pieces that go with it.
   The inner comments are stripped because CSS comments do not nest.

.row-actions { display: inline-flex; gap: 4px; vertical-align: middle; }
.row-actions .icon-btn-sm { padding: 0; font: inherit; cursor: pointer; }
.row-actions .bi { font-size: 17px; line-height: 1; }
.icon-btn-sm--ok { color: var(--green-text); }
.icon-btn-sm--ok:hover { color: #52a83f; border-color: #bcdf8e; background: #eef7e6; }
.icon-btn-sm--no { color: #d84a3b; }
.icon-btn-sm--no:hover { color: #c33a2c; border-color: #f3b6ae; background: #fdeeec; }
.confirm {
    max-width: 380px;
    padding: 22px;
    color: var(--text);
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-pop);
}
.confirm::backdrop { background: rgba(15, 23, 42, .45); }
.confirm__text { margin: 0 0 18px; font-size: 14px; line-height: 1.5; }
.confirm__actions { display: flex; justify-content: flex-end; gap: 8px; }
.btn--strong { color: #fff; background: var(--brand-orange); border-color: var(--brand-orange); }
.btn--strong:hover { background: #d5641f; border-color: #d5641f; }

*/

/* A per-row dropdown — same shape as .lang-menu, which is also a bare
   <details> so that rows arriving as an AJAX batch need nothing bound to
   them. Anchored on the cell, because the row itself is not positioned. */
.cell-actions .row-toggle { vertical-align: middle; margin-left: 4px; }
.row-toggle-spacer { display: inline-block; width: 28px; margin-left: 4px; }

/* Expanded RFQ parts */
.rfq-detail-row > td { padding: 0; background: #eff5fb; border-bottom: 1px solid var(--border); }
.rfq-detail-row.is-hidden { display: none; }
.rfq-detail { padding: 6px 22px 22px 22px; }
.rfq-detail__title {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--text-muted);
    margin: 14px 0 12px;
}
.subtable {
    border-collapse: collapse;
    min-width: 480px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.subtable thead th {
    padding: 10px 16px;
    text-align: left;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--text-soft);
    background: #fafbfc;
    border-bottom: 1px solid var(--border);
    white-space: nowrap;
}
.subtable tbody td { padding: 11px 16px; border-bottom: 1px solid var(--border); }
.subtable tbody tr:last-child td { border-bottom: none; }
.subtable__name { font-weight: 600; color: var(--text); }

/* 18. Shipment status bar (ordered parts) -------------------------------- */
.ship-status { position: relative; min-width: 300px; }
.ship-status__labels {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    margin-bottom: 7px;
}
.ship-status__label {
    font-size: 10px;
    font-weight: 500;
    line-height: 16px;
    letter-spacing: 0;
    text-align: right;
    text-transform: uppercase;
    color: var(--text-soft);
    white-space: nowrap;
}
.ship-status__label b {
    color: var(--text);
    font-weight: 600;
    font-size: 10px;
    line-height: 16px;
    letter-spacing: 0;
}
.ship-status__label--shipped b { color: var(--success-secondary); }

.ship-status__bar {
    display: flex;
    align-items: center;
    height: 16px;
    border-radius: 999px;
    background: var(--green-track);
}
.ship-status__seg { height: 16px; }
.ship-status__seg--delivered { background: var(--success-subtle); border-radius: 999px 0 0 999px; }
.ship-status__seg--remaining { background: transparent; }
/* Planned before the marked shipment but not shipped yet: an empty gap, so the
   marker keeps its place on the timeline. */
.ship-status__seg--planned { background: transparent; }
/* Closes the bar off when no "next shipment" pill follows it. */
.ship-status__seg--delivered.ship-status__seg--last { border-radius: 999px; }
/* Delivered pieces that came *after* the marked shipment — same green, but it
   starts mid-bar, so it is square on the left and only rounds off at the end. */
.ship-status__seg--tail { background: var(--success-subtle); border-radius: 0; }
.ship-status__seg--tail.ship-status__seg--last { border-radius: 0 999px 999px 0; }

/* The "next shipment" marker pill sitting on the bar. */
.ship-status__pill {
    display: flex;
    align-items: center;
    justify-content: center;
    height: 16px;
    min-width: 16px;
    font-size: 11px;
    font-weight: 700;
    color: var(--success-primary);
    background: var(--success-bold);
    border: 1.5px solid #111827;
    border-radius: 999px;
    z-index: 1;
}
/* One row per shipment in the shipping-dates layout, so the marker says which
   shipment the row is about. Same three states as the cards in the expanded
   part row (.op-ship): the nearest one keeps the filled green marker above,
   a later one is grey, and one already gone reads like a delivered card. */
.ship-status__pill--remaining {
    color: var(--brand-secondary);
    background: var(--border-strong);
    border-color: var(--text-soft);
}
.ship-status__pill--past {
    color: var(--success-secondary);
    background: var(--surface);
    border-color: var(--border-strong);
}

/* Floating breakdown tooltip (built in ordered-parts.js, appended to body). */
.ship-tooltip {
    position: absolute;
    z-index: 200;
    min-width: 244px;
    padding: 12px 16px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    box-shadow: var(--shadow-pop);
    font-size: 13px;
    pointer-events: none;
}
.ship-tooltip.is-hidden { display: none; }
.ship-tooltip__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding: 5px 0;
}
/* Nothing on the way: one plain line, no dot and no quantity to align. */
.ship-tooltip__row--empty { color: var(--text-muted); }
.ship-tooltip__row--sub {
    padding: 3px 0 3px 19px;
    color: var(--text-muted);
    font-size: 12.5px;
}
.ship-tooltip__label { display: inline-flex; align-items: center; gap: 9px; }
.ship-tooltip__dot { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
/* One dot per pill state (.ship-status__pill--*), same colours: the tooltip's
   first row is about the marker being hovered, so it has to look like it. */
.ship-tooltip__dot--current { background: var(--success-bold); border: 1.5px solid #111827; }
.ship-tooltip__dot--remaining { background: var(--border-strong); border: 1px solid var(--text-soft); }
.ship-tooltip__dot--past { background: var(--surface); border: 1px solid var(--border-strong); }
.ship-tooltip__val { font-weight: 700; white-space: nowrap; }
.ship-tooltip__row--sub .ship-tooltip__val { font-weight: 600; }

/* "Show closed orders" toggle + hidden closed rows */
.check--upper {
    font-size: 12px;
    font-weight: 500;
    line-height: 18px;
    letter-spacing: 0;
    text-transform: uppercase;
    color: var(--brand-secondary);
}
.data-table tbody tr.closed-hidden { display: none; }

/* Owner cell + expand chevron */
.owner-cell { display: inline-flex; align-items: center; gap: 6px; }

/* 19. Expanded ordered-parts row (shipment breakdown) -------------------- */
.op-detail-row > td { padding: 0; background: #eff5fb; border-bottom: 1px solid var(--border); }
.op-detail-row.is-hidden { display: none; }
.op-detail {
    display: flex;
    align-items: stretch;
    gap: 18px;
    padding: 18px 22px 22px;
}
.op-detail__total {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;
    min-width: 128px;
    padding: 14px 20px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
}
.op-detail__total-num { font-size: 30px; font-weight: 700; line-height: 1; color: var(--brand-primary); }
.op-detail__total-label {
    margin-top: 6px;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--brand-secondary);
}
.op-detail__ships {
    /* A grid rather than wrapping flex: flex cards size to their contents, so
       how many land on a row depends on how long the dates happen to be. Ten
       equal columns put ten on every row and line the cards up down the block. */
    display: grid;
    grid-template-columns: repeat(10, minmax(0, 1fr));
    align-content: start;
    gap: 10px;
    flex: 1 1 auto;
}
/* Not a card — a sentence, so it takes the whole row instead of one column. */
.op-detail__empty { grid-column: 1 / -1; align-self: center; color: var(--text-soft); }

.op-ship {
    /* The grid column sets the width now; this only stops a long date from
       pushing its own column wider than its share. */
    min-width: 0;
    padding: 8px 12px;
    background: var(--surface);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius-sm);
}
.op-ship__date { display: block; font-size: 14px; font-weight: 700; color: var(--brand-primary); }
.op-ship__pieces {
    display: block;
    margin-top: 2px;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--brand-secondary);
}
/* Delivered (past) shipments — green date. */
.op-ship--past .op-ship__date { color: var(--success-secondary); }
/* Next shipment (current) — highlighted card. */
.op-ship--current { background: var(--success-bold); border-color: #111827; }
.op-ship--current .op-ship__date,
.op-ship--current .op-ship__pieces { color: var(--success-primary); }

/* 15. Material -----------------------------------------------------------
   Quantities read as figures, so they sit right-aligned with the unit kept
   quiet beside them; the balance is the one number people scan for. */
.cell-num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
.cell-num--strong { font-weight: 700; color: var(--brand-primary); }
.cell-unit { font-size: 11.5px; font-weight: 500; color: var(--text-muted); }
.data-table > thead > tr > th.cell-num { text-align: right; }

/* Expanded material row: the movement history behind the balances. */
.mat-detail { padding: 14px 22px 18px; }
.mat-moves {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
}
.mat-moves thead th {
    padding: 9px 14px;
    text-align: left;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--brand-secondary);
    background: #f7f9fb;
    border-bottom: 1px solid var(--border);
}
.mat-moves tbody td { padding: 9px 14px; border-bottom: 1px solid var(--border); }
.mat-moves tbody tr:last-child td { border-bottom: none; }
.mat-moves .part-meta { margin-left: 8px; }
.mat-detail__empty { text-align: center; color: var(--text-soft); }

/* Direction chip — receipt adds to the shelf, issue takes off it. */
.mat-type {
    display: inline-block;
    padding: 2px 10px;
    font-size: 11.5px;
    font-weight: 600;
    border-radius: 999px;
    white-space: nowrap;
}
.mat-type--receipt { color: var(--success-primary); background: var(--success-subtle); }
.mat-type--issue { color: #8a5a12; background: #fdf0d5; }

/* 16. Language switcher ---------------------------------------------------
   The active code, opening into the four language names. Built on <details>
   rather than a <select> so it needs no JavaScript and works on the login
   screen exactly as it does inside the portal; app.js only adds closing it by
   clicking elsewhere. Four codes used to sit here side by side, which on a
   phone took more room than the whole main menu. */
.lang-menu { position: relative; }
.lang-menu__toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    height: 30px;
    padding: 0 8px;
    font-size: 11.5px;
    font-weight: 700;
    letter-spacing: .04em;
    color: var(--text-muted);
    background: #eef0f3;
    border-radius: var(--radius-sm);
    list-style: none;
    cursor: pointer;
    transition: background .15s ease, color .15s ease;
}
/* The default disclosure triangle, in both spellings — the chevron is ours. */
.lang-menu__toggle::-webkit-details-marker { display: none; }
.lang-menu__toggle::marker { content: ""; }
.lang-menu__toggle:hover { color: var(--text); background: #e2e5ea; }
.lang-menu__toggle .icon { width: 13px; height: 13px; transition: transform .2s ease; }
.lang-menu[open] .lang-menu__toggle { color: var(--text); }
.lang-menu[open] .lang-menu__toggle .icon { transform: rotate(180deg); }

.lang-menu__list {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    z-index: 45;
    display: flex;
    flex-direction: column;
    min-width: 132px;
    padding: 6px;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow-pop);
}
.lang-menu__item {
    padding: 8px 10px;
    font-size: 13px;
    color: var(--text);
    border-radius: 6px;
    white-space: nowrap;
}
.lang-menu__item:hover { background: #f4f5f7; }
.lang-menu__item.is-active {
    font-weight: 700;
    background: #f4f5f7;
    cursor: default;
}

/* On the auth pages it sits under the logo, centred with it — and there the
   list has nothing to its right to avoid, so it opens centred too. */
.auth-shell .lang-menu { margin: 0 auto 18px; width: fit-content; }
.auth-shell .lang-menu__list { right: auto; left: 50%; transform: translateX(-50%); }

/* 17. "Viewing as" banner -------------------------------------------------
   Sits above everything, in a colour used nowhere else in the portal. The
   whole risk of the feature is reading a customer's numbers without noticing
   whose they are, so this is meant to be impossible to overlook. */
.viewing-as {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 14px;
    padding: 9px 18px;
    font-size: 13.5px;
    font-weight: 600;
    color: #4a2c00;
    background: #ffce4d;
    border-bottom: 1px solid #e0ad1f;
}
.viewing-as__text strong { font-weight: 800; }
.viewing-as__btn {
    height: 28px;
    padding: 0 12px;
    font-size: 12.5px;
    font-weight: 700;
    color: #4a2c00;
    background: rgba(255, 255, 255, .75);
    border: 1px solid #e0ad1f;
    border-radius: var(--radius-sm);
    white-space: nowrap;
}
.viewing-as__btn:hover { background: #fff; }

/* The picker on My profile */
.view-as-form .form-field { max-width: 520px; }
.view-as-stop { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.viewing-as__note { display: inline-block; margin-left: 8px; font-weight: 700; opacity: .85; }
