/* ============================================
   TABLE STYLES
   ============================================ */

.table-container {
    padding: 0.25rem 1px;
    overflow: hidden;
}

.table-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 0.75rem;
    flex-wrap: wrap;
    gap: 0.75rem;
}

.table-title {
    font-family: 'Space Grotesk', sans-serif;
    font-size: 1rem;
    color: var(--text-secondary);
}

.table-title strong {
    color: var(--text-primary);
}

.table-controls {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.row-counter {
    font-size: 0.7rem;
    color: var(--text-muted);
    background: var(--bg-tertiary);
    padding: 0.4rem 0.75rem;
    border-radius: var(--radius-sm);
    border: 1px solid var(--border-color);
}

.row-counter span {
    color: var(--accent-orange);
    font-weight: 600;
}

/* Excel Wrapper */
.excel-wrapper {
    background: var(--bg-secondary);
    border-radius: 2px;
    border: 1px solid var(--border-color);
    overflow: hidden;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2);
}

.excel-scroll {
    overflow: overlay;
    max-height: calc(100vh - 340px);
}

/* Excel Table */
.excel-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 14px;
    min-width: 2400px;
}

.excel-table thead {
    position: sticky;
    top: 0;
    z-index: 10;
}

.excel-table th {
    background: linear-gradient(180deg, var(--bg-tertiary) 0%, var(--bg-secondary) 100%);
    border: 1px solid var(--border-color);
    padding: 0.7rem 0.6rem;
    font-weight: 600;
    text-transform: uppercase;
    font-size: 14px;
    letter-spacing: 0.5px;
    color: var(--text-secondary);
    white-space: nowrap;
    text-align: center;
    cursor: pointer;
    user-select: none;
    transition: all 0.15s;
}

.excel-table th:hover {
    background: var(--bg-hover);
    color: var(--text-primary);
}

.excel-table th.selected,
.excel-table th.col-selected {
    background: var(--accent-orange);
    color: white;
}

/* Column cell selection */
.excel-table td.col-selected {
    background: rgba(249, 115, 22, 0.1) !important;
    box-shadow: inset 0 2px 0 0 var(--accent-orange), inset 0 -2px 0 0 var(--accent-orange);
}

/* Row Number Column */
.excel-table th:first-child,
.excel-table td:first-child {
    background: var(--bg-tertiary);
    color: var(--text-muted);
    font-weight: 600;
    width: 36px;
    min-width: 36px;
    text-align: center;
    cursor: grab;
    user-select: none;
    position: sticky;
    left: 0;
    z-index: 5;
    font-size: 14px;
}

.excel-table td:first-child:hover {
    background: var(--accent-orange);
    color: white;
}

.excel-table td:first-child.dragging {
    cursor: grabbing;
    background: var(--accent-blue);
    color: white;
}

/* Table Cells */
.excel-table td {
    border: 1px solid #e2e8f0;
    padding: 0.3rem 0;
    background: var(--row-white);
    transition: background 0.15s;
}

.excel-table tbody tr:nth-child(even) td:not(:first-child) {
    background: var(--row-alt);
}

.excel-table tbody tr.selected td {
    background: var(--grid-sel-fill) !important;
}

/* Multi-row selection — outline around the WHOLE selection block, using the
   shared selection token so cell + row selection share one look in both themes.
   Borders (not 1px) win the border-collapse conflict against neighbour grey
   borders. Left/right edges go on every selected row's first/last cell; JS marks
   the block's top & bottom rows with sel-block-top / sel-block-bottom so
   non-contiguous selections each get their own rectangle. */
.excel-table tbody tr.selected td:first-child { border-left: 2px solid var(--grid-sel-border) !important; }
.excel-table tbody tr.selected td:last-child  { border-right: 2px solid var(--grid-sel-border) !important; }
.excel-table tbody tr.selected.sel-block-top td    { border-top: 2px solid var(--grid-sel-border) !important; }
.excel-table tbody tr.selected.sel-block-bottom td { border-bottom: 2px solid var(--grid-sel-border) !important; }

/* Warning highlight — yellow cell + red bold text. PHYTO (MISSING/COPY),
   Freight (ASKED), Release (MISSING). */
.excel-table td.cell-warn { background: #fbff00 !important; }
.excel-table td.cell-warn input {
    color: #f12121 !important;
    font-weight: 700 !important;
    background: transparent !important;
}

/* Quick-edit cell popover (PHYTO / QC / Freight / Release). Floats over the
   table on document.body; white in both themes (the table is always white). */
.cell-popover {
    position: fixed;
    z-index: 9999;
    background: #ffffff;
    border: 1px solid #b9cedb;
    border-radius: 8px;
    box-shadow: 0 10px 30px rgba(16, 49, 107, 0.22);
    padding: 8px;
    min-width: 180px;
    max-width: 380px;
    font-family: 'JetBrains Mono', monospace;
}
.cell-popover-title {
    font-size: 0.58rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.5px;
    color: #6c7b88;
    margin-bottom: 6px;
}
/* Options laid out horizontally; each button = icon on top, label centred under. */
.cell-popover-opts { display: flex; flex-flow: row wrap; gap: 6px; justify-content: center; }
/* An option flagged `full` (e.g. Not applicable / N/A) takes a whole row of
   its own BELOW the normal choices, instead of wrapping in beside them. */
.cell-popover-btn.cell-popover-btn-full {
    flex: 0 0 100%;
    flex-direction: row;
    min-width: 0;
    padding: 6px 10px;
    margin-top: 2px;
}
.cell-popover-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    text-align: center;
    padding: 8px 10px;
    min-width: 62px;
    border: 1px solid #e2e8f0;
    border-radius: 6px;
    background: #f8fafc;
    color: #102033;
    font-size: 0.72rem;
    line-height: 1.1;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
.cell-popover-btn:hover { background: #e8f0f7; border-color: #0f7ea2; }
/* "Applied value" choice — the popover is ALWAYS a white box (both themes), so a
   solid dark-navy fill read as a heavy dark-blue block on freight/release/qc/phyto.
   Soft light-blue fill + marine text/border keeps it clearly selected without the
   dark fill, in BOTH themes. */
.cell-popover-btn.active { background: #dbeafe !important; border-color: #0f7ea2 !important; color: #0a5989 !important; font-weight: 700; }
.cell-popover-btn i { font-size: 1.05rem; }
.cell-popover-type { margin-top: 6px; }
.cell-popover-input {
    width: 100%;
    box-sizing: border-box;
    padding: 6px 8px;
    border: 1px solid #b9cedb;
    border-radius: 6px;
    font-family: inherit;
    font-size: 0.78rem;
    color: #102033;
    outline: none;
}
.cell-popover-input:focus { border-color: #0f7ea2; box-shadow: 0 0 0 2px rgba(15, 126, 162, 0.16); }
.cell-popover-sug { margin-top: 4px; max-height: 144px; overflow: auto; }
.cell-popover-sug-item {
    padding: 5px 8px;
    border-radius: 5px;
    cursor: pointer;
    font-size: 0.76rem;
    color: #102033;
}
.cell-popover-sug-item:hover, .cell-popover-sug-item.first { background: #eef4f8; }
/* Arrow pointing at the cell (down when the popover is above; up when below). */
.cell-popover-arrow { position: absolute; width: 0; height: 0; transform: translateX(-50%); }
.cell-popover.arrow-bottom .cell-popover-arrow {
    bottom: -8px;
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    border-top: 8px solid #ffffff;
    filter: drop-shadow(0 2px 1px rgba(16, 49, 107, 0.18));
}
.cell-popover.arrow-top .cell-popover-arrow {
    top: -8px;
    border-left: 8px solid transparent;
    border-right: 8px solid transparent;
    border-bottom: 8px solid #ffffff;
    filter: drop-shadow(0 -2px 1px rgba(16, 49, 107, 0.18));
}

/* ── Edit-multiples bulk modal ── */
#editMultiplesModal .em-panel {
    background: #ffffff;
    color: #102033;
    width: min(560px, 94vw);
    max-height: 88vh;
    display: flex;
    flex-direction: column;
    border-radius: 12px;
    box-shadow: 0 24px 60px rgba(16, 49, 107, 0.35);
    overflow: hidden;
}
#editMultiplesModal .em-header {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1rem 1.25rem;
    border-bottom: 1px solid #e2e8f0;
}
#editMultiplesModal .em-header h2 { margin: 0; font-family: 'Space Grotesk', sans-serif; font-size: 1.05rem; color: #102033; }
#editMultiplesModal .em-headtext { min-width: 0; flex: 1; }
#editMultiplesModal .em-sub { font-size: 0.72rem; color: #6c7b88; margin-top: 0.2rem; }
#editMultiplesModal .em-chips {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    margin-top: 6px;
    max-height: 84px;
    overflow-y: auto;
}
#editMultiplesModal .em-chip {
    display: inline-block;
    padding: 2px 8px;
    border-radius: 999px;
    background: #eef4f8;
    border: 1px solid #cdd9e3;
    color: #0a5989;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.68rem;
    font-weight: 600;
    white-space: nowrap;
}
#editMultiplesModal .em-actions { display: flex; gap: 0.5rem; flex-shrink: 0; }
#editMultiplesModal .em-body { padding: 0.75rem 1.25rem 1.1rem; overflow-y: auto; }
#editMultiplesModal .em-field {
    display: grid;
    grid-template-columns: 110px 1fr;
    align-items: center;
    gap: 0.75rem;
    padding: 0.45rem 0;
    border-bottom: 1px solid #f1f5f9;
}
#editMultiplesModal .em-label { font-size: 0.74rem; font-weight: 600; color: #435468; }
#editMultiplesModal .em-control { display: flex; flex-wrap: wrap; gap: 0.4rem; align-items: center; }
#editMultiplesModal .em-control input[type="date"],
#editMultiplesModal .em-control input[type="text"] {
    padding: 0.4rem 0.55rem;
    border: 1px solid #b9cedb;
    border-radius: 6px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 0.78rem;
    color: #102033;
    min-width: 160px;
    outline: none;
}
#editMultiplesModal .em-control input:focus { border-color: #0f7ea2; box-shadow: 0 0 0 2px rgba(15, 126, 162, 0.16); }
#editMultiplesModal .em-inline-input { min-width: 120px; }
#editMultiplesModal .em-toggle-row { display: flex; flex-wrap: wrap; gap: 0.35rem; }
#editMultiplesModal .em-toggle {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 0.35rem 0.6rem;
    border: 1px solid #cdd9e3;
    border-radius: 6px;
    background: #f8fafc;
    color: #102033;
    font-size: 0.74rem;
    cursor: pointer;
    transition: background 0.12s, border-color 0.12s;
}
#editMultiplesModal .em-toggle:hover { background: #e8f0f7; border-color: #0f7ea2; }
#editMultiplesModal .em-toggle.active { background: #0a5989; border-color: #0a5989; color: #ffffff; }

