﻿/* ==========================================================
   BEE-ONLINE 2.0 — design system
   Ported from docs/design/beeonline-redesign-2.0.html

   Scoping rules (IMPORTANT):
   - Global chrome (topnav, layout, footer) uses the .bo-  prefix
     and is applied through .bo-layout on RadzenLayout.
   - Page content styles live under .bo2 so pages can opt in one
     at a time while the rest of the app keeps the old look.
   - NEVER blanket-reset generic elements inside .bo2 (e.g.
     `.bo2 button`) — Radzen components are still rendered there
     (dialogs, dropdowns, notifications) and would break.
   Light theme only.
   ========================================================== */

:root {
    --bo-ground: #EEF2F6;
    --bo-surface: #FFFFFF;
    --bo-surface-2: #F5F8FA;
    --bo-surface-3: #EBF0F4;
    --bo-ink: #182430;
    --bo-ink-2: #46586A;
    --bo-ink-3: #7E90A1;
    --bo-line: #DEE6ED;
    --bo-line-soft: #E9EEF3;

    /* skeleton placeholder + the highlight that sweeps across it */
    --bo-sk-base: #E4EBF2;
    --bo-sk-shine: #F4F8FB;

    --bo-brand: #1489C8;
    --bo-brand-deep: #0E6DA4;
    --bo-brand-navy: #0B3C5C;
    --bo-brand-ink: #0A5C8C;
    --bo-brand-soft: #E4F2FA;
    --bo-brand-tint: #EFF7FC;

    --bo-orange: #F2A31C;
    --bo-orange-deep: #DE8A06;
    --bo-orange-soft: #FBEED4;
    --bo-orange-ink: #8A5A00;

    --bo-green: #2FA35C;
    --bo-green-deep: #268A4D;
    --bo-green-soft: #E1F4E8;
    --bo-green-ink: #186B3C;

    --bo-red: #DA4C4C;
    --bo-red-deep: #C43A3A;
    --bo-red-soft: #FBE9E9;
    --bo-red-ink: #8E2020;

    /* Warehouse Manager only: the decompiled state needs a hue that is neither
       a warning nor a success, since a decompiled master is neither. */
    --bo-purple: #7C5CBF;
    --bo-purple-soft: #EEE9F8;
    --bo-purple-ink: #5A3F97;

    --bo-amber-mark: #F2B33D;

    --bo-shadow-xs: 0 1px 2px rgba(16,42,64,.06);
    --bo-shadow-sm: 0 1px 3px rgba(16,42,64,.08), 0 1px 2px rgba(16,42,64,.04);
    --bo-shadow-md: 0 8px 28px rgba(16,42,64,.10), 0 2px 6px rgba(16,42,64,.05);
    --bo-radius-lg: 14px;
    --bo-radius: 10px;
    --bo-radius-sm: 8px;

    --bo-font-ui: "Segoe UI Variable Text", "Segoe UI", system-ui, -apple-system, sans-serif;
    --bo-font-display: "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
    --bo-font-mono: "Cascadia Mono", "Consolas", ui-monospace, monospace;

    --bo-nav-h: 56px;
}

/* ============ LAYOUT SHELL ============ */
/* Applied to RadzenLayout so the whole authenticated app picks up the
   2.0 ground colour without touching other layouts.

   NOTE on Radzen's layout: .rz-layout is `height:100dvh; overflow:hidden`
   and .rz-body is the scroll container. Two consequences:
     - the header never scrolls, so it needs no position:sticky;
     - .rz-body MUST keep its `overflow:auto` or the app stops scrolling. */
.bo-layout {
    font-family: var(--bo-font-ui);
    color: var(--bo-ink);
    background: radial-gradient(1200px 400px at 50% -140px, rgba(20,137,200,.07), transparent 70%), var(--bo-ground);
    -webkit-font-smoothing: antialiased;
    line-height: 1.45;
}

/* z-index stays below Radzen's dialog/notification layers (>=1000) but above
   .rz-body so the nav dropdowns paint over page content; overflow must stay
   visible so those dropdowns are not clipped to the 56px header box. */
.bo-layout > .rz-header {
    z-index: 100;
    height: var(--bo-nav-h) !important;
    min-height: var(--bo-nav-h);
    padding: 0 !important;
    margin: 0 !important;
    background: transparent !important;
    box-shadow: none !important;
    border: none !important;
    overflow: visible;
}

.bo-layout > .rz-body {
    background: transparent;
}

/* Only pages that opted into the 2.0 shell drop Radzen's body padding —
   .bo-shell brings its own. Pages still on the old style keep theirs.

   The column layout is what keeps the footer at the bottom: .rz-body is the
   scroll container, so min-height:100% makes its content at least a full
   viewport tall and .bo-page-foot's margin-top:auto pushes it down. On a long
   page nothing changes — the footer simply follows the content. */
.bo-layout > .rz-body:has(> .bo2) {
    margin: 0 !important;
    padding: 0 !important;
    display: flex;
    flex-direction: column;
    min-height: 100%;
}

.bo-layout > .rz-body:has(> .bo2) > .bo2 { flex: 1 0 auto; }

/* RadzenFooter is unused — MainLayout renders .bo-page-foot at the end of
   .rz-body so it scrolls with the content instead of staying pinned. */
.bo-layout > .rz-footer { display: none; }