/* Whole-row block — another user has these rows open in Edit-multiples. */
.excel-table tbody tr.row-blocked-by-other td {
    background: rgba(99, 102, 241, 0.08) !important;
    background: color-mix(in srgb, var(--lock-color, #6366f1) 12%, #ffffff) !important;
    cursor: not-allowed;
}
.excel-table tbody tr.row-blocked-by-other td:first-child {
    box-shadow: inset 3px 0 0 0 var(--lock-color, #6366f1);
}
.excel-table tbody tr.row-blocked-by-other input { pointer-events: none; }
.row-block-chip {
    display: inline-block;
    margin-left: 4px;
    min-width: 16px;
    height: 14px;
    line-height: 14px;
    padding: 0 3px;
    border-radius: 7px;
    font-size: 9px;
    font-weight: 700;
    color: #fff;
    vertical-align: middle;
    font-family: 'JetBrains Mono', monospace;
}

.excel-table tbody tr.drag-over {
    border-top: 3px solid var(--accent-orange);
}

.excel-table tbody tr.dragging {
    opacity: 0.5;
}

/* Table Inputs */
.excel-table input {
    width: 100%;
    padding: 0.45rem 0.5rem;
    border: none;
    background: transparent;
    color: var(--text-dark);
    font-family: 'JetBrains Mono', monospace;
    font-size: 16px;
    outline: none;
    text-align: center;
}

.excel-table input::placeholder {
    color: #94a3b8;
    opacity: 0.4;
}

.excel-table td.selected-cell {
    /* Local selection — SAME palette as the row selection block (Bug 3), driven
       by the theme token so light theme is Harbor teal, never the dark navy
       --accent-blue (Bug 1). Other users' selections use the separate
       *-by-other classes, so own-selection no longer needs --user-color.
       2026-08: the 2px border is GONE. This table is border-collapse:collapse,
       where each shared edge has one owning cell; promoting the td to a
       stacking context painted its opaque background over the top and left
       edges (owned by the neighbours above/left), so only bottom+right showed.
       The outline is now drawn by a ::after overlay in enhancements.css, which
       collapsing cannot touch. position/z-index stay — the lock chip and the
       comment badge are absolutely positioned inside the cell. */
    background: var(--grid-sel-fill) !important;
    position: relative;
    z-index: 2;
}

/* Light theme - sharper Harbor table treatment */
[data-theme="light"] .table-container {
    background: #f6f9fc;
}

[data-theme="light"] .table-title {
    color: #435468;
}

[data-theme="light"] .table-title strong {
    color: #102033;
}

[data-theme="light"] .row-counter {
    background: #eef4f8;
    border-color: #d6e2ea;
    color: #6c7b88;
}

[data-theme="light"] .row-counter span {
    color: #0f7ea2;
}

[data-theme="light"] .excel-wrapper {
    background: #ffffff;
    border-color: #b9cedb;
    box-shadow: 0 14px 38px rgba(23, 45, 64, 0.12);
}

[data-theme="light"] .excel-table th {
    background: #0a5989;
    border-color: #084a73;
    color: #ffffff;
}

[data-theme="light"] .excel-table th:hover {
    background: #084a73;
    color: #ffffff;
}

[data-theme="light"] .excel-table th.selected,
[data-theme="light"] .excel-table th.col-selected {
    background: #0f7ea2;
    color: #ffffff;
}

[data-theme="light"] .excel-table th:first-child,
[data-theme="light"] .excel-table td:first-child {
    background: #eef4f8;
    color: #6c7b88;
}

[data-theme="light"] .excel-table td {
    border-color: #d6e2ea;
    background: #ffffff;
}

[data-theme="light"] .excel-table tbody tr:nth-child(even) td:not(:first-child) {
    background: #f8fbfd;
}

[data-theme="light"] .excel-table tbody tr:hover td {
    background: #e7f6e7 !important;   /* light green hover — keeps black text readable */
}

[data-theme="light"] .excel-table input {
    color: #1d2c3b;
}

[data-theme="light"] .excel-table td.selected-cell {
    border-color: var(--grid-sel-border) !important;
    background: var(--grid-sel-fill) !important;
}

/* Light theme: the generic `[data-theme="light"] .excel-table td { background:#fff !important }`
   has EQUAL specificity to `.cell-warn` and wins by source order, hiding the warning
   yellow (freight ASKED / phyto + release MISSING). Re-assert with higher specificity. */
[data-theme="light"] .excel-table td.cell-warn { background: #fbff00 !important; }
[data-theme="light"] .excel-table td.cell-warn input { color: #f12121 !important; font-weight: 700 !important; background: transparent !important; }

/* (popover "applied value" button is now styled once, theme-agnostic, above —
   the white popover means the soft light-blue active state works in both themes.) */

[data-theme="light"] .excel-table td.col-selected {
    background: rgba(15, 126, 162, 0.08) !important;
    box-shadow: inset 0 2px 0 0 #0f7ea2, inset 0 -2px 0 0 #0f7ea2;
}

/* Status Cell */
.status-cell {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem;
}

.status-badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.55rem;
    border-radius: 4px;
    font-size: 0.72rem;
    font-weight: 700;
    text-transform: uppercase;
    white-space: nowrap;
}

.status-badge .status-icon {
    font-size: 0.8rem;
}

/* Status Colors — one unique color per status */
.status-new              { background: rgba(124, 58, 237, 0.15); color: #7c3aed; }  /* violet    */
.status-in-transit       { background: rgba(99, 102, 241, 0.15); color: #4f46e5; }  /* indigo    */
.status-unload-pending   { background: rgba(245, 158, 11, 0.15); color: #b45309; }  /* amber     */
.status-unload-approved  { background: rgba(16, 185, 129, 0.15); color: #059669; }  /* emerald   */
.status-unload-rejected  { background: rgba(239, 68, 68, 0.15);  color: #dc2626; }  /* red       */
.status-arrived          { background: rgba(59, 130, 246, 0.15); color: #2563eb; }  /* blue      */
.status-checked-in       { background: rgba(59, 130, 246, 0.15); color: #2563eb; }  /* blue      */
.status-in-stock         { background: rgba(34, 197, 94, 0.15);  color: #16a34a; }  /* green     */
.status-storage          { background: rgba(217, 119, 6, 0.15);  color: #b45309; }  /* amber — bonded storage (STG) */
.status-released         { background: rgba(14, 165, 233, 0.15); color: #0284c7; }  /* sky       */
.status-dispatched       { background: rgba(13, 148, 136, 0.15); color: #0d9488; }  /* teal      */
.status-archived         { background: rgba(107, 114, 128, 0.15); color: #6b7280; } /* gray      */
.status-compliance-blocked { background: rgba(239, 68, 68, 0.15); color: #dc2626; } /* red       */
/* Legacy aliases */
.status-on-hold          { background: rgba(245, 158, 11, 0.15); color: #b45309; }
.status-blocked          { background: rgba(239, 68, 68, 0.15);  color: #dc2626; }
.status-in-process       { background: rgba(59, 130, 246, 0.15); color: #2563eb; }
.status-needs-action     { background: rgba(245, 158, 11, 0.15); color: #b45309; }
/* Cleared but still in transit — green to differentiate */
.status-cleared-transit  { background: rgba(34, 197, 94, 0.15);  color: #16a34a; }  /* green     */
/* Stock-specific statuses */
.status-in-order         { background: rgba(14, 165, 233, 0.15); color: #0284c7; }  /* sky       */
.status-picked           { background: rgba(124, 58, 237, 0.15); color: #7c3aed; }  /* violet    */
.status-allocated        { background: rgba(14, 165, 233, 0.15); color: #0284c7; }  /* sky       */

/* Column Widths */
.col-status { width: 115px; min-width: 115px; }
.col-notes { width: 85px; min-width: 85px; }
.col-file { width: 90px; min-width: 90px; }
/* File column reads as a code (REF-MYN-001 etc.), not a free-form name —
   keep it 2px smaller than the rest so it doesn't dominate the row. */
.excel-table th.col-file { font-size: 12px; }
.excel-table input[data-col="file"] { font-size: 14px; }
.col-customer { width: 130px; min-width: 130px; }
.col-shipper { width: 200px; min-width: 200px; }
.col-container { width: 120px; min-width: 120px; }
.col-vessel { width: 130px; min-width: 130px; }
.col-cia { width: 75px; min-width: 75px; }
.col-terminal { width: 85px; min-width: 85px; }
.col-whs { width: 75px; min-width: 75px; }
.col-freight { width: 80px; min-width: 80px; }
.col-release { width: 80px; min-width: 80px; }
.col-qc { width: 60px; min-width: 60px; }
.col-phyto { width: 70px; min-width: 70px; }
.col-tdoc { width: 80px; min-width: 80px; }
.col-kcb { width: 80px; min-width: 80px; }
.col-customs { width: 75px; min-width: 75px; }
.col-planned { width: 68px; min-width: 68px; }
.col-arrived { width: 68px; min-width: 68px; }
.col-carrier { width: 90px; min-width: 90px; }

/* Dashboard panes */
.dashboard-pane {
    display: none;
}

.dashboard-pane.active {
    display: block;
}

/* Re-export board */
.table-container.reexport-pane {
    padding-left: 1px;
    padding-right: 1px;
}

.reexport-toolbar {
    display: flex;
    justify-content: flex-end;
    align-items: center;
    padding: 0.25rem 0;
    margin-bottom: 0.25rem;
}

.reexport-pane .excel-wrapper {
    background: #f7faf2;
    border-color: #cfd9bf;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
}

.reexport-help,
.reexport-empty,
.crossdock-placeholder {
    border-radius: 8px;
}

.reexport-help {
    margin-bottom: 0.9rem;
    padding: 0.85rem 1rem;
    border: 1px solid #cdddbb;
    background: #f4f6f8;
    color: #29403c;
    font-size: 0.78rem;
    line-height: 1.5;
}

.reexport-empty,
.crossdock-placeholder {
    padding: 1.4rem;
    border: 1px dashed var(--border-color);
    background: var(--bg-secondary);
    color: var(--text-secondary);
    text-align: center;
}

.crossdock-placeholder strong {
    display: inline-block;
    margin-bottom: 0.35rem;
    color: var(--text-primary);
}

.reexport-scroll {
    max-height: calc(100vh - 330px);
}

.reexport-table {
    /* NOT width:100%. Under CSS `zoom` a percentage resolves inside the zoomed
       coordinate space — `100%` becomes paneWidth/zoom, which renders back at
       exactly paneWidth. It is therefore zoom-INVARIANT: once the table has
       shrunk to fit the pane it snaps to the pane's full width and only the px
       font sizes keep shrinking. That is the reported "zoom out just makes the
       text smaller", and the grid stretching to the right edge.
       `max-content` makes the rendered width = sum(column widths) x zoom, so it
       genuinely shrinks. min-width:0 neutralises the 2400px floor inherited from
       .excel-table (:64-69) — do NOT touch that rule, the Register shares it.
       `table-layout: fixed` is load-bearing, not cosmetic: with `auto`, one long
       shipper/product string sets its column's preferred width from content and
       blows the grid past the column budget, making the zoom win depend on the
       data. Fixed takes the widths from the header row.
       Sticky <thead> is unaffected — we scale with `zoom`, never
       `transform: scale()`, which creates a containing block and breaks it. */
    width: max-content;
    min-width: 0;
    table-layout: fixed;
}

.reexport-table th {
    /* Light-grey header, flat — was a green gradient. */
    background: #d0d3d5;
    border-color: #cfd8dc;
    color: #37474f;
    font-weight: 700;
}
.reexport-table th .reexport-head-main { font-weight: 700; }
.reexport-table th .reexport-head-sub { font-weight: 600; }

.reexport-table td {
    border-color: #dfe4e8;
    background: #ffffff;
    vertical-align: middle;
}

.reexport-table tbody tr:nth-child(even) td:not(:first-child) {
    background: #fafbfc;
}

.reexport-table tbody tr:hover td {
    background: #f2f6f9;
}

/* Column 1 used to be Source Status, hence the 120px. It is now the row
   counter, so the width belongs to .reexport-col-num — this rule only cancels
   the Register's sticky row-number chrome, which is what it was really for. */
.reexport-table th:first-child,
.reexport-table td:first-child {
    position: static;
    left: auto;
    cursor: default;
    color: inherit;
    background: inherit;
}

.reexport-table td:first-child:hover,
.reexport-table td:first-child.dragging {
    background: inherit;
    color: inherit;
}

.reexport-table th:hover {
    background: #e0e5e8;
    color: #1d2b20;
}

.reexport-table .status-badge {
    font-size: 0.7rem;
}

.reexport-head-main {
    font-size: 12px;
    line-height: 1.3;
}

.reexport-head-sub {
    font-size: 10px;
    line-height: 1.3;
    text-transform: none;
    color: #5b6d5f;
    font-weight: 500;
}

.reexport-readonly {
    padding: 0.45rem 0.55rem;
    text-align: center;
    color: #1f2937;
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
}

.reexport-col-customer,
.reexport-col-shipper,
.reexport-col-vessel {
    font-family: 'Space Grotesk', sans-serif;
}

.reexport-table input,
.reexport-table select {
    width: 100%;
    padding: 0.42rem 0.45rem;
    border: none;
    background: transparent;
    color: #1f2937;
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    outline: none;
    text-align: center;
}

.reexport-table select {
    cursor: pointer;
}

.reexport-date-time {
    display: grid;
    grid-template-columns: minmax(55px, 1fr) 70px;
    align-items: center;
}

.reexport-date-time input + input {
    border-left: 1px solid #d4ddc8;
}

.reexport-action-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    width: 100%;
    padding: 0.4rem 0.45rem;
    color: #1f2937;
    font-size: 14px;
    font-family: 'JetBrains Mono', monospace;
}

.reexport-action-toggle input {
    width: auto;
    margin: 0;
}

.reexport-row-focus td {
    box-shadow: inset 0 0 0 2px #16a34a;
}

.reexport-row-archiving td {
    background: #86efac !important;
    transition: background 0.2s ease;
}

.reexport-source-missing td {
    opacity: 0.7;
}

.mono {
    font-family: 'JetBrains Mono', monospace;
}

/* Just wide enough for three digits. Stated on th AND td at first-child
   specificity so it beats .excel-table th:first-child { width: 36px }. */
.reexport-table th.reexport-col-num,
.reexport-table td.reexport-col-num,
.reexport-table th:first-child.reexport-col-num,
.reexport-table td:first-child.reexport-col-num {
    /* EXACTLY the Shipment Register's row-number column
       (.excel-table th/td:first-child, table.css): 36px declared, which with
       content-box padding renders the same as the register's. Do not "tidy"
       these numbers — they are matched to that rule on purpose. */
    width: 36px;
    min-width: 36px;
    max-width: 36px;
    padding-left: 0;
    padding-right: 0;
}
.reexport-col-status-source { width: 110px; }
.reexport-col-notes { width: 110px; }
.reexport-col-file { width: 85px; }
.reexport-col-customer { width: 130px; }
.reexport-col-shipper { width: 180px; }
.reexport-col-cargo { width: 135px; }
.reexport-col-vessel { width: 140px; }
.reexport-col-whs { width: 90px; }
.reexport-col-docs { width: 140px; }
.reexport-col-workflow { width: 100px; }
.reexport-col-label { width: 80px; }
.reexport-col-qc { width: 70px; }
.reexport-col-weight { width: 100px; }
.reexport-col-invoice { width: 110px; }
.reexport-col-phyto { width: 80px; }
.reexport-col-cvo { width: 85px; }
.reexport-col-transport { width: 110px; }
.reexport-col-fullset { width: 75px; }
.reexport-col-seal { width: 100px; }
.reexport-col-loading { width: 125px; }
.reexport-col-takeout { width: 110px; }
.reexport-col-deadline { width: 140px; }
.reexport-col-slot { width: 140px; }
.reexport-col-action { width: 95px; }

/* ── Re-export picker cells + their one-row popover ──────────────────────
   The board's pickers replaced native <select>s. The visible value is a span;
   the real value rides in a hidden input[data-col] that CellPopover writes to. */
.reexport-table td.rx-pop-cell { cursor: pointer; }
.reexport-table .rx-val {
    display: block;
    min-height: 1.1em;
    padding: 0.2rem 0.1rem;
    font-size: 14px;
    line-height: 1.25;
}
.reexport-table .rx-val:focus-visible { outline: 2px solid #0f7ea2; outline-offset: -2px; }
/* Status is derived-with-override: italic means "automatic, not pinned". */
.reexport-table .rx-val.rx-derived { font-style: italic; opacity: 0.85; }

/* One row of options, SCOPED to this board's popovers only.
   Doing it globally would change the Register's phyto/release popovers and the
   planner's release-note popover, whose `full: true` option deliberately takes
   its own row so the destructive choice is NOT under the pointer when the
   popover opens centred above the cell. It would also break mechanically:
   .cell-popover-btn-full is `flex: 0 0 100%`, which cannot shrink under nowrap,
   so siblings overflow a max-width:380px box that has no `overflow` — spilling
   outside the card and corrupting the arrow position. These lists carry no
   `full` option, so nothing here can regress the others. */
.cell-popover.rx-pop { max-width: min(92vw, 640px); }
.cell-popover.rx-pop .cell-popover-opts { flex-wrap: nowrap; }
.cell-popover.rx-pop .cell-popover-btn {
    min-width: 52px;
    padding: 7px 9px;
    white-space: nowrap;
}
.cell-popover.rx-pop .cell-popover-btn-full { flex: 0 1 auto; }

/* Picker polish — dark theme is the base, light is overridden below. */
.cell-popover.rx-pop {
    padding: 10px;
    border-radius: 10px;
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.28);
}
.cell-popover.rx-pop .cell-popover-title {
    font-size: 0.62rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    opacity: 0.7;
    margin-bottom: 7px;
}
.cell-popover.rx-pop .cell-popover-opts { gap: 5px; }
.cell-popover.rx-pop .cell-popover-btn {
    border-radius: 7px;
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.02em;
    border: 1px solid #3b4a57;
    background: #263340;
    color: #dbe6f0;
    transition: background 0.12s ease, border-color 0.12s ease, transform 0.08s ease;
}
.cell-popover.rx-pop .cell-popover-btn:hover {
    background: #33475a;
    border-color: #5b7f96;
    transform: translateY(-1px);
}
.cell-popover.rx-pop .cell-popover-btn.active {
    background: #0f7ea2;
    border-color: #0f7ea2;
    color: #ffffff;
}
/* The Clear / Auto entry is a reset, not a value — keep it visually quieter. */
.cell-popover.rx-pop .cell-popover-btn[data-val=""] {
    background: transparent;
    border-style: dashed;
    opacity: 0.8;
}

[data-theme="light"] .cell-popover.rx-pop {
    background: #ffffff !important;
    border-color: #cfd8dc !important;
    box-shadow: 0 10px 28px rgba(15, 42, 63, 0.16);
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-title { color: #546e7a !important; }
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn {
    background: #f4f7f9 !important;
    border-color: #cfd8dc !important;
    color: #263238 !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn:hover {
    background: #e6f3f8 !important;
    border-color: #0f7ea2 !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn.active {
    background: #0f7ea2 !important;
    border-color: #0f7ea2 !important;
    color: #ffffff !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val=""] {
    background: transparent !important;
    border-style: dashed !important;
}

/* ── Semantic colours on the picker options ─────────────────────────────
   A status list reads far faster when DONE is green and MISSING is red than
   when every button is the same grey. Keyed off the stored value so it works
   for whichever picker shows it. */
.cell-popover.rx-pop .cell-popover-btn[data-val="DONE"],
.cell-popover.rx-pop .cell-popover-btn[data-val="READY"],
.cell-popover.rx-pop .cell-popover-btn[data-val="SENT"],
.cell-popover.rx-pop .cell-popover-btn[data-val="YES"],
.cell-popover.rx-pop .cell-popover-btn[data-val="OK"] {
    border-color: #2e7d32; color: #7ee2a8;
}
.cell-popover.rx-pop .cell-popover-btn[data-val="WAITING"],
.cell-popover.rx-pop .cell-popover-btn[data-val="CHECK"],
.cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT"],
.cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT EXA"],
.cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT T1"] {
    border-color: #b8860b; color: #f0c674;
}
.cell-popover.rx-pop .cell-popover-btn[data-val="NO"],
.cell-popover.rx-pop .cell-popover-btn[data-val="--"] {
    border-color: #a13c3c; color: #f2a7a7;
}
.cell-popover.rx-pop .cell-popover-btn[data-val^="STEP"] { border-color: #2f6f9f; color: #9fd0f0; }
/* active always wins — the choice must be unmistakable */
.cell-popover.rx-pop .cell-popover-btn.active { background: #0f7ea2 !important; border-color: #0f7ea2 !important; color: #fff !important; }

[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="DONE"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="READY"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="SENT"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="YES"] {
    background: #e8f6ec !important; border-color: #2e7d32 !important; color: #1b5e20 !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="WAITING"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="CHECK"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT EXA"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="DRAFT T1"] {
    background: #fdf4e3 !important; border-color: #b8860b !important; color: #8a6209 !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="NO"],
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val="--"] {
    background: #fdecec !important; border-color: #c0392b !important; color: #9b2c20 !important;
}
[data-theme="light"] .cell-popover.rx-pop .cell-popover-btn[data-val^="STEP"] {
    background: #eaf3fa !important; border-color: #2f6f9f !important; color: #1d4e73 !important;
}

/* ── Re-export right-click menu ──────────────────────────────────────── */
.rx-menu {
    position: fixed;
    z-index: 10000;
    min-width: 210px;
    padding: 6px;
    border-radius: 10px;
    background: #1f2b36;
    border: 1px solid #38495a;
    box-shadow: 0 14px 34px rgba(0, 0, 0, 0.36);
    font-family: 'Space Grotesk', sans-serif;
    font-size: 0.78rem;
    color: #dbe6f0;
}
.rx-menu-item {
    display: flex; align-items: center; gap: 8px;
    padding: 7px 9px; border-radius: 6px; cursor: pointer;
}
.rx-menu-item:hover { background: #2c3d4d; }
.rx-menu-item.rx-menu-danger:hover { background: #5a2b2b; color: #ffd7d7; }
.rx-menu-icon { width: 15px; text-align: center; opacity: 0.85; }
.rx-menu-sep { height: 1px; margin: 5px 4px; background: #38495a; }
.rx-menu-label {
    padding: 6px 9px 3px; font-size: 0.6rem; letter-spacing: 0.08em;
    text-transform: uppercase; opacity: 0.62;
}
.rx-menu-swatches { display: flex; flex-wrap: wrap; gap: 5px; padding: 2px 9px 7px; }

/* ── Re-export: "Remove from board" confirmation ─────────────────────────
   The MARKUP is the app's generic modal (.modal-overlay > .modal-panel with
   header / body / footer, css/components.css) — the same idiom as the Cargo
   Planner modals — so almost nothing is needed here: a narrower panel and the
   two paragraphs. A native confirm() was here first; it cannot show the scope,
   cannot say "archived, not deleted", and looks nothing like the rest of this
   UI.

   Specificity note: components.css defines .modal-panel and loads AFTER
   table.css, so every rule below is doubled with .modal-panel or scoped under
   the overlay to out-specify it rather than relying on order. */
.modal-panel.rx-confirm {
    width: 460px;
    /* A confirm is read, not scrolled. */
    overflow: visible;
}
.rx-confirm .modal-header h3 { font-size: 0.95rem; }
.rx-confirm-lead {
    margin: 0 0 0.8rem;
    font-size: 0.86rem;
    line-height: 1.5;
    color: var(--text-primary);
}
.rx-confirm-note {
    margin: 0;
    padding: 0.1rem 0 0.1rem 0.7rem;
    border-left: 3px solid var(--border-color);
    font-size: 0.78rem;
    line-height: 1.55;
    color: var(--text-muted);
}
.rx-confirm-note strong { color: var(--text-primary); }
.rx-confirm .modal-footer .btn:focus-visible {
    outline: 2px solid #0f7ea2;
    outline-offset: 2px;
}

/* THEMING — this, not the layout, is where this component can go wrong.
   css/themes.css carries a broad `[data-theme="light"] div { background-color:
   inherit }`. Every nested container div inside a panel therefore RE-INHERITS
   the panel's fill and stacks layer on layer — the "solid white picker" bug
   that took three passes to kill on the colour picker. What finally killed it
   there was a BLANKET :not() over every descendant div instead of a list of
   container class names, because a named list only ever covers the wrappers
   that existed when it was written and silently misses the next one added.
   Same shape here on purpose: clear EVERY descendant div, exempt only the one
   element that legitimately paints — the panel. Do not convert this back into
   a list of .modal-header / .modal-body / .modal-footer. */
[data-theme="light"] .rx-confirm-overlay {
    /* Re-assert the dim: the broad rule above would otherwise make the overlay
       inherit its parent's fill and the backdrop would vanish. */
    background: rgba(15, 42, 63, 0.45) !important;
}
[data-theme="light"] .rx-confirm-overlay div:not(.rx-confirm) {
    background-color: transparent !important;
}
[data-theme="light"] .modal-panel.rx-confirm {
    /* The single painted layer. Near-opaque on purpose — a confirmation has to
       be readable over whatever it covers, unlike the frosted colour picker. */
    background: rgba(246, 249, 252, 0.97) !important;
    border-color: rgba(15, 126, 162, 0.28) !important;
    box-shadow: 0 20px 60px rgba(15, 42, 63, 0.28);
}
[data-theme="light"] .rx-confirm-note { border-left-color: #cfd8dc; }

/* The danger button needs re-asserting in light theme for the same class of
   reason as the backgrounds above: themes.css carries
   `[data-theme="light"] button { background: #ffffff !important }`, which
   flattens .btn-danger into a plain button — the confirm and the cancel would
   look identical on the one dialog where telling them apart matters most.
   Higher specificity beats it (both are !important, so specificity decides). */
[data-theme="light"] .rx-confirm .modal-footer .btn-danger {
    background: #fdecec !important;
    border: 1px solid #d64545 !important;
    color: #9b2c20 !important;
}
[data-theme="light"] .rx-confirm .modal-footer .btn-danger:hover {
    background: #d64545 !important;
    color: #ffffff !important;
}

/* ── Re-export toolbar ───────────────────────────────────────────────────
   The MARKUP is the Register's ribbon — .ribbon-group / .ribbon-group-label /
   .ribbon-btn / .color-picker-wrapper / .ribbon-favorites / .ribbon-toggle /
   .zoom-controls, all of it. Everything below re-tunes those same classes for
   THIS bar only, always through the `.reexport-toolbar` ancestor, and adds no
   parallel class of its own. Two reasons it lives here and not in ribbon.css:
   the Register's ribbon is a dark chrome strip above a page header while this
   one is a thin rule between the sub-tabs and a white grid, so they want
   different weights; and ribbon.css is shared with every other table in the
   app, where an unrequested restyle is a regression. Nothing here changes the
   Register.

   The layout is three bands, in the order the work happens:
     [ creation | selection ]   [ formatting ]   → [ view ]
   Creation is left for the row-adding control; selection is the live count;
   formatting is the paint/format tools; view (focus + zoom) is pushed right by
   `.rx-bar-right { margin-left: auto }` and everything after it follows along.

   Grouping is by RULE, not by chip. ribbon.css fills each .ribbon-group with a
   dark translucent block, which reads as five floating tiles on a bar this
   thin; a 1px vertical rule between adjacent children is the ribbon idiom and
   it makes the bands legible without adding five more boxes. It is drawn with
   `> * + *` rather than a .ribbon-divider element on purpose: a group inserted
   later — the "+ Add row" control now being built — gets its separator with no
   markup and no coordination. Wrapping is the one cost (the first group on a
   wrapped line keeps its rule); at those widths the labels are gone anyway and
   it reads as a continuation, which is the better trade.

   One height for every control. --rx-tool-h is the single knob: the pickers,
   the buttons, the toggle, the count pill and the zoom chip are all pinned to
   it, so they share a baseline instead of the 17-to-30px spread the shared
   classes give when they are simply dropped next to each other. */
.reexport-toolbar {
    --rx-tool-h: 26px;
    /* The separator is the whole grouping mechanism, so it has to be readable
       at 1px on both surfaces — the first pass was invisible in the screenshot
       in both themes. */
    --rx-bar-sep: rgba(255, 255, 255, 0.22);
    --rx-bar-ctl: rgba(255, 255, 255, 0.06);
    --rx-bar-ctl-line: rgba(255, 255, 255, 0.16);
    --rx-bar-ctl-hover: rgba(255, 255, 255, 0.14);
    --rx-bar-ink: #dbe4ea;
    --rx-bar-label: #94a8b5;
    --rx-bar-accent: #0f7ea2;          /* the grid's own selection teal */
    display: flex;
    align-items: center;
    gap: 0;                            /* spacing belongs to the groups */
    row-gap: 0.35rem;
    padding: 0.45rem 0.55rem;
    background: var(--bg-secondary);
    border-bottom: 1px solid var(--border-color);
    flex-wrap: wrap;
}
[data-theme="light"] .reexport-toolbar {
    --rx-bar-sep: #bcc7ce;
    --rx-bar-ctl: #ffffff;
    --rx-bar-ctl-line: #c3ced5;
    --rx-bar-ctl-hover: #e6f3f8;
    --rx-bar-ink: #37474f;
    --rx-bar-label: #5b6b76;
    background: #f4f7f9;
    border-bottom-color: #cfd8dc;
}

.reexport-toolbar .ribbon-group {
    margin: 0;
    padding: 0 0.6rem;
    gap: 0.3rem;
    min-height: var(--rx-tool-h);
    border-radius: 0;
    /* !important: ribbon.css's own [data-theme="light"] .ribbon-group [0,2,1]
       is !important, and importance outranks specificity. */
    background: transparent !important;
}
.reexport-toolbar .ribbon-group-label {
    margin-right: 0.1rem;
    font-size: 0.55rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    /* !important twice over: ribbon.css pins the label white for the dark
       ribbon, and themes.css carries `[data-theme="light"] span { color:
       inherit !important }`. */
    color: var(--rx-bar-label) !important;
}

/* Buttons. themes.css gives EVERY light-theme button a white fill, a #b9cedb
   border and a hover of its own, all !important — so the ribbon buttons on
   this bar have to answer in kind or they arrive as form buttons. */
.reexport-toolbar .ribbon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.25rem;
    height: var(--rx-tool-h);
    min-width: var(--rx-tool-h);
    padding: 0 0.55rem;
    border-radius: 5px;
    font-size: 0.68rem;
    font-weight: 600;
    line-height: 1;
    background: var(--rx-bar-ctl) !important;
    border: 1px solid var(--rx-bar-ctl-line) !important;
    color: var(--rx-bar-ink) !important;
    transition: background 0.12s ease, border-color 0.12s ease;
}
.reexport-toolbar .ribbon-btn:hover {
    background: var(--rx-bar-ctl-hover) !important;
    border-color: var(--rx-bar-accent) !important;
    color: var(--rx-bar-ink) !important;
}
.reexport-toolbar .ribbon-btn:active {
    transform: none;                   /* ribbon.css scales; too jumpy this small */
    background: var(--rx-bar-accent) !important;
    border-color: var(--rx-bar-accent) !important;
    color: #ffffff !important;
}
.reexport-toolbar .ribbon-btn:focus-visible,
.reexport-toolbar .zoom-btn:focus-visible,
.reexport-toolbar .rx-selection-indicator:focus-visible {
    outline: 2px solid var(--rx-bar-accent);
    outline-offset: 1px;
}

/* Colour pickers + their favourite strips. The strip's own dark chip and its
   24px swatches are what make this bar look ragged: two nested fills and a
   control 4px taller than its neighbours. Flatten it and pin the height. */
.reexport-toolbar .color-picker-wrapper { display: inline-flex; align-items: center; }
.reexport-toolbar .color-picker-btn {
    width: var(--rx-tool-h);
    height: var(--rx-tool-h);
    border: 1px solid var(--rx-bar-ctl-line);
    border-radius: 5px;
}
.reexport-toolbar .color-picker-btn:hover {
    border-color: var(--rx-bar-accent);
    transform: none;                   /* scaling one control mid-row breaks the line */
}
.reexport-toolbar .ribbon-favorites {
    margin-left: 0.15rem;
    padding: 0;
    gap: 3px;
    background: transparent !important;
    border-radius: 0;
}
.reexport-toolbar .ribbon-favorite-color {
    width: 22px;
    height: 22px;
    border-radius: 4px;
    border: 1px solid var(--rx-bar-ctl-line);
}
.reexport-toolbar .ribbon-favorite-color:hover {
    transform: none;
    border-color: var(--rx-bar-accent);
}

/* Focus toggle. `[data-theme="light"] label { color: #475569 !important }`. */
.reexport-toolbar .ribbon-toggle {
    height: var(--rx-tool-h);
    gap: 5px;
    font-size: 0.68rem;
    font-weight: 600;
    color: var(--rx-bar-ink) !important;
}
.reexport-toolbar .ribbon-toggle input { accent-color: var(--rx-bar-accent); }

/* Zoom chip. Same height and the same border language as everything else. */
.reexport-toolbar .zoom-controls {
    height: var(--rx-tool-h);
    margin-left: 0;                    /* the right band starts at .rx-bar-right */
    padding: 0 0.2rem;
    gap: 0.1rem;
    background: transparent;
    /* NOT `border: none`. enhancements.css boxes this chip; the box has to go,
       but the shorthand would also wipe the border-LEFT that the band
       separator below draws on it, and at equal specificity the shorthand
       would win by source order. Clearing only the colour leaves the widths
       in place for the separator to re-colour. */
    border-color: transparent;
}
.reexport-toolbar .zoom-btn {
    width: 22px;
    height: 22px;
    border-radius: 4px;
    background: var(--rx-bar-ctl) !important;
    border: 1px solid var(--rx-bar-ctl-line) !important;
    color: var(--rx-bar-ink) !important;
}
.reexport-toolbar .zoom-btn:hover {
    background: var(--rx-bar-ctl-hover) !important;
    border-color: var(--rx-bar-accent) !important;
}
.reexport-toolbar .zoom-input {
    height: 22px;
    width: 46px;
    border-radius: 4px;
    background: var(--rx-bar-ctl) !important;
    border: 1px solid var(--rx-bar-ctl-line) !important;
    color: var(--rx-bar-ink) !important;
    font-size: 0.68rem;
}
.reexport-toolbar .zoom-pct {
    margin: 0 0.1rem 0 0;
    font-size: 0.6rem;
    color: var(--rx-bar-label) !important;
}

/* Row-text-size chip. It reuses .zoom-controls/.zoom-btn wholesale so it is
   the zoom chip's twin rather than merely similar — same height, same borders,
   same hover, and the toolbar's `> * + *` rule separates the two for free.
   Only three things differ:
     - the labels are "A−"/"A+"/"A", not single glyphs, so the 22px square the
       zoom buttons use has to relax into a min-width;
     - the reset "A" is quieter than the two it sits beside: it is the least
       used of the three and should not read as a third step;
     - a disabled button (at 10px or 18px) has to LOOK disabled, or the chip
       reads as broken at the ends of the range. */
.reexport-toolbar .rx-font-controls .zoom-btn {
    width: auto;
    min-width: 22px;
    padding: 0 4px;
    font-size: 0.66rem;
    font-weight: 700;
    line-height: 1;
}
.reexport-toolbar .rx-font-controls .rx-font-value {
    min-width: 14px;
    margin: 0 0.1rem 0 0.1rem;
    text-align: center;
    font-variant-numeric: tabular-nums;   /* 9 -> 10 must not shuffle the buttons */
    font-size: 0.66rem;
    color: var(--rx-bar-ink);
}

/* ── Telling the two chips apart ─────────────────────────────────────────
   This one and the zoom sit side by side in the same shell, and until now the
   only difference was the glyphs on the buttons: `− 80 % +` against
   `A− 14 A+`, with the 14 wearing the very class that draws the per-cent sign.
   The owner read it as a second zoom, which is a fair reading of what it
   looked like.
   "Aa" in front of the number is the mark every text-size control uses, and it
   is the one thing a magnification chip never carries; `px` behind it says the
   number is a type size rather than a ratio. Both are quieter than the
   buttons — they label the chip, they are not part of it. */
.reexport-toolbar .rx-font-controls .rx-font-tag {
    margin-right: 0.2rem;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
    letter-spacing: -0.02em;
    color: var(--rx-bar-label);
}
.reexport-toolbar .rx-font-controls .rx-font-unit {
    margin: 0 0.15rem 0 0;
    font-size: 0.55rem;
    line-height: 1;
    opacity: 0.75;
    color: var(--rx-bar-label);
}
.reexport-toolbar .rx-font-controls #rxFontReset {
    font-weight: 600;
    opacity: 0.85;
}
.reexport-toolbar .rx-font-controls .zoom-btn:disabled {
    opacity: 0.4;
    cursor: default;
}
.reexport-toolbar .rx-font-controls .zoom-btn:disabled:hover {
    background: var(--rx-bar-ctl) !important;
    border-color: var(--rx-bar-ctl-line) !important;
}

/* ── Layout, written last and deliberately ───────────────────────────────
   Both rules here lost to rules ABOVE them until they were scoped through
   .reexport-pane, and the reason is worth writing down: `*` and `>` add
   nothing to specificity, so `.reexport-toolbar > * + *` is [0,1,0] — LESS
   than `.reexport-toolbar .zoom-controls` [0,2,0] — and `margin-left:auto`
   on `.rx-bar-right` [0,2,0] tied with `.ribbon-group { margin: 0 }` and lost
   on source order. Three classes and two classes respectively settle it
   without !important. The harness caught both; reading did not.

   The separator is `> * + *` rather than a .ribbon-divider element so a group
   added later is ruled off with no markup and no coordination — which is how
   the "+ Add row" group arrived already separated. */
.reexport-pane .reexport-toolbar > * + * {
    border-left: 1px solid var(--rx-bar-sep);
}
.reexport-pane .reexport-toolbar .rx-bar-right {
    margin-left: auto;
}
/* The filter cluster now STARTS the right-hand band, so the auto margin is
   its. Only ONE element in a flex row may carry `margin-left:auto`: two of
   them SPLIT the free space between them and the band tears in half, which is
   exactly what happens if Focus keeps its own. The general sibling selector
   ([0,4,0], beating the [0,3,0] rule above) hands it over without the JS
   having to rewrite anyone's classes — and it simply does not match when the
   cluster is absent, so an index.html with no filter markup lays out as
   before. */
.reexport-pane .reexport-toolbar .rx-filters {
    margin-left: auto;
}
.reexport-pane .reexport-toolbar .rx-filters ~ .rx-bar-right {
    margin-left: 0;
}

/* Narrow widths: drop the uppercase labels before anything wraps. Every
   control that loses one keeps its title tooltip, and the count pill says
   what it is in words, so nothing becomes unidentifiable. */
/* The filter cluster is the widest group on this bar (a customer name and two
   date fields), so it is the one that gives ground first — and only it, so
   nobody else's controls change size because of a group that arrived later.
   Its own label goes before anyone else's: "Filter" over a customer dropdown
   and a date range is the most guessable label on the row. Below 1180px the
   general rule takes every label anyway.

   The bar still WRAPS on a 1366 laptop, and that is the documented trade at the
   top of this block rather than a regression: the toolbar is flex-wrap, the
   text-size and zoom chips fall to a second line together, and both keep their
   title tooltips. A date range cannot be made much narrower than two date
   fields. */
@media (max-width: 1600px) {
    .reexport-toolbar .rx-filters .ribbon-group-label { display: none; }
    .reexport-toolbar .rx-filter-dash { display: none; }
    .reexport-toolbar .rx-filter-select { max-width: 150px; }
    .reexport-toolbar .rx-filter-date { width: 100px; }
}

@media (max-width: 1180px) {
    .reexport-toolbar .ribbon-group-label { display: none; }
    .reexport-toolbar .ribbon-group { padding: 0 0.45rem; }
    .reexport-toolbar .rx-filter-select { max-width: 128px; }
}

/* ── Selection count ─────────────────────────────────────────────────────
   Reads "3 cells" / "2 rows", written only by ReExportGrid.repaint().
   Its own class, not ribbon.css's .selection-indicator: that one is themed
   off --accent-blue/--bg-tertiary for the dark ribbon and then overridden
   again for light, and this bar is the board's grey-and-white palette in
   BOTH themes. One opaque pill therefore serves both, which is the same
   reason the grid itself is white in both — a translucent fill would
   composite over the dark page behind the toolbar and go unreadable.
   Sized to the widest real string ("No selection") so the ribbon does not
   jog sideways every time the count appears or clears.

   Scoped through .reexport-toolbar, and that is not decoration: themes.css
   carries a blanket `[data-theme="light"] div { background-color: inherit }`
   at [0,1,1] which beats a lone `.rx-selection-indicator` [0,1,0] and makes
   the pill take the ribbon group's fill in light theme only. Two classes
   ([0,2,0]) out-rank it honestly, so no !important and no duplicated
   `[data-theme="light"]` block is needed for the box. The count colour is the
   one exception — `[data-theme="light"] span { color: inherit !important }`
   is IMPORTANT, and importance beats specificity, so that one declaration has
   to answer in kind. */
.reexport-toolbar .rx-selection-indicator {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.28rem;
    height: var(--rx-tool-h);           /* the bar's one control height */
    min-width: 82px;
    padding: 0 0.55rem;
    border: 1px solid #9aa3a9;          /* the grid's own row rule */
    border-radius: 5px;
    background: #ffffff;
    color: #55606a;
    font-size: 0.68rem;
    font-weight: 600;
    letter-spacing: 0.01em;
    text-align: center;
    white-space: nowrap;
    user-select: none;
}
.reexport-toolbar .rx-selection-indicator.active {
    border-color: #0f7ea2;              /* the grid's selection teal */
    background: #eaf4f8;
    color: #0b5c76;
}
.reexport-toolbar .rx-selection-indicator .rx-sel-count {
    font-family: 'JetBrains Mono', monospace;
    font-weight: 700;
    color: #0f7ea2 !important;          /* vs [data-theme="light"] span, above */
}

.rx-swatch {
    width: 21px; height: 21px; border-radius: 5px; cursor: pointer;
    border: 1px solid rgba(255, 255, 255, 0.28); padding: 0;
    transition: transform 0.1s ease, box-shadow 0.1s ease;
}
.rx-swatch:hover { transform: scale(1.14); box-shadow: 0 0 0 2px rgba(15, 126, 162, 0.6); }
.rx-swatch-none {
    background: transparent; color: #9fb0c0; font-size: 0.7rem; line-height: 1;
    border-style: dashed;
}

[data-theme="light"] .rx-menu {
    background: #ffffff; border-color: #cfd8dc; color: #263238;
    box-shadow: 0 14px 34px rgba(15, 42, 63, 0.18);
}
[data-theme="light"] .rx-menu-item:hover { background: #e6f3f8; }
[data-theme="light"] .rx-menu-item.rx-menu-danger:hover { background: #fdecec; color: #9b2c20; }
[data-theme="light"] .rx-menu-sep { background: #e0e6ea; }
[data-theme="light"] .rx-swatch { border-color: rgba(0, 0, 0, 0.2); }
[data-theme="light"] .rx-swatch-none { color: #78909c; }

/* ── Selection + first column ────────────────────────────────────────────
   The authoritative selection block in css/enhancements.css targets
   `.excel-table.excel-table` generally and #reexportTable carries `excel-table`,
   so the whole Excel selection look arrives for free. Its blue palette is
   correct now that this board is white — the only rule that does not fit is
   the hover on td:first-child, which exists for the Register's row-number
   chrome. Here column 1 is Source Status: real data. */
.reexport-table.reexport-table tbody tr:hover td:first-child:not(.cell-warn) {
    background: inherit !important;
    color: inherit !important;
}

/* ── Row text size, operator-adjustable ──────────────────────────────────
   ONE number, set as `--rx-font-size` on .table-container.reexport-pane by
   ReExportBoard (js/reexport-board.js, the "Row text size" section) and stored
   per user. The fallback in every var() below is the 14px this board has
   always used, so the board renders identically for anybody who never touches
   the control and on any surface where the JS has not run.

   The declaration lives on the PANE and is read under #reexportTable, which is
   what keeps the preference off the Shipments Register: the Register is a
   different pane with a different table id, so no combination of open panes
   lets this reach it.

   Specificity is not accidental. The sizes these override are
   `.reexport-readonly` [0,1,0], `.reexport-table input` [0,2,0],
   `.reexport-table .rx-val` [0,2,0] and `.reexport-table td.rx-num` [0,2,1];
   every selector here leads with the #reexportTable id, so each wins outright
   and none of them needs !important — which matters because paintCell() sets
   inline `color`/`background-color` with !important on these same cells and an
   importance war would take the painted colours with it.

   THEAD is deliberately excluded. The column widths are fixed px
   (.reexport-col-*) and `table-layout: fixed` takes them from the header row,
   so growing the header type would wrap or clip the labels while changing
   nothing about the data the operator is trying to read. */
.table-container.reexport-pane {
    --rx-font-size: 14px;
}

#reexportTable tbody td.reexport-readonly,
#reexportTable tbody td.rx-num,
#reexportTable tbody td input,
#reexportTable tbody td select,
#reexportTable tbody td .rx-val {
    font-size: var(--rx-font-size, 14px);
    /* THE LINE THAT MAKES THIS A TEXT SIZE AND NOT A SECOND ZOOM.
       A px line-height, and it has to be px: `normal` (and any ratio) is a
       multiple of the font size, so every step also grew the line box, and the
       line box is what sets the row height on this grid — .excel-table sizes
       its rows from padding plus content alone. The board therefore got TALLER
       at 16 and 18px, which is exactly what the zoom beside it does, and the
       owner read the two controls as the same tool. Measured before the fix:
       44.7px per row at 14, 48.9px at 18.
       19px is `normal` for JetBrains Mono at the 14px default (its hhea
       ascender+descender is 1.32em ≈ 18.5px) rounded up, so the board at its
       default setting is within half a pixel of what it has always been, and
       18px type — the maximum — still has a pixel of room in the box.
       Above that the glyphs simply crowd the line, which is the accepted
       trade: the operator asked for bigger TEXT in the same layout. */
    line-height: 19px;
}

/* The picker spans sized themselves in `em` (min-height: 1.1em, line-height:
   1.25 in the .rx-val rule above), which is the same defect in miniature —
   they grew from 18.9px to 28.9px across the range and dragged the row with
   them. Pinned to the one line box everything else now uses. */
#reexportTable tbody td .rx-val {
    min-height: 19px;
}

/* `input[type="time"]` is the one control line-height cannot hold: Chrome
   lays it out from internal field elements sized off the FONT, so at 18px it
   stood 38.3px tall inside a row whose every other cell had stopped growing —
   D.O.T and Loading Slot alone were still stretching the board. An explicit
   content box settles it.
   content-box is stated because main.css sets `box-sizing: border-box` on
   everything (:56): under that, `height: 19px` would be the whole box and the
   0.42rem padding would eat it down to a 5px sliver. Written this way the
   number means the same thing it means in the line-height above.
   32.4px total, which is under the 33.8px Action toggle that actually sets
   this row's height — so the board keeps EXACTLY the row height it has today
   at 14px, at every setting from 10 to 18. */
#reexportTable tbody td input[type="time"] {
    box-sizing: content-box;
    height: 19px;
}

/* Column widths were never the problem and still are not: they are px
   (.reexport-col-*) under `table-layout: fixed`, taken from the header row,
   and THEAD is deliberately outside this whole block. Text that no longer fits
   wraps or clips as it always would. */

/* ── Centre every cell ───────────────────────────────────────────────── */
.reexport-table th,
.reexport-table td { text-align: center; }
.reexport-table td input,
.reexport-table td .rx-val { text-align: center; }
.reexport-table .reexport-date-time { justify-items: center; }
.reexport-table .reexport-action-toggle { justify-content: center; }

/* ── WHS Plan: greyed until the goods can actually be worked ─────────────
   The planned warehouse date is not actionable while the shipment is still
   inbound, so it is muted for the pre-unload statuses (new / in transit /
   unload pending / douane control) and returns to normal the moment unload is
   permitted — set by ReExportBoard from the source row's status. */
/* ── Loaded rows ─────────────────────────────────────────────────────────
   The floor ticking "loaded" on the WMS screen no longer archives the task —
   it paints the whole row green here so the office can see at a glance what
   has already gone out, with the Status cell reading LOADED.

   ONE mechanism, and it is this one. The wash used to be applied TWICE — here
   AND inline from paintCell() — which is how it became a mystery nobody could
   explain: two sources that can disagree, and a probe that reads one while the
   screen shows the other. paintCell() no longer touches it; the row class is
   now the whole story, so `rx-loaded` on/off IS green on/off.

   ID-scoped on purpose, not `!important`-stacked. The doubled-class form this
   replaces (`.reexport-table.reexport-table …`, [0,4,3]) is out-specified by
   enhancements.css's authoritative grid block — `tr:hover td` is [0,6,3] and
   the focus crosshair [0,7,3], both `!important` and both loading LATER — so
   the green lost the moment the pointer crossed the row. One id ([1,3,3])
   settles every one of them without another round of !important escalation.
   Still important: those rules are !important, and specificity cannot beat
   importance on its own.

   Deliberately NOT theme-scoped: the grid is white in both themes, so one rule
   is the correct answer for both, and a `[data-theme]` copy would only be one
   more thing to keep in sync.

   What still wins over it, by design: an explicitly painted colour, which
   paintCell writes INLINE with !important. An inline important declaration
   beats every author rule no matter how specific, so the operator's own
   marking is never overridden by the loaded wash. */
/* The Loaded view is entirely loaded rows, so the whole table carries the
   green wash — that is the point of the tab. */
#rxLoadedTable tbody td {
    background: #e4f5e8 !important;
}
#rxLoadedTable tbody tr:hover td {
    background: #d7eedd !important;
}
.rx-loaded-pager {
    display: flex; align-items: center; gap: 0.6rem;
    padding: 0.45rem 0.75rem;
    font-size: 0.72rem; color: var(--text-muted);
    border-top: 1px solid var(--border-color);
}
.rx-loaded-pager select {
    padding: 2px 6px; border-radius: 5px;
    background: var(--bg-tertiary); color: var(--text-primary);
    border: 1px solid var(--border-color);
}
[data-theme="light"] .rx-loaded-pager select {
    background: #ffffff; color: #263238; border-color: #cfd8dc;
}

/* ── Board filters: customer + date range ────────────────────────────────
   RELOCATED. These controls were a strip of their own inside the Loaded view
   (`.rx-loaded-filters`, written as the pager's twin). The owner moved them
   into the board toolbar next to the font chip and the zoom cluster, and they
   now filter BOTH views — so they are written in the TOOLBAR's language
   instead: `.ribbon-group` for the shell, `--rx-tool-h` for the height,
   `--rx-bar-ctl*` for the control skin. Everything below re-tunes classes this
   bar already owns; nothing here is a parallel idiom.

   The old `.rx-loaded-filters` block is gone with the strip. js/reexport-board.js
   REMOVES any surviving `#rxLoadedFilters` markup from the DOM, so an
   index.html that has not taken the removal hunk cannot paint a dead control
   even with this CSS absent. */
.reexport-toolbar .rx-filters {
    gap: 0.4rem;
}
.reexport-toolbar .rx-filter-select {
    /* Customer names are long ("Bakker Barendrecht B.V."), but this cluster
       sits in a bar that already carries six groups: it sizes to its content
       and stops here rather than pushing the zoom chip onto a second line at
       1366px, where a wrapped toolbar costs a whole row of grid. The full name
       is still in the option list when the dropdown is open. */
    max-width: 190px;
    height: var(--rx-tool-h);
    padding: 0 0.4rem;
    border-radius: 4px;
    background: var(--rx-bar-ctl) !important;
    /* !important throughout: themes.css dresses EVERY light-theme select as a
       form control (white fill, #b9cedb border) with !important, and importance
       outranks specificity — the same reason the ribbon buttons on this bar
       have to answer in kind. */
    border: 1px solid var(--rx-bar-ctl-line) !important;
    color: var(--rx-bar-ink) !important;
    font-size: 0.68rem;
}
.reexport-toolbar .rx-filter-select:hover {
    border-color: var(--rx-bar-accent) !important;
}
.reexport-toolbar .rx-filter-dates {
    display: inline-flex;
    align-items: center;
    gap: 0.2rem;
}
.reexport-toolbar .rx-filter-date {
    height: var(--rx-tool-h);
    /* Wide enough for dd/mm/yyyy plus Chrome's calendar glyph — a date input
       that clips its own picker button looks broken and cannot be opened by
       mouse — and no wider, for the reason on the select above. */
    width: 106px;
    padding: 0 0.2rem;
    border-radius: 4px;
    background: var(--rx-bar-ctl) !important;
    border: 1px solid var(--rx-bar-ctl-line) !important;
    color: var(--rx-bar-ink) !important;
    font-size: 0.66rem;
}
.reexport-toolbar .rx-filter-date:hover {
    border-color: var(--rx-bar-accent) !important;
}
/* Chrome paints the picker glyph near-black, which vanishes on the dark bar. */
.reexport-toolbar .rx-filter-date::-webkit-calendar-picker-indicator {
    filter: invert(0.75);
    cursor: pointer;
}
[data-theme="light"] .reexport-toolbar .rx-filter-date::-webkit-calendar-picker-indicator {
    filter: none;
}
.reexport-toolbar .rx-filter-dash {
    color: var(--rx-bar-label) !important;
    font-size: 0.7rem;
}
/* The × is a .zoom-btn so it is the same 22px square as every other small
   button on this bar; only its glyph weight differs. It is hidden while the
   range is empty (there is nothing to clear) — `hidden` is set by the JS and
   loses to `display:inline-flex` from .zoom-btn without this. */
.reexport-toolbar .rx-filter-clear {
    font-size: 0.95rem;
    line-height: 1;
}
.reexport-toolbar .rx-filter-clear[hidden] {
    display: none !important;
}
/* "12 of 30" — only ever populated while a filter is live, so it takes no
   space on an unfiltered board. */
.reexport-toolbar .rx-filter-count {
    color: var(--rx-bar-label) !important;
    font-size: 0.62rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    white-space: nowrap;
}
.reexport-toolbar .rx-filter-select:focus-visible,
.reexport-toolbar .rx-filter-date:focus-visible {
    outline: 2px solid var(--rx-bar-accent);
    outline-offset: 1px;
}
[data-theme="light"] .reexport-toolbar .rx-filter-select,
[data-theme="light"] .reexport-toolbar .rx-filter-date {
    background: #ffffff !important;
    color: #263238 !important;
    border-color: #c3ced5 !important;
}


#reexportTable tbody tr.rx-loaded td:not(.cell-warn) {
    background: #e4f5e8 !important;
}
#reexportTable tbody tr.rx-loaded:hover td:not(.cell-warn) {
    background: #d7eedd !important;
}
.reexport-table tbody tr.rx-loaded td[data-rx-col="workflow"] .rx-val {
    color: #15803d;
    font-weight: 700;
    font-style: normal;
}


/* ── The dispatched-but-not-confirmed wash ──────────────────────────────────
   A shipment whose position went to `dispatched` while nobody ever ticked
   Loaded on its task. Such a row satisfied NEITHER of the board's two views —
   not "loaded" (the Loaded list) and not "not finished" (the Active board) —
   so it fell between them and disappeared, taking a fully filled-in row with
   it. Owner report 2026-08-27 (SI-023089; four more were sitting in the same
   blind spot). The row now STAYS here, amber, until a person ticks Loaded or
   archives it. Amber and not green on purpose: green already means "confirmed
   gone", and this row is precisely the one nobody has confirmed.

   Same id-scoped, non-!important-stacked, non-theme-scoped form as .rx-loaded
   above, for the same three reasons documented there: enhancements.css's grid
   rules are !important and load later, the grid is white in both themes, and a
   [data-theme] copy would only be one more thing to keep in sync. */
#reexportTable tbody tr.rx-gone td:not(.cell-warn) {
    background: #fdf1dc !important;
}
#reexportTable tbody tr.rx-gone:hover td:not(.cell-warn) {
    background: #f9e6c6 !important;
}
.reexport-table tbody tr.rx-gone td[data-rx-col="workflow"] .rx-val {
    color: #b45309;
    font-weight: 700;
    font-style: normal;
}

.reexport-table.reexport-help {
    /* Sits under the table now — a legend, not a preamble. */
    margin-top: 0.5rem;
    border-top: 1px solid var(--border-color);
}
/* Focus crosshair, board-local (the register's is #tableBody-scoped). */
.reexport-table.reexport-table tbody tr td.focus-row:not(.rx-num):not(.cell-selected),
.reexport-table.reexport-table tbody tr td.focus-col:not(.rx-num):not(.cell-selected) {
    background: #caead8 !important;
}

/* Darker bottom edge so each row reads as a distinct band — the default
   hairline disappears once the board is white. */
.reexport-table.reexport-table tbody td {
    border-bottom: 1px solid #9aa3a9 !important;
}
[data-theme="light"] .reexport-table.reexport-table tbody td {
    border-bottom: 1px solid #9aa3a9 !important;
}

.reexport-table td.rx-num {
    /* Same darker grey as the header — the counter is chrome, not data. */
    background: #d0d3d5 !important;
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    font-weight: 700;
    color: #343b3f !important;
    padding-left: 0;
    padding-right: 0;
    text-align: center;
    cursor: pointer;
    /* THE reason shift-clicking the counter does not drag a blue text
       selection across the board. It used to be done in JS with
       `e.preventDefault()` on the rownum mousedown — which also cancelled
       Chrome's native drag initiation and left drag-to-reorder dead on arrival
       (see the ReExportGrid mousedown handler in js/reexport-board.js). The
       prefixed pair is not decoration: -webkit-user-select is still what
       Safari and older WebKit read, and losing the suppression there would
       bring the selection back on exactly the browsers that cannot be tested
       on the warehouse floor. */
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
}
.reexport-table.reexport-table td.rx-num:hover { background: #bcc1c4 !important; }
[data-theme="light"] .reexport-table.reexport-table td.rx-num {
    background: #d0d3d5 !important;
    color: #4a5257 !important;
}

/* ── Drag the # cell to reorder ──────────────────────────────────────────
   The handle is the counter cell and only the counter cell: every other cell
   begins a range selection on mousedown, so the gesture has to be somewhere
   that is not part of the grid proper. `grab` says so before the operator
   tries it, and the drop line is drawn on the ROW rather than as a floating
   indicator so it cannot drift out of step with what will actually happen. */
.reexport-table td.rx-num[draggable="true"] { cursor: grab; }
.reexport-table td.rx-num[draggable="true"]:active { cursor: grabbing; }

#reexportTable tbody tr.rx-dragging td { opacity: 0.45; }

/* box-shadow, not border: a border changes the row's height mid-drag and the
   rows below it visibly jump as the marker moves between them. inset so it is
   painted inside the cell box and cannot be clipped by the scroll container. */
#reexportTable tbody tr.rx-drop-above td {
    box-shadow: inset 0 2px 0 0 #2f81f7;
}
#reexportTable tbody tr.rx-drop-below td {
    box-shadow: inset 0 -2px 0 0 #2f81f7;
}

/* Muted, not illegible. The greys here were #9aa5ad / #98a2ab AND `opacity:
   0.75` on top, and the two compounded: 0.75 of #9aa5ad over the cell's white
   composites to roughly #b3b9be, which is a 2.1:1 contrast against #ffffff —
   below every readability floor there is, and the owner's report was simply
   that the WHS Plan date could not be read.

   Both cells here are WHITE in both themes (`.reexport-table td` is #ffffff
   unconditionally and the [data-theme="light"] copy repeats it), so "darken"
   means darken in both — a lighter dark-theme grey, which is the usual answer
   on a dark grid, would be the wrong direction on this one.

   The shades are the file's own: #5f6f7c and #556575 are the muted end of the
   blue-grey family the header sub-label (#5b6d5f), .rx-swatch-none (#78909c)
   and the header ink (#37474f) already come from. They measure 5.2:1 and
   6.0:1 against white — readable — while staying obviously quiet next to the
   #1f2937 a live cell uses (~14:1).

   The opacity is GONE rather than raised. It faded the whole cell box (border
   and background included, since opacity makes a stacking context) to say one
   thing about the TEXT; the italic and the grey already say it, and they say
   it without a second multiplier on top of a colour that has to be legible. */
.reexport-table td.rx-whs-muted {
    color: #5f6f7c !important;
    font-style: italic;
}
[data-theme="light"] .reexport-table td.rx-whs-muted { color: #556575 !important; }

/* ── Loaded sub-tab ──────────────────────────────────────────────────────
   Two views over the same task list: Active (the board) and Loaded (a
   read-only list of the tasks the floor has ticked).

   WHY THE UNDERLINE-TAB IDIOM AND NOT THE RIBBON
   The .reexport-toolbar ribbon is a row of TOOLS that act on the current
   view; a view SWITCH rendered as another ribbon button would read as a
   third paint tool. pages/wms.html's .shipment-tab strip is exactly this
   gesture and is already the app's answer for it — but that CSS lives in
   that page's own <style> block, so the class name alone would arrive here
   unstyled. Hence the idiom is copied, under rx-* names, not the class.

   The green accent is not decoration: #059669/#065f46 is what .shipment-tab
   uses AND the family of the board's own loaded wash (#e4f5e8 / #15803d),
   so the active tab, the count pill and a loaded row all read as one thing. */
.rx-subtabs {
    display: flex;
    gap: 0;
    align-items: flex-end;
    padding: 0 0.25rem;
    margin-bottom: 0.35rem;
    background: var(--bg-secondary);
    border-bottom: 2px solid var(--border-color);
}
.rx-subtab {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.6rem 1.25rem;
    margin-bottom: -2px;          /* sit the underline ON the strip's edge */
    border: none;
    border-bottom: 3px solid transparent;
    background: none;
    color: var(--text-muted);
    font-family: inherit;
    font-size: 0.82rem;
    font-weight: 600;
    cursor: pointer;
    transition: color 0.15s ease, border-color 0.15s ease;
}
.rx-subtab:hover { color: var(--text-primary); }
.rx-subtab.active {
    color: #065f46;
    border-bottom-color: #059669;
}
.rx-subtab-count {
    min-width: 1.4rem;
    padding: 0.15rem 0.5rem;
    border-radius: 10px;
    background: rgba(5, 150, 105, 0.12);
    color: #059669;
    font-size: 0.68rem;
    font-weight: 700;
    text-align: center;
}

/* [hidden] is a UA rule and loses to anything that sets display, so state it. */
.rx-view[hidden] { display: none !important; }

/* In the Loaded view the toolbar's TOOLS have nothing to act on: paint/bold/
   focus all resolve their target from ReExportGrid's selection (scoped to
   #reexportTableBody) and ReexportZoomManager zooms #reexportTable only.

   The bar itself no longer goes away with them. It carries the customer and
   date filters now, and those are BOARD-level — a control that vanished when
   the operator changed tab would read as two different filters, which is the
   whole reason they were moved up here. So every child EXCEPT the filter
   cluster is hidden, and the cluster loses the auto margin so it sits at the
   left of an otherwise empty bar rather than floating alone on the right. */
.reexport-pane.rx-view-loaded .reexport-toolbar > *:not(.rx-filters) {
    display: none !important;
}
.reexport-pane.rx-view-loaded .reexport-toolbar .rx-filters {
    margin-left: 0;
    border-left: 0;
}
/* …and the bar has to be told to pack from the LEFT while it does.
   `.reexport-toolbar` sets `justify-content: flex-end` far higher up in this
   file (the first, older block for this bar). In the Active view that never
   showed: `margin-left:auto` on the right band swallows every pixel of free
   space, so there is nothing left for justify-content to place. Hide the other
   groups and that margin goes with them — the free space comes back and the
   lone filter cluster is thrown to the right edge of an empty bar, which is
   exactly what the first screenshot of this view showed. */
.reexport-pane.rx-view-loaded .reexport-toolbar {
    justify-content: flex-start;
}

/* Read-only twins of the board's date+time inputs — same .reexport-date-time
   grid, so both halves land under the "date / time" sub-header at the same
   widths as the Active board. */
.rx-loaded-table .rx-ro {
    display: block;
    padding: 0.42rem 0.45rem;
    color: #1f2937;
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    line-height: 1.25;
    text-align: center;
}
.rx-loaded-table .reexport-date-time .rx-ro + .rx-ro {
    border-left: 1px solid #d4ddc8;
}
.rx-col-loadedat { width: 140px; }

.rx-unmark-btn {
    padding: 0.3rem 0.6rem;
    border: 1px solid #9aa3a9;
    border-radius: 5px;
    background: #ffffff;
    color: #15803d;
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    font-weight: 700;
    cursor: pointer;
}
.rx-unmark-btn:hover { background: #e4f5e8; border-color: #15803d; }

/* Light theme. themes.css carries broad, !important rules that out-rank a
   plain declaration here:
     [data-theme="light"] button { background/color/border ... !important }
     [data-theme="light"] span   { color: inherit !important }
     [data-theme="light"] div    { background-color: inherit }   (0,1,1)
   so every rule below is both !important AND deeper than those selectors. */
[data-theme="light"] .rx-subtabs {
    background: #f4f7f9 !important;
    border-bottom-color: #cfd8dc !important;
}
[data-theme="light"] .rx-subtabs .rx-subtab {
    background: transparent !important;
    border: none !important;
    border-bottom: 3px solid transparent !important;
    color: #64748b !important;
}
[data-theme="light"] .rx-subtabs .rx-subtab:hover { color: #0f172a !important; }
[data-theme="light"] .rx-subtabs .rx-subtab.active {
    color: #065f46 !important;
    border-bottom-color: #059669 !important;
}
[data-theme="light"] .rx-subtabs .rx-subtab .rx-subtab-count {
    background: rgba(5, 150, 105, 0.12) !important;
    color: #059669 !important;
}
[data-theme="light"] .rx-loaded-table .rx-ro { color: #1f2937 !important; }
[data-theme="light"] .reexport-table .rx-unmark-btn {
    background: #ffffff !important;
    border: 1px solid #9aa3a9 !important;
    color: #15803d !important;
}
[data-theme="light"] .reexport-table .rx-unmark-btn:hover {
    background: #e4f5e8 !important;
    border-color: #15803d !important;
}

/* ============================================
   LIGHT THEME - TABLE STYLING
   ============================================ */

[data-theme="light"] .table-container {
    background: transparent !important;
}

[data-theme="light"] .table-title {
    color: #64748b !important;
}

[data-theme="light"] .table-title strong {
    color: #0f172a !important;
}

[data-theme="light"] .row-counter {
    background: #f8fafc !important;
    border-color: #cbd5e1 !important;
    color: #64748b !important;
}

[data-theme="light"] .row-counter span {
    color: #475569 !important;
}

[data-theme="light"] .excel-wrapper {
    background: #ffffff !important;
    border-color: #cbd5e1 !important;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08) !important;
}

/* Table Headers - Light Theme — marine-blue title bar (matches the
   WMS header navy #0a5989) with white typography so the backoffice
   table title reads like a colored sheet header on white pages. */
[data-theme="light"] .excel-table th {
    background: #0a5989 !important;
    border-color: #084a73 !important;
    color: #ffffff !important;
}

[data-theme="light"] .excel-table th:hover {
    background: #084a73 !important;
    color: #ffffff !important;
}

[data-theme="light"] .excel-table th.selected,
[data-theme="light"] .excel-table th.col-selected {
    background: #063a5a !important;
    color: #ffffff !important;
}

/* Column cell selection - Light Theme */
[data-theme="light"] .excel-table td.col-selected {
    background: rgba(71, 85, 105, 0.1) !important;
    box-shadow: inset 0 2px 0 0 #475569, inset 0 -2px 0 0 #475569 !important;
}

/* Row Number Column - Light Theme */
[data-theme="light"] .excel-table th:first-child,
[data-theme="light"] .excel-table td:first-child {
    background: #e2e8f0 !important;
    color: #475569 !important;
    border-color: #cbd5e1 !important;
}

[data-theme="light"] .excel-table td:first-child:hover {
    background: #d6efd6 !important;   /* light green (was dark slate) — readable dark text */
    color: #14532d !important;
}

[data-theme="light"] .excel-table td:first-child.dragging {
    background: #475569 !important;
    color: #ffffff !important;
}

/* Table Cells - Light Theme */
[data-theme="light"] .excel-table td {
    border-color: #e2e8f0 !important;
    background: #ffffff !important;
}

[data-theme="light"] .excel-table tbody tr:nth-child(even) td:not(:first-child) {
    background: #f8fafc !important;
}

[data-theme="light"] .excel-table tbody tr.selected td {
    background: rgba(71, 85, 105, 0.1) !important;
}

[data-theme="light"] .excel-table tbody tr.drag-over {
    border-top-color: #475569 !important;
}

/* Table Inputs - Light Theme */
[data-theme="light"] .excel-table input {
    color: #0f172a !important;
}

[data-theme="light"] .excel-table input::placeholder {
    color: #94a3b8 !important;
}

/* Light-theme override removed — the theme-agnostic .excel-table
   td.selected-cell rule above serves both themes since the table cell
   background is always white regardless of theme. */

[data-theme="light"] .reexport-pane .excel-wrapper {
    background: #f7faf2 !important;
    border-color: #cfd9bf !important;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08) !important;
}

[data-theme="light"] .reexport-table th {
    background: #d0d3d5 !important;
    border-color: #cfd8dc !important;
    color: #37474f !important;
    /* !important: [data-theme="light"] .excel-table th (themes.css:507, :1806
       and table.css:453/:1115) all set the header weight and out-rank a plain
       declaration here. */
    font-weight: 700 !important;
}
[data-theme="light"] .reexport-table th .reexport-head-main { font-weight: 700 !important; }
[data-theme="light"] .reexport-table th .reexport-head-sub  { font-weight: 600 !important; }

[data-theme="light"] .reexport-table th:hover {
    background: #e0e5e8 !important;
    color: #263238 !important;
}

[data-theme="light"] .reexport-table td {
    background: #ffffff !important;
    border-color: #dfe4e8 !important;
}

[data-theme="light"] .reexport-table tbody tr:nth-child(even) td:not(:first-child) {
    background: #fafbfc !important;
}

[data-theme="light"] .reexport-table tbody tr:hover td {
    background: #f2f6f9 !important;
}

[data-theme="light"] .reexport-table th:first-child,
[data-theme="light"] .reexport-table td:first-child {
    background: inherit !important;
    color: inherit !important;
}

/* The first column special-case below exists because the Register's column 1
   is row-number chrome. On this board it is Source Status — real data — so the
   HEADER cell must not inherit a transparent background from the row; the
   header has to read as one continuous light-grey band. */
.reexport-table th:first-child { background: #d0d3d5; }
[data-theme="light"] .reexport-table th:first-child { background: #d0d3d5 !important; }

[data-theme="light"] .reexport-table td:first-child:hover,
[data-theme="light"] .reexport-table td:first-child.dragging {
    background: inherit !important;
    color: inherit !important;
}

[data-theme="light"] .reexport-help {
    background: #f4f6f8 !important;
    border-color: #cdddbb !important;
    color: #29403c !important;
}

/* ============================================
   MINI CALENDAR DATE PICKER
   ============================================ */

.mini-calendar-overlay {
    position: fixed;
    z-index: 9999;
    background: var(--bg-secondary, #1e293b);
    border: 1px solid var(--border-color, #334155);
    border-radius: 8px;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.4);
    padding: 10px;
    width: 220px;
    display: none;
    font-family: 'Space Grotesk', 'JetBrains Mono', sans-serif;
    font-size: 12px;
}

.mini-calendar-overlay.visible {
    display: block;
}

.mini-cal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 8px;
}

.mini-cal-title {
    font-weight: 600;
    font-size: 14px;
    color: var(--text-primary, #f1f5f9);
}

.mini-cal-nav {
    background: none;
    border: 1px solid var(--border-color, #334155);
    color: var(--text-secondary, #94a3b8);
    cursor: pointer;
    border-radius: 4px;
    width: 26px;
    height: 26px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 10px;
    transition: all 0.15s;
}

.mini-cal-nav:hover {
    background: var(--bg-hover, #334155);
    color: var(--text-primary, #f1f5f9);
}

.mini-cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 2px;
}

.mini-cal-day-header {
    text-align: center;
    font-size: 10px;
    font-weight: 600;
    color: var(--text-muted, #64748b);
    padding: 4px 0;
    text-transform: uppercase;
}

.mini-cal-cell {
    text-align: center;
    padding: 5px 2px;
    border-radius: 4px;
    cursor: pointer;
    color: var(--text-secondary, #cbd5e1);
    transition: all 0.1s;
    font-size: 11px;
}

.mini-cal-cell:hover {
    background: var(--accent-orange, #f97316);
    color: white;
}

.mini-cal-cell.today {
    background: rgba(59, 130, 246, 0.25);
    color: #60a5fa;
    font-weight: 700;
}

.mini-cal-cell.today:hover {
    background: var(--accent-orange, #f97316);
    color: white;
}

.mini-cal-cell.empty {
    cursor: default;
}

.mini-cal-cell.empty:hover {
    background: none;
}

.mini-cal-footer {
    display: flex;
    gap: 6px;
    margin-top: 8px;
    border-top: 1px solid var(--border-color, #334155);
    padding-top: 8px;
}

.mini-cal-footer button {
    flex: 1;
    padding: 5px 0;
    border: 1px solid var(--border-color, #334155);
    border-radius: 4px;
    background: var(--bg-tertiary, #0f172a);
    color: var(--text-secondary, #94a3b8);
    cursor: pointer;
    font-size: 11px;
    font-weight: 500;
    transition: all 0.15s;
}

.mini-cal-footer button:hover {
    background: var(--bg-hover, #334155);
    color: var(--text-primary, #f1f5f9);
}

/* Mini Calendar - Light Theme */
[data-theme="light"] .mini-calendar-overlay {
    background: #ffffff !important;
    border-color: #cbd5e1 !important;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.12) !important;
}

[data-theme="light"] .mini-cal-title {
    color: #0f172a !important;
}

[data-theme="light"] .mini-cal-nav {
    border-color: #cbd5e1 !important;
    color: #64748b !important;
}

[data-theme="light"] .mini-cal-nav:hover {
    background: #f1f5f9 !important;
    color: #0f172a !important;
}

[data-theme="light"] .mini-cal-cell {
    color: #334155 !important;
}

[data-theme="light"] .mini-cal-cell:hover {
    background: #475569 !important;
    color: #ffffff !important;
}

[data-theme="light"] .mini-cal-cell.today {
    background: rgba(59, 130, 246, 0.15) !important;
    color: #2563eb !important;
}

[data-theme="light"] .mini-cal-cell.today:hover {
    background: #475569 !important;
    color: #ffffff !important;
}

[data-theme="light"] .mini-cal-footer button {
    background: #f8fafc !important;
    border-color: #cbd5e1 !important;
    color: #475569 !important;
}

[data-theme="light"] .mini-cal-footer button:hover {
    background: #e2e8f0 !important;
    color: #0f172a !important;
}

/* ============================================
   LIVE SYNC — Cell locks, dirty cells, presence
   ============================================ */

/* Cell locked by another user: 2px colored border + tinted background. The
   <td> stays clickable (cursor: pointer) so 3rd users can still click the
   row to select it; the <input> stays focusable and selectable but is
   read-only, with a "not-allowed" cursor making it clear that copy/select
   work but typing does not. The --lock-color custom property is set inline
   by LockOverlay using the owner's avatar color. */
.cell-locked-by-other {
    position: relative;
    cursor: pointer;
    box-shadow: inset 0 0 0 2px var(--lock-color, #a855f7);
    background: color-mix(in srgb, var(--lock-color, #a855f7) 10%, transparent);
}
.cell-locked-by-other input {
    cursor: not-allowed;
    color: inherit;
    opacity: 0.85;
    background: transparent;
}
.cell-lock-chip {
    position: absolute;
    top: 2px;
    right: 2px;
    z-index: 4;
    font-size: 9px;
    font-weight: 700;
    line-height: 1;
    color: #fff;
    padding: 2px 4px;
    border-radius: 3px;
    pointer-events: none;
    letter-spacing: 0.5px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
}

/* Row with at least one foreign lock: faintly dim the non-locked cells so
   users notice another editor is active in this row. */
.row-has-active-edit > td:not(.cell-locked-by-other):not(:first-child) {
    opacity: 0.78;
}

/* Dirty cell — the local user has typed but the debounced save hasn't
   flushed yet. Subtle yellow left-border, fades automatically once the
   save resolves and clearDirty is called. */
.dirty-cell {
    box-shadow: inset 3px 0 0 0 #f59e0b;
}

/* Presence bar — small avatar list above the table. */
#presenceBar {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px;
    font-size: 12px;
    color: var(--text-muted, #94a3b8);
}
#presenceBar .presence-label {
    margin-right: 4px;
}
#presenceBar .presence-avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    color: #fff;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.5px;
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}

/* Live sync indicator — green dot when poll is healthy, grey when paused
   (tab hidden), red on consecutive errors. State is set as a data attr by
   ControlBoardPoller._setIndicator. */
#liveSyncIndicator {
    display: inline-flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    padding: 2px 6px;
    border-radius: 4px;
    background: rgba(255, 255, 255, 0.04);
    color: var(--text-muted, #94a3b8);
}
#liveSyncIndicator[data-state="error"] {
    color: #f87171;
    background: rgba(248, 113, 113, 0.08);
}

/* ============================================
   PEER SELECTIONS (live presence cursors)
   ============================================
   Rendered by SelectionOverlay from each poll tick. Distinct from
   .cell-locked-by-other: never blocks input, just shows where peers are
   working. The --peer-color custom property is set inline using the peer's
   avatar color. Multiple peers selecting the same target → last wins
   (acceptable for a soft indicator). */

/* A cell another user has selected. Thin colored border, subtle tint. */
.cell-selected-by-other {
    box-shadow: inset 0 0 0 1px var(--peer-color, #a855f7);
    background: color-mix(in srgb, var(--peer-color, #a855f7) 6%, transparent);
}
/* The cell another user is currently focused on. Stronger border + chip-ish
   inner glow so you can pick out their cursor at a glance. */
.cell-focused-by-other {
    box-shadow: inset 0 0 0 2px var(--peer-color, #a855f7),
                0 0 0 1px color-mix(in srgb, var(--peer-color, #a855f7) 40%, transparent);
}
/* If a peer has BOTH a foreign lock and a peer-selection on the same cell
   (lock wins visually — typing must be blocked, not just shown). */
.cell-locked-by-other.cell-selected-by-other {
    box-shadow: inset 0 0 0 2px var(--lock-color, #a855f7);
    background: color-mix(in srgb, var(--lock-color, #a855f7) 10%, transparent);
}

/* A row another user has selected — left border in their color so it doesn't
   conflict with row-has-active-edit (which dims) or with the local
   .selected class (which highlights). */
/* Peer row selection: thin colored top + bottom borders across every cell
   so the row reads as a "boxed" selection on either theme. NO background
   tint — it composes badly with the dark theme's already-dark cell bg
   (produced muddy / unreadable colors). The :not() guards keep cell-level
   peer styling (locks, per-cell selections) intact on overlap. */
.row-selected-by-other > td:not(.cell-locked-by-other):not(.cell-selected-by-other) {
    box-shadow: inset 0 2px 0 0 var(--peer-color, #a855f7),
                inset 0 -2px 0 0 var(--peer-color, #a855f7);
}

/* Anchor on the row-number cell: keep the 4 px left-bar plus the same top
   and bottom rails so the # column reads as the row's selection label. */
.row-selected-by-other > td:first-child {
    box-shadow: inset 4px 0 0 0 var(--peer-color, #a855f7),
                inset 0 2px 0 0 var(--peer-color, #a855f7),
                inset 0 -2px 0 0 var(--peer-color, #a855f7);
}

/* A column another user has selected — top border on the header. */
.col-selected-by-other {
    box-shadow: inset 0 4px 0 0 var(--peer-color, #a855f7);
}

/* ============================================
   SELECT vs EDIT — visual differentiation
   ============================================
   Read-only cells (display mode): show the Excel-style "cell" cursor so
   it's clear you can click-and-copy but not type. Double-click promotes
   to edit mode (input becomes writable, cursor reverts to text). */
.excel-table input[readonly] {
    cursor: cell;
}
.excel-table input:not([readonly]) {
    cursor: text;
}

/* Cell currently in EDIT mode — 2px green frame (wider than the gray
   default so it wins under border-collapse). Distinguishes "I'm typing"
   from the user-color "selected" frame. */
.excel-table td:has(> input[data-edit-mode="1"]) {
    border: 2px solid var(--accent-green, #22c55e) !important;
    box-shadow: none !important;
    outline: none !important;
    position: relative;
    z-index: 3;
}

/* ============================================
   PICK-THEN-POINT — the armed paint mode
   ============================================
   ColorPicker.armColor() (enhancements.js) puts `cp-armed` on <body> and the
   NEXT click on a cell or row paints it. That is a MODE, and an unsignalled
   mode is a mis-click waiting to happen — the re-export board has no undo, so
   a stray click is a colour the operator has to hunt down and clear by hand.

   Two signals, and deliberately no new DOM and no JS change: a crosshair
   everywhere the click would land, and a pulse on the swatch that armed it.

   Here rather than in enhancements.css because both ribbons that own those
   swatches are styled in this file (.reexport-toolbar, ~:1140), and
   enhancements.css carries unshipped work from other sessions. */
body.cp-armed {
    cursor: crosshair;
}

/* The grid's own cursors (`cell` on read-only inputs, `text` on editable ones,
   ~:2288 above) are more specific than a bare body rule, so without this they
   would win over exactly the cells the user is aiming at. */
body.cp-armed td,
body.cp-armed th,
body.cp-armed .excel-table input {
    cursor: crosshair !important;
}

/* The armed swatch keeps pulsing until the click lands or Esc cancels.
   `outline` not `border`: it is drawn outside the box, so an inline-block
   24px swatch in a packed ribbon does not shift its neighbours. */
body.cp-armed .color-picker-wrapper {
    outline: 2px solid var(--accent-orange, #f97316);
    outline-offset: 2px;
    border-radius: var(--radius-sm, 4px);
    animation: cp-armed-pulse 1.1s ease-in-out infinite;
}

@keyframes cp-armed-pulse {
    0%, 100% { outline-color: var(--accent-orange, #f97316); }
    50%      { outline-color: transparent; }
}

/* A blinking ring is exactly the pattern reduced-motion asks us to drop; the
   static ring alone still says "armed". */
@media (prefers-reduced-motion: reduce) {
    body.cp-armed .color-picker-wrapper { animation: none; }
}