/* ============ TOP NAV ============ */
.bo-topnav {
    background: linear-gradient(180deg,#1587C4 0%,#0F6FA6 100%);
    color: #fff;
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 0 22px;
    height: var(--bo-nav-h);
    box-shadow: 0 1px 0 rgba(255,255,255,.12) inset, 0 2px 10px rgba(11,60,92,.25);
    font-family: var(--bo-font-ui);
}

.bo-brand {
    display: flex;
    align-items: center;
    gap: 11px;
    margin-right: 26px;
    flex-shrink: 0;
    text-decoration: none;
    color: #fff;
}

.bo-brand:hover { color: #fff; text-decoration: none; }

.bo-brand-name {
    font-family: var(--bo-font-display);
    font-weight: 650;
    font-size: 1.04rem;
    letter-spacing: -.01em;
    white-space: nowrap;
}

/* Scrolls horizontally so a long link set can never push the topnav wider
   than the viewport. The Invoice dropdown lives in here, so its menu is
   position:fixed (see .bo-nav-drop) to escape this scroll container. */
.bo-nav-links {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1px;
    flex: 1;
    min-width: 0;
    overflow-x: auto;
    scrollbar-width: none;
    height: 100%;
}

.bo-nav-links::-webkit-scrollbar { display: none; }

.bo-nav-link {
    height: 100%;
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 0 13px;
    font-size: .88rem;
    font-weight: 480;
    color: rgba(255,255,255,.82);
    white-space: nowrap;
    text-decoration: none;
    position: relative;
    transition: color .15s;
    background: none;
    border: none;
    cursor: pointer;
}

.bo-nav-link:hover { color: #fff; text-decoration: none; }

.bo-nav-link::after {
    content: "";
    position: absolute;
    left: 13px;
    right: 13px;
    bottom: 0;
    height: 3px;
    border-radius: 3px 3px 0 0;
    background: transparent;
    transition: background .15s;
}

.bo-nav-link:hover::after { background: rgba(255,255,255,.35); }
.bo-nav-link.bo-on { color: #fff; font-weight: 600; }
.bo-nav-link.bo-on::after { background: rgba(255,255,255,.95); }
.bo-nav-link .bo-chev { opacity: .65; font-size: .68em; }

.bo-nav-right {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-shrink: 0;
    margin-left: 14px;
}

.bo-nav-sep {
    width: 1px;
    height: 22px;
    background: rgba(255,255,255,.22);
    margin: 0 4px;
}

.bo-user-chip {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 4px 11px 4px 5px;
    border-radius: 999px;
    background: rgba(255,255,255,.13);
    transition: background .15s;
    color: #fff;
    border: none;
    cursor: pointer;
    font: inherit;
    list-style: none;
}

.bo-user-chip:hover { background: rgba(255,255,255,.2); }
.bo-user-chip::-webkit-details-marker { display: none; }

.bo-avatar {
    width: 27px;
    height: 27px;
    border-radius: 50%;
    background: #fff;
    color: var(--bo-brand-deep);
    font-size: .68rem;
    font-weight: 700;
    display: grid;
    place-items: center;
    flex-shrink: 0;
}

.bo-user-chip .bo-name {
    font-size: .86rem;
    font-weight: 600;
    max-width: 160px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bo-user-chip .bo-chev { opacity: .7; font-size: .62rem; margin-left: 2px; }

/* --- dropdowns (pure CSS via <details>) --- */
.bo-drop { position: relative; }
.bo-drop > summary { cursor: pointer; }
.bo-drop > summary::-webkit-details-marker { display: none; }
.bo-drop > summary::marker { content: ""; }

.bo-drop-menu {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    min-width: 210px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    box-shadow: var(--bo-shadow-md);
    padding: 6px;
    z-index: 1200;
    display: flex;
    flex-direction: column;
    gap: 1px;
}

.bo-drop-menu.bo-drop-left { right: auto; left: 0; }

.bo-drop-item {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 11px;
    border-radius: 7px;
    font-size: .85rem;
    font-weight: 520;
    color: var(--bo-ink-2);
    text-decoration: none;
    white-space: nowrap;
    background: none;
    border: none;
    cursor: pointer;
    text-align: left;
    width: 100%;
}

.bo-drop-item:hover {
    background: var(--bo-brand-tint);
    color: var(--bo-brand-ink);
    text-decoration: none;
}

.bo-drop-item.bo-danger:hover { background: var(--bo-red-soft); color: var(--bo-red-deep); }
.bo-drop-sep { height: 1px; background: var(--bo-line-soft); margin: 4px 2px; }

/* Radzen's material-base.css ships ".rz-header a, .rz-header a:hover,
   .rz-header a:focus { color: var(--rz-on-primary) }" (white) — specificity
   (0,1,1) beats a plain ".bo-drop-item"/".bo-nav-link" class (0,1,0) no matter
   the load order, since NavMenu renders inside <RadzenHeader>. That forced
   every <a> item in these menus to white-on-white, invisible against the
   menu's white background — <button> items (Log Out, and formerly Calculate
   hash) were never touched by an "a" selector and rendered fine throughout.
   Chaining a second class beats Radzen's specificity outright. */
.bo-drop-menu .bo-drop-item,
.bo-drop-menu .bo-drop-item:hover,
.bo-drop-menu .bo-drop-item:focus {
    color: var(--bo-ink-2);
}

.bo-drop-menu .bo-drop-item:hover,
.bo-drop-menu .bo-drop-item:focus {
    color: var(--bo-brand-ink);
}

.bo-drop-menu .bo-drop-item.bo-danger:hover,
.bo-drop-menu .bo-drop-item.bo-danger:focus {
    color: var(--bo-red-deep);
}

/* Same collision for the top-level links: Radzen's rule forced every <a>
   among them to solid white, while "Invoice" (a <summary>, not an <a>) kept
   our intended rgba(255,255,255,.82) — making Invoice read as duller than
   its solid-white siblings instead of all of them matching. */
.bo-topnav .bo-nav-link,
.bo-topnav .bo-nav-link:hover,
.bo-topnav .bo-nav-link:focus {
    color: rgba(255,255,255,.82);
}

.bo-topnav .bo-nav-link:hover,
.bo-topnav .bo-nav-link:focus,
.bo-topnav .bo-nav-link.bo-on {
    color: #fff;
}

/* Nav dropdown for the top bar: full-height trigger.
   The menu is position:fixed so the scrolling .bo-nav-links strip cannot clip
   it. `top` is correct as-is (the topnav is always the first viewport row);
   `left` is set by the toggle handler in _Host.cshtml when the menu opens. */
.bo-nav-drop { height: 100%; display: flex; align-items: center; position: relative; }
.bo-nav-drop > summary { height: 100%; display: flex; align-items: center; list-style: none; }
.bo-nav-drop > summary::-webkit-details-marker { display: none; }
.bo-nav-drop > summary::marker { content: ""; }

.bo-nav-drop .bo-drop-menu {
    position: fixed;
    top: var(--bo-nav-h);
    left: 0;
    right: auto;
}

/* ============ PAGE FOOT ============ */
/* Sits at the bottom of the body: margin-top:auto in the flex column above
   drops it to the bottom of the viewport when the page is short, and it simply
   follows the content when the page is long. Not pinned — it scrolls away. */
.bo-page-foot {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    max-width: 1520px;
    width: 100%;
    margin: auto auto 0;
    padding: 4px 28px 20px;
    font-size: .76rem;
    color: var(--bo-ink-3);
    font-family: var(--bo-font-ui);
}

.bo-page-foot img { height: 32px; }

.bo-page-foot .bo-env { text-align: right; line-height: 1.35; }
.bo-page-foot .bo-env b { color: var(--bo-ink-2); font-weight: 620; }

/* ==========================================================
   PAGE CONTENT — everything below is scoped under .bo2
   ========================================================== */

.bo2 {
    font-family: var(--bo-font-ui);
    color: var(--bo-ink);
    line-height: 1.45;
    text-align: left;
}

.bo2 ::selection { background: var(--bo-brand-soft); }

.bo-shell {
    max-width: 1520px;
    width: 100%;
    margin: 0 auto;
    padding: 26px 28px 34px;
}

/* ============ PAGE HEAD ============ */
.bo2 .bo-page-head { margin-bottom: 16px; }

/* Trucks puts a page-level action beside the title, so the head becomes a row:
   title + tabs on the left, the action pinned right. The dashboard head has no
   .bo-ph-left and is unaffected. */
.bo2 .bo-page-head:has(> .bo-ph-left) {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.bo2 .bo-ph-left { min-width: 0; }

/* The actions pinned right. Its own flex row so a section can put a secondary
   button (Import, Print) beside the primary one. */
.bo2 .bo-ph-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }

.bo2 .bo-page-head h1 {
    font-family: var(--bo-font-display);
    font-size: 1.5rem;
    font-weight: 680;
    letter-spacing: -.022em;
    margin: 0;
    color: var(--bo-ink);
}

.bo2 .bo-page-head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.bo2 .bo-section-tabs {
    display: flex;
    gap: 2px;
    margin-top: 12px;
    border-bottom: 1px solid var(--bo-line);
}

.bo2 .bo-stab {
    padding: 9px 16px;
    font-size: .8rem;
    font-weight: 620;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    position: relative;
    transition: color .15s;
    background: none;
    border: none;
    cursor: pointer;
    font-family: inherit;
}

.bo2 .bo-stab:hover { color: var(--bo-ink-2); }
.bo2 .bo-stab.bo-on { color: var(--bo-brand-ink); }

.bo2 .bo-stab.bo-on::after {
    content: "";
    position: absolute;
    left: 10px;
    right: 10px;
    bottom: -1px;
    height: 3px;
    border-radius: 3px 3px 0 0;
    background: var(--bo-brand);
}

/* ============ BUTTONS ============ */
.bo2 .bo-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    padding: 9px 16px;
    border-radius: var(--bo-radius-sm);
    font-size: .87rem;
    font-weight: 580;
    font-family: inherit;
    border: none;
    cursor: pointer;
    transition: background .15s, border-color .15s, box-shadow .15s, transform .1s;
}

.bo2 .bo-btn:active:not(:disabled) { transform: translateY(1px); }

/* A disabled button has to read as disabled on every variant — a primary that
   still looks solid blue invites the click it is going to swallow. */
.bo2 .bo-btn:disabled {
    opacity: .45;
    cursor: not-allowed;
    box-shadow: none;
    filter: none;
    transform: none;
}

.bo2 .bo-btn-primary {
    background: linear-gradient(180deg,#1B93D0,#1180BC);
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, 0 2px 6px rgba(17,128,188,.35);
}

.bo2 .bo-btn-primary:hover:not(:disabled) { background: linear-gradient(180deg,#259CD8,#178AC6); }

.bo2 .bo-btn-ghost {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line);
    color: var(--bo-ink-2);
    box-shadow: var(--bo-shadow-xs);
}

.bo2 .bo-btn-ghost:hover:not(:disabled) { border-color: #C4D0DB; color: var(--bo-ink); }

/* The committing button of a destructive dialog. Solid red, so it never reads
   as the safe default the way a plain primary would. */
.bo2 .bo-btn-danger {
    background: linear-gradient(180deg,var(--bo-red),var(--bo-red-deep));
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(218,76,76,.35);
}

.bo2 .bo-btn-danger:hover:not(:disabled) { filter: brightness(1.06); }

/* ============ PANEL ============ */
.bo2 .bo-panel {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-lg);
    box-shadow: var(--bo-shadow-md);
    overflow: hidden;
    position: relative;
}

/* ============ TOOLBAR ============ */
.bo2 .bo-toolbar {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    padding: 14px 18px;
    border-bottom: 1px solid var(--bo-line-soft);
}

/* Fixed height keeps every toolbar control on one line regardless of what it
   wraps — native inputs, date inputs and Radzen dropdowns all differ
   intrinsically. */
.bo2 .bo-field {
    display: flex;
    align-items: center;
    gap: 8px;
    height: 38px;
    box-sizing: border-box;
    background: var(--bo-surface-2);
    border: 1px solid transparent;
    border-radius: var(--bo-radius-sm);
    padding: 0 12px;
    font-size: .85rem;
    color: var(--bo-ink-2);
    transition: border-color .15s, background .15s, box-shadow .15s;
    margin: 0;
}

.bo2 .bo-field:hover { border-color: var(--bo-line); }

/* No focus ring here on purpose. A filter that lit up with a blue halo the
   moment it was clicked read as an error state; the field turning white against
   the tinted toolbar is signal enough, and the caret says where you are. */
.bo2 .bo-field:focus-within {
    background: var(--bo-surface);
    border-color: var(--bo-line);
}

.bo2 .bo-field > input,
.bo2 .bo-field > select {
    border: none;
    background: transparent;
    font: inherit;
    color: var(--bo-ink);
    outline: none;
    min-width: 0;
    height: 100%;
    padding: 0;
    box-shadow: none;
}

.bo2 .bo-field > input::placeholder { color: var(--bo-ink-3); }
.bo2 .bo-field > svg { flex-shrink: 0; color: var(--bo-ink-3); }
.bo2 .bo-field.bo-search { flex: 1; min-width: 190px; max-width: 330px; }
.bo2 .bo-field.bo-search > input { flex: 1; }
.bo2 .bo-field-date > input { width: 104px; }
.bo2 .bo-field-label { font-size: .72rem; font-weight: 640; letter-spacing: .05em; text-transform: uppercase; color: var(--bo-ink-3); flex-shrink: 0; }

/* Native date/datetime inputs always paint a dd.mm.yyyy(.--:--) mask, which
   shouts louder than the rest of the toolbar. While the filter is empty (the
   host adds .bo-empty) the text is made transparent — the mask inherits the
   input's colour, so this works in every engine, unlike ::-webkit-datetime-edit.
   The calendar button is a background image and stays visible. Colour returns
   on focus so the field is still typeable, and whenever a date is actually set. */
.bo2 .bo-field input[type="date"].bo-empty,
.bo2 .bo-field input[type="datetime-local"].bo-empty { color: transparent; }
.bo2 .bo-field input[type="date"].bo-empty:focus,
.bo2 .bo-field input[type="datetime-local"].bo-empty:focus { color: var(--bo-ink); }

.bo2 .bo-field input[type="date"]::-webkit-calendar-picker-indicator,
.bo2 .bo-field input[type="datetime-local"]::-webkit-calendar-picker-indicator {
    opacity: .45;
    cursor: pointer;
    transition: opacity .13s;
}

.bo2 .bo-field input[type="date"]::-webkit-calendar-picker-indicator:hover,
.bo2 .bo-field input[type="datetime-local"]::-webkit-calendar-picker-indicator:hover { opacity: .9; }

/* Volume report's filter card gives each date its own labelled grid cell
   (unlike PreAlertTab's compact toolbar), so the field can stretch full width
   instead of the fixed 104px toolbar sizing. */
.bo2 .bo-f-grid .bo-field-date > input { width: 100%; }

/* Radzen inputs living inside a .bo-field (the customer dropdown keeps its
   filtering behaviour, so we only strip its chrome and match the field height).
   Radzen lays .rz-dropdown out as a column flexbox with an absolutely
   positioned trigger/clear icon — leave that intact and only zero the padding
   and stretch it to the field, otherwise the icons detach from the box.

   Note .rz-calendar, NOT .rz-datepicker: in Radzen 4 the date *input* is
   .rz-calendar and .rz-datepicker is the pop-up. Targeting the wrong one left
   the field with Radzen's own border and accent focus ring inside ours. */
.bo2 .bo-field .rz-dropdown,
.bo2 .bo-field .rz-textbox,
.bo2 .bo-field .rz-spinner,
.bo2 .bo-field .rz-calendar {
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    height: 100% !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    justify-content: center !important;
    font: inherit !important;
    color: var(--bo-ink) !important;
}

.bo2 .bo-field .rz-dropdown .rz-dropdown-label,
.bo2 .bo-field .rz-spinner .rz-spinner-input,
.bo2 .bo-field .rz-dropdown .rz-inputtext {
    padding-block: 0 !important;
    padding-inline-start: 0 !important;
    margin: 0 !important;
    min-height: 0 !important;
    line-height: 1.45 !important;
    font: inherit !important;
    background: transparent !important;
    color: var(--bo-ink) !important;
}

/* Recolour only — the icons stay absolutely positioned inside .rz-dropdown. */
.bo2 .bo-field .rz-dropdown .rz-dropdown-trigger,
.bo2 .bo-field .rz-dropdown .rz-dropdown-clear-icon {
    color: var(--bo-ink-3) !important;
}

.bo2 .bo-toolbar-sep {
    width: 1px;
    height: 26px;
    background: var(--bo-line);
    margin: 0 3px;
}

.bo2 .bo-kbd {
    font-family: var(--bo-font-mono);
    font-size: .64rem;
    color: var(--bo-ink-3);
    border: 1px solid var(--bo-line);
    border-bottom-width: 2px;
    border-radius: 5px;
    padding: 1px 6px;
    background: var(--bo-surface);
    white-space: nowrap;
}

/* --- segmented control --- */
.bo2 .bo-seg {
    display: flex;
    background: var(--bo-surface-2);
    border-radius: var(--bo-radius-sm);
    padding: 3px;
    gap: 2px;
}

.bo2 .bo-seg button {
    padding: 6px 13px;
    border-radius: 6px;
    font-size: .8rem;
    font-weight: 560;
    font-family: inherit;
    color: var(--bo-ink-3);
    display: flex;
    align-items: center;
    gap: 7px;
    background: none;
    border: none;
    cursor: pointer;
    transition: background .15s, color .15s, box-shadow .15s;
}

.bo2 .bo-seg button:hover { color: var(--bo-ink-2); }
.bo2 .bo-seg button.bo-on { background: var(--bo-surface); color: var(--bo-ink); box-shadow: var(--bo-shadow-xs); }

.bo2 .bo-seg .bo-n {
    font-size: .68rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-3);
}

.bo2 .bo-seg button.bo-on .bo-n { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 .bo-seg button.bo-on .bo-n.bo-warn { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }

/* --- switch --- */
.bo2 .bo-switch {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .82rem;
    font-weight: 520;
    color: var(--bo-ink-2);
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    margin: 0;
}

.bo2 .bo-switch input { position: absolute; opacity: 0; width: 0; height: 0; }

.bo2 .bo-switch .bo-track {
    width: 34px;
    height: 19px;
    border-radius: 999px;
    flex-shrink: 0;
    background: #CBD6DF;
    position: relative;
    transition: background .18s;
}

.bo2 .bo-switch .bo-track::after {
    content: "";
    position: absolute;
    top: 2px;
    left: 2px;
    width: 15px;
    height: 15px;
    border-radius: 50%;
    background: #fff;
    box-shadow: 0 1px 3px rgba(16,42,64,.3);
    transition: translate .18s;
}

.bo2 .bo-switch input:checked + .bo-track { background: var(--bo-brand); }
.bo2 .bo-switch input:checked + .bo-track::after { translate: 15px 0; }
.bo2 .bo-switch input:focus-visible + .bo-track { outline: 2px solid var(--bo-brand); outline-offset: 2px; }

.bo2 .bo-toolbar-right { margin-left: auto; display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }

.bo2 .bo-f-clear {
    font-size: .8rem;
    font-weight: 560;
    font-family: inherit;
    color: var(--bo-ink-3);
    padding: 7px 11px;
    border-radius: var(--bo-radius-sm);
    display: flex;
    align-items: center;
    gap: 6px;
    background: none;
    border: none;
    cursor: pointer;
    transition: color .15s, background .15s;
}

.bo2 .bo-f-clear:hover { color: var(--bo-red); background: var(--bo-red-soft); }

/* ============ TABLE ============ */
.bo2 .bo-table-wrap { overflow-x: auto; }

.bo2 table.bo-table {
    width: 100%;
    border-collapse: collapse;
    min-width: 1150px;
    max-width: none;
    margin: 0;
    background: transparent;
    box-shadow: none;
}

.bo2 table.bo-table thead th {
    font-size: .68rem;
    font-weight: 680;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    text-align: left;
    padding: 11px 14px;
    background: var(--bo-surface);
    border-bottom: 1px solid var(--bo-line);
    white-space: nowrap;
    /* Offset is 0, not the nav height: the nav lives outside .rz-body (the
       scroll container), so there is nothing to clear. Sticky only engages
       when .bo-table-wrap is not itself the vertical scrollport. */
    position: sticky;
    top: 0;
    z-index: 10;
}

/* ---- resizable columns ----
   The <colgroup> drives the widths; wwwroot/js/bo-table-resize.js owns them.

   The table's `width` MUST stay a definite length (an inline px value that the
   script keeps equal to the sum of the columns). With `auto` or `max-content`,
   browsers fall back to the automatic table layout, columns then grow to fit
   their content and can never be dragged narrower than the text inside them.
   `min-width: 100%` still lets a narrow set of columns fill the panel. */
.bo2 table.bo-table.bo-resizable {
    table-layout: fixed;
    min-width: 100%;
}

.bo2 table.bo-table.bo-resizable thead th,
.bo2 table.bo-table.bo-resizable tbody td {
    overflow: hidden;
    text-overflow: ellipsis;
}

/* When a tooltip fires in a resizable table:
   1. Release the cell's overflow clip so the bubble can paint outside the td.
   2. Lift the whole row above siblings (z-index:1 > auto=0) so the tooltip
      isn't painted over by the adjacent row's opaque background.
   The td gets no position/z-index — that would trap the button's z-index:1000
   inside a new stacking context and reduce its global layer to whatever the td
   has. The row-level lift is cheap: one new stacking context per hovered row. */
.bo2 table.bo-table.bo-resizable tbody td:has([data-bo-tip]:hover) {
    overflow: visible;
}
.bo2 table.bo-table tbody tr:has([data-bo-tip]:hover) {
    position: relative;
    z-index: 1;
}

/* First tbody row: the upward tooltip would collide with the sticky thead
   (z-index:10 > row z-index:1). Flip the tooltip to point downward instead —
   it then lands in row 2's area where the row's own z-index:1 keeps it on top.
   Arrow and entry animation are mirrored. */
.bo2 table.bo-table tbody tr:first-child [data-bo-tip]::after {
    bottom: auto;
    top: calc(100% + 8px);
    translate: -50% -3px;
}
.bo2 table.bo-table tbody tr:first-child [data-bo-tip]:hover::after {
    translate: -50% 0;
}
.bo2 table.bo-table tbody tr:first-child [data-bo-tip]::before {
    bottom: auto;
    top: calc(100% + 3px);
    border-top-color: transparent;
    border-bottom-color: var(--bo-brand-navy);
}

/* A single-row tbody is both :first-child and :last-child, so the flip above
   aims the bubble into empty space below the table — where .bo-table-wrap
   (overflow-x:auto makes overflow-y auto too) and .bo-panel (overflow:hidden)
   both clip it, and the tooltip is simply never seen. There is no row 2 to
   flip into, so point it back up and lift the row over the sticky thead
   instead: the bubble paints across the header, which is inside the wrap. */
.bo2 table.bo-table tbody tr:first-child:last-child [data-bo-tip]::after {
    top: auto;
    bottom: calc(100% + 8px);
}
.bo2 table.bo-table tbody tr:first-child:last-child [data-bo-tip]::before {
    top: auto;
    bottom: calc(100% + 3px);
    border-bottom-color: transparent;
    border-top-color: var(--bo-brand-navy);
}
/* Above the thead's z-index:10, not the z-index:1 the row-level lift gives it.
   Safe here in a way it would not be generally: one row means nothing scrolls
   under the header. */
.bo2 table.bo-table tbody tr:first-child:last-child:has([data-bo-tip]:hover) {
    z-index: 20;
}

/* Cells whose content is a pill, not prose. An ellipsis rendered inside a
   rounded badge reads as broken, so these clip instead — the column defaults
   are sized so it never comes to that unless the user drags them narrow. */
.bo2 table.bo-table.bo-resizable tbody td.bo-cell-pill { text-overflow: clip; }

/* Pills sit against the right edge of their column, like the numeric columns. */
.bo2 table.bo-table tbody td.bo-cell-pill { text-align: right; }

/* Tighter side padding on pill and chip cells. Their content already carries
   its own visual padding (a rounded badge, a row of tiles), so the default
   14px cell gutter only widens the column and leaves dead space around it. */
.bo2 table.bo-table tbody td.bo-cell-actions,
.bo2 table.bo-table tbody td.bo-cell-pill { padding-left: 8px; padding-right: 8px; }

/* The grip needs the header cell as its containing block. position:sticky
   already establishes one, so no extra position declaration is required. */
.bo2 table.bo-table.bo-resizable thead th { padding-right: 18px; }

.bo2 .bo-th-grip {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 11px;
    display: flex;
    justify-content: center;
    cursor: col-resize;
    touch-action: none;
    user-select: none;
    z-index: 2;
}

.bo2 .bo-th-grip::after {
    content: "";
    width: 2px;
    height: 58%;
    align-self: center;
    border-radius: 2px;
    background: var(--bo-line);
    transition: background .13s, height .13s;
}

.bo2 .bo-th-grip:hover::after,
.bo2 .bo-th-grip.bo-grabbing::after {
    background: var(--bo-brand);
    height: 78%;
}

/* Whole-document feedback while a column is being dragged. */
body.bo-col-resizing,
body.bo-col-resizing * { cursor: col-resize !important; user-select: none !important; }

.bo2 table.bo-table thead th.bo-num { text-align: right; }
.bo2 table.bo-table thead th.bo-right { text-align: right; padding-right: 22px; }
.bo2 table.bo-table thead th .bo-sort { color: var(--bo-brand); font-size: .95em; margin-left: 3px; }

.bo2 table.bo-table th.bo-sel,
.bo2 table.bo-table td.bo-sel {
    width: 44px;
    padding-right: 4px !important;
    padding-left: 18px !important;
}

/* group header row (grouping by day) */
.bo2 table.bo-table tr.bo-grp td {
    background: var(--bo-surface-2);
    border-top: 1px solid var(--bo-line-soft);
    border-bottom: 1px solid var(--bo-line-soft);
    padding: 8px 18px;
    font-size: .72rem;
    font-weight: 680;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-2);
    white-space: nowrap;
}

.bo2 table.bo-table tr.bo-grp .bo-day { color: var(--bo-ink); margin-right: 4px; }

.bo2 table.bo-table tr.bo-grp .bo-agg {
    color: var(--bo-ink-3);
    font-weight: 560;
    letter-spacing: .03em;
    text-transform: none;
    font-size: .76rem;
}

.bo2 table.bo-table tr.bo-grp .bo-agg b { color: var(--bo-ink-2); font-weight: 640; font-variant-numeric: tabular-nums; }
.bo2 table.bo-table tr.bo-grp .bo-agg .bo-dotsep { margin: 0 7px; opacity: .5; }

.bo2 table.bo-table tbody td {
    padding: 12px 14px;
    border-bottom: 1px solid var(--bo-line-soft);
    font-size: .87rem;
    vertical-align: middle;
    white-space: nowrap;
    background: transparent;
}

.bo2 table.bo-table tbody td.bo-num { text-align: right; font-variant-numeric: tabular-nums; }
.bo2 table.bo-table tbody td.bo-date { font-variant-numeric: tabular-nums; }
.bo2 table.bo-table tbody tr.bo-row { transition: background .12s, box-shadow .12s; }
.bo2 table.bo-table tbody tr.bo-row:hover { background: var(--bo-brand-tint); }
.bo2 table.bo-table tbody tr.bo-row:hover td:first-child { box-shadow: 3px 0 0 var(--bo-brand) inset; }

/* empty / loading states */
.bo2 .bo-table-empty {
    padding: 56px 18px;
    text-align: center;
    color: var(--bo-ink-3);
    font-size: .9rem;
}

.bo2 .bo-loading-bar {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 3px;
    overflow: hidden;
    background: var(--bo-brand-soft);
    z-index: 20;
}

.bo2 .bo-loading-bar::after {
    content: "";
    position: absolute;
    inset: 0;
    width: 40%;
    background: linear-gradient(90deg, transparent, var(--bo-brand), transparent);
    animation: bo-slide 1.1s ease-in-out infinite;
}

@keyframes bo-slide {
    0% { transform: translateX(-100%); }
    100% { transform: translateX(350%); }
}

.bo2 .bo-spin {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    border: 2px solid rgba(255,255,255,.45);
    border-top-color: #fff;
    animation: bo-spin .7s linear infinite;
}

@keyframes bo-spin { to { transform: rotate(360deg); } }

/* The same spinner on a light background — the white one vanishes there. */
.bo2 .bo-spin.bo-spin-ink {
    border-color: rgba(126,144,161,.35);
    border-top-color: var(--bo-ink-2);
}

/* ============================================================
   SKELETONS
   A skeleton stands in for content that is on its way, so the
   layout is already in place when the data lands and nothing
   jumps. Every block is the same .bo-sk box with a light sweep
   running across it; the shapes below only change the size.

   Sizing rule: a skeleton must occupy the same box as the real
   thing. Inside table cells the blocks are inline-block, so the
   line-box strut of the cell's own font keeps the row exactly as
   tall as a row of text — no jump when the real rows arrive.
   ============================================================ */
.bo2 .bo-sk {
    display: inline-block;
    vertical-align: middle;
    position: relative;
    overflow: hidden;
    border-radius: 5px;
    background: var(--bo-sk-base);
}

.bo2 .bo-sk::after {
    content: "";
    position: absolute;
    inset: 0;
    transform: translateX(-100%);
    background: linear-gradient(90deg, transparent, var(--bo-sk-shine), transparent);
    animation: bo-shimmer 1.35s ease-in-out infinite;
    /* --bo-i is the row index; the sweep rolls down the list instead of
       every row flashing in unison. Capped by the host at ~12 rows. */
    animation-delay: calc(var(--bo-i, 0) * 70ms);
}

@keyframes bo-shimmer {
    to { transform: translateX(100%); }
}

/* text lines — width classes read as "how much of the cell is filled" */
.bo2 .bo-sk-line { height: 10px; }
.bo2 .bo-sk-line.bo-w-xs { width: 32%; }
.bo2 .bo-sk-line.bo-w-sm { width: 48%; }
.bo2 .bo-sk-line.bo-w-md { width: 66%; }
.bo2 .bo-sk-line.bo-w-lg { width: 84%; }
.bo2 .bo-sk-line.bo-w-full { width: 100%; }

/* Numeric cells are text-align:right, and the blocks are inline-block, so
   they line up with the real figures without any extra rule. */
.bo2 .bo-sk-pill { height: 19px; width: 76px; border-radius: 999px; }
.bo2 .bo-sk-cb { height: 15px; width: 15px; border-radius: 4px; }
.bo2 .bo-sk-ic { height: 20px; width: 20px; border-radius: 999px; }
.bo2 .bo-sk-circle { border-radius: 999px; }
/* Action chips are sized off the real buttons they stand in for, so the row
   keeps its height when the skeleton is swapped out: .bo-act (36x38) in the
   roomy tables, .bo-icon-btn (30x30) in the tight ones. */
.bo2 .bo-sk-chip { height: 38px; width: 36px; border-radius: 6px; }
.bo2 table.bo-table.bo-tight .bo-sk-chip,
.bo2 table.bo-table.bo-compact .bo-sk-chip { height: 30px; width: 30px; border-radius: 8px; }

.bo2 .bo-sk-chips {
    display: inline-flex;
    vertical-align: middle;
    gap: 4px;
}

/* Stand-in for a two-line cell (a code with a smaller line of meta under it).
   The min-height is what such a cell actually measures, and in Pre-Alert it is
   the tallest cell in the row — so it, not the action chips, sets the height. */
.bo2 .bo-sk-2l {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    vertical-align: middle;
    gap: 7px;
    width: 100%;
    min-height: 39px;
}

.bo2 .bo-sk-2l .bo-sk-line:last-child { height: 8px; }

/* Stand-in for a .bo-provider-chip — taller than a text line, so it drives the
   row height in the warehouse parcel table the same way the real chip does. */
.bo2 .bo-sk-tag { height: 26px; width: 76%; border-radius: 999px; }

/* Warehouse Manager's location column. 28px, not the chip's own 26: the row is
   sized by the icon button standing next to the chip, and the placeholder has
   to match the row, not the chip. */
.bo2 .bo-sk-code { height: 28px; width: 72%; border-radius: 6px; }

/* Stand-in for the .bo-expand caret in the customs table — the tallest thing
   in that row, so it is what sets the height there. */
.bo2 .bo-sk-exp { height: 28px; width: 28px; border-radius: 8px; }

/* Skeleton rows are inert: no hover tint, no pointer, no left edge marker. */
.bo2 table.bo-table tbody tr.bo-sk-row { cursor: default; }
.bo2 table.bo-table tbody tr.bo-sk-row:hover { background: transparent; }
.bo2 table.bo-table tbody tr.bo-sk-row:hover td:first-child { box-shadow: none; }
.bo2 table.bo-table.bo-resizable tbody tr.bo-sk-row td { text-overflow: clip; }

/* Card skeleton for the warehouse AWB list. Padding, gaps and border are
   .bo-awb's, and each placeholder line sits in a block carrying the same
   font-size as the text it replaces — the line-box strut then gives the row
   exactly the real height, so a card of placeholders matches a loaded card to
   the pixel without any magic numbers to keep in sync. */
.bo2 .bo-sk-awb {
    padding: 11px 12px;
    display: flex;
    flex-direction: column;
    gap: 7px;
    border: 1px solid transparent;
}

.bo2 .bo-sk-awb .bo-sk-stats { display: flex; flex-direction: column; gap: 3px; }

/* Each carries the font-size of the text it replaces; the line-box strut does
   the rest. Reused anywhere a skeleton has to match a stack of text lines. */
.bo2 .bo-sk-ln { display: block; }
.bo2 .bo-sk-ln.bo-ln-xs { font-size: .64rem; }    /* tile key, section heading, field label */
.bo2 .bo-sk-ln.bo-ln-txt { font-size: .72rem; }   /* .bo-awb-cust, .bo-stat-line, .bo-prog-label */
.bo2 .bo-sk-ln.bo-ln-code { font-size: .8rem; }   /* .bo-awb-code */
.bo2 .bo-sk-ln.bo-ln-lg { font-size: 1.02rem; }   /* .bo-tile .bo-t-v */

/* Block skeletons used outside tables (parcel detail, page shell) */
.bo2 .bo-sk-stack { display: flex; flex-direction: column; gap: 11px; }
.bo2 .bo-sk-row-h { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* Page shell placeholder: a toolbar row over a stack of table lines, on the
   same 16/18px rhythm the real toolbar and table use. */
.bo2 .bo-sk-page { padding: 16px 18px 22px; }
.bo2 .bo-sk-page .bo-sk-row-h { margin-bottom: 22px; }

/* ============================================================
   MOTION
   Entrances are short and only ever run once, when an element
   first enters the DOM. Blazor reuses keyed nodes across renders,
   so a filter change does not re-trigger these — only genuinely
   new content animates in.
   ============================================================ */
@keyframes bo-rise {
    from { opacity: 0; transform: translateY(7px); }
    to { opacity: 1; transform: none; }
}

@keyframes bo-fade {
    from { opacity: 0; }
    to { opacity: 1; }
}

@keyframes bo-underline {
    from { transform: scaleX(.35); opacity: .4; }
    to { transform: none; opacity: 1; }
}

.bo2 .bo-panel,
.bo2 .bo-page-head { animation: bo-rise .34s cubic-bezier(.22,.61,.36,1) both; }
.bo2 .bo-panel:nth-of-type(2) { animation-delay: .05s; }
.bo2 .bo-panel:nth-of-type(3) { animation-delay: .1s; }

/* The AWB list panel is position:sticky — animating its transform would
   detach it from the scroll container, so it only fades. */
.bo2 .bo-list-panel,
.bo2 .bo-detail { animation: bo-fade .3s ease both; }

/* Rows arrive with a short cascade. Only the first screenful is staggered;
   past that the delay would outlast the render and feel sluggish. */
.bo2 table.bo-table tbody tr.bo-row { animation: bo-fade .26s ease both; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(1) { animation-delay: 0ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(2) { animation-delay: 22ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(3) { animation-delay: 44ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(4) { animation-delay: 66ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(5) { animation-delay: 88ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(6) { animation-delay: 110ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(7) { animation-delay: 132ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(8) { animation-delay: 154ms; }
.bo2 table.bo-table tbody tr.bo-row:nth-child(n+9) { animation-delay: 176ms; }

.bo2 .bo-awb { animation: bo-rise .28s cubic-bezier(.22,.61,.36,1) both; }
.bo2 .bo-awb:nth-child(1) { animation-delay: 0ms; }
.bo2 .bo-awb:nth-child(2) { animation-delay: 26ms; }
.bo2 .bo-awb:nth-child(3) { animation-delay: 52ms; }
.bo2 .bo-awb:nth-child(4) { animation-delay: 78ms; }
.bo2 .bo-awb:nth-child(5) { animation-delay: 104ms; }
.bo2 .bo-awb:nth-child(n+6) { animation-delay: 130ms; }

/* Detail sections are keyed on the waybill, so picking another AWB
   re-creates them and this replays as a cross-fade. */
.bo2 .bo-detail-head,
.bo2 .bo-prog-strip,
.bo2 .bo-pdetail { animation: bo-rise .3s cubic-bezier(.22,.61,.36,1) both; }

/* The active tab's underline grows out of the label instead of blinking
   into place. The pseudo-element only exists while .bo-on is set, so
   toggling the class is what replays it. */
.bo2 .bo-stab.bo-on::after,
.bo2 .bo-tab.bo-on::after { animation: bo-underline .28s cubic-bezier(.22,.61,.36,1) both; }

/* checkbox */
.bo2 .bo-cb {
    appearance: none;
    -webkit-appearance: none;
    width: 16px;
    height: 16px;
    border-radius: 5px;
    border: 1.5px solid #B9C6D2;
    background: var(--bo-surface);
    display: inline-grid;
    place-items: center;
    cursor: pointer;
    vertical-align: middle;
    margin: 0;
    transition: border-color .13s, background .13s;
}

.bo2 .bo-cb:hover { border-color: var(--bo-brand); }
.bo2 .bo-cb:checked { background: var(--bo-brand); border-color: var(--bo-brand); }

.bo2 .bo-cb:checked::after {
    content: "";
    width: 9px;
    height: 9px;
    background: #fff;
    clip-path: polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0,43% 62%);
}

/* waybill cell */
.bo2 .bo-wb { display: flex; flex-direction: column; gap: 2px; min-width: 0; }

.bo2 .bo-wb-code {
    font-family: var(--bo-font-mono);
    font-size: .84rem;
    font-weight: 520;
    letter-spacing: -.01em;
    color: var(--bo-ink);
    display: flex;
    align-items: center;
    gap: 7px;
}

.bo2 .bo-wb-code a {
    color: inherit;
    text-decoration: none;
    border-bottom: 1px dotted transparent;
    cursor: pointer;
}

.bo2 table.bo-table tbody tr.bo-row:hover .bo-wb-code a {
    border-bottom-color: var(--bo-brand);
    color: var(--bo-brand-ink);
}

.bo2 .bo-copy {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    display: grid;
    place-items: center;
    color: var(--bo-ink-3);
    opacity: 0;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: opacity .13s, background .13s, color .13s;
}

.bo2 table.bo-table tbody tr.bo-row:hover .bo-copy { opacity: 1; }
.bo2 .bo-copy:hover { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }

.bo2 .bo-wb-meta { display: flex; align-items: center; gap: 6px; font-size: .7rem; color: var(--bo-ink-3); }

.bo2 .bo-tag {
    font-size: .62rem;
    font-weight: 720;
    letter-spacing: .07em;
    padding: 1.5px 6px;
    border-radius: 4px;
}

.bo2 .bo-tag.bo-tag-api { color: var(--bo-brand-ink); background: var(--bo-brand-soft); }
.bo2 .bo-tag.bo-tag-file { color: var(--bo-ink-2); background: var(--bo-surface-3); }
.bo2 .bo-tag.bo-tag-wh { color: var(--bo-orange-ink); background: var(--bo-orange-soft); }
.bo2 .bo-tag.bo-tag-t1 { color: var(--bo-green-ink); background: var(--bo-green-soft); }

/* A deactivated account. Red rather than grey: it is not a quiet attribute of
   the row, it is the reason that person cannot sign in. */
.bo2 .bo-tag.bo-tag-off { color: var(--bo-red-ink); background: var(--bo-red-soft); }

/* B2B / B2C, as the customer supplied it. One neutral look for both — the
   two words say which, and the app does nothing differently for either, so
   giving one of them a colour would imply a meaning that is not there. */
.bo2 .bo-tag.bo-tag-type { color: var(--bo-ink-2); background: var(--bo-surface-3); }

/* Customer cell. No max-width: the name must keep revealing itself as the
   column is dragged wider, so it truncates against the cell, not a fixed cap.
   min-width:0 is what lets the flex item ellipsise instead of overflowing. */
.bo2 .bo-cust {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-width: 0;
}

.bo2 .bo-cust .bo-cn {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-weight: 400;
    font-size: .85rem;
}

/* Masters pill. Default (awaiting NOA) is a soft amber tint — same quiet
   tinted-surface treatment as the notified/green state, rather than a
   saturated gradient. Green = fully notified, red = blocked by customs. */
.bo2 .bo-masters {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .8rem;
    font-weight: 680;
    font-variant-numeric: tabular-nums;
    padding: 5px 6px 5px 11px;
    border-radius: 999px;
    background: var(--bo-orange-soft);
    color: var(--bo-orange-ink);
    border: 1px solid #F0DBA6;
    box-shadow: none;
    /* No min-width: the badge hugs its content. A fixed floor combined with
       space-between left a wide hole between a short count and the magnifier. */
    justify-content: flex-start;
}

.bo2 .bo-masters .bo-m-zoom {
    width: 22px;
    height: 22px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: rgba(138,90,0,.1);
    border: none;
    cursor: pointer;
    padding: 0;
    color: inherit;
    flex-shrink: 0;
    transition: background .13s, transform .13s;
}

.bo2 .bo-masters .bo-m-zoom:hover { background: rgba(138,90,0,.2); transform: scale(1.06); }

.bo2 .bo-masters.bo-notified {
    background: var(--bo-green-soft);
    color: var(--bo-green-ink);
    border-color: #BFE6CD;
}

.bo2 .bo-masters.bo-notified .bo-m-zoom { background: rgba(24,107,60,.1); }
.bo2 .bo-masters.bo-notified .bo-m-zoom:hover { background: rgba(24,107,60,.18); }

.bo2 .bo-masters.bo-blocked {
    background: var(--bo-red-soft);
    color: var(--bo-red-ink);
    border-color: #F3C9C9;
}

.bo2 .bo-masters.bo-blocked .bo-m-zoom { background: rgba(142,32,32,.1); }
.bo2 .bo-masters.bo-blocked .bo-m-zoom:hover { background: rgba(142,32,32,.18); }

.bo2 .bo-masters .bo-check { font-size: .9em; margin-right: 2px; }

/* Inline zoom button. Always visible — it opens the parcels/items dialog, so
   it is a real action and must be discoverable without hovering the row; it
   just sits quiet until pointed at. */
.bo2 .bo-mini-zoom {
    width: 22px;
    height: 22px;
    border-radius: 6px;
    display: inline-grid;
    place-items: center;
    color: var(--bo-ink-3);
    vertical-align: middle;
    opacity: .55;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: opacity .13s, background .13s, color .13s;
    margin-left: 2px;
}

.bo2 table.bo-table tbody tr.bo-row:hover .bo-mini-zoom { opacity: .8; }
.bo2 .bo-mini-zoom:hover { opacity: 1; background: var(--bo-brand-soft); color: var(--bo-brand-ink); }

.bo2 .bo-weight-unit { font-size: .72rem; color: var(--bo-ink-3); margin-left: 3px; }

/* items info dot */
.bo2 .bo-idot {
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 50%;
    font-size: .64rem;
    font-weight: 800;
    margin-left: 8px;
    vertical-align: middle;
    cursor: help;
}

.bo2 .bo-idot.bo-idot-green { background: var(--bo-green-soft); color: var(--bo-green-ink); border: 1px solid #BFE6CD; }
.bo2 .bo-idot.bo-idot-amber { background: var(--bo-orange-soft); color: var(--bo-orange-ink); border: 1px solid #F1DCA9; }
.bo2 .bo-idot.bo-idot-grey { background: var(--bo-surface-3); color: var(--bo-ink-3); border: 1px solid var(--bo-line); }

/* Product-identifier (PID) coverage of a waybill, a small round badge reading "PID".
   Green: every item has a PID. Orange: only some do. Red: none does. */
.bo2 .bo-pid-dot {
    display: inline-grid;
    place-items: center;
    width: 24px;
    height: 24px;
    border-radius: 50%;
    font-size: .5rem;
    font-weight: 800;
    letter-spacing: .02em;
    flex-shrink: 0;
    cursor: help;
}

.bo2 .bo-pid-dot.bo-pid-green { background: var(--bo-green-soft); color: var(--bo-green-ink); border: 1px solid #BFE6CD; }
.bo2 .bo-pid-dot.bo-pid-orange { background: var(--bo-orange-soft); color: var(--bo-orange-ink); border: 1px solid #F1DCA9; }
.bo2 .bo-pid-dot.bo-pid-red { background: var(--bo-red-soft); color: var(--bo-red-ink); border: 1px solid #F3C5C5; }

/* ============ ACTIONS ============ */
/* Left-aligned so the chips always start right after the data, never leaving a
   gap in front of them. It also fails safe: if the column is ever narrower than
   the chip row, the overflow runs off the right, where the wrapper's horizontal
   scroll can reach it — right-aligning would hide the first chips on the left.
   The column is additionally sized to the chips actually rendered by the
   auto-fit in wwwroot/js/bo-table-resize.js. */
.bo2 .bo-actions {
    display: flex;
    align-items: center;
    gap: 4px;
    justify-content: flex-start;
}

/* 36x38 keeps the 34:36 aspect of the icon tiles in wwwroot/icons and renders
   their baked-in labels (NOA, TEMU, …) above their native size so they stay
   legible. */
.bo2 .bo-act {
    width: 36px;
    height: 38px;
    border-radius: 6px;
    display: grid;
    place-items: center;
    position: relative;
    color: #fff;
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    overflow: visible;
    flex-shrink: 0;
    transition: transform .12s, box-shadow .12s, filter .12s;
    box-shadow: 0 1px 3px rgba(20,40,60,.2);
}

.bo2 .bo-act > img,
.bo2 .bo-act > svg {
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 6px;
}

.bo2 .bo-act:hover { transform: translateY(-1px); box-shadow: 0 3px 8px rgba(20,40,60,.25); filter: brightness(1.07); }
.bo2 .bo-act:active { transform: translateY(0); }

.bo2 .bo-act:disabled {
    cursor: not-allowed;
    filter: grayscale(.75) opacity(.5);
    transform: none;
    box-shadow: none;
}

/* Keeps chips vertically aligned across rows when an action is not
   available for a given row but is present elsewhere on the page. */
.bo2 .bo-act-slot {
    width: 36px;
    height: 38px;
    flex-shrink: 0;
}

/* solid variants for actions without a pre-coloured tile asset */
.bo2 .bo-act-blue { background: linear-gradient(180deg,var(--bo-brand) 0%,var(--bo-brand-deep) 100%); }
.bo2 .bo-act-orange { background: linear-gradient(180deg,var(--bo-orange) 0%,var(--bo-orange-deep) 100%); color: #3A2600; }
.bo2 .bo-act-green { background: linear-gradient(180deg,var(--bo-green) 0%,var(--bo-green-deep) 100%); }
.bo2 .bo-act-red { background: linear-gradient(180deg,var(--bo-red) 0%,var(--bo-red-deep) 100%); }
.bo2 .bo-act-busy { background: linear-gradient(180deg,#8FA5B7,#71889C); }

/* tooltips */
.bo2 [data-bo-tip]:hover { z-index: 1000; }

.bo2 [data-bo-tip]::after {
    content: attr(data-bo-tip);
    position: absolute;
    bottom: calc(100% + 8px);
    left: 50%;
    background: var(--bo-brand-navy);
    color: #fff;
    font-size: .7rem;
    font-weight: 560;
    font-family: var(--bo-font-ui);
    text-transform: none;
    letter-spacing: 0;
    padding: 5px 10px;
    border-radius: 7px;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    translate: -50% 3px;
    transition: opacity .14s, translate .14s;
    z-index: 1000;
    box-shadow: var(--bo-shadow-sm);
}

.bo2 [data-bo-tip]::before {
    content: "";
    position: absolute;
    bottom: calc(100% + 3px);
    left: 50%;
    translate: -50% 0;
    border: 5px solid transparent;
    border-top-color: var(--bo-brand-navy);
    opacity: 0;
    transition: opacity .14s;
    pointer-events: none;
    z-index: 1000;
}

.bo2 [data-bo-tip]:hover::after { opacity: 1; translate: -50% 0; }
.bo2 [data-bo-tip]:hover::before { opacity: 1; }

/* ============ TABLE FOOT / PAGER ============ */
.bo2 .bo-table-foot {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    padding: 13px 18px;
    border-top: 1px solid var(--bo-line);
    background: var(--bo-surface-2);
}

.bo2 .bo-per-page { display: flex; align-items: center; gap: 8px; font-size: .8rem; color: var(--bo-ink-3); }

.bo2 .bo-per-page select {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line);
    border-radius: 7px;
    padding: 5px 9px;
    font: inherit;
    color: var(--bo-ink);
    box-shadow: var(--bo-shadow-xs);
}

.bo2 .bo-pager { display: flex; align-items: center; gap: 3px; }

.bo2 .bo-pg {
    min-width: 32px;
    height: 32px;
    padding: 0 7px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    font-size: .83rem;
    font-weight: 520;
    font-family: inherit;
    color: var(--bo-ink-2);
    font-variant-numeric: tabular-nums;
    background: none;
    border: none;
    cursor: pointer;
    transition: background .13s, color .13s;
}

.bo2 .bo-pg:hover:not(:disabled) { background: var(--bo-surface); }

.bo2 .bo-pg.bo-on {
    background: linear-gradient(180deg,#1B93D0,#1180BC);
    color: #fff;
    font-weight: 650;
    box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, 0 2px 5px rgba(17,128,188,.35);
}

.bo2 .bo-pg.bo-arr { color: var(--bo-ink-3); }
.bo2 .bo-pg:disabled { opacity: .35; cursor: not-allowed; }
.bo2 .bo-pg.bo-gap { pointer-events: none; }

.bo2 .bo-rows-info { font-size: .8rem; color: var(--bo-ink-3); font-variant-numeric: tabular-nums; }

/* Compact pager (BoPagination Compact="true") for narrow panels. */
.bo2 .bo-table-foot.bo-compact-foot { padding: 8px 12px; gap: 8px; }
.bo2 .bo-table-foot.bo-compact-foot .bo-pager { gap: 2px; }
.bo2 .bo-table-foot.bo-compact-foot .bo-rows-info { font-size: .7rem; white-space: nowrap; }
.bo2 .bo-pg.bo-sm { min-width: 26px; height: 26px; padding: 0 5px; font-size: .75rem; border-radius: 6px; }

/* ============ MISC ============ */
.bo2 .bo-no-perm {
    padding: 60px 18px;
    text-align: center;
    color: var(--bo-ink-3);
    font-size: 1rem;
    font-weight: 560;
}

/* ============ FOCUS APPEARANCE ============
   Clicking never leaves a ring behind. Everything below is keyboard-only
   (:focus-visible), so pointer users see nothing; the black UA ring and the
   blue halo that used to stick to a tab or a filter after a click are gone. */
.bo2 :focus,
.bo-topnav :focus { outline: none; }

.bo2 a:focus-visible,
.bo2 button:focus-visible,
.bo-topnav a:focus-visible,
.bo-topnav button:focus-visible,
.bo-topnav summary:focus-visible {
    outline: 2px solid var(--bo-brand);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Tabs and text inputs opt out even for the keyboard: the active underline and
   the caret already say where you are, and a ring around them looks like a bug.
   Radzen's own focus shadow (dropdown/datepicker) is stripped with it. */
.bo2 .bo-stab:focus-visible,
.bo2 .bo-tab:focus-visible,
.bo2 input:focus,
.bo2 input:focus-visible,
.bo2 select:focus,
.bo2 select:focus-visible,
.bo2 textarea:focus,
.bo2 textarea:focus-visible {
    outline: none;
    box-shadow: none;
}

.bo2 .bo-field .rz-state-focused,
.bo2 .bo-field .rz-dropdown:focus,
.bo2 .bo-field .rz-dropdown:focus-within,
.bo2 .bo-field .rz-textbox:focus,
.bo2 .bo-field .rz-datepicker:focus-within {
    outline: none !important;
    box-shadow: none !important;
    border-color: transparent !important;
}

@media (prefers-reduced-motion: reduce) {
    .bo2 *, .bo-topnav * { transition: none !important; animation: none !important; }
}

/* Tighten the link strip before it can push the user chip off-screen. */
@media (max-width: 1360px) {
    .bo-topnav { padding: 0 14px; }
    .bo-brand { margin-right: 14px; }
    .bo-nav-link { padding: 0 9px; font-size: .84rem; }
    .bo-nav-link::after { left: 9px; right: 9px; }
}

@media (max-width: 1120px) {
    .bo-nav-link { padding: 0 6px; font-size: .8rem; }
    .bo-nav-link::after { left: 6px; right: 6px; }
    .bo-user-chip .bo-name { display: none; }
}

@media (max-width: 960px) {
    .bo-shell { padding: 16px 12px 26px; }
    .bo-nav-links { display: none; }
    .bo-page-foot { padding: 0 12px 14px; }
}

/* ==========================================================
   WAREHOUSE MASTER-DETAIL (variant B)
   Ported from docs/design/beeonline-warehouse-detail-2.0-variantaB.html
   Left: AWB list. Right: detail with Parcels/Masters tabs, bulk
   actions and the detail of the selected parcel. Scoped under .bo2.
   ========================================================== */

.bo2 .bo-wh-layout {
    display: grid;
    grid-template-columns: 352px minmax(0, 1fr);
    gap: 16px;
    align-items: stretch;
}

/* ---------- LEFT: AWB list ---------- */
/* Sticky against .rz-body, which is the scroll container, so top:0 means the
   top of the visible area rather than of the document. */
.bo2 .bo-list-panel {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-lg);
    box-shadow: var(--bo-shadow-md);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    align-self: start;
    position: sticky;
    top: 0;
    max-height: calc(100dvh - 96px);
    min-height: 520px;
}

.bo2 .bo-list-head {
    padding: 13px 14px 11px;
    border-bottom: 1px solid var(--bo-line-soft);
    display: flex;
    flex-direction: column;
    gap: 9px;
}

.bo2 .bo-list-head .bo-field { width: 100%; }
.bo2 .bo-list-head-row { display: flex; flex-direction: column; gap: 8px; }
.bo2 .bo-list-foot-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bo2 .bo-list-count { font-size: .72rem; color: var(--bo-ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }

.bo2 .bo-awb-list {
    overflow-y: auto;
    flex: 1;
    padding: 8px;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-awb-list::-webkit-scrollbar { width: 9px; }
.bo2 .bo-awb-list::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }
.bo2 .bo-awb-list::-webkit-scrollbar-thumb:hover { background: #A9B8C6; }

.bo2 .bo-awb {
    width: 100%;
    text-align: left;
    border-radius: var(--bo-radius);
    padding: 11px 12px;
    display: flex;
    flex-direction: column;
    gap: 7px;
    border: 1px solid transparent;
    position: relative;
    background: none;
    cursor: pointer;
    font: inherit;
    color: inherit;
    transition: background .13s, border-color .13s;
}

.bo2 .bo-awb:hover { background: var(--bo-surface-2); }
.bo2 .bo-awb.bo-on { background: var(--bo-brand-tint); border-color: #C7E3F4; }

.bo2 .bo-awb.bo-on::before {
    content: "";
    position: absolute;
    left: -1px;
    top: 10px;
    bottom: 10px;
    width: 3px;
    border-radius: 0 3px 3px 0;
    background: var(--bo-brand);
}

.bo2 .bo-awb-top { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.bo2 .bo-awb-code { font-family: var(--bo-font-mono); font-size: .8rem; font-weight: 560; letter-spacing: -.01em; }
.bo2 .bo-awb.bo-on .bo-awb-code { color: var(--bo-brand-ink); }
.bo2 .bo-awb-cust { font-size: .72rem; color: var(--bo-ink-3); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bo2 .bo-awb-stats { display: flex; flex-direction: column; gap: 3px; }

.bo2 .bo-stat-line {
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: .72rem;
    font-variant-numeric: tabular-nums;
    color: var(--bo-ink-2);
    white-space: nowrap;
}

.bo2 .bo-stat-line .bo-k { width: 16px; font-weight: 720; color: var(--bo-ink-3); font-size: .64rem; letter-spacing: .03em; }
.bo2 .bo-stat-line .bo-sep { color: var(--bo-ink-3); opacity: .6; }
.bo2 .bo-stat-line .bo-tot { color: var(--bo-ink-3); }

.bo2 .bo-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; display: inline-block; }
.bo2 .bo-dot-g { background: var(--bo-green); }
.bo2 .bo-dot-y { background: var(--bo-orange); }
.bo2 .bo-dot-r { background: var(--bo-red); }

.bo2 .bo-list-pager { border-top: 1px solid var(--bo-line); background: var(--bo-surface-2); }

/* ---------- RIGHT: detail ---------- */
.bo2 .bo-detail {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-lg);
    box-shadow: var(--bo-shadow-md);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
    position: relative;
}

.bo2 .bo-detail-empty {
    padding: 90px 24px;
    text-align: center;
    color: var(--bo-ink-3);
    font-size: .92rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
}

.bo2 .bo-detail-empty svg { color: #C3CFDA; }

/* The entrance animation makes this a stacking context, so a z-index set on a
   button inside it can no longer lift anything above the progress strip that
   follows — the head as a whole is painted first. Stacking the head above its
   siblings puts its tooltips back on top. The strip and the tabs are given
   explicit lower layers rather than left to source order, so the intent
   survives anything reordered later. */
.bo2 .bo-detail-head {
    padding: 16px 20px 0;
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    position: relative;
    z-index: 3;
}

.bo2 .bo-dh-left { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.bo2 .bo-dh-code-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.bo2 .bo-dh-code { font-family: var(--bo-font-mono); font-size: 1.16rem; font-weight: 620; letter-spacing: -.01em; }
.bo2 .bo-dh-meta { font-size: .74rem; color: var(--bo-ink-3); display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.bo2 .bo-dh-meta b { color: var(--bo-ink-2); font-weight: 580; }
.bo2 .bo-dh-actions { display: flex; gap: 7px; flex-wrap: wrap; }

/* Detail-head actions are secondary to the waybill itself — a size down from
   the default button keeps the header calm. */
.bo2 .bo-dh-actions .bo-btn { padding: 7px 12px; font-size: .79rem; gap: 6px; }
.bo2 .bo-dh-actions .bo-btn svg { width: 13px; height: 13px; }
.bo2 .bo-dh-code-row .bo-copy { opacity: 1; width: 24px; height: 24px; }

.bo2 .bo-btn-danger-ghost {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line);
    color: var(--bo-red-deep);
    box-shadow: var(--bo-shadow-xs);
}

.bo2 .bo-btn-danger-ghost:hover:not(.bo-off) { border-color: var(--bo-red); background: var(--bo-red-soft); }

/* Disabled actions stay visible and explain themselves through the tooltip
   instead of vanishing, so the workflow order stays discoverable. */
.bo2 .bo-btn.bo-off { opacity: .45; cursor: not-allowed; box-shadow: none; }
.bo2 .bo-btn.bo-off:hover { background: var(--bo-surface); border-color: var(--bo-line); color: var(--bo-ink-2); }
.bo2 .bo-btn.bo-off:active { transform: none; }
.bo2 .bo-btn-primary.bo-off:hover { background: linear-gradient(180deg,#1B93D0,#1180BC); color: #fff; }
.bo2 .bo-btn-danger-ghost.bo-off:hover { color: var(--bo-red-deep); }

/* Tooltip below the button. Safe here because the detail head is not inside a
   scroll container (unlike .bo-table-wrap, where tooltips get clipped). */
.bo2 .bo-btn[data-bo-tip-b] { position: relative; }
.bo2 .bo-btn[data-bo-tip-b]:hover { z-index: 1000; }

.bo2 .bo-btn[data-bo-tip-b]::after {
    content: attr(data-bo-tip-b);
    position: absolute;
    top: calc(100% + 8px);
    left: 50%;
    translate: -50% -3px;
    background: var(--bo-brand-navy);
    color: #fff;
    font-size: .7rem;
    font-weight: 520;
    line-height: 1.45;
    padding: 5px 10px;
    border-radius: 7px;
    /* max-content, not the default shrink-to-fit: the containing block is the
       button, so an auto width would wrap a long reason into a 40px column. */
    width: max-content;
    max-width: min(320px, 60vw);
    pointer-events: none;
    opacity: 0;
    transition: opacity .14s, translate .14s;
    z-index: 1000;
    box-shadow: var(--bo-shadow-sm);
}

/* The actions row is right-aligned inside a panel that clips its overflow, so
   a tooltip centred on the button at either end hangs outside the panel — the
   T1 one landed under the AWB list. Those two anchor to their own edge instead;
   everything between them is far enough from both edges to stay centred. The
   arrow keeps pointing at the middle of its button either way. */
.bo2 .bo-dh-actions .bo-btn[data-bo-tip-b]:first-child::after { left: 0; translate: 0 -3px; }
.bo2 .bo-dh-actions .bo-btn[data-bo-tip-b]:first-child:hover::after { translate: 0 0; }

.bo2 .bo-dh-actions .bo-btn[data-bo-tip-b]:last-child::after { left: auto; right: 0; translate: 0 -3px; }
.bo2 .bo-dh-actions .bo-btn[data-bo-tip-b]:last-child:hover::after { translate: 0 0; }

.bo2 .bo-btn[data-bo-tip-b]::before {
    content: "";
    position: absolute;
    top: calc(100% + 3px);
    left: 50%;
    translate: -50% 0;
    border: 5px solid transparent;
    border-bottom-color: var(--bo-brand-navy);
    opacity: 0;
    transition: opacity .14s;
    pointer-events: none;
    z-index: 1000;
}

.bo2 .bo-btn[data-bo-tip-b]:hover::after { opacity: 1; translate: -50% 0; }
.bo2 .bo-btn[data-bo-tip-b]:hover::before { opacity: 1; }

/* ---------- progress strip ---------- */
/* Below .bo-detail-head so the tooltips hanging off its buttons stay on top. */
.bo2 .bo-prog-strip {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 10px;
    padding: 14px 20px 16px;
    position: relative;
    z-index: 1;
}

.bo2 .bo-prog {
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    padding: 10px 14px;
    display: flex;
    flex-direction: column;
    gap: 6px;
    min-width: 0;
}

/* wrap + flex-shrink:0 on the value: in a narrow column the nowrap figure would
   otherwise be squeezed and clipped instead of moving to its own line. */
.bo2 .bo-prog-top { display: flex; align-items: baseline; justify-content: space-between; gap: 4px 8px; flex-wrap: wrap; }
.bo2 .bo-prog-label { font-size: .68rem; font-weight: 680; letter-spacing: .07em; text-transform: uppercase; color: var(--bo-ink-3); }
.bo2 .bo-prog-val { font-size: .86rem; font-weight: 680; font-variant-numeric: tabular-nums; white-space: nowrap; flex-shrink: 0; }
.bo2 .bo-prog-val .bo-of { color: var(--bo-ink-3); font-weight: 500; }
.bo2 .bo-prog-right { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }

.bo2 .bo-blocked-chip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .66rem;
    font-weight: 720;
    letter-spacing: .03em;
    padding: 2px 8px;
    border-radius: 999px;
    background: var(--bo-red-soft);
    color: var(--bo-red-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.bo2 .bo-blocked-chip svg { flex-shrink: 0; }

.bo2 .bo-bar { height: 5px; border-radius: 3px; background: #DCE4EB; overflow: hidden; }
.bo2 .bo-bar i { display: block; height: 100%; border-radius: 3px; }
.bo2 .bo-bar i.bo-g { background: linear-gradient(90deg,var(--bo-green),var(--bo-green-deep)); }
.bo2 .bo-bar i.bo-y { background: linear-gradient(90deg,var(--bo-orange),var(--bo-orange-deep)); }
.bo2 .bo-bar i.bo-b { background: linear-gradient(90deg,#2E9FD9,var(--bo-brand-deep)); }

/* ---------- inner tabs ---------- */
.bo2 .bo-tabs { display: flex; align-items: flex-end; gap: 2px; padding: 0 20px; border-bottom: 1px solid var(--bo-line); }

.bo2 .bo-tab {
    padding: 9px 15px;
    font-size: .86rem;
    font-weight: 590;
    font-family: inherit;
    color: var(--bo-ink-3);
    position: relative;
    transition: color .15s;
    display: flex;
    align-items: center;
    gap: 7px;
    background: none;
    border: none;
    cursor: pointer;
}

.bo2 .bo-tab:hover { color: var(--bo-ink-2); }
.bo2 .bo-tab.bo-on { color: var(--bo-brand-ink); }
.bo2 .bo-tab.bo-on::after { content: ""; position: absolute; left: 10px; right: 10px; bottom: -1px; height: 3px; border-radius: 3px 3px 0 0; background: var(--bo-brand); }

.bo2 .bo-tab .bo-n {
    font-size: .66rem;
    font-weight: 680;
    font-variant-numeric: tabular-nums;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-3);
}

.bo2 .bo-tab.bo-on .bo-n { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }

/* ---------- bulk toolbar ---------- */
.bo2 .bo-bulkbar {
    display: flex;
    align-items: center;
    gap: 8px;
    flex-wrap: wrap;
    padding: 11px 20px;
    border-bottom: 1px solid var(--bo-line-soft);
    background: var(--bo-surface-2);
}

.bo2 .bo-bulk-info {
    font-size: .78rem;
    font-weight: 620;
    color: var(--bo-brand-ink);
    background: var(--bo-brand-soft);
    padding: 4px 11px;
    border-radius: 999px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.bo2 .bo-bulk-sep { width: 1px; height: 22px; background: var(--bo-line); margin: 0 3px; }

.bo2 .bo-chipbtn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 12px;
    border-radius: var(--bo-radius-sm);
    font-size: .74rem;
    font-weight: 680;
    letter-spacing: .02em;
    font-family: inherit;
    border: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background .13s, color .13s, transform .12s, box-shadow .12s;
}

.bo2 .bo-chipbtn:hover:not(:disabled) { transform: translateY(-1px); }
.bo2 .bo-chipbtn:disabled { opacity: .4; cursor: not-allowed; }
.bo2 .bo-chipbtn svg { flex-shrink: 0; }

.bo2 .bo-chipbtn.bo-blue { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 .bo-chipbtn.bo-blue:hover:not(:disabled) { background: var(--bo-brand); color: #fff; box-shadow: 0 3px 8px rgba(20,137,200,.35); }
.bo2 .bo-chipbtn.bo-red { background: var(--bo-red-soft); color: var(--bo-red-ink); }
.bo2 .bo-chipbtn.bo-red:hover:not(:disabled) { background: var(--bo-red); color: #fff; box-shadow: 0 3px 8px rgba(218,76,76,.35); }
.bo2 .bo-chipbtn.bo-green { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-chipbtn.bo-green:hover:not(:disabled) { background: var(--bo-green-deep); color: #fff; box-shadow: 0 3px 8px rgba(38,138,77,.35); }

.bo2 .bo-search-row { display: flex; align-items: center; gap: 10px; padding: 9px 20px; border-bottom: 1px solid var(--bo-line-soft); flex-wrap: wrap; }
.bo2 .bo-field.bo-bulk-search { flex: 0 1 260px; min-width: 180px; }

/* ---------- compact table inside the detail ---------- */
.bo2 .bo-tbl-wrap {
    overflow: auto;
    max-height: 430px;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-tbl-wrap::-webkit-scrollbar { width: 9px; height: 9px; }
.bo2 .bo-tbl-wrap::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }
.bo2 .bo-tbl-wrap::-webkit-scrollbar-thumb:hover { background: #A9B8C6; }

.bo2 table.bo-table.bo-compact { min-width: 0; }
.bo2 table.bo-table.bo-compact thead th { padding: 9px 8px; font-size: .64rem; letter-spacing: .06em; }
.bo2 table.bo-table.bo-compact thead th.bo-center { text-align: center; }
.bo2 table.bo-table.bo-compact tbody td { padding: 10px 8px; font-size: .82rem; }
.bo2 table.bo-table.bo-compact tbody td.bo-center { text-align: center; }

.bo2 table.bo-table.bo-compact th.bo-sel,
.bo2 table.bo-table.bo-compact td.bo-sel {
    width: 36px;
    padding-right: 2px !important;
    padding-left: 12px !important;
}

.bo2 table.bo-table tbody tr.bo-prow { cursor: pointer; }
.bo2 table.bo-table tbody tr.bo-prow.bo-on { background: var(--bo-brand-tint); }
.bo2 table.bo-table tbody tr.bo-prow.bo-on td:first-child { box-shadow: 3px 0 0 var(--bo-brand) inset; }

.bo2 .bo-mono { font-family: var(--bo-font-mono); font-size: .76rem; font-weight: 530; letter-spacing: -.01em; }
.bo2 .bo-mono-2 { color: var(--bo-ink-2); }
.bo2 .bo-guid { font-family: var(--bo-font-mono); font-size: .64rem; color: var(--bo-ink-3); letter-spacing: -.02em; white-space: nowrap; }
.bo2 .bo-sub { font-size: .7rem; color: var(--bo-ink-3); }

/* ---------- status triplet ---------- */
.bo2 .bo-st3 { display: inline-flex; align-items: center; gap: 5px; }
.bo2 .bo-st { display: inline-flex; flex-direction: column; align-items: center; gap: 2px; width: 24px; }
.bo2 .bo-st .bo-ic { width: 20px; height: 20px; border-radius: 50%; display: grid; place-items: center; }
.bo2 .bo-st .bo-ic.bo-ok { background: var(--bo-green-soft); color: var(--bo-green-deep); }
.bo2 .bo-st .bo-ic.bo-no { background: var(--bo-surface-3); color: #AEBBC6; }
.bo2 .bo-st .bo-ic.bo-blk { background: var(--bo-red-soft); color: var(--bo-red-deep); }
.bo2 .bo-st .bo-ic.bo-wait { background: var(--bo-orange-soft); color: var(--bo-orange-deep); }
.bo2 .bo-st .bo-ic.bo-q { background: var(--bo-surface-3); color: var(--bo-ink-3); }
.bo2 .bo-st .bo-ic.bo-info { background: var(--bo-brand-soft); color: var(--bo-brand-deep); }
.bo2 .bo-st .bo-lb { font-size: .55rem; font-weight: 720; letter-spacing: .04em; color: var(--bo-ink-3); }

/* ---------- provider chip ---------- */
.bo2 .bo-provider-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .72rem;
    font-weight: 620;
    padding: 3px 9px 3px 4px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-2);
    max-width: 100%;
}

.bo2 .bo-plogo {
    width: 20px;
    height: 20px;
    border-radius: 6px;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    font-size: .46rem;
    font-weight: 800;
    letter-spacing: -.02em;
    color: #fff;
    box-shadow: 0 1px 2px rgba(16,42,64,.2);
}

.bo2 .bo-plogo.bo-ppl { background: #0A4E9B; }
.bo2 .bo-plogo.bo-dpd { background: #DC0032; }
.bo2 .bo-plogo.bo-zas { background: #BA1B02; }
.bo2 .bo-plogo.bo-cp { background: #FFCC00; color: #004B93; }
.bo2 .bo-plogo.bo-ara { background: #C8102E; }
.bo2 .bo-plogo.bo-gei { background: #E2001A; }
.bo2 .bo-plogo.bo-bee { background: var(--bo-orange-deep); color: #3B2600; }
.bo2 .bo-plogo.bo-gen { background: #7E90A1; }

/* ---------- selected parcel detail ---------- */
.bo2 .bo-pdetail {
    border-top: 1px solid var(--bo-line);
    background: var(--bo-surface-2);
    padding: 14px 20px 18px;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

.bo2 .bo-pd-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.bo2 .bo-pd-title { display: flex; align-items: center; gap: 9px; font-size: .9rem; font-weight: 640; color: var(--bo-ink-2); }
.bo2 .bo-pd-title .bo-mono { font-size: .88rem; color: var(--bo-ink); font-weight: 600; }
.bo2 .bo-pd-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.bo2 .bo-pd-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); gap: 10px; }

.bo2 .bo-pd-card {
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    padding: 12px 14px;
    box-shadow: var(--bo-shadow-xs);
    display: flex;
    flex-direction: column;
    gap: 4px;
    min-width: 0;
}

.bo2 .bo-pd-card-title { font-size: .62rem; font-weight: 720; letter-spacing: .08em; text-transform: uppercase; color: var(--bo-ink-3); margin-bottom: 3px; }
.bo2 .bo-pd-name { font-weight: 620; font-size: .85rem; }
.bo2 .bo-pd-line { font-size: .77rem; color: var(--bo-ink-2); }
.bo2 .bo-pd-empty { font-size: .77rem; color: var(--bo-ink-3); font-style: italic; }
.bo2 .bo-pd-kv { display: flex; align-items: center; justify-content: space-between; gap: 10px; font-size: .77rem; }
.bo2 .bo-pd-kv .bo-k { color: var(--bo-ink-3); }
.bo2 .bo-pd-kv .bo-v { font-weight: 600; font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.bo2 .bo-pd-kv .bo-v.bo-good { color: var(--bo-green-ink); }
.bo2 .bo-pd-kv .bo-v.bo-bad { color: var(--bo-red-ink); }

.bo2 .bo-items-title { font-size: .68rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--bo-ink-3); margin-bottom: 8px; }

/* Cells don't wrap (see tbody td below), so a long Description can push the
   zoom button in the last column off-screen with no way to reach it — this
   wrapper adds a horizontal scrollbar instead of letting the table overflow
   its parent silently. */
.bo2 .bo-items-tbl-wrap {
    overflow-x: auto;
    border-radius: var(--bo-radius-sm);
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-items-tbl-wrap::-webkit-scrollbar { height: 9px; }
.bo2 .bo-items-tbl-wrap::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }
.bo2 .bo-items-tbl-wrap::-webkit-scrollbar-thumb:hover { background: #A9B8C6; }

.bo2 table.bo-items-tbl {
    width: 100%;
    border-collapse: collapse;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-sm);
    overflow: hidden;
    box-shadow: var(--bo-shadow-xs);
}

.bo2 table.bo-items-tbl thead th {
    background: var(--bo-surface-2);
    padding: 7px 12px;
    font-size: .62rem;
    font-weight: 680;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    text-align: left;
    border-bottom: 1px solid var(--bo-line-soft);
    white-space: nowrap;
}

.bo2 table.bo-items-tbl thead th.bo-num { text-align: right; }
.bo2 table.bo-items-tbl tbody td { padding: 8px 12px; font-size: .8rem; border-bottom: 1px solid var(--bo-line-soft); white-space: nowrap; }
.bo2 table.bo-items-tbl tbody td.bo-num { text-align: right; font-variant-numeric: tabular-nums; }
.bo2 table.bo-items-tbl tbody tr:last-child td { border-bottom: none; }

.bo2 .bo-lbl-btn {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .72rem;
    font-weight: 680;
    padding: 5px 10px;
    border-radius: 7px;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-ink);
    border: none;
    cursor: pointer;
    font-family: inherit;
    transition: background .13s, color .13s;
}

.bo2 .bo-lbl-btn:hover { background: var(--bo-brand); color: #fff; }

/* ---------- sortable column headers ----------
   line-height:0 on the cell stops the inherited text box from adding a couple of
   dead pixels below the button, so the whole header is a hit target. */
.bo2 th.bo-sortable { padding: 0 !important; line-height: 0; }

.bo2 .bo-sort-btn {
    display: flex;
    align-items: center;
    gap: 5px;
    width: 100%;
    height: 100%;
    padding: 9px 8px;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
    /* must come after the `font` shorthand — that shorthand resets line-height,
       and the cell sets it to 0 to avoid a stray line box under the button. */
    line-height: 1.45;
    color: inherit;
    letter-spacing: inherit;
    text-transform: inherit;
    text-align: inherit;
    transition: color .13s, background .13s;
}

.bo2 .bo-sort-btn:hover { color: var(--bo-ink-2); background: var(--bo-surface-2); }
.bo2 .bo-sort-btn.bo-on { color: var(--bo-brand-ink); }
.bo2 th.bo-num .bo-sort-btn { justify-content: flex-end; }
.bo2 th.bo-center .bo-sort-btn { justify-content: center; }

/* Arrow is reserved even when unsorted, so headers do not jump on click. */
.bo2 .bo-sort-arrow {
    width: 9px;
    flex-shrink: 0;
    font-size: .85em;
    line-height: 1;
    opacity: 0;
    transition: opacity .13s;
}

.bo2 .bo-sort-btn:hover .bo-sort-arrow { opacity: .45; }
.bo2 .bo-sort-btn.bo-on .bo-sort-arrow { opacity: 1; color: var(--bo-brand); }

/* ---------- parcel timeline ---------- */
.bo2 .bo-timeline {
    display: flex;
    flex-direction: column;
    gap: 0;
    position: relative;
    padding-left: 4px;
}

.bo2 .bo-tl-item {
    display: grid;
    grid-template-columns: 26px minmax(0, 1fr);
    gap: 10px;
    position: relative;
    padding-bottom: 14px;
}

.bo2 .bo-tl-item:last-child { padding-bottom: 0; }

/* Connector runs from each dot down to the next one. */
.bo2 .bo-tl-item:not(:last-child)::before {
    content: "";
    position: absolute;
    left: 12px;
    top: 24px;
    bottom: 0;
    width: 2px;
    background: var(--bo-line);
    border-radius: 2px;
}

.bo2 .bo-tl-ic {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    flex-shrink: 0;
    z-index: 1;
    border: 2px solid var(--bo-surface-2);
    box-sizing: content-box;
    margin-left: -2px;
    margin-top: -2px;
}

.bo2 .bo-tl-ic.bo-k-milestone { background: var(--bo-brand-soft); color: var(--bo-brand-deep); }
.bo2 .bo-tl-ic.bo-k-customs { background: var(--bo-orange-soft); color: var(--bo-orange-deep); }
.bo2 .bo-tl-ic.bo-k-transit { background: var(--bo-surface-3); color: var(--bo-ink-2); }
.bo2 .bo-tl-ic.bo-k-problem { background: var(--bo-red-soft); color: var(--bo-red-deep); }
.bo2 .bo-tl-ic.bo-k-done { background: var(--bo-green-soft); color: var(--bo-green-deep); }

.bo2 .bo-tl-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; padding-top: 3px; }

.bo2 .bo-tl-top {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    flex-wrap: wrap;
}

.bo2 .bo-tl-label { font-size: .82rem; font-weight: 600; color: var(--bo-ink); }
.bo2 .bo-tl-date { font-size: .72rem; color: var(--bo-ink-3); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bo2 .bo-tl-meta { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: .72rem; color: var(--bo-ink-3); }

.bo2 .bo-tl-chip {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    padding: 1px 7px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-2);
    font-size: .66rem;
    font-weight: 640;
    white-space: nowrap;
}

.bo2 .bo-tl-chip.bo-code { font-family: var(--bo-font-mono); letter-spacing: -.02em; }

/* The timeline card spans the full detail width — it is a list, not a stat block. */
.bo2 .bo-pd-card.bo-pd-wide { grid-column: 1 / -1; }
.bo2 .bo-pd-card.bo-pd-wide .bo-timeline { margin-top: 4px; }

@media (max-width: 1100px) {
    .bo2 .bo-wh-layout { grid-template-columns: 1fr; }
    .bo2 .bo-list-panel { position: static; max-height: 360px; min-height: 0; }
    .bo2 .bo-prog-strip { grid-template-columns: 1fr; }
}

/* ==========================================================
   CUSTOMS — block / unblock card and blocked waybills table
   Ported from docs/design/beeonline-customs-detail-2.0.html
   ========================================================== */

.bo2 .bo-actions-card {
    display: grid;
    grid-template-columns: 1.4fr auto 1fr;
    gap: 0;
    margin-bottom: 18px;
}

.bo2 .bo-block-col { padding: 18px 22px; display: flex; flex-direction: column; gap: 14px; }

.bo2 .bo-col-title {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .7rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    margin-bottom: 2px;
}

.bo2 .bo-col-title svg { color: var(--bo-red); }
.bo2 .bo-col-title.bo-good svg { color: var(--bo-green); }

.bo2 .bo-block-row { display: flex; flex-direction: column; gap: 6px; }
.bo2 .bo-block-label { font-size: .78rem; font-weight: 600; color: var(--bo-ink-2); }
.bo2 .bo-block-input-row { display: flex; gap: 9px; align-items: stretch; }

/* The block form uses a bordered field variant — it is a form, not a filter bar. */
.bo2 .bo-block-input-row .bo-field { flex: 1; border-color: var(--bo-line); height: auto; padding: 9px 12px; }
.bo2 .bo-block-input-row .bo-field:hover { border-color: var(--bo-ink-3); }
.bo2 .bo-field .bo-hint { font-size: .66rem; color: var(--bo-ink-3); white-space: nowrap; }

.bo2 .bo-btn-block {
    background: linear-gradient(180deg,var(--bo-red) 0%,var(--bo-red-deep) 100%);
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(218,76,76,.32);
    justify-content: center;
}

.bo2 .bo-btn-unblock {
    background: linear-gradient(180deg,var(--bo-green) 0%,var(--bo-green-deep) 100%);
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(38,138,77,.32);
    padding: 11px 22px;
    font-size: .87rem;
    justify-content: center;
}

.bo2 .bo-btn-block:hover:not(:disabled),
.bo2 .bo-btn-unblock:hover:not(:disabled) { filter: brightness(1.06); }

.bo2 .bo-btn-block:disabled,
.bo2 .bo-btn-unblock:disabled { opacity: .4; cursor: not-allowed; box-shadow: none; filter: none; transform: none; }

.bo2 .bo-card-sep { width: 1px; background: var(--bo-line-soft); margin: 16px 0; }

.bo2 .bo-unblock-col {
    padding: 18px 22px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 12px;
    background: var(--bo-surface-2);
}

.bo2 .bo-unblock-icon {
    width: 46px;
    height: 46px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    background: var(--bo-green-soft);
    color: var(--bo-green-deep);
}

.bo2 .bo-unblock-copy { text-align: center; display: flex; flex-direction: column; gap: 2px; }
.bo2 .bo-unblock-copy .bo-t { font-size: .86rem; font-weight: 640; }
.bo2 .bo-unblock-copy .bo-s { font-size: .74rem; color: var(--bo-ink-3); }

.bo2 .bo-sel-count {
    font-size: .72rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    color: var(--bo-brand-ink);
    background: var(--bo-brand-soft);
    padding: 2px 9px;
    border-radius: 999px;
}

/* ---------- table head with title + filters ---------- */
.bo2 .bo-table-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
    padding: 14px 18px;
    border-bottom: 1px solid var(--bo-line-soft);
}

.bo2 .bo-th-title { display: flex; align-items: center; gap: 10px; }
.bo2 .bo-th-title h2 { font-size: 1rem; font-weight: 660; letter-spacing: -.01em; margin: 0; }

.bo2 .bo-count-pill {
    font-size: .72rem;
    font-weight: 650;
    font-variant-numeric: tabular-nums;
    color: var(--bo-red-ink);
    background: var(--bo-red-soft);
    padding: 3px 11px;
    border-radius: 999px;
}

.bo2 .bo-count-pill.bo-quiet { color: var(--bo-ink-3); background: var(--bo-surface-3); }
/* flex-shrink:0 keeps both filters on one line — as a wrapping flex container it
   would otherwise be shrunk below its content and break onto two rows. When the
   head really is too narrow, .bo-table-head wraps the whole block instead. */
/* align-items:center, so a bare separator between two 38px fields sits on their
   midline instead of riding the top edge. */
.bo2 .bo-filters { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; flex-shrink: 0; }
.bo2 .bo-field.bo-filter { flex: 0 0 210px; }

/* A date range is two fields, so they are narrower than a standalone filter. */
.bo2 .bo-field.bo-filter.bo-filter-date { flex: 0 0 158px; }

/* ---------- master row + expandable parcels ---------- */
.bo2 table.bo-table th.bo-exp,
.bo2 table.bo-table td.bo-exp { width: 40px; padding-right: 0 !important; }

.bo2 .bo-expand {
    width: 28px;
    height: 28px;
    border-radius: 8px;
    display: inline-grid;
    place-items: center;
    color: var(--bo-ink-3);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: background .13s, color .13s, rotate .18s;
}

.bo2 .bo-expand:hover { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 tr.bo-expanded .bo-expand { rotate: 90deg; color: var(--bo-brand-ink); }
.bo2 table.bo-table tbody tr.bo-mrow.bo-expanded { background: var(--bo-brand-tint); }

.bo2 .bo-wb-code-lg { font-family: var(--bo-font-mono); font-size: .86rem; font-weight: 560; letter-spacing: -.01em; }

.bo2 .bo-blocked-badge {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .8rem;
    font-weight: 680;
    font-variant-numeric: tabular-nums;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--bo-red-soft);
    color: var(--bo-red-ink);
}

.bo2 .bo-blocked-badge svg { flex-shrink: 0; }

.bo2 table.bo-table tbody tr.bo-parcels-row > td {
    padding: 0 !important;
    border-bottom: 1px solid var(--bo-line-soft);
    background: var(--bo-brand-tint);
}

.bo2 .bo-parcels-box { padding: 12px 18px 15px 58px; }

.bo2 .bo-parcels-title {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    margin-bottom: 8px;
}

.bo2 table.bo-sub-tbl {
    width: 100%;
    border-collapse: collapse;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-sm);
    overflow: hidden;
    box-shadow: var(--bo-shadow-xs);
}

.bo2 table.bo-sub-tbl thead th {
    background: var(--bo-surface-2);
    padding: 8px 13px;
    font-size: .62rem;
    font-weight: 680;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    text-align: left;
    border-bottom: 1px solid var(--bo-line-soft);
    white-space: nowrap;
}

.bo2 table.bo-sub-tbl thead th.bo-right { text-align: right; padding-right: 16px; }
.bo2 table.bo-sub-tbl td { padding: 9px 13px; font-size: .82rem; border-bottom: 1px solid var(--bo-line-soft); white-space: nowrap; }
.bo2 table.bo-sub-tbl td.bo-right { text-align: right; }
.bo2 table.bo-sub-tbl tr:last-child td { border-bottom: none; }
.bo2 table.bo-sub-tbl tbody tr:hover td { background: var(--bo-surface-2); }
.bo2 table.bo-sub-tbl th.bo-sel, .bo2 table.bo-sub-tbl td.bo-sel { width: 46px; }

.bo2 .bo-remark {
    font-size: .68rem;
    color: var(--bo-orange-ink);
    background: var(--bo-orange-soft);
    padding: 2px 8px;
    border-radius: 5px;
    font-weight: 600;
    display: inline-flex;
    align-items: center;
    gap: 4px;
    max-width: 260px;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bo2 .bo-remark svg { flex-shrink: 0; }

/* The text needs its own box to ellipsise — as a bare text node inside the
   inline-flex chip it becomes an anonymous flex item and just gets cut off. */
.bo2 .bo-remark > span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.bo2 .bo-remark-none { color: var(--bo-ink-3); font-size: .78rem; }

.bo2 .bo-pactions { display: flex; align-items: center; gap: 3px; justify-content: flex-end; opacity: .5; transition: opacity .13s; }
.bo2 table.bo-sub-tbl tbody tr:hover .bo-pactions { opacity: 1; }

.bo2 .bo-iconbtn {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    display: grid;
    place-items: center;
    color: var(--bo-ink-3);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: background .13s, color .13s;
}

.bo2 .bo-iconbtn:hover { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 .bo-iconbtn.bo-remark-btn:hover { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }

/* Tri-state master checkbox: dash when only some parcels of the master are picked. */
.bo2 .bo-cb.bo-tri { background: var(--bo-brand); border-color: var(--bo-brand); }
.bo2 .bo-cb.bo-tri::after { content: ""; width: 9px; height: 2.5px; background: #fff; clip-path: none; border-radius: 2px; }

@media (max-width: 900px) {
    .bo2 .bo-actions-card { grid-template-columns: 1fr; }
    .bo2 .bo-card-sep { width: auto; height: 1px; margin: 0 22px; }
}

/* ==========================================================
   RETURNS — filter card and returned parcels table
   Ported from docs/design/beeonline-returns-detail-2.0.html
   ========================================================== */

.bo2 .bo-filter-card { margin-bottom: 18px; padding: 16px 20px; display: flex; flex-direction: column; gap: 16px; }
.bo2 .bo-filter-row { display: flex; align-items: flex-end; gap: 20px; flex-wrap: wrap; }
.bo2 .bo-f-group { display: flex; flex-direction: column; gap: 6px; }
.bo2 .bo-f-label { font-size: .68rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; color: var(--bo-ink-3); }
.bo2 .bo-f-dates { display: flex; align-items: center; gap: 8px; }
.bo2 .bo-dash { color: var(--bo-ink-3); font-weight: 600; }
.bo2 .bo-vsep { width: 1px; align-self: stretch; background: var(--bo-line-soft); margin: 2px 0; }

/* Bordered variant — the filter card is a form, not a toolbar. */
.bo2 .bo-filter-card .bo-field { border-color: var(--bo-line); }
.bo2 .bo-filter-card .bo-field:hover { border-color: var(--bo-ink-3); }
.bo2 .bo-field.bo-date { width: 148px; }

/* .bo-f-group is a COLUMN flex, so any flex-basis on a child is a height, not
   a width. .bo-field.bo-filter (flex:0 0 210px) and .bo-field.bo-search
   (flex:1) are written for the horizontal .bo-filters row; dropped into a
   group they stretched the input box to 210px tall. Pin the basis back to the
   content and express the size as an actual width. */
.bo2 .bo-f-group > .bo-field { flex: 0 0 auto; }
.bo2 .bo-f-group > .bo-field.bo-filter,
.bo2 .bo-f-group > .bo-field.bo-search { width: 230px; max-width: none; }
.bo2 .bo-f-group > .bo-field.bo-filter > input,
.bo2 .bo-f-group > .bo-field.bo-search > input { flex: 1; min-width: 0; }

.bo2 .bo-status-toggles { display: flex; gap: 8px; flex-wrap: wrap; }

.bo2 .bo-stoggle {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px;
    border-radius: 999px;
    border: 1px solid var(--bo-line);
    background: var(--bo-surface);
    font-size: .8rem;
    font-weight: 560;
    color: var(--bo-ink-2);
    cursor: pointer;
    user-select: none;
    white-space: nowrap;
    margin: 0;
    transition: background .13s, border-color .13s, color .13s;
}

.bo2 .bo-stoggle input { position: absolute; opacity: 0; width: 0; height: 0; }
.bo2 .bo-stoggle .bo-dot { width: 9px; height: 9px; border-radius: 50%; flex-shrink: 0; }
.bo2 .bo-stoggle .bo-dot.bo-returned { background: var(--bo-orange); }
.bo2 .bo-stoggle .bo-dot.bo-ready { background: var(--bo-green); }
.bo2 .bo-stoggle .bo-dot.bo-resend { background: var(--bo-green-deep); }
.bo2 .bo-stoggle .bo-dot.bo-destroyed { background: var(--bo-red); }

.bo2 .bo-stoggle .bo-chk {
    width: 15px;
    height: 15px;
    border-radius: 4px;
    border: 1.5px solid #B9C6D2;
    background: var(--bo-surface);
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
    transition: background .13s, border-color .13s;
}

.bo2 .bo-stoggle input:checked ~ .bo-chk { background: var(--bo-brand); border-color: var(--bo-brand); }
.bo2 .bo-stoggle input:checked ~ .bo-chk::after {
    content: "";
    width: 8px;
    height: 8px;
    background: #fff;
    clip-path: polygon(14% 44%,0 65%,50% 100%,100% 16%,80% 0,43% 62%);
}

.bo2 .bo-stoggle:has(input:checked) { background: var(--bo-brand-tint); border-color: #BEDFF2; color: var(--bo-ink); }
.bo2 .bo-stoggle input:focus-visible ~ .bo-chk { outline: 2px solid var(--bo-brand); outline-offset: 2px; }

.bo2 .bo-filter-actions {
    display: flex;
    gap: 10px;
    flex-wrap: wrap;
    border-top: 1px solid var(--bo-line-soft);
    margin-top: 2px;
    padding-top: 14px;
}

/* ---------- table cells ---------- */
.bo2 .bo-bc-cell { display: flex; align-items: center; gap: 6px; }

.bo2 .bo-mini-search {
    width: 24px;
    height: 24px;
    border-radius: 6px;
    display: inline-grid;
    place-items: center;
    color: var(--bo-ink-3);
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: background .13s, color .13s;
}

.bo2 .bo-mini-search:hover { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }

/* Ten-column tables (Returns) need tighter gutters to stay inside the panel
   without a horizontal scrollbar. */
.bo2 table.bo-table.bo-tight thead th,
.bo2 table.bo-table.bo-tight tbody td { padding-left: 10px; padding-right: 10px; }
.bo2 table.bo-table.bo-tight thead th.bo-right,
.bo2 table.bo-table.bo-tight tbody td.bo-right { padding-right: 14px; }
.bo2 table.bo-table.bo-tight .bo-text-cell { max-width: 118px; }

/* Resize grips need room on the right of the header; bo-tight would otherwise
   win the padding cascade and let the label run underneath the grip. */
.bo2 table.bo-table.bo-tight.bo-resizable thead th:not(.bo-right) { padding-right: 16px; }
/* Waybill uses the same size as the other barcodes here — at .86rem it cost
   ~16px of a column that has none to spare. */
.bo2 table.bo-table.bo-tight .bo-wb-code-lg { font-size: .76rem; font-weight: 540; }

.bo2 .bo-text-cell { display: flex; align-items: center; gap: 3px; max-width: 170px; }
.bo2 .bo-text-cell .bo-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: .79rem; color: var(--bo-ink-2); }
.bo2 .bo-text-cell.bo-empty .bo-txt { color: var(--bo-ink-3); }

/* Damaged column. The tick/cross answers "damaged?" and the colour follows the
   tick/cross, not a good/bad reading: yes = green tick, no = red cross. This is
   the house convention — do not "fix" it to red-for-damaged. */
.bo2 .bo-dmg { display: inline-grid; place-items: center; width: 22px; height: 22px; border-radius: 6px; }
.bo2 .bo-dmg.bo-yes { background: var(--bo-green-soft); color: var(--bo-green-deep); }
.bo2 .bo-dmg.bo-no { background: var(--bo-red-soft); color: var(--bo-red-deep); }

.bo2 .bo-status {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 3px 11px;
    border-radius: 999px;
    font-size: .74rem;
    font-weight: 660;
    white-space: nowrap;
}

.bo2 .bo-status .bo-dot { width: 7px; height: 7px; border-radius: 50%; flex-shrink: 0; }
.bo2 .bo-status.bo-returned { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }
.bo2 .bo-status.bo-returned .bo-dot { background: var(--bo-orange); }
.bo2 .bo-status.bo-ready { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-status.bo-ready .bo-dot { background: var(--bo-green); }
.bo2 .bo-status.bo-resend { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-status.bo-resend .bo-dot { background: var(--bo-green-deep); }
.bo2 .bo-status.bo-destroyed { background: var(--bo-red-soft); color: var(--bo-red-ink); }
.bo2 .bo-status.bo-destroyed .bo-dot { background: var(--bo-red); }

.bo2 .bo-attn { display: inline-grid; place-items: center; margin-right: 5px; vertical-align: middle; }
.bo2 .bo-attn svg { color: var(--bo-red); }

/* ---------- row actions ---------- */
.bo2 .bo-ractions { display: flex; align-items: center; gap: 4px; justify-content: flex-end; }

.bo2 .bo-pill-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 5px 11px;
    border-radius: 999px;
    font-size: .72rem;
    font-weight: 660;
    font-family: inherit;
    border: none;
    cursor: pointer;
    white-space: nowrap;
    transition: background .13s, color .13s, transform .12s, box-shadow .12s;
}

.bo2 .bo-pill-btn:hover { transform: translateY(-1px); }
.bo2 .bo-pill-btn.bo-info { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 .bo-pill-btn.bo-info:hover { background: var(--bo-brand); color: #fff; box-shadow: 0 3px 8px rgba(20,137,200,.3); }
.bo2 .bo-pill-btn.bo-warn { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }
.bo2 .bo-pill-btn.bo-warn:hover { background: var(--bo-orange-deep); color: #fff; box-shadow: 0 3px 8px rgba(222,138,6,.3); }

.bo2 .bo-icon-btn {
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    color: #fff;
    border: none;
    cursor: pointer;
    padding: 0;
    flex-shrink: 0;
    transition: transform .12s, filter .12s, box-shadow .12s;
}

.bo2 .bo-icon-btn:hover { transform: translateY(-1px); filter: brightness(1.08); box-shadow: 0 3px 8px rgba(20,40,60,.22); }
.bo2 .bo-icon-btn.bo-info { background: linear-gradient(180deg,var(--bo-brand),var(--bo-brand-deep)); }
.bo2 .bo-icon-btn.bo-danger { background: linear-gradient(180deg,var(--bo-red),var(--bo-red-deep)); }
.bo2 .bo-icon-btn.bo-warn { background: linear-gradient(180deg,var(--bo-orange),var(--bo-orange-deep)); color: #3A2600; }
.bo2 .bo-icon-btn.bo-secondary { background: var(--bo-surface-3); color: var(--bo-ink-2); box-shadow: var(--bo-shadow-xs); }
.bo2 .bo-icon-btn.bo-secondary:hover { background: var(--bo-surface); color: var(--bo-brand-ink); }

@media (max-width: 900px) {
    .bo2 .bo-filter-row { gap: 14px; }
    .bo2 .bo-vsep { display: none; }
}

/* ==========================================================
   MODALS
   Radzen owns the dialog shell, so the 2.0 look is opt-in: pass
   CssClass="bo-dialog" in DialogOptions and the rules below take
   over its titlebar, close button and content padding. Dialogs
   that have not been converted yet keep the Radzen material
   chrome, so this can be rolled out one dialog at a time.

   The shell rules are NOT scoped under .bo2 — the dialog element
   is a sibling of the app root, outside the page markup. The body
   classes below are scoped, and the dialog content starts with a
   .bo2 wrapper of its own.
   ========================================================== */
.bo-dialog.rz-dialog {
    border: 1px solid var(--bo-line-soft);
    border-radius: 14px;
    box-shadow: 0 24px 60px rgba(11,40,64,.26), 0 2px 8px rgba(11,40,64,.1);
    overflow: hidden;
    animation: bo-dialog-in .22s cubic-bezier(.22,.61,.36,1) both;
}

@keyframes bo-dialog-in {
    from { opacity: 0; transform: translateY(10px) scale(.985); }
    to { opacity: 1; transform: none; }
}

.bo-dialog .rz-dialog-titlebar {
    padding: 13px 16px 13px 20px;
    background: var(--bo-surface-2);
    border-bottom: 1px solid var(--bo-line);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.bo-dialog .rz-dialog-title {
    font-size: .95rem;
    font-weight: 660;
    letter-spacing: -.01em;
    color: var(--bo-ink);
    line-height: 1.3;
}

/* Radzen floats the close button; in a flex titlebar the float does nothing
   and would leave it stuck to the title, so it is reset to a normal item. */
.bo-dialog .rz-dialog-titlebar-close {
    float: none;
    flex-shrink: 0;
    width: 30px;
    height: 30px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    color: var(--bo-ink-3);
    transition: background .13s, color .13s;
}

.bo-dialog .rz-dialog-titlebar-close:hover { background: var(--bo-surface-3); color: var(--bo-ink); }
.bo-dialog .rz-dialog-titlebar-close .rzi-times { color: inherit; }

/* The modal body owns its own padding so the footer can sit flush. */
.bo-dialog .rz-dialog-content { padding: 0; }

/* ---------- confirm / alert ---------- */
/* DialogService.Confirm and .Alert build their own markup, so they cannot use
   .bo-modal. These rules give them the same shell and buttons. Padding is put
   back — the rule above zeroes it because a converted dialog pads its own body.
   Add bo-danger to the CssClass when the committing action destroys data. */
.bo-dialog.bo-dialog-confirm .rz-dialog-content { padding: 18px 20px 16px; }

.bo-dialog .rz-dialog-confirm-message,
.bo-dialog .rz-dialog-alert-message {
    font-size: .88rem;
    line-height: 1.6;
    color: var(--bo-ink-2);
    margin-bottom: 18px;
}

.bo-dialog .rz-dialog-confirm-buttons,
.bo-dialog .rz-dialog-alert-buttons {
    display: flex;
    gap: 9px;
    justify-content: flex-end;
}

.bo-dialog .rz-dialog-confirm-buttons .rz-button,
.bo-dialog .rz-dialog-alert-buttons .rz-button {
    flex: 0 0 auto;
    min-width: 92px;
    justify-content: center;
    padding: 9px 16px !important;
    border-radius: var(--bo-radius-sm) !important;
    font-family: inherit !important;
    font-size: .87rem !important;
    font-weight: 580 !important;
    text-transform: none !important;
    letter-spacing: 0 !important;
    border: 1px solid var(--bo-line) !important;
    background: var(--bo-surface) !important;
    color: var(--bo-ink-2) !important;
    box-shadow: none !important;
    transition: background .15s, border-color .15s, color .15s;
}

.bo-dialog .rz-dialog-confirm-buttons .rz-button:hover,
.bo-dialog .rz-dialog-alert-buttons .rz-button:hover {
    border-color: #C4D0DB !important;
    color: var(--bo-ink) !important;
}

/* Radzen renders the committing button first. An Alert has only the one. */
.bo-dialog .rz-dialog-confirm-buttons .rz-button:first-child,
.bo-dialog .rz-dialog-alert-buttons .rz-button:first-child {
    border-color: transparent !important;
    background: linear-gradient(180deg,#1B93D0,#1180BC) !important;
    color: #fff !important;
    box-shadow: 0 1px 0 rgba(255,255,255,.25) inset, 0 2px 6px rgba(17,128,188,.35) !important;
}

/* Lists inside a confirm or alert. Radzen renders the message as raw markup, so
   this is the only way to give it structure — a column of barcodes, each with
   its outcome, instead of one long line of text separated by <br>. */
.bo-dialog .bo-confirm-list,
.bo-dialog .bo-res-list {
    display: flex;
    flex-direction: column;
    gap: 4px;
    max-height: 220px;
    overflow: auto;
    padding: 2px;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo-dialog .bo-confirm-list code,
.bo-dialog .bo-res-list code {
    font-family: var(--bo-font-mono);
    font-size: .78rem;
    color: var(--bo-ink);
}

/* The confirm list has no second column, so each code gets the row treatment
   itself — otherwise it reads as a wall of loose text. */
.bo-dialog .bo-confirm-list code {
    display: block;
    padding: 5px 9px;
    border-radius: 7px;
    background: var(--bo-surface-2);
}

.bo-dialog .bo-res-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    padding: 5px 9px;
    border-radius: 7px;
    background: var(--bo-surface-2);
}

.bo-dialog .bo-res-ok { font-size: .72rem; font-weight: 680; color: var(--bo-green-ink); }
.bo-dialog .bo-res-bad { font-size: .72rem; font-weight: 680; color: var(--bo-red-ink); }

.bo-dialog.bo-danger .rz-dialog-confirm-buttons .rz-button:first-child {
    background: linear-gradient(180deg,var(--bo-red),var(--bo-red-deep)) !important;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(218,76,76,.35) !important;
}

/* ---------- modal body ---------- */
.bo2 .bo-modal { display: flex; flex-direction: column; min-height: 0; }

.bo2 .bo-modal-body {
    padding: 18px 20px 20px;
    display: flex;
    flex-direction: column;
    gap: 18px;
}

.bo2 .bo-modal-sec { display: flex; flex-direction: column; gap: 9px; min-width: 0; }

.bo2 .bo-modal-sec > h3 {
    margin: 0;
    font-size: .66rem;
    font-weight: 720;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

/* Sticky against .rz-dialog-content, which is the dialog's scroll container —
   on a short viewport the form scrolls under the actions rather than pushing
   them out of reach. */
.bo2 .bo-modal-foot {
    padding: 13px 20px;
    border-top: 1px solid var(--bo-line);
    background: var(--bo-surface-2);
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 9px;
    flex-wrap: wrap;
    position: sticky;
    bottom: 0;
}

/* The confirmation question lives in the footer next to the button it is
   asking about, instead of floating in the middle of the form. */
.bo2 .bo-modal-note {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-right: auto;
    font-size: .8rem;
    color: var(--bo-ink-2);
    min-width: 0;
}

.bo2 .bo-modal-note svg { flex-shrink: 0; color: var(--bo-ink-3); }

/* ---------- stat tiles ---------- */
.bo2 .bo-tiles { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 10px; }

.bo2 .bo-tile {
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    padding: 10px 13px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-width: 0;
}

.bo2 .bo-tile .bo-t-k {
    font-size: .62rem;
    font-weight: 720;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

.bo2 .bo-tile .bo-t-v {
    font-size: 1.02rem;
    font-weight: 680;
    letter-spacing: -.015em;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bo2 .bo-tile .bo-t-u { font-size: .72rem; font-weight: 520; color: var(--bo-ink-3); margin-left: 3px; }

/* A figure that wants a second look — a weight that does not reconcile, say. */
.bo2 .bo-tile .bo-t-v.bo-warn { color: var(--bo-orange-ink); }

/* Three-up rather than the default four. */
.bo2 .bo-tiles.bo-tiles-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

/* Two progress cards side by side — .bo-prog-strip is the three-up page
   version with its own padding, this is the modal's. */
.bo2 .bo-prog-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }

/* A scrolling list inside a modal. Shorter than the page's .bo-tbl-wrap so the
   footer stays in view — about six rows before it starts to scroll. */
.bo2 .bo-modal-list {
    overflow: auto;
    max-height: 236px;
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-modal-list::-webkit-scrollbar { width: 9px; height: 9px; }
.bo2 .bo-modal-list::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }
.bo2 .bo-modal-list table.bo-table thead th { top: 0; }

/* Pushes what follows to the right edge of the footer — for a secondary action
   ("New flight", "Back") that belongs with the actions but not next to them. */
.bo2 .bo-modal-foot .bo-foot-left { margin-right: auto; }

/* A quiet explanatory line. Not an error and not a label — it tells the user
   why a list looks the way it does. */
.bo2 .bo-hint {
    margin: 0;
    display: flex;
    align-items: flex-start;
    gap: 7px;
    font-size: .74rem;
    line-height: 1.5;
    color: var(--bo-ink-3);
}

.bo2 .bo-hint svg { flex-shrink: 0; margin-top: 2px; }

/* A value with a drill-down magnifier next to it. The button only appears on
   hover so a column of them does not shout over the data — .bo-mini-zoom
   already carries that behaviour from the pre-alert table. */
.bo2 .bo-drill {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    min-width: 0;
    max-width: 100%;
}

.bo2 .bo-drill.bo-drill-end { justify-content: flex-end; width: 100%; }
.bo2 .bo-drill > span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
.bo2 table.bo-table tbody tr.bo-row:hover .bo-drill .bo-mini-zoom { opacity: .8; }

/* A .bo-field holding a textarea: it grows instead of being one line tall,
   and the text starts at the top rather than being vertically centred. */
.bo2 .bo-field.bo-field-area {
    height: auto;
    align-items: stretch;
    padding: 9px 12px;
}

.bo2 .bo-field.bo-field-area textarea {
    width: 100%;
    border: none;
    background: transparent;
    font: inherit;
    line-height: 1.55;
    color: var(--bo-ink);
    outline: none;
    resize: vertical;
    min-height: 76px;
    padding: 0;
}

.bo2 .bo-field.bo-field-area textarea::placeholder { color: var(--bo-ink-3); }

/* Key/value pairs stacked inside a table cell (customs message amounts). */
.bo2 .bo-kvlist { display: inline-flex; flex-direction: column; gap: 2px; }

.bo2 .bo-kvlist .bo-kv {
    display: inline-flex;
    align-items: baseline;
    gap: 6px;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.bo2 .bo-kvlist .bo-kv .bo-k { color: var(--bo-ink-3); font-size: .74rem; }

/* A cell's full text, shown in a small dialog when it is too long for its
   column. Wraps and breaks, because the thing that overflowed is usually one
   unbroken barcode or remark. */
.bo2 .bo-longtext {
    margin: 0;
    font-size: .86rem;
    line-height: 1.6;
    color: var(--bo-ink-2);
    overflow-wrap: anywhere;
}

/* ---------- attachments ---------- */
.bo2 .bo-filelist { display: flex; flex-direction: column; gap: 5px; }

.bo2 .bo-filerow {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 7px 9px 7px 11px;
    border-radius: 8px;
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    font-size: .8rem;
    color: var(--bo-ink-2);
    min-width: 0;
}

.bo2 .bo-filerow > svg { flex-shrink: 0; color: var(--bo-ink-3); }

/* Takes the slack so the buttons stay pinned right and a long name ellipsises
   rather than pushing them out of the row. */
.bo2 .bo-filerow .bo-fname {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bo2 .bo-mini-zoom.bo-danger { color: var(--bo-red-deep); }
.bo2 .bo-mini-zoom.bo-danger:hover:not(:disabled) { background: var(--bo-red-soft); }

/* Drop zone wrapping RadzenUpload. Radzen owns the input and its choose button;
   this supplies the dashed frame and the accepted-formats note around it. */
.bo2 .bo-dropzone {
    border: 1.5px dashed #C9D6E1;
    border-radius: var(--bo-radius);
    background: var(--bo-surface-2);
    padding: 14px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    transition: border-color .15s, background .15s;
}

.bo2 .bo-dropzone:hover { border-color: var(--bo-brand); background: var(--bo-brand-tint); }

/* Applied while a file is dragged over the zone — see wwwroot/js/bo-dropzone.js. */
.bo2 .bo-dropzone.bo-dz-drag { border-color: var(--bo-brand); background: var(--bo-brand-tint); border-style: solid; }

.bo2 .bo-dropzone .rz-fileupload { width: 100%; }

/* Plain <InputFile> lands here too (the truck POD and invoice dialogs use it
   rather than RadzenUpload); the native control is left alone apart from
   centring it, since restyling a file input is a per-browser fight. */
.bo2 .bo-dropzone input[type="file"] {
    font: inherit;
    font-size: .8rem;
    color: var(--bo-ink-2);
    max-width: 100%;
}

.bo2 .bo-dropzone .rz-fileupload-choose {
    width: 100%;
    justify-content: center;
    background: transparent !important;
    border: none !important;
    box-shadow: none !important;
    color: var(--bo-ink-2) !important;
    font-family: inherit !important;
    font-size: .82rem !important;
    font-weight: 560 !important;
    text-transform: none !important;
    letter-spacing: 0 !important;
}

/* The whole frame is the click target, not just Radzen's choose line - the click is
   forwarded to the file input in wwwroot/js/bo-dropzone.js. It cannot be done with an
   overlay: Radzen's own .rz-fileupload-choose is position:relative with overflow:hidden,
   so anything stretched inside it is clipped back to that one line. */
.bo2 .bo-dropzone.bo-dz-click { cursor: pointer; }

.bo2 .bo-dropzone.bo-dz-click.bo-off { cursor: default; }

.bo2 .bo-dropzone .bo-dz-note {
    font-size: .68rem;
    font-weight: 620;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

/* A status word with its colour dot. */
.bo2 .bo-status-line { display: inline-flex; align-items: center; gap: 8px; }

/* A wrapping row of chips (current providers, tags, picked waybills). */
.bo2 .bo-chiprow { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }

/* A removable chip: the value plus an x that takes it back out. */
.bo2 .bo-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 4px 5px 4px 10px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    border: 1px solid var(--bo-line);
    font-size: .78rem;
    color: var(--bo-ink);
    max-width: 100%;
}

.bo2 .bo-chip .bo-mono { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }

.bo2 .bo-chip-x {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    border: none;
    background: none;
    color: var(--bo-ink-3);
    cursor: pointer;
    flex-shrink: 0;
    transition: background .13s, color .13s;
}

.bo2 .bo-chip-x:hover { background: var(--bo-red-soft); color: var(--bo-red-deep); }

/* ---------- callout ---------- */
/* A statement the dialog exists to make. Louder than .bo-hint, quieter than a
   toast — it stays on screen while the detail below is read. */
.bo2 .bo-callout {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    padding: 12px 14px;
    border-radius: var(--bo-radius);
    border: 1px solid var(--bo-line-soft);
    background: var(--bo-surface-2);
    font-size: .84rem;
    line-height: 1.55;
    color: var(--bo-ink-2);
}

.bo2 .bo-callout svg { flex-shrink: 0; margin-top: 1px; }
.bo2 .bo-callout strong { color: var(--bo-ink); font-weight: 680; }

.bo2 .bo-callout.bo-callout-warn {
    border-color: #F3DCA8;
    background: var(--bo-orange-soft);
    color: var(--bo-orange-ink);
}

.bo2 .bo-callout.bo-callout-warn svg { color: var(--bo-orange-deep); }
.bo2 .bo-callout.bo-callout-warn strong { color: var(--bo-orange-ink); }

.bo2 .bo-callout.bo-callout-err {
    border-color: #F0C2C2;
    background: var(--bo-red-soft);
    color: var(--bo-red-ink);
}

.bo2 .bo-callout.bo-callout-err svg { color: var(--bo-red-deep); }
.bo2 .bo-callout.bo-callout-err strong { color: var(--bo-red-ink); }

/* Confirmation tick inside a field that saves on blur. It fades in and stays,
   so the user can see the write landed without a toast interrupting them. */
.bo2 .bo-saved {
    display: inline-flex;
    color: var(--bo-green-deep);
    flex-shrink: 0;
    animation: bo-fade .2s ease both;
}

/* Customs cell in the parcels dialog: the state icon plus its two actions. */
.bo2 .bo-cust-cell { display: inline-flex; align-items: center; gap: 3px; }

/* A magnifier that is always visible, for a button that is the only way to
   reach something rather than a shortcut to it. */
.bo2 .bo-mini-zoom.bo-always { opacity: .75; }
.bo2 .bo-mini-zoom.bo-always:disabled { opacity: .3; cursor: not-allowed; }

/* ---------- chip filter ---------- */
/* A short, closed set of states reads better laid out than folded into a
   dropdown — you can see at a glance which ones are on. */
.bo2 .bo-chipfilter { display: flex; align-items: center; gap: 5px; flex-wrap: wrap; }

.bo2 .bo-fchip {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 10px 4px 6px;
    border-radius: 999px;
    border: 1px solid var(--bo-line);
    background: var(--bo-surface);
    color: var(--bo-ink-3);
    font-family: inherit;
    font-size: .7rem;
    font-weight: 620;
    cursor: pointer;
    white-space: nowrap;
    transition: border-color .13s, color .13s, background .13s;
}

.bo2 .bo-fchip:hover { border-color: #C4D0DB; color: var(--bo-ink-2); }

.bo2 .bo-fchip.bo-on {
    border-color: var(--bo-brand);
    background: var(--bo-brand-tint);
    color: var(--bo-brand-ink);
}

/* Search box, any extra filters, and a count of what is listed. */
.bo2 .bo-modal-tools {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
}

.bo2 .bo-modal-tools .bo-tools-count {
    margin-left: auto;
    font-size: .74rem;
    font-weight: 600;
    color: var(--bo-ink-3);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* A row that carries a switch on the left and its action on the right. */
.bo2 .bo-searchrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

/* ---------- single-choice rows ---------- */
/* A radio dot for tables where the row itself is the control. The row already
   carries .bo-prow/.bo-on for the tint and the left edge marker; this makes the
   "one of these" nature legible without a real radio input. */
.bo2 .bo-pick {
    width: 15px;
    height: 15px;
    border-radius: 999px;
    border: 2px solid #C3CFDA;
    background: var(--bo-surface);
    display: inline-block;
    vertical-align: middle;
    transition: border-color .13s, background .13s, box-shadow .13s;
}

.bo2 table.bo-table tbody tr.bo-prow:hover .bo-pick { border-color: #9FB3C4; }

.bo2 table.bo-table tbody tr.bo-prow.bo-on .bo-pick {
    border-color: var(--bo-brand);
    background: var(--bo-brand);
    box-shadow: inset 0 0 0 2.5px var(--bo-surface);
}

/* ---------- an option with a follow-up field ---------- */
.bo2 .bo-optgroup { display: flex; flex-direction: column; gap: 10px; }

/* Indented to the switch's label: 34px track + 8px gap. The flex reset matters:
   .bo-form-f grows by default, and in this column container growing means
   growing vertically — it would stretch into a tall empty block. */
.bo2 .bo-optgroup .bo-opt-f {
    margin-left: 42px;
    max-width: 210px;
    flex: 0 0 auto;
}

/* ---------- labelled form fields ---------- */
.bo2 .bo-form-row { display: flex; gap: 10px; flex-wrap: wrap; }

.bo2 .bo-form-f { display: flex; flex-direction: column; gap: 5px; min-width: 0; flex: 1 1 180px; }

/* Takes the whole row — for values that are prose rather than a figure, where
   sharing a line with two numerics would leave it too narrow to read. */
.bo2 .bo-form-f.bo-wide { flex: 1 1 100%; }

/* Smaller basis so four short fields (a date and three codes) still share one
   row instead of the last one wrapping and stretching across the dialog. */
.bo2 .bo-form-f.bo-narrow { flex: 1 1 132px; }

/* :not(.bo-field) is load-bearing. The field wrapper in this pattern is itself
   a <label> (it wraps the input so clicking the box focuses it), so a bare
   "> label" matched it too — and at (0,2,1) it outranked .bo2 .bo-field (0,2,0).
   The wrapper then took this rule's .66rem/700/uppercase, and the input's
   `font: inherit` pulled the size and weight down with it: every native input
   in a labelled form rendered at 10.56px bold instead of 13.6px regular. */
.bo2 .bo-form-f > label:not(.bo-field) {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

.bo2 .bo-form-f .bo-field { width: 100%; }
.bo2 .bo-form-f .bo-field > input { width: 100%; }
.bo2 .bo-form-f .bo-unit { font-size: .74rem; color: var(--bo-ink-3); flex-shrink: 0; }

/* A field whose enabling condition (eg. "tick a row that already has this
   value") isn't met yet — dimmed the same way a disabled .bo-btn is, so it
   reads as unavailable rather than merely unfilled. */
.bo2 .bo-form-f.bo-off { opacity: .45; }
.bo2 .bo-form-f.bo-off label { cursor: not-allowed; }

/* Figures read right-aligned, text does not — so this is keyed on the input
   type rather than applied to every field in the row. */
.bo2 .bo-form-f .bo-field > input[type="number"] { text-align: right; }

/* RadzenNumeric keeps its min/max clamping; only its chrome is stripped (see
   the .bo-field Radzen block above) and the figure is right-aligned like the
   native number inputs next to it. */
.bo2 .bo-form-f .bo-field .rz-spinner { width: 100%; }

.bo2 .bo-form-f .bo-field .rz-spinner-input {
    width: 100%;
    text-align: right;
    padding-inline-end: 0 !important;
}

@media (max-width: 620px) {
    .bo2 .bo-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .bo2 .bo-prog-grid { grid-template-columns: 1fr; }
}

/* ==========================================================
   TOASTS
   Radzen renders notifications into .rz-growl at body level,
   so these rules are unscoped like the dialog shell. Every
   toast in the app goes through NotificationService, which
   means restyling here covers all of them at once — there is
   no opt-in class to add at each call site.

   The shape follows .bo-callout: a white card with a coloured
   accent down the left edge and a matching icon tile, rather
   than Radzen's fully tinted block. Colour then marks the
   severity without drowning the text.
   ========================================================== */
.rz-growl {
    position: fixed;
    /* Clear of the topnav rather than Radzen's flat 100px, which left a gap
       on this layout and would collide on a shorter one. */
    top: calc(var(--bo-nav-h) + 14px);
    right: 18px;
    min-width: 0;
    width: 380px;
    max-width: calc(100vw - 36px);
    z-index: 1200;
}

.rz-growl-item-container { background: none; }

.rz-growl-item {
    display: flex;
    align-items: flex-start;
    gap: 11px;
    margin: 0 0 10px;
    padding: 12px 13px 12px 14px;
    border-radius: 11px;
    border: 1px solid var(--bo-line-soft);
    border-left: 3px solid var(--bo-ink-3);
    background: var(--bo-surface);
    box-shadow: 0 10px 30px rgba(11,40,64,.16), 0 2px 6px rgba(11,40,64,.08);
    color: var(--bo-ink-2);
    font-family: var(--bo-font-ui);
    animation: bo-toast-in .24s cubic-bezier(.22,.61,.36,1) both;
}

@keyframes bo-toast-in {
    from { opacity: 0; transform: translateX(14px) scale(.98); }
    to { opacity: 1; transform: none; }
}

/* Explicit order, because the icon and the close button are floated in
   Radzen's markup — floats are ignored once this is a flex row, and the DOM
   order of the three parts is not something to depend on. */
.rz-growl-image { order: 1; }
.rz-growl-message { order: 2; }
.rz-growl-icon-close { order: 3; }

/* The icon is a Material ligature; it keeps the glyph and gains a tile. */
.rz-growl-image {
    float: none;
    margin: 0;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    border-radius: 8px;
    display: grid;
    place-items: center;
    font-size: 16px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-2);
}

.rz-growl-message {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.rz-growl-title {
    font-size: .83rem;
    font-weight: 660;
    line-height: 1.4;
    color: var(--bo-ink);
    letter-spacing: -.005em;
}

.rz-growl-message p {
    display: block;
    margin: 0;
    font-size: .79rem;
    line-height: 1.5;
    color: var(--bo-ink-2);
}

.rz-growl-icon-close {
    float: none;
    flex-shrink: 0;
    width: 22px;
    height: 22px;
    border-radius: 6px;
    display: grid;
    place-items: center;
    font-size: 15px;
    color: var(--bo-ink-3);
    cursor: pointer;
    transition: background .13s, color .13s;
}

.rz-growl-icon-close:hover { background: var(--bo-surface-3); color: var(--bo-ink); }

/* ---------- severities ---------- */
.rz-growl-message-success .rz-growl-item {
    background: var(--bo-surface);
    border-left-color: var(--bo-green);
    color: var(--bo-ink-2);
}

.rz-growl-message-success .rz-growl-image { background: var(--bo-green-soft); color: var(--bo-green-ink); }

.rz-growl-message-warn .rz-growl-item {
    background: var(--bo-surface);
    border-left-color: var(--bo-orange);
    color: var(--bo-ink-2);
}

.rz-growl-message-warn .rz-growl-image { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }

.rz-growl-message-error .rz-growl-item {
    background: var(--bo-surface);
    border-left-color: var(--bo-red);
    color: var(--bo-ink-2);
}

.rz-growl-message-error .rz-growl-image { background: var(--bo-red-soft); color: var(--bo-red-ink); }

.rz-growl-message-info .rz-growl-item {
    background: var(--bo-surface);
    border-left-color: var(--bo-brand);
    color: var(--bo-ink-2);
}

.rz-growl-message-info .rz-growl-image { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }

@media (prefers-reduced-motion: reduce) {
    .rz-growl-item { animation: none; }
}

@media (max-width: 620px) {
    .rz-growl { right: 12px; left: 12px; width: auto; top: calc(var(--bo-nav-h) + 10px); }
}

/* ==========================================================
   TRUCKS
   Ported from docs/design/beeonline-trucks-{plan,departed,all}-2.0.html.
   Three tables over the same rows, so the cell vocabulary is
   shared and only the columns differ per tab.
   ========================================================== */

/* The licence plate is the thing you scan the table for, so it is set as a
   plate rather than as text in a column. */
.bo2 .bo-plate {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-family: var(--bo-font-mono);
    font-size: .82rem;
    font-weight: 600;
    letter-spacing: .02em;
    padding: 4px 10px;
    border-radius: 6px;
    background: var(--bo-surface-3);
    color: var(--bo-ink);
    border: 1px solid var(--bo-line);
    white-space: nowrap;
}

.bo2 .bo-plate svg { color: var(--bo-ink-3); flex-shrink: 0; }

/* The column is resizable and starts narrow, so a long plate is ellipsised and
   reveals itself progressively as the column is widened. */
.bo2 .bo-plate { max-width: 100%; min-width: 0; }

.bo2 .bo-plate .bo-plate-t {
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

/* A figure with a drill-down magnifier that appears on row hover — the count
   and the way to see what it counts, without a column of buttons shouting. */
.bo2 .bo-count-cell {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    justify-content: flex-end;
    font-variant-numeric: tabular-nums;
    font-weight: 560;
}

.bo2 .bo-weight-cell { font-variant-numeric: tabular-nums; font-weight: 560; white-space: nowrap; }
.bo2 .bo-weight-cell .bo-u { font-size: .7rem; color: var(--bo-ink-3); margin-left: 3px; font-weight: 400; }

/* Order column: Show / Send / status. Fixed width so the three line up down
   the column instead of drifting with the button labels. */
.bo2 .bo-order-cell { display: flex; align-items: center; gap: 8px; width: 238px; margin: 0 auto; }
.bo2 .bo-order-cell .bo-sent-badge { margin-left: auto; }

.bo2 .bo-sent-badge,
.bo2 .bo-dep {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 5px;
    font-size: .7rem;
    font-weight: 650;
    padding: 3px 9px;
    border-radius: 999px;
    white-space: nowrap;
    min-width: 74px;
}

.bo2 .bo-sent-badge .bo-dot,
.bo2 .bo-dep .bo-dot { width: 6px; height: 6px; border-radius: 50%; }

.bo2 .bo-sent-badge.bo-yes { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-sent-badge.bo-yes .bo-dot { background: var(--bo-green); }
.bo2 .bo-sent-badge.bo-no { background: var(--bo-surface-3); color: var(--bo-ink-3); }
.bo2 .bo-sent-badge.bo-no .bo-dot { background: var(--bo-ink-3); }

/* Departed is a state of the truck, not a document — orange for "still here"
   rather than the grey used for "no order sent yet". */
.bo2 .bo-dep.bo-yes { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-dep.bo-yes .bo-dot { background: var(--bo-green); }
.bo2 .bo-dep.bo-no { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }
.bo2 .bo-dep.bo-no .bo-dot { background: var(--bo-orange); }

/* Labelled pills may wrap onto a second line in a narrow column — two of them
   side by side do not fit a 1366 laptop otherwise. */
.bo2 .bo-doc-actions { display: flex; align-items: center; gap: 6px; justify-content: center; flex-wrap: wrap; }

/* A row of square icon buttons must not, though: stacked edit-over-delete
   reads as two separate controls and doubles the row height. */
.bo2 .bo-doc-actions:has(> .bo-icon-btn) { flex-wrap: nowrap; }
.bo2 .bo-file-cell { display: inline-flex; align-items: center; gap: 7px; justify-content: center; }
.bo2 .bo-file-acts { display: inline-flex; align-items: center; gap: 4px; }

/* Small square action button, used where a labelled pill would not fit. */
.bo2 .bo-icon-btn.bo-sm { width: 27px; height: 27px; border-radius: 7px; }

.bo2 .bo-icon-btn:disabled,
.bo2 .bo-icon-btn.bo-off {
    opacity: .38;
    cursor: not-allowed;
    box-shadow: none;
}

.bo2 .bo-icon-btn:disabled:hover,
.bo2 .bo-icon-btn.bo-off:hover { transform: none; filter: none; box-shadow: none; }

.bo2 .bo-pill-btn:disabled { opacity: .4; cursor: not-allowed; }
.bo2 .bo-pill-btn:disabled:hover { transform: none; background: var(--bo-surface-3); color: var(--bo-ink-3); box-shadow: none; }

/* An em dash standing in for a value that does not apply to this row. */
.bo2 .bo-na { color: var(--bo-ink-3); font-size: .8rem; }

/* Between the two date fields of a range. flex-shrink:0 keeps it from being
   squeezed to nothing when the filter row runs out of room. */
.bo2 .bo-dash {
    color: var(--bo-ink-3);
    font-size: .8rem;
    line-height: 1;
    flex-shrink: 0;
    user-select: none;
}

/* ==========================================================
   WAREHOUSE MANAGER
   Ported from docs/design/beeonline-warehouse-manager-2.0.html
   ========================================================== */

/* Filter card: one auto-fitting row of labelled fields, the action pinned
   right under a rule. auto-fit rather than a fixed column count so the four
   fields collapse to two and then one without a media query. */
.bo2 .bo-f-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 12px;
}

.bo2 .bo-f-grid .bo-field { width: 100%; }

/* A field that needs more room than one auto-fit cell — the searchable
   consignee grid-dropdown on the PreAlert page, for instance. */
.bo2 .bo-f-group.bo-wide { grid-column: 1 / -1; }

.bo2 .bo-filter-actions.bo-right { justify-content: flex-end; }

/* Key to the row tint. Without it the purple rows read as an error state. */
.bo2 .bo-legend {
    display: flex;
    gap: 14px;
    flex-wrap: wrap;
    font-size: .72rem;
    color: var(--bo-ink-3);
}

.bo2 .bo-legend span { display: inline-flex; align-items: center; gap: 5px; }
.bo2 .bo-legend .bo-dot { width: 9px; height: 9px; border-radius: 3px; flex-shrink: 0; }
.bo2 .bo-legend .bo-dot.bo-master { background: var(--bo-brand); }
.bo2 .bo-legend .bo-dot.bo-decomp { background: var(--bo-purple); }

/* A master that has been broken into its parcels occupies one row per parcel;
   the tint and the inset edge are what tie those rows together visually. */
.bo2 table.bo-table tbody tr.bo-decompiled { background: var(--bo-purple-soft); }
.bo2 table.bo-table tbody tr.bo-decompiled:hover { background: #E7DFF5; }
.bo2 table.bo-table tbody tr.bo-decompiled td:first-child { box-shadow: 3px 0 0 var(--bo-purple) inset; }

/* ---------- location cell ---------- */
.bo2 .bo-loc { display: inline-flex; align-items: center; gap: 8px; min-width: 0; }

.bo2 .bo-loc-code {
    font-family: var(--bo-font-mono);
    font-size: .78rem;
    font-weight: 620;
    padding: 3px 9px;
    border-radius: 6px;
    background: var(--bo-surface-3);
    color: var(--bo-ink);
    border: 1px solid var(--bo-line);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    min-width: 0;
}

.bo2 .bo-loc-code.bo-empty { color: var(--bo-ink-3); background: none; border-style: dashed; font-weight: 520; }

/* Row-level actions rest dimmed rather than invisible: a control at opacity 0
   cannot be found without hovering the right cell first. Focus reveals them
   too, so they stay reachable from the keyboard. */
.bo2 .bo-transfers,
.bo2 .bo-lock {
    display: inline-flex;
    gap: 3px;
    opacity: .4;
    transition: opacity .13s;
}

.bo2 table.bo-table tbody tr:hover .bo-transfers,
.bo2 table.bo-table tbody tr:hover .bo-lock,
.bo2 .bo-transfers:focus-within,
.bo2 .bo-lock:focus-within { opacity: 1; }

/* ---------- pallet cell ---------- */
.bo2 .bo-pallet { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }

.bo2 .bo-pallet-label {
    font-family: var(--bo-font-mono);
    font-size: .77rem;
    font-weight: 560;
    color: var(--bo-ink);
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.bo2 .bo-pallet-label svg { color: var(--bo-orange-deep); flex-shrink: 0; }

/* Bare text in an inline-flex box is an anonymous flex item, which
   text-overflow does not reach — hence the inner span. */
.bo2 .bo-pallet-label > span { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

.bo2 .bo-pallet-none { font-size: .78rem; color: var(--bo-ink-3); }

/* ---------- master / parcel cells ---------- */
.bo2 .bo-master-cell { display: inline-flex; align-items: center; gap: 7px; min-width: 0; }
.bo2 .bo-master-cell > .bo-mono { overflow: hidden; text-overflow: ellipsis; min-width: 0; }

/* Marks a row the warehouse has physically placed, as opposed to one that is
   only recorded against the master. */
.bo2 .bo-pin { color: var(--bo-red); flex-shrink: 0; }

.bo2 .bo-parcel-count {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-weight: 560;
    font-variant-numeric: tabular-nums;
}

.bo2 .bo-parcel-count .bo-lbl { font-size: .7rem; color: var(--bo-ink-3); font-weight: 500; }

.bo2 .bo-tag.bo-tag-decomp { color: var(--bo-purple-ink); background: var(--bo-purple-soft); }

/* ---------- icon button colour variants ---------- */
/* position:relative is what lets [data-bo-tip] anchor its bubble to the
   button rather than to the table cell. */
.bo2 .bo-iconbtn { position: relative; flex-shrink: 0; }
.bo2 .bo-iconbtn.bo-purple:hover { background: var(--bo-purple-soft); color: var(--bo-purple-ink); }
.bo2 .bo-iconbtn.bo-green:hover { background: var(--bo-green-soft); color: var(--bo-green-deep); }
.bo2 .bo-iconbtn:disabled { opacity: .3; cursor: not-allowed; }
.bo2 .bo-iconbtn:disabled:hover { background: none; color: var(--bo-ink-3); }

/* The first column's tooltip would otherwise be centred over the panel edge
   and clipped; the last column's over the right edge. */
.bo2 table.bo-table td:first-child .bo-iconbtn[data-bo-tip]::after { left: 0; translate: 0 3px; }
.bo2 table.bo-table td:first-child .bo-iconbtn[data-bo-tip]:hover::after { translate: 0 0; }

/* Settings rows put their actions in the last column, hard against the panel's
   right edge, so those anchor to their own right instead of centring. */
.bo2 table.bo-table td:last-child .bo-iconbtn[data-bo-tip]::after { left: auto; right: 0; translate: 0 3px; }
.bo2 table.bo-table td:last-child .bo-iconbtn[data-bo-tip]:hover::after { translate: 0 0; }

/* ---------- totals strip ---------- */
.bo2 .bo-totals {
    display: flex;
    flex-wrap: wrap;
    padding: 14px 18px;
    border-top: 1px solid var(--bo-line);
    background: var(--bo-surface-2);
}

.bo2 .bo-total-tile {
    flex: 1;
    min-width: 120px;
    display: flex;
    flex-direction: column;
    gap: 3px;
    padding: 4px 18px;
    border-right: 1px solid var(--bo-line);
}

.bo2 .bo-total-tile:last-child { border-right: none; }

.bo2 .bo-total-label {
    font-size: .66rem;
    font-weight: 700;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

.bo2 .bo-total-value {
    font-family: var(--bo-font-display);
    font-size: 1.3rem;
    font-weight: 700;
    letter-spacing: -.02em;
    font-variant-numeric: tabular-nums;
}

.bo2 .bo-total-value .bo-u { font-size: .72rem; color: var(--bo-ink-3); font-weight: 500; margin-left: 3px; }

/* Placeholder figures while the query runs — the strip keeps its height so
   the pager below does not jump when the numbers arrive. */
.bo2 .bo-total-value .bo-sk { height: 22px; width: 62px; display: block; }

@media (max-width: 900px) {
    .bo2 .bo-total-tile { border-right: none; padding: 4px 10px; }
}

/* ============================================================
   FORM PAGE — Load XLSX
   Follows docs/design/beeonline-loadxlsx-2.0.html: a single narrow
   card of numbered steps ending in a drop zone and one submit.
   ============================================================ */

/* The import form is one column of decisions, so it is read as a column.
   At the 1520px default the fields would stretch to three times the length
   of anything typed into them. */
.bo-shell.bo-narrow { max-width: 680px; }

.bo2 .bo-page-head.bo-center { text-align: center; }
.bo2 .bo-page-head.bo-center .bo-sub { margin-inline: auto; }

.bo2 .bo-form-card {
    display: flex;
    flex-direction: column;
    gap: 20px;
    padding: 24px 26px;
}

/* ---------- numbered step block ---------- */
.bo2 .bo-fb { display: flex; flex-direction: column; gap: 8px; }

.bo2 .bo-fb-label {
    display: flex;
    align-items: center;
    gap: 8px;
    font-size: .72rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
}

.bo2 .bo-step {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-ink);
    font-size: .66rem;
    font-weight: 750;
    flex-shrink: 0;
}

/* A step that has been answered. The colour is the only progress indicator on
   the page, so it has to survive the step being revisited. */
.bo2 .bo-fb.bo-done .bo-step { background: var(--bo-green-soft); color: var(--bo-green-ink); }

.bo2 .bo-fb .bo-field { width: 100%; }

/* Radzen owns the customer and template pickers; .bo-field already restyles
   .rz-dropdown, this only stops the inline width attributes from winning. */
.bo2 .bo-fb .bo-field .rz-dropdown { width: 100% !important; max-width: none !important; }

/* ---------- switch with its explanation ---------- */
.bo2 .bo-switch-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 11px 14px;
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
}

.bo2 .bo-switch-copy { display: flex; flex-direction: column; gap: 1px; }
.bo2 .bo-switch-copy .bo-t { font-size: .86rem; font-weight: 580; color: var(--bo-ink); }
.bo2 .bo-switch-copy .bo-s { font-size: .74rem; color: var(--bo-ink-3); }

/* ---------- large drop zone ---------- */
/* The dialog .bo-dropzone is sized for a modal; this is the page's primary
   target and carries an icon, a prompt and the accepted extension. Radzen's
   choose button is the click and drop target — it is stretched to fill the
   frame width so the whole prompt line is hittable. */
.bo2 .bo-dropzone.bo-dz-lg { padding: 22px 18px; gap: 7px; border-width: 2px; }

.bo2 .bo-dropzone.bo-dz-lg .rz-fileupload-choose {
    padding: 2px 8px !important;
    font-size: .9rem !important;
    font-weight: 600 !important;
    color: var(--bo-ink) !important;
}

.bo2 .bo-dz-icon {
    width: 48px;
    height: 48px;
    border-radius: 13px;
    display: grid;
    place-items: center;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-deep);
}

.bo2 .bo-dz-sub { font-size: .76rem; color: var(--bo-ink-3); text-align: center; }

/* Radzen lists the picked file itself; the page shows it as .bo-file-chip
   instead, which also carries the remove button. */
.bo2 .bo-dropzone .rz-fileupload-files { display: none; }

/* Disabled until the steps above are answered. pointer-events is what stops a
   click landing on Radzen's button, which does not dim itself. */
.bo2 .bo-dropzone.bo-off { opacity: .5; pointer-events: none; }
.bo2 .bo-dropzone.bo-off:hover { border-color: #C9D6E1; background: var(--bo-surface-2); }

/* ---------- picked file ---------- */
.bo2 .bo-file-chip {
    display: flex;
    align-items: center;
    gap: 11px;
    padding: 11px 13px;
    background: var(--bo-green-soft);
    border: 1px solid #BFE6CD;
    border-radius: var(--bo-radius);
}

.bo2 .bo-file-ico {
    width: 36px;
    height: 36px;
    border-radius: 9px;
    display: grid;
    place-items: center;
    background: var(--bo-surface);
    color: var(--bo-green-deep);
    flex-shrink: 0;
}

.bo2 .bo-file-meta { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }

.bo2 .bo-file-name {
    font-size: .85rem;
    font-weight: 600;
    color: var(--bo-ink);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.bo2 .bo-file-size { font-size: .72rem; color: var(--bo-green-ink); }

.bo2 .bo-file-x {
    width: 28px;
    height: 28px;
    border-radius: 7px;
    display: grid;
    place-items: center;
    border: none;
    background: none;
    color: var(--bo-green-ink);
    cursor: pointer;
    flex-shrink: 0;
    transition: background .13s;
}

.bo2 .bo-file-x:hover { background: rgba(24,107,60,.12); }
.bo2 .bo-file-x:disabled { opacity: .45; cursor: not-allowed; }

/* ---------- progress ---------- */
.bo2 .bo-progress { display: flex; flex-direction: column; gap: 7px; }

.bo2 .bo-progress-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: .8rem;
}

/* Named bo-pg-* rather than the shorter bo-st / bo-pct: .bo-st is already the
   24px column of status glyphs used in the parcel tables, and it would have
   squeezed this label to 24px and broken it over four lines. */
.bo2 .bo-progress-top .bo-pg-st { color: var(--bo-ink-2); font-weight: 560; }
.bo2 .bo-progress-top .bo-pg-st b { color: var(--bo-ink); font-weight: 680; }
.bo2 .bo-progress-top .bo-pg-pct { color: var(--bo-brand-ink); font-weight: 700; font-variant-numeric: tabular-nums; }

.bo2 .bo-bar.bo-bar-lg { height: 8px; border-radius: 5px; }

/* An indeterminate stripe for the stretches the backend reports no percentage
   for — otherwise a 0% bar reads as a stalled import. */
.bo2 .bo-bar.bo-bar-idle i {
    width: 40% !important;
    background: linear-gradient(90deg,#2E9FD9,var(--bo-brand-deep));
    animation: bo-bar-slide 1.4s ease-in-out infinite;
}

@keyframes bo-bar-slide {
    0% { margin-left: -40%; }
    100% { margin-left: 100%; }
}

/* ---------- full-width submit ---------- */
/* Not .bo-btn-block — that name is already the red full-width destructive
   button, whose background would have won over .bo-btn-primary and turned the
   import's submit red. */
.bo2 .bo-btn.bo-btn-wide { width: 100%; padding: 12px 18px; font-size: .92rem; }

/* ---------- error list ---------- */
/* A rejected file can produce one complaint per row, so the callout scrolls
   rather than pushing the submit button off screen. */
.bo2 .bo-err-list {
    margin: 0;
    padding-left: 18px;
    max-height: 168px;
    overflow-y: auto;
    scrollbar-width: thin;
    display: flex;
    flex-direction: column;
    gap: 3px;
}

.bo2 .bo-err-list li { line-height: 1.45; }
.bo2 .bo-err-more { font-size: .76rem; color: var(--bo-ink-3); margin-top: 6px; }

/* ============================================================
   LABEL PRINT
   ============================================================ */

/* Four columns do not need the full 1520px, and a barcode search reads better
   when the results sit under the field that produced them. */
.bo-shell.bo-mid { max-width: 1040px; }

/* Stand-in for a text button, as opposed to .bo-sk-chip which stands in for a
   square icon button. Sized to a default .bo-btn (37px). */
.bo2 .bo-sk-btn { height: 37px; width: 118px; border-radius: var(--bo-radius-sm); }

/* The download action is the point of the row, so unlike the hover-revealed
   chips elsewhere it stays fully visible. Named bo-cell-btn to keep it clear
   of the existing td.bo-cell-actions, which is the icon-chip row. */
.bo2 .bo-cell-btn { text-align: right; }
.bo2 .bo-cell-btn .bo-btn { padding: 8px 14px; font-size: .82rem; }

/* The action-cell button is the tighter variant above (35px, 144px wide), so
   the placeholder is resized with it — otherwise the skeleton row stands 2px
   taller than the row it replaces and the table twitches when data lands. */
.bo2 td.bo-cell-btn .bo-sk-btn { height: 35px; width: 144px; }

/* Unit suffix after a figure in a numeric cell. The totals strip has its own
   .bo-u; this is the table-cell equivalent. */
.bo2 td.bo-num .bo-u { font-size: .72rem; color: var(--bo-ink-3); font-weight: 500; margin-left: 3px; }

/* Row under the table offering the next slice. The query returns no total, so
   there is no page count to show — only whether more exist. */
.bo2 .bo-more-row {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 10px;
    padding: 14px 20px 4px;
}

.bo2 .bo-more-note { font-size: .78rem; color: var(--bo-ink-3); }

/* ============================================================
   SETTINGS
   The section list is a column beside the section, not a Radzen
   sidebar docked to the viewport: it scrolls with the page until
   it reaches the top, then stays. Pages under SettingsLayout emit
   their content only — the layout owns .bo2, the shell and the nav.
   ============================================================ */
.bo2 .bo-settings {
    display: grid;
    grid-template-columns: 236px minmax(0, 1fr);
    gap: 20px;
    align-items: start;
}

/* minmax(0,1fr) above is what lets this column's tables scroll instead of
   forcing the grid wider than the viewport. */
.bo2 .bo-set-main { min-width: 0; }

.bo2 .bo-set-nav {
    position: sticky;
    top: 14px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-lg);
    box-shadow: var(--bo-shadow-sm);
    padding: 7px;
    display: flex;
    flex-direction: column;
    gap: 1px;
    max-height: calc(100dvh - 88px);
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-set-nav::-webkit-scrollbar { width: 8px; }
.bo2 .bo-set-nav::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }

.bo2 .bo-set-grp {
    font-size: .62rem;
    font-weight: 720;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    padding: 12px 10px 5px;
}

.bo2 .bo-set-grp:first-child { padding-top: 5px; }

.bo2 .bo-set-link {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 8px 10px;
    border-radius: 8px;
    font-size: .84rem;
    font-weight: 520;
    color: var(--bo-ink-2);
    text-decoration: none;
    transition: background .13s, color .13s;
}

.bo2 .bo-set-link:hover { background: var(--bo-surface-2); color: var(--bo-ink); }
.bo2 .bo-set-link svg { color: var(--bo-ink-3); flex-shrink: 0; transition: color .13s; }
.bo2 .bo-set-link:hover svg { color: var(--bo-ink-2); }

.bo2 .bo-set-link.bo-on { background: var(--bo-brand-soft); color: var(--bo-brand-ink); font-weight: 640; }
.bo2 .bo-set-link.bo-on svg { color: var(--bo-brand-deep); }

/* Below this the two columns cannot both hold their width, so the nav becomes
   a scrolling strip above the section instead of squeezing it. */
@media (max-width: 1080px) {
    .bo2 .bo-settings { grid-template-columns: minmax(0, 1fr); }

    .bo2 .bo-set-nav {
        position: static;
        flex-direction: row;
        max-height: none;
        overflow-x: auto;
        overflow-y: hidden;
        gap: 3px;
    }

    .bo2 .bo-set-grp { display: none; }
    .bo2 .bo-set-link { white-space: nowrap; }
}

/* ---------- hub ---------- */
/* The landing page used to read "Please select setting's page on your right",
   which is neither a destination nor a description of what is behind each
   link. These cards say what each section holds. */
.bo2 .bo-hub {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(230px, 1fr));
    gap: 13px;
}

.bo2 .bo-hub-card {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 15px 16px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-lg);
    box-shadow: var(--bo-shadow-xs);
    text-decoration: none;
    transition: border-color .15s, box-shadow .15s, transform .12s;
}

.bo2 .bo-hub-card:hover {
    border-color: var(--bo-brand);
    box-shadow: var(--bo-shadow-md);
    transform: translateY(-1px);
}

.bo2 .bo-hub-ico {
    width: 34px;
    height: 34px;
    border-radius: 10px;
    display: grid;
    place-items: center;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-deep);
}

.bo2 .bo-hub-t { font-size: .89rem; font-weight: 640; color: var(--bo-ink); }
.bo2 .bo-hub-s { font-size: .755rem; color: var(--bo-ink-3); line-height: 1.45; }

/* ---------- settings forms ---------- */
/* Save and Cancel sit on their own line, separated from the last field, so a
   long form does not end with the submit crowding the input above it. */
.bo2 .bo-form-foot {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    gap: 8px;
    margin-top: 6px;
    padding-top: 16px;
    border-top: 1px solid var(--bo-line-soft);
}

/* Pushes a secondary action (Delete) to the left of Save/Cancel. */
.bo2 .bo-form-foot .bo-foot-left { margin-right: auto; }

/* Inline validation. The old pages stacked a ValidationSummary above the card
   and repeated every message; saying it under the field it belongs to is
   shorter and points at the thing to fix. */
.bo2 .bo-form-f .bo-err {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .72rem;
    font-weight: 540;
    color: var(--bo-red-ink);
}

.bo2 .bo-form-f.bo-invalid .bo-field { border-color: var(--bo-red); background: var(--bo-red-soft); }
.bo2 .bo-form-f.bo-invalid > label { color: var(--bo-red-ink); }

/* A required field is marked once, on the label, rather than explained in a
   validator message that only appears after a failed submit. */
.bo2 .bo-form-f > label .bo-req { color: var(--bo-red); margin-left: 3px; font-weight: 700; }

/* A checkbox with its own explanation, for the odd boolean in a form of text
   fields (Spedition's "Default", Customer's flags). */
.bo2 .bo-check-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 11px 13px;
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    cursor: pointer;
}

.bo2 .bo-check-row input[type="checkbox"] { width: 16px; height: 16px; margin-top: 1px; accent-color: var(--bo-brand); flex-shrink: 0; cursor: pointer; }
.bo2 .bo-check-row .bo-t { font-size: .85rem; font-weight: 560; color: var(--bo-ink); }
.bo2 .bo-check-row .bo-s { font-size: .74rem; color: var(--bo-ink-3); }
.bo2 .bo-check-row .bo-cr-copy { display: flex; flex-direction: column; gap: 1px; }

/* ---------- settings list ---------- */
/* Edit and delete on a settings row. Dimmed until the row is hovered, like the
   warehouse-manager actions, so a long list is not a wall of icons. */
.bo2 .bo-row-acts { display: flex; align-items: center; gap: 2px; justify-content: flex-end; opacity: .45; transition: opacity .13s; }
.bo2 table.bo-table tbody tr.bo-row:hover .bo-row-acts { opacity: 1; }
.bo2 .bo-row-acts .bo-iconbtn.bo-red:hover { background: var(--bo-red-soft); color: var(--bo-red-deep); }

/* Keyboard users never trigger :hover, so focus reveals the actions too. */
.bo2 .bo-row-acts:focus-within { opacity: 1; }

/* Grouped bands on the settings landing page. */
.bo2 .bo-hub-sec { margin-bottom: 22px; }

.bo2 .bo-sec-head {
    font-size: .7rem;
    font-weight: 720;
    letter-spacing: .09em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    margin: 0 0 9px 2px;
}

/* A panel whose whole content is a sentence explaining why it is empty. */
.bo2 .bo-empty-panel {
    padding: 34px 20px;
    text-align: center;
    font-size: .86rem;
    color: var(--bo-ink-3);
}

/* Back to the list a form belongs to. Editing is reached from a list and
   returns to it, so the way back is stated rather than left to the browser. */
.bo2 .bo-back {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .76rem;
    font-weight: 560;
    color: var(--bo-ink-3);
    text-decoration: none;
    margin-bottom: 5px;
    transition: color .13s;
}

.bo2 .bo-back:hover { color: var(--bo-brand-ink); }
.bo2 .bo-back svg { flex-shrink: 0; }

/* ---------- inline multi-select ---------- */
/* A short, fully visible set of choices — regions on a country, permissions on
   a role. A paged, sortable grid for a list this size costs more to read than
   the list itself. */
/* Named bo-opt* rather than bo-pick*: .bo-pick is already the 15px radio dot
   used by single-choice table rows, and an equally specific rule later in the
   file would have turned every one of those into a padded pill. */
.bo2 .bo-optlist {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 10px;
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    max-height: 240px;
    overflow-y: auto;
    scrollbar-width: thin;
}

.bo2 .bo-optpill {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 7px 12px 7px 9px;
    border-radius: 999px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line);
    font-size: .82rem;
    color: var(--bo-ink-2);
    cursor: pointer;
    transition: border-color .13s, background .13s, color .13s;
}

.bo2 .bo-optpill:hover { border-color: var(--bo-ink-3); }

.bo2 .bo-optpill.bo-on {
    background: var(--bo-brand-soft);
    border-color: var(--bo-brand);
    color: var(--bo-brand-ink);
    font-weight: 580;
}

.bo2 .bo-optpill input[type="checkbox"] {
    width: 14px;
    height: 14px;
    accent-color: var(--bo-brand);
    cursor: pointer;
    flex-shrink: 0;
}

/* Sits on the field label and says how many are picked, so the count does not
   have to be taken by eye off a wrapped row of chips. */
.bo2 .bo-opt-count {
    margin-left: 7px;
    font-size: .68rem;
    font-weight: 620;
    letter-spacing: 0;
    text-transform: none;
    color: var(--bo-brand-ink);
    background: var(--bo-brand-soft);
    padding: 1px 7px;
    border-radius: 999px;
}

/* ---------- colour swatches ---------- */
/* A row of named colours, one click each. The picker they replace was a
   dropdown of bare dots — the colour had to be opened to be seen and had no
   name against it anywhere. */
.bo2 .bo-swatches { display: inline-flex; align-items: center; gap: 5px; }

.bo2 .bo-swatch {
    width: 20px;
    height: 20px;
    border-radius: 50%;
    border: 2px solid transparent;
    background: var(--bo-sw, var(--bo-ink-3));
    box-shadow: 0 0 0 1px rgba(16,42,64,.14) inset;
    cursor: pointer;
    padding: 0;
    position: relative;
    flex-shrink: 0;
    transition: transform .12s, border-color .12s, box-shadow .12s;
}

.bo2 .bo-swatch:hover:not(:disabled) { transform: scale(1.12); }

/* The picked one is ringed rather than merely larger, so which is set is
   readable without comparing sizes. */
.bo2 .bo-swatch.bo-on {
    border-color: var(--bo-surface);
    box-shadow: 0 0 0 2px var(--bo-ink-2);
}

.bo2 .bo-swatch:disabled { opacity: .45; cursor: not-allowed; }

/* ---------- two-line address cell ---------- */
.bo2 .bo-addr { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.bo2 .bo-addr > span { overflow: hidden; text-overflow: ellipsis; }
.bo2 .bo-addr .bo-addr-sub { font-size: .74rem; color: var(--bo-ink-3); }

/* The row currently being edited in place. Tinted so it is obvious which row
   the save and cancel buttons belong to when the table is long. */
.bo2 table.bo-table tbody tr.bo-editing { background: var(--bo-brand-tint); }
.bo2 table.bo-table tbody tr.bo-editing:hover { background: var(--bo-brand-tint); }
.bo2 table.bo-table tbody tr.bo-editing td { padding-top: 8px; padding-bottom: 8px; }
.bo2 table.bo-table tbody tr.bo-editing .bo-row-acts { opacity: 1; }

/* ============================================================
   GAPS FOUND WHILE CONVERTING SETTINGS
   ============================================================ */

/* A value shown but not editable. Putting one in a .bo-field reads as an input
   the user may type into and cannot. */
.bo2 .bo-static {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .87rem;
    color: var(--bo-ink);
    font-variant-numeric: tabular-nums;
}

.bo2 .bo-static .bo-u { font-size: .72rem; color: var(--bo-ink-3); font-weight: 500; }

/* Validation state was reachable only under .bo-form-f, so an editable table
   cell had to be wrapped in a labelless .bo-form-f to turn it red. These make
   the state usable wherever an input lives. */
.bo2 .bo-err {
    display: flex;
    align-items: center;
    gap: 5px;
    font-size: .72rem;
    font-weight: 540;
    color: var(--bo-red-ink);
}

.bo2 .bo-invalid > .bo-field,
.bo2 .bo-field.bo-invalid { border-color: var(--bo-red); background: var(--bo-red-soft); }

/* An open-ended set of choices (every provider, every carrier) overflows a
   single line; a fixed pair like Customer/Czech Post does not. Wrapping is
   harmless for the short ones and necessary for the long ones. */
.bo2 .bo-seg { flex-wrap: wrap; }

/* A section heading that carries its own action — "Add band" belongs beside
   the band table's title, not stranded under the table. */
.bo2 .bo-sec-head-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 9px 2px;
}

.bo2 .bo-sec-head-row .bo-sec-head { margin: 0; }

/* Many small fields of equal weight — a column map, a table of limits.
   .bo-form-row flows by content and leaves ragged ends; this lines them up. */
.bo2 .bo-form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(178px, 1fr));
    gap: 12px 10px;
}

.bo2 .bo-form-grid .bo-form-f { flex: none; }

/* Stacked panels on one page. Deliberately a wrapper rather than
   `.bo-panel + .bo-panel`: .bo-filter-card already carries its own bottom
   margin, and the settings landing page lays .bo-panel cards out in a grid,
   where an adjacent-sibling margin would fight the grid gap. */
.bo2 .bo-stack { display: flex; flex-direction: column; gap: 16px; }

/* A tab strip standing between the page head and a panel, rather than sitting
   inside one. Its bottom border needs clearance from the panel below. */
.bo2 .bo-tabs.bo-standalone { margin-bottom: 14px; }

/* ---------- neutral aliases ---------- */
/* The same two-column master/detail shape as .bo-wh-layout, under a name that
   is not tied to the warehouse screen. Invoices uses it for invoice + items.
   Declared alongside the original rather than renaming it, so the warehouse
   markup keeps working. */
.bo2 .bo-split {
    display: grid;
    grid-template-columns: 352px minmax(0, 1fr);
    gap: 16px;
    align-items: stretch;
}

@media (max-width: 1100px) {
    .bo2 .bo-split { grid-template-columns: 1fr; }
}

/* Selected row in any clickable list. .bo-prow/.bo-on does the same but reads
   as "parcel row"; this says what it means. */
.bo2 table.bo-table tbody tr.bo-row.bo-picked { background: var(--bo-brand-soft); }
.bo2 table.bo-table tbody tr.bo-row.bo-picked td:first-child { box-shadow: 3px 0 0 var(--bo-brand) inset; }
.bo2 table.bo-table tbody tr.bo-row.bo-pickable { cursor: pointer; }

/* .bo-tabs is padded to line up with panel content. Standing on its own under
   the page head that indent is a coincidence, not an intent. */
.bo2 .bo-tabs.bo-bare { padding-left: 0; padding-right: 0; }

/* A plain block inside a panel, carrying the panel's own gutters and a rule
   under it. .bo-toolbar and .bo-table-head are the same shape but both mean
   "controls live here", so using either for ordinary content reads wrong. */
.bo2 .bo-panel-sec {
    padding: 14px 18px;
    border-bottom: 1px solid var(--bo-line-soft);
}

.bo2 .bo-panel-sec:last-child { border-bottom: none; }
.bo2 .bo-panel-sec > .bo-sec-head { margin-top: 0; }

/* A long table that should scroll inside its panel rather than push the page
   down — a parsed import preview, a country × weight-band matrix. The header
   stays put because .bo-table thead is already sticky. */
.bo2 .bo-table-wrap.bo-scroll {
    max-height: 460px;
    overflow-y: auto;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-table-wrap.bo-scroll::-webkit-scrollbar { width: 9px; height: 9px; }
.bo2 .bo-table-wrap.bo-scroll::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }

/* ============================================================
   TWO-PANEL MOVE LIST (BoPickList)
   Restyled RadzenPickListEdited: two scrollable boxes with a
   column of four arrow buttons between them.
   ============================================================ */
.bo2 .bo-picker {
    --bo-pk-h: 420px;
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    gap: 14px;
    align-items: stretch;
}

@media (max-width: 760px) {
    .bo2 .bo-picker { grid-template-columns: 1fr; }
    .bo2 .bo-picker-actions { flex-direction: row; justify-content: center; }
}

.bo2 .bo-picker-col {
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    padding: 10px;
}

.bo2 .bo-picker-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 0 2px;
}

.bo2 .bo-picker-title {
    font-size: .78rem;
    font-weight: 640;
    color: var(--bo-ink-2);
    display: inline-flex;
    align-items: center;
    gap: 6px;
}

.bo2 .bo-picker-count {
    font-size: .68rem;
    font-weight: 620;
    color: var(--bo-ink-3);
    background: var(--bo-surface-3);
    padding: 1px 7px;
    border-radius: 999px;
}

.bo2 .bo-picker-search { background: var(--bo-surface); }

.bo2 .bo-picker-list {
    height: var(--bo-pk-h);
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 1px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-sm);
    padding: 4px;
    scrollbar-width: thin;
    scrollbar-color: #C3CFDA transparent;
}

.bo2 .bo-picker-list::-webkit-scrollbar { width: 8px; }
.bo2 .bo-picker-list::-webkit-scrollbar-thumb { background: #C3CFDA; border-radius: 5px; border: 2px solid var(--bo-surface); }

.bo2 .bo-picker-empty {
    margin: auto;
    font-size: .82rem;
    color: var(--bo-ink-3);
    text-align: center;
    padding: 20px;
}

.bo2 .bo-picker-row {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 8px;
    border-radius: 6px;
    font-size: .84rem;
    color: var(--bo-ink);
    cursor: pointer;
    transition: background .1s;
}

.bo2 .bo-picker-row:hover { background: var(--bo-surface-2); }
.bo2 .bo-picker-row.bo-on { background: var(--bo-brand-soft); }
.bo2 .bo-picker-row .bo-cb { pointer-events: none; flex-shrink: 0; }
.bo2 .bo-picker-row .bo-picker-text { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bo2 .bo-picker-row .bo-picker-extra { flex-shrink: 0; cursor: default; }

.bo2 .bo-picker-actions {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: 6px;
    padding: 0 2px;
}

.bo2 .bo-iconbtn.bo-picker-arrow {
    width: 32px;
    height: 32px;
    border: 1px solid var(--bo-line);
    background: var(--bo-surface);
}

.bo2 .bo-iconbtn.bo-picker-arrow:hover:not(:disabled) { background: var(--bo-brand-soft); border-color: var(--bo-brand); color: var(--bo-brand-ink); }

/* Compact "Write" checkbox + label, used per-row and per-column in BoPickList. */
.bo2 .bo-mini-check {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    font-size: .74rem;
    font-weight: 560;
    color: var(--bo-ink-3);
    cursor: pointer;
    flex-shrink: 0;
}

.bo2 .bo-mini-check .bo-cb { flex-shrink: 0; }

/* ============================================================
   REPORTS — advanced filters, status matrix, yes/no flags
   Ported from docs/design/beeonline-reports-volume-2.0.html
   ============================================================ */

/* Collapsible second row of a filter card. A plain conditional render (no
   hide/show animation) — the toggle button already carries the on/off state. */
.bo2 .bo-adv {
    border-top: 1px solid var(--bo-line-soft);
    padding-top: 14px;
    display: flex;
    flex-direction: column;
    gap: 14px;
}

/* Two small yes/no matrices side by side — status flags and scan channel,
   each too narrow on its own to justify a full .bo-f-grid row. */
.bo2 .bo-matrix-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 16px;
}

.bo2 .bo-matrix {
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    overflow: hidden;
}

.bo2 .bo-matrix table { width: 100%; border-collapse: collapse; }

.bo2 .bo-matrix th {
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    padding: 8px 12px;
    background: var(--bo-surface-2);
    text-align: center;
    border-bottom: 1px solid var(--bo-line-soft);
}

.bo2 .bo-matrix th:first-child { text-align: left; }

.bo2 .bo-matrix td {
    padding: 6px 12px;
    font-size: .8rem;
    border-bottom: 1px solid var(--bo-line-soft);
    text-align: center;
}

.bo2 .bo-matrix td:first-child { text-align: left; font-weight: 520; color: var(--bo-ink-2); }
.bo2 .bo-matrix tr:last-child td { border-bottom: none; }

/* ---------- yes / no status flags ---------- */
/* A parcel's progress through the pipeline, one glyph per stage — cheaper to
   scan as a row of dots than as a row of "Yes"/"No" table cells. */
.bo2 .bo-flag {
    width: 21px;
    height: 21px;
    border-radius: 50%;
    display: inline-grid;
    place-items: center;
    flex-shrink: 0;
}

.bo2 .bo-flag.bo-yes { background: var(--bo-green-soft); color: var(--bo-green-deep); }
.bo2 .bo-flag.bo-no { background: var(--bo-surface-3); color: #AEBBC6; }

.bo2 .bo-flag-wrap { display: inline-flex; align-items: center; gap: 5px; }

/* Which channel a scan came through — only shown once the stage is done, so it
   never implies a channel for something that has not happened yet. */
.bo2 .bo-chan {
    width: 17px;
    height: 17px;
    border-radius: 5px;
    display: inline-grid;
    place-items: center;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-deep);
    flex-shrink: 0;
}

/* Pushes the Advanced-filters toggle to the left of a right-aligned
   .bo-filter-actions row, same trick as .bo-modal-foot/.bo-form-foot. */
.bo2 .bo-filter-actions .bo-foot-left { margin-right: auto; }

/* ============================================================
   REPORTS — activity log timestamp, truck chip, user cell
   Ported from docs/design/beeonline-reports-activity-2.0.html
   ============================================================ */

/* Two-line date+time cell — pairing them on one baseline made the row read
   as a single long number instead of a date. */
.bo2 .bo-ts { display: flex; flex-direction: column; gap: 1px; }
.bo2 .bo-ts .bo-d { font-variant-numeric: tabular-nums; font-weight: 560; font-size: .82rem; }
.bo2 .bo-ts .bo-t { font-size: .72rem; color: var(--bo-ink-3); font-variant-numeric: tabular-nums; }

.bo2 .bo-truck-chip {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-family: var(--bo-font-mono);
    font-size: .75rem;
    font-weight: 600;
    padding: 3px 9px;
    border-radius: 6px;
    background: var(--bo-surface-3);
    color: var(--bo-ink);
    border: 1px solid var(--bo-line);
}

.bo2 .bo-truck-chip svg { color: var(--bo-ink-3); flex-shrink: 0; }

.bo2 .bo-user-cell { display: inline-flex; align-items: center; gap: 8px; }

.bo2 .bo-user-av {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    flex-shrink: 0;
    display: grid;
    place-items: center;
    font-size: .64rem;
    font-weight: 700;
    background: var(--bo-brand-soft);
    color: var(--bo-brand-deep);
}

/* No width/overflow of its own — both hosts (Activity log, Generated labels)
   put this in a .bo-resizable column, whose <td> already clips to whatever
   width the user dragged it to. A fixed max-width here would cap it below
   that regardless of how far the column was widened. */
.bo2 .bo-desc { color: var(--bo-ink-2); }

/* ============================================================
   CUSTOMS PRE-ALERT — filter sub-headings, status pill, address
   blocks, colour swatch, bulk-action columns.
   ============================================================ */

.bo2 .bo-btn-success {
    background: linear-gradient(180deg,var(--bo-green),var(--bo-green-deep));
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(38,138,77,.35);
}
.bo2 .bo-btn-success:hover:not(:disabled) { filter: brightness(1.06); }

.bo2 .bo-btn-warn {
    background: linear-gradient(180deg,var(--bo-orange),var(--bo-orange-deep));
    color: #fff;
    box-shadow: 0 1px 0 rgba(255,255,255,.2) inset, 0 2px 6px rgba(222,138,6,.35);
}
.bo2 .bo-btn-warn:hover:not(:disabled) { filter: brightness(1.06); }

/* A filter group's own label ("Shipper info") with a Reset link beside it, so
   clearing one cluster does not require the page-wide reset. */
.bo2 .bo-f-subhead { display: flex; align-items: center; justify-content: space-between; margin: 2px 0 -2px; }

.bo2 .bo-mini-reset {
    font-size: .7rem;
    font-weight: 640;
    color: var(--bo-brand-ink);
    background: none;
    border: none;
    cursor: pointer;
    padding: 2px 6px;
    border-radius: 5px;
}
.bo2 .bo-mini-reset:hover { background: var(--bo-brand-tint); }

/* Status pill for the results table — same shape as the reports status
   flags, three fixed variants (not started / blocked / approved) instead
   of a boolean. */
.bo2 .bo-cst-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: .78rem;
    font-weight: 620;
    padding: 4px 11px;
    border-radius: 999px;
    white-space: nowrap;
}
.bo2 .bo-cst-badge .bo-dot { width: 7px; height: 7px; }
.bo2 .bo-cst-badge.bo-wait { background: var(--bo-surface-3); color: var(--bo-ink-2); }
.bo2 .bo-cst-badge.bo-wait .bo-dot { background: var(--bo-orange); }
.bo2 .bo-cst-badge.bo-block { background: var(--bo-red-soft); color: var(--bo-red-ink); }
.bo2 .bo-cst-badge.bo-block .bo-dot { background: var(--bo-red); }
.bo2 .bo-cst-badge.bo-ok { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-cst-badge.bo-ok .bo-dot { background: var(--bo-green); }

/* Shipper/consignee address block in the results table. */
.bo2 .bo-addr { display: flex; flex-direction: column; gap: 1px; line-height: 1.35; }
.bo2 .bo-addr .bo-addr-name { font-size: .84rem; font-weight: 620; color: var(--bo-ink); }
.bo2 .bo-addr .bo-addr-line { font-size: .76rem; color: var(--bo-ink-3); }

.bo2 .bo-cust-cell { display: flex; align-items: flex-start; gap: 10px; }

/* The consignee's traffic-light colour, doubling as the button that opens
   ChangeColorDialog — bigger and interactive, unlike the plain static .bo-dot
   used elsewhere for a status pill. */
.bo2 .bo-color-dot {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    flex-shrink: 0;
    cursor: pointer;
    margin-top: 2px;
    border: none;
    padding: 0;
    box-shadow: 0 0 0 1px var(--bo-line);
    transition: transform .12s, box-shadow .12s;
}
.bo2 .bo-color-dot:hover { transform: scale(1.14); box-shadow: 0 0 0 1px var(--bo-brand); }
.bo2 .bo-color-dot.bo-dot-g { background: var(--bo-green); }
.bo2 .bo-color-dot.bo-dot-y { background: var(--bo-orange); }
.bo2 .bo-color-dot.bo-dot-r { background: var(--bo-red); }
.bo2 .bo-color-dot.bo-dot-none { background: var(--bo-surface-3); }

/* Bulk action card: two matching columns (selected vs. filtered) rather than
   CustomsTab's block/unblock pair — reuses .bo-panel/.bo-card-sep/.bo-col-title/
   .bo-sel-count as-is, including their existing max-width:900px stacking rule. */
.bo2 .bo-bulk-actions-card { display: flex; align-items: stretch; margin-bottom: 18px; }
.bo2 .bo-bulk-col { flex: 1; padding: 18px 22px; display: flex; flex-direction: column; gap: 12px; }
.bo2 .bo-bulk-row { display: flex; gap: 9px; flex-wrap: wrap; }
.bo2 .bo-bulk-row .bo-btn { flex: 1; min-width: 150px; justify-content: center; }

/* Shipper/consignee side-by-side in ItemDetailDialog's shipment summary. */
.bo2 .bo-summary-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; }
@media (max-width: 520px) { .bo2 .bo-summary-grid { grid-template-columns: 1fr; } }

/* ChangeColorDialog's swatch picker — bigger than the table's .bo-color-dot
   since it is the only control on the dialog, not a compact row accent. */
.bo2 .bo-color-picker { display: flex; gap: 14px; }
.bo2 .bo-color-swatch {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: none;
    cursor: pointer;
    box-shadow: 0 0 0 1px var(--bo-line);
    transition: transform .12s, box-shadow .12s;
}
.bo2 .bo-color-swatch:hover { transform: scale(1.08); }
.bo2 .bo-color-swatch.bo-picked { box-shadow: 0 0 0 3px var(--bo-surface), 0 0 0 5px var(--bo-brand); }

/* Icon-button row in a primary table's action column — unlike .bo-pactions
   (CustomsTab's expanded sub-table), these stay fully visible: the PreAlert
   table is the main grid, not a dense secondary list to declutter on hover. */
.bo2 .bo-actions-row { display: flex; align-items: center; gap: 3px; justify-content: center; }

/* A bordered box of independent checkboxes (customs status, consignee colour)
   — reuses .bo-matrix's box chrome without its yes/no table layout. */
.bo2 .bo-matrix-checks { display: flex; flex-wrap: wrap; gap: 14px; padding: 12px 14px; }

/* ============================================================
   CUSTOMER DASHBOARD — waybill progress stages
   ============================================================
   The customer's waybill row answers one question: how far along is my
   shipment? The old grid stacked five "LABEL  ● n / m 🔍" lines inside a
   cell, which made every row five lines tall and impossible to compare
   across rows. The same five numbers are laid out as a fixed grid of small
   cards instead, so the eye scans a column (all the NOA figures) rather
   than re-reading a paragraph per row. */
.bo2 .bo-stage-grid {
    display: grid;
    grid-template-columns: repeat(5, minmax(96px, 1fr));
    gap: 8px;
}

.bo2 .bo-stage {
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-sm);
    padding: 7px 9px 8px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    min-width: 0;
}

/* A finished stage tints green rather than only filling its bar — at a glance
   the row reads as a row of green cards with the unfinished ones standing out,
   which is the state the customer is actually looking for. */
.bo2 .bo-stage.bo-done { background: var(--bo-green-soft); border-color: #CDE9D8; }
.bo2 .bo-stage.bo-alert { background: var(--bo-red-soft); border-color: #F0C2C2; }

.bo2 .bo-stage-top { display: flex; align-items: center; justify-content: space-between; gap: 4px; min-width: 0; }

.bo2 .bo-stage-lbl {
    font-size: .6rem;
    font-weight: 720;
    letter-spacing: .07em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bo2 .bo-stage.bo-done .bo-stage-lbl { color: var(--bo-green-ink); }
.bo2 .bo-stage.bo-alert .bo-stage-lbl { color: var(--bo-red-ink); }

.bo2 .bo-stage-val { font-size: .84rem; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--bo-ink); line-height: 1.2; }

/* "3 of 4" written as 3/4: the denominator is context, not data, so it steps
   back everywhere it appears — .bo-prog-val and .bo-stage-val already said
   this locally, this makes it the default for a bare table cell too. */
.bo2 .bo-of { color: var(--bo-ink-3); font-weight: 500; }
.bo2 .bo-stage.bo-done .bo-stage-val { color: var(--bo-green-ink); }
.bo2 .bo-stage.bo-alert .bo-stage-val { color: var(--bo-red-ink); }

/* Smaller than the table's drill button and pulled into the card's padding,
   so it sits on the label line without making the card taller. */
.bo2 .bo-stage .bo-mini-zoom { width: 18px; height: 18px; margin: -2px -3px -2px 0; flex-shrink: 0; }

.bo2 .bo-bar i.bo-r { background: linear-gradient(90deg,var(--bo-red),var(--bo-red-deep)); }

/* The bar is decoration over the figure above it; on an empty waybill
   (0 of 0) there is nothing to fill, so it stays a flat track. */
.bo2 .bo-stage .bo-bar { background: #DCE4EB; }
.bo2 .bo-stage.bo-done .bo-bar { background: rgba(38,138,77,.18); }
.bo2 .bo-stage.bo-alert .bo-bar { background: rgba(196,58,58,.18); }

/* "Has this happened, and when?" — a green tick with the timestamp once it
   has, a quiet dash while it has not. Deliberately not a red cross: a stage
   that has not been reached yet is pending, not failed, and four red crosses
   per row made a perfectly healthy in-transit parcel look broken. */
.bo2 .bo-stamp {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    font-size: .79rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.bo2 .bo-stamp .bo-tick {
    display: inline-grid;
    place-items: center;
    width: 20px;
    height: 20px;
    border-radius: 6px;
    background: var(--bo-green-soft);
    color: var(--bo-green-deep);
    flex-shrink: 0;
}

.bo2 .bo-stamp.bo-pending { color: var(--bo-ink-3); }
.bo2 .bo-stamp.bo-pending .bo-tick { background: var(--bo-surface-3); color: var(--bo-ink-3); }

/* A list of bare barcodes (parcels not warehoused in/out, not departed).
   Monospace and wrapped, so 200 of them stay readable in a dialog. */
.bo2 .bo-code-list {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

.bo2 .bo-code-list span {
    font-family: var(--bo-font-mono);
    font-size: .78rem;
    color: var(--bo-ink-2);
    background: var(--bo-surface-2);
    border: 1px solid var(--bo-line-soft);
    border-radius: 6px;
    padding: 3px 8px;
}

/* ============================================================
   AUTH PAGES (Login, Forgotten password)
   ============================================================
   These render outside the app shell — MainLayout's NotAuthorized branch
   emits @Body on its own, with no .bo-layout and no topnav — so this block
   owns the full-viewport ground itself instead of inheriting it.

   Flat brand blue, not the topnav's gradient: at 100vh a vertical gradient
   banded visibly, and the request was for one solid colour matching the bar
   the user sees straight after signing in. */
.bo2.bo-auth {
    min-height: 100vh;
    display: grid;
    place-items: center;
    padding: 32px 20px 76px;
    background: #127EB8;
    position: relative;
    -webkit-font-smoothing: antialiased;
}

.bo2 .bo-auth-inner { width: 100%; max-width: 396px; }

.bo2 .bo-auth-brand {
    font-family: var(--bo-font-display);
    font-weight: 650;
    font-size: 1.45rem;
    letter-spacing: -.01em;
    color: #fff;
    text-align: center;
    margin: 0 0 20px;
}

.bo2 .bo-auth-card {
    background: var(--bo-surface);
    border-radius: var(--bo-radius-lg);
    box-shadow: 0 18px 44px rgba(8,44,70,.24), 0 2px 6px rgba(8,44,70,.12);
    padding: 30px 30px 26px;
}

.bo2 .bo-auth-card h1 {
    font-family: var(--bo-font-display);
    font-size: 1.16rem;
    font-weight: 640;
    color: var(--bo-ink);
    margin: 0;
}

.bo2 .bo-auth-sub {
    font-size: .85rem;
    color: var(--bo-ink-3);
    margin: 5px 0 22px;
    line-height: 1.5;
}

.bo2 .bo-auth-row { margin-bottom: 15px; }

.bo2 .bo-auth-lbl {
    display: block;
    font-size: .68rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    margin-bottom: 6px;
}

/* Taller than a toolbar .bo-field, and it keeps a focus ring. The no-ring rule
   on .bo-field is a filter-toolbar decision (a halo there read as an error);
   on a form you are typing into blind, the ring is the point. */
.bo2 .bo-auth-field { height: 42px; }
.bo2 .bo-auth-field > input { flex: 1; }

.bo2 .bo-auth-field:focus-within {
    background: var(--bo-surface);
    border-color: var(--bo-brand);
    box-shadow: 0 0 0 3px var(--bo-brand-soft);
}

/* Reveal toggle: sits inside the field box, so it must not inherit the
   field's padding-driven hit area — it gets its own. */
.bo2 .bo-auth-reveal {
    flex-shrink: 0;
    display: grid;
    place-items: center;
    width: 26px;
    height: 26px;
    margin-right: -4px;
    border: none;
    border-radius: 6px;
    background: none;
    color: var(--bo-ink-3);
    cursor: pointer;
    transition: background .15s, color .15s;
}

.bo2 .bo-auth-reveal:hover { background: var(--bo-surface-3); color: var(--bo-ink-2); }

.bo2 .bo-auth-submit {
    width: 100%;
    height: 42px;
    justify-content: center;
    margin-top: 4px;
    font-size: .9rem;
}

.bo2 .bo-auth-msg { margin-bottom: 15px; }

.bo2 .bo-auth-foot {
    text-align: center;
    margin: 18px 0 0;
    font-size: .83rem;
    color: var(--bo-ink-3);
}

.bo2 .bo-auth-foot a { color: var(--bo-brand-deep); font-weight: 560; text-decoration: none; }
.bo2 .bo-auth-foot a:hover { text-decoration: underline; }

.bo2 .bo-auth-logo {
    position: absolute;
    right: 20px;
    bottom: 20px;
    height: 40px;
    opacity: .9;
}

/* The confirmation twin of .bo-callout-err — used by the password-reset
   page once the mail is away. */
.bo2 .bo-callout.bo-callout-ok {
    border-color: #BCE4CB;
    background: var(--bo-green-soft);
    color: var(--bo-green-ink);
}

.bo2 .bo-callout.bo-callout-ok svg { color: var(--bo-green-deep); }
.bo2 .bo-callout.bo-callout-ok strong { color: var(--bo-green-ink); }

/* ============================================================
   STAT CARDS  (.bo-statrow / .bo-statcard — see BoStatCards.razor)
   ============================================================
   The strip above a tab's table. It is a summary, not a control panel:
   quiet surfaces, one accent line per card and a single coloured figure,
   so the eye lands on the number that is out of place rather than on the
   cards themselves.

   A card is dense — headline figure, a period badge, up to three labelled
   bars and up to three small facts — but it is read top to bottom in one
   order every time, which is what keeps the density legible. The sizes
   below step down at each level (1.4rem figure, .72rem bar labels,
   .69rem facts) so that order is obvious without any rules or boxes.

   Tone is meaning, not decoration. .bo-t-* tones a whole card and only
   .bo-t-bad tints its body, which is reserved for a figure that needs
   somebody to act. .bo-r-* tones one bar, badge or fact inside a card and
   never touches the background — the two sets are deliberately separate
   so a red bar cannot turn its card red. */

.bo2 .bo-statrow {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(248px, 1fr));
    gap: 12px;
    margin-bottom: 18px;
    align-items: stretch;
}

.bo2 .bo-statcard {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 13px 15px 14px;
    background: var(--bo-surface);
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius);
    box-shadow: var(--bo-shadow-sm);
    overflow: hidden;
    text-align: left;
    /* A card can be a <button>; strip the control look so both tags match. */
    font: inherit;
    color: inherit;
    margin: 0;
    -webkit-appearance: none;
    appearance: none;
}

/* The accent line. Painted on a pseudo-element so the tone can change
   without touching the card's own 1px border. */
.bo2 .bo-statcard::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--bo-sc-accent, var(--bo-line));
}

/* ---- head: icon, label, period badge ---- */
.bo2 .bo-sc-top {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

.bo2 .bo-sc-ic {
    display: inline-flex;
    color: var(--bo-sc-accent, var(--bo-ink-3));
    flex: none;
}

.bo2 .bo-sc-label {
    font-size: .68rem;
    font-weight: 640;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The period the figures cover. It is pushed right and kept quiet: it is
   never the thing being read, but it has to be there or the number above
   it means nothing. */
.bo2 .bo-sc-badge {
    margin-left: auto;
    flex: none;
    font-size: .645rem;
    font-weight: 620;
    letter-spacing: .01em;
    font-variant-numeric: tabular-nums;
    padding: 2px 7px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    color: var(--bo-ink-3);
    white-space: nowrap;
}

.bo2 .bo-sc-badge.bo-r-brand { background: var(--bo-brand-soft); color: var(--bo-brand-ink); }
.bo2 .bo-sc-badge.bo-r-good { background: var(--bo-green-soft); color: var(--bo-green-ink); }
.bo2 .bo-sc-badge.bo-r-warn { background: var(--bo-orange-soft); color: var(--bo-orange-ink); }
.bo2 .bo-sc-badge.bo-r-bad { background: var(--bo-red-soft); color: var(--bo-red-ink); }

/* ---- headline figure ---- */
.bo2 .bo-sc-value {
    font-family: var(--bo-font-display);
    font-size: 1.4rem;
    font-weight: 660;
    line-height: 1.12;
    letter-spacing: -.02em;
    color: var(--bo-sc-figure, var(--bo-ink));
    font-variant-numeric: tabular-nums;
    display: flex;
    align-items: baseline;
    gap: 5px;
    min-width: 0;
}

/* While the tab reloads the previous figures stay put and simply fade —
   blanking them would make the whole strip jump for a few hundred ms. */
.bo2 .bo-sc-value.bo-sc-stale { opacity: .45; transition: opacity .18s ease; }

.bo2 .bo-sc-unit {
    font-family: var(--bo-font-ui);
    font-size: .74rem;
    font-weight: 560;
    letter-spacing: 0;
    color: var(--bo-ink-3);
    white-space: nowrap;
}

/* ---- bars ---- */
.bo2 .bo-sc-bar {
    display: block;
    height: 4px;
    border-radius: 999px;
    background: var(--bo-surface-3);
    overflow: hidden;
}

.bo2 .bo-sc-bar > i {
    display: block;
    height: 100%;
    border-radius: inherit;
    background: var(--bo-sc-accent, var(--bo-ink-3));
    transition: width .35s cubic-bezier(.4, 0, .2, 1);
    /* A share that rounds to nothing still gets a visible sliver, so "1 of
       4000" does not read as an empty bar. */
    min-width: 2px;
}

.bo2 .bo-sc-bars {
    display: flex;
    flex-direction: column;
    gap: 7px;
    margin-top: 1px;
}

.bo2 .bo-sc-brow { display: flex; flex-direction: column; gap: 3px; min-width: 0; }

.bo2 .bo-sc-btop {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    min-width: 0;
}

.bo2 .bo-sc-bk {
    font-size: .72rem;
    color: var(--bo-ink-2);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.bo2 .bo-sc-bv {
    font-size: .72rem;
    font-weight: 620;
    font-variant-numeric: tabular-nums;
    color: var(--bo-sc-accent, var(--bo-ink));
    white-space: nowrap;
    flex: none;
}

/* ---- facts row ---- */
/* Pushed to the bottom so cards with different numbers of bars still line
   their facts up with each other across the strip. */
.bo2 .bo-sc-facts {
    display: flex;
    flex-wrap: wrap;
    gap: 3px 12px;
    margin-top: auto;
    padding-top: 7px;
    border-top: 1px solid var(--bo-line-soft);
}

.bo2 .bo-sc-fact {
    font-size: .69rem;
    color: var(--bo-ink-3);
    white-space: nowrap;
}

.bo2 .bo-sc-fact > b {
    font-weight: 660;
    font-variant-numeric: tabular-nums;
    color: var(--bo-sc-accent, var(--bo-ink-2));
    margin-right: 4px;
}

.bo2 .bo-sc-hint {
    font-size: .69rem;
    color: var(--bo-ink-3);
    line-height: 1.35;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* A card that has facts already ends on a bordered row, so the hint sits
   right under it rather than starting a third block. */
.bo2 .bo-sc-facts + .bo-sc-hint { margin-top: -3px; }

/* ---- card tones ---- */
.bo2 .bo-statcard.bo-t-neutral { --bo-sc-accent: var(--bo-ink-3); --bo-sc-figure: var(--bo-ink); }
.bo2 .bo-statcard.bo-t-brand { --bo-sc-accent: var(--bo-brand); --bo-sc-figure: var(--bo-brand-ink); }
.bo2 .bo-statcard.bo-t-good { --bo-sc-accent: var(--bo-green); --bo-sc-figure: var(--bo-green-ink); }
.bo2 .bo-statcard.bo-t-warn { --bo-sc-accent: var(--bo-orange); --bo-sc-figure: var(--bo-orange-ink); }

.bo2 .bo-statcard.bo-t-bad {
    --bo-sc-accent: var(--bo-red);
    --bo-sc-figure: var(--bo-red-ink);
    background: var(--bo-red-soft);
    border-color: #F3D2D2;
}

.bo2 .bo-statcard.bo-t-bad .bo-sc-label { color: var(--bo-red-ink); opacity: .78; }
.bo2 .bo-statcard.bo-t-bad .bo-sc-hint { color: var(--bo-red-ink); opacity: .72; }
.bo2 .bo-statcard.bo-t-bad .bo-sc-bk { color: var(--bo-red-ink); opacity: .82; }
.bo2 .bo-statcard.bo-t-bad .bo-sc-fact { color: var(--bo-red-ink); opacity: .78; }
.bo2 .bo-statcard.bo-t-bad .bo-sc-bar { background: rgba(142,32,32,.14); }
.bo2 .bo-statcard.bo-t-bad .bo-sc-facts { border-top-color: rgba(142,32,32,.16); }
.bo2 .bo-statcard.bo-t-bad .bo-sc-badge { background: rgba(142,32,32,.1); color: var(--bo-red-ink); }

/* ---- row tones: recolour one bar / badge / fact, never the card ---- */
.bo2 .bo-statcard .bo-r-neutral { --bo-sc-accent: var(--bo-ink-3); }
.bo2 .bo-statcard .bo-r-brand { --bo-sc-accent: var(--bo-brand); }
.bo2 .bo-statcard .bo-r-good { --bo-sc-accent: var(--bo-green); }
.bo2 .bo-statcard .bo-r-warn { --bo-sc-accent: var(--bo-orange); }
.bo2 .bo-statcard .bo-r-bad { --bo-sc-accent: var(--bo-red); }

/* ---- clickable card ---- */
.bo2 .bo-statcard.bo-sc-act { cursor: pointer; transition: box-shadow .16s ease, transform .16s ease, border-color .16s ease; }
.bo2 .bo-statcard.bo-sc-act:hover { box-shadow: var(--bo-shadow-md); transform: translateY(-1px); border-color: var(--bo-line); }
.bo2 .bo-statcard.bo-sc-act:active { transform: none; }

/* Under roughly two cards' worth of width the strip would give each card a
   column too narrow for "812 / 900" beside its label, so it drops to two up
   and then to one. */
@media (max-width: 1100px) {
    .bo2 .bo-statrow { grid-template-columns: repeat(auto-fit, minmax(218px, 1fr)); }
}

@media (max-width: 560px) {
    .bo2 .bo-statrow { grid-template-columns: 1fr; gap: 10px; }
    .bo2 .bo-sc-value { font-size: 1.26rem; }
}

@media (prefers-reduced-motion: reduce) {
    .bo2 .bo-sc-bar > i,
    .bo2 .bo-statcard.bo-sc-act { transition: none; }
    .bo2 .bo-statcard.bo-sc-act:hover { transform: none; }
}

/* ============================================================
   ITEM DETAIL DIALOG  (.bo-item-*)
   ============================================================
   Opened from a row of the items table. One item can carry a handful of
   product identifiers that have nowhere to live in an eight-column table,
   so they get a dialog of their own instead of more columns nobody can
   read. Identifiers the customer did not send are left out entirely
   rather than shown as a row of dashes. */

.bo2 .bo-item-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding-bottom: 12px;
    margin-bottom: 14px;
    border-bottom: 1px solid var(--bo-line-soft);
}

.bo2 .bo-item-desc {
    font-family: var(--bo-font-display);
    font-size: 1.02rem;
    font-weight: 620;
    letter-spacing: -.01em;
    color: var(--bo-ink);
    flex: 1 1 auto;
    min-width: 0;
}

.bo2 .bo-item-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(212px, 1fr));
    gap: 12px;
}

.bo2 .bo-item-card {
    border: 1px solid var(--bo-line-soft);
    border-radius: var(--bo-radius-sm);
    background: var(--bo-surface-2);
    padding: 11px 13px 12px;
}

.bo2 .bo-item-card.bo-wide { grid-column: 1 / -1; }

.bo2 .bo-item-card-title {
    font-size: .64rem;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--bo-ink-3);
    margin-bottom: 8px;
}

.bo2 .bo-item-kv {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 14px;
    padding: 3px 0;
    font-size: .78rem;
}

.bo2 .bo-item-kv .bo-k { color: var(--bo-ink-2); white-space: nowrap; }

.bo2 .bo-item-kv .bo-v {
    font-weight: 560;
    color: var(--bo-ink);
    text-align: right;
    overflow-wrap: anywhere;
}

.bo2 .bo-item-kv .bo-v.bo-mono { font-family: var(--bo-font-mono); font-weight: 500; }

/* A PID list is space separated and can be long — let it wrap onto its own
   lines instead of squeezing the label off the card. */
.bo2 .bo-item-kv.bo-stack { display: block; }
.bo2 .bo-item-kv.bo-stack .bo-k { display: block; margin-bottom: 2px; }
.bo2 .bo-item-kv.bo-stack .bo-v { display: block; text-align: left; }

.bo2 .bo-item-empty {
    font-size: .76rem;
    color: var(--bo-ink-3);
    font-style: italic;
}

/* The magnifier that opens this dialog from an items-table row. */
.bo2 .bo-items-tbl .bo-item-zoom {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    padding: 0;
    border: 1px solid var(--bo-line);
    border-radius: 6px;
    background: var(--bo-surface);
    color: var(--bo-ink-3);
    cursor: pointer;
    transition: color .14s ease, border-color .14s ease, background .14s ease;
}

.bo2 .bo-items-tbl .bo-item-zoom:hover {
    color: var(--bo-brand-ink);
    border-color: var(--bo-brand);
    background: var(--bo-brand-tint);
}
