/* Vessel Log ticker — when visible (captain on Fleet Board), the body
   gets data-vlog-ticker="on" so the section reserves enough bottom
   padding for the ~60px sticky bar. Applied only to Fleet Board
   because that's the only section that hosts the ticker. */
body[data-vlog-ticker="on"] #fleet-board-section { padding-bottom: 120px; }

/* ── Modernization pass: typography, cards, buttons, pills ──────────
   This block applies modernization options 1–4 globally so individual
   templates don't need to be touched. Anything that previously read
   `bg-white shadow rounded` automatically picks up the new softer
   card treatment; existing buttons get larger hit areas + focus rings
   + transitions without per-element edits. Status pills are upgraded
   by changing the helper function (see statusPill in app.js).
   --------------------------------------------------------------------
   1. Typography
   ------------------------------------------------------------------ */
html, body {
  font-family: 'Inter', system-ui, -apple-system, "Segoe UI", sans-serif;
  letter-spacing: -0.005em;
}
/* Mono columns / barge numbers keep JetBrains Mono so digits line up. */
.font-mono, [class*="font-mono"] {
  font-family: 'JetBrains Mono', ui-monospace, Menlo, Consolas, monospace;
  letter-spacing: 0;
}
h1, h2, h3 { letter-spacing: -0.015em; }
h1 { font-weight: 700; }
h2 { font-weight: 600; }

/* 2. Cards — soften the look of the legacy `shadow rounded` combo
   without changing the markup. Any element that has BOTH the
   `shadow` AND `rounded` utility classes (the universal card
   pattern in this codebase) gets the new treatment. We use a
   selector union so the new shadow + radius + border kick in
   automatically. */
.shadow.rounded {
  box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.04), 0 1px 3px 0 rgb(0 0 0 / 0.06);
  border-radius: 0.75rem;
  border: 1px solid rgb(226 232 240 / 0.7);
}

/* 3. Buttons — global polish for the dominant button shapes used
   throughout the app. We target both Tailwind utility combos and
   plain <button> elements that already carry a `bg-*` background
   class, applying a consistent radius, font weight, transition,
   and focus ring. The selectors are deliberately narrow to avoid
   touching toggle pills + status chips. */
button[class*="bg-slate-900"],
button[class*="bg-sky-600"],
button[class*="bg-emerald-600"],
button[class*="bg-rose-600"],
button[class*="bg-indigo-600"] {
  border-radius: 0.5rem;
  font-weight: 500;
  transition: background-color 0.15s ease, box-shadow 0.15s ease, transform 0.05s ease;
}
button[class*="bg-slate-900"]:hover,
button[class*="bg-sky-600"]:hover,
button[class*="bg-emerald-600"]:hover,
button[class*="bg-rose-600"]:hover,
button[class*="bg-indigo-600"]:hover {
  box-shadow: 0 2px 6px -1px rgb(0 0 0 / 0.10);
}
button[class*="bg-slate-900"]:active,
button[class*="bg-sky-600"]:active,
button[class*="bg-emerald-600"]:active,
button[class*="bg-rose-600"]:active,
button[class*="bg-indigo-600"]:active {
  transform: translateY(1px);
}
button:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgb(99 102 241 / 0.5);
  border-radius: 0.5rem;
}

/* 4. Pill-with-dot status indicators. Driven by .pill-dot wrapper
   from the statusPill() helper. The ::before pseudo carries a
   colored dot; the wrapper supplies the background tint via the
   color modifier classes. */
.pill-dot {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.125rem 0.625rem;
  font-size: 0.6875rem;
  font-weight: 500;
  border-radius: 9999px;
  border: 1px solid;
  white-space: nowrap;
  line-height: 1.4;
}
.pill-dot::before {
  content: '';
  display: inline-block;
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 9999px;
  background: currentColor;
  opacity: 0.85;
}
.pill-dot.pill-slate  { background: rgb(241 245 249); color: rgb(71 85 105);  border-color: rgb(226 232 240); }
.pill-dot.pill-sky    { background: rgb(240 249 255); color: rgb(2 132 199);   border-color: rgb(186 230 253); }
.pill-dot.pill-amber  { background: rgb(255 251 235); color: rgb(180 83 9);    border-color: rgb(253 230 138); }
.pill-dot.pill-emerald{ background: rgb(236 253 245); color: rgb(4 120 87);    border-color: rgb(167 243 208); }
.pill-dot.pill-rose   { background: rgb(255 241 242); color: rgb(190 18 60);   border-color: rgb(254 205 211); }
.pill-dot.pill-indigo { background: rgb(238 242 255); color: rgb(67 56 202);   border-color: rgb(199 210 254); }
.pill-dot.pill-cancelled { background: rgb(248 250 252); color: rgb(148 163 184); border-color: rgb(226 232 240); text-decoration: line-through; }

/* 6. Sidebar redesign — modernized nav items.
   --------------------------------------------------------------------
   The section-btn elements get a base treatment (icon + label,
   subtle hover slide, padding tuned for stroke icons). The JS in
   setSection() still applies `bg-slate-900 text-white` to the
   active item; we intercept that combination on `.section-btn`
   specifically and replace it with the indigo soft-tint + 3px
   vertical rail treatment so the rest of the app's bg-slate-900
   usages aren't affected. */
.section-btn.nav-item {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.625rem;
  padding: 0.5rem 0.75rem;
  border-radius: 0.5rem;
  font-weight: 500;
  font-size: 0.875rem;
  color: rgb(71 85 105);
  transition: background-color 0.12s ease, color 0.12s ease, transform 0.12s ease;
  width: 100%;
}
/* Permission-gated nav buttons get .hidden added by applyModuleVisibility.
   Tailwind's `.hidden { display: none }` has specificity (0,1,0), but
   `.section-btn.nav-item { display: flex }` above is (0,2,0) and wins
   the cascade — the button keeps rendering visually even though the
   class is present. This pair of overrides bumps specificity high
   enough that .hidden wins for every nav button shape we ship. */
.section-btn.nav-item.hidden,
.nav-emp-shortcut.hidden {
  display: none;
}
.section-btn.nav-item:hover {
  background: rgb(241 245 249);
  color: rgb(15 23 42);
  transform: translateX(2px);
}
.section-btn.nav-item .nav-svg-icon {
  flex-shrink: 0;
  width: 16px;
  height: 16px;
}
/* Active state — JS adds bg-slate-900 text-white; we replace the
   visual with the new indigo soft-tint + rail. !important is required
   to win against the inline Tailwind utility classes. */
.section-btn.nav-item.bg-slate-900 {
  background: rgb(238 242 255) !important;
  color: rgb(67 56 202) !important;
  transform: none;
}
.section-btn.nav-item.bg-slate-900::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.375rem;
  bottom: 0.375rem;
  width: 3px;
  border-radius: 0 9999px 9999px 0;
  background: rgb(79 70 229);
}
.section-btn.nav-item.bg-slate-900.text-white {
  /* JS also flips text-white on; force the indigo color through. */
  color: rgb(67 56 202) !important;
}

/* Section group headers — small uppercase dividers between
   Operations / Records / Admin clusters of nav items. */
.nav-section-header {
  font-size: 0.625rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 600;
  color: rgb(148 163 184);
  padding: 0.5rem 0.75rem 0.25rem;
  margin-top: 0.5rem;
}
.nav-section-header:first-child { margin-top: 0; }

/* Sub-group labels inside a subnav (e.g. Catalogs -> "Fleet & assets"). */
.nav-subgroup-header {
  font-size: 0.5625rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  font-weight: 600;
  color: rgb(148 163 184);
  padding: 0.3rem 0.6rem 0.1rem;
}
.nav-subnav-divider {
  border-top: 1px solid rgb(226 232 240);
  margin: 0.35rem 0.5rem 0.15rem;
}
/* Destructive admin actions -- fenced + tinted red. */
.su-sub-btn.nav-su-danger { color: rgb(185 28 28); }
.su-sub-btn.nav-su-danger:hover { background: rgb(254 242 242); }
.nav-subgroup-header.nav-su-danger-h { color: rgb(185 28 28); }

/* 7. Rate + Escalator edit forms as modals — they live inline at the
   bottom of their respective lists, which works fine for short forms
   but the rate form in particular is tall (name, amount, unit,
   triggers, escalator picker, GL account, effective/expiration dates,
   notes) and scrolls off the bottom of the screen when opened.
   Float them as a centered modal when shown. The :not(.hidden)
   selector mirrors the makeCrudModule show/hide convention so we
   don't need any JS wiring. The huge spread box-shadow doubles as a
   semi-opaque backdrop without needing a separate overlay element. */
/* (Pre-existing pseudo-modal CSS for #disp-rate-form / #disp-esc-form was
   removed — the shared #crud-modal-host now wraps every CRUD form
   uniformly, so per-form fixed-position hacks would fight that wrapper.) */

/* ── End modernization pass ─────────────────────────────────────── */

/* Count pill on Dispatch subnav items. Hidden by default — only renders
   when JS sets textContent to a non-empty value. Tabular-nums so the
   pill doesn't reflow as the count changes from "9" to "10". */
.count-badge {
  display: none;
  padding: 0.05rem 0.4rem;
  border-radius: 9999px;
  background: #e0f2fe;
  color: #075985;
  font-size: 0.65rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.count-badge:not(:empty) { display: inline-block; }
/* Amber variant — pending read-acknowledgments on the Library nav item
   (something is owed, not just informational). */
.count-badge--warn {
  background: #fef3c7;
  color: #92400e;
}
html.dark .count-badge--warn {
  background: #78350f;
  color: #fde68a;
}

/* Sidebar search results dropdown — looks like a Mac-app palette. */
#sidebar-search-results .ssr-item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
  color: #334155;
  border-bottom: 1px solid #f1f5f9;
  cursor: pointer;
}
#sidebar-search-results .ssr-item:last-child { border-bottom: none; }
#sidebar-search-results .ssr-item:hover,
#sidebar-search-results .ssr-item.ssr-active { background: #e0f2fe; color: #0c4a6e; }
#sidebar-search-results .ssr-group {
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: #94a3b8;
  margin-right: 0.5rem;
}

.th {
  text-align: left;
  padding: 0.5rem 0.75rem;
  font-weight: 600;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  user-select: none;
  cursor: pointer;
  white-space: nowrap;
}
.th-num { text-align: right; }
.th:hover { background: #e2e8f0; }
.th.th-static { cursor: default; }
.th.th-static:hover { background: transparent; }
.th.sorted-asc::after  { content: " \25B2"; font-size: 0.6em; }
.th.sorted-desc::after { content: " \25BC"; font-size: 0.6em; }

#rows td {
  padding: 0.5rem 0.75rem;
  border-top: 1px solid #f1f5f9;
}
#rows tr { cursor: pointer; }
#rows tr:hover { background: #f8fafc; }
#rows tr.transit-row { cursor: default; }
#rows tr.transit-row:hover { background: rgb(248 250 252 / 0.8); }
#rows .num { text-align: right; font-variant-numeric: tabular-nums; }

.delay-pill {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.delay-green  { background: #d1fae5; color: #065f46; }
.delay-yellow { background: #fef3c7; color: #92400e; }
.delay-red    { background: #fee2e2; color: #991b1b; }
.delay-none   { background: #e2e8f0; color: #475569; }

.view-btn { transition: background-color 0.15s, color 0.15s; }

.locks-config-btn[aria-expanded="false"] .config-chevron { display: inline-block; transform: rotate(-90deg); }
.locks-config-panel.collapsed { display: none; }

/* Collapsed = compact icon rail (hover an icon for its label tooltip).
   On phones it still fully hides so it doesn't steal screen width. */
body.sidebar-collapsed #sidebar { width: 56px !important; }
body.sidebar-collapsed #sidebar h2,
body.sidebar-collapsed #sidebar-search,
body.sidebar-collapsed #sidebar-search-results,
body.sidebar-collapsed #main-nav .nav-section-header,
body.sidebar-collapsed #main-nav .nav-subgroup-header,
body.sidebar-collapsed #main-nav .nav-subnav-divider,
body.sidebar-collapsed #locks-sidebar { display: none !important; }
body.sidebar-collapsed #main-nav [id$="-subnav"] { display: none !important; }
body.sidebar-collapsed #main-nav .section-btn.nav-item > span { display: none; }
body.sidebar-collapsed #main-nav .section-btn.nav-item {
  justify-content: center;
  padding-left: 0;
  padding-right: 0;
  gap: 0;
}
body.sidebar-collapsed #main-nav .section-btn.nav-item:hover { transform: none; }
@media (max-width: 767px) {
  body.sidebar-collapsed #sidebar { display: none; }
}

/* ── Sticky sidebar (Modules) ─────────────────────────────────────────────
   Keep the Modules nav in view while the main column scrolls. Only at md+,
   where the sidebar is a left column; below 768px the layout stacks (flex-
   col) and a sticky sidebar would pin a full-width block over the content.
   align-self:flex-start stops the flex row from stretching the aside to the
   full container height — a stretched flex item fills its container and so
   never gets the slack it needs to "stick". max-height + overflow-y let a
   tall nav scroll internally instead of clipping its lower items once pinned.
   Offset by the shared --app-header-h (synced in app.js) so it parks just
   under the global header; the literal fallback covers first paint. */
@media (min-width: 768px) {
  #sidebar {
    position: sticky;
    top: var(--app-header-h, 64px);
    align-self: flex-start;
    max-height: calc(100vh - var(--app-header-h, 64px) - 1rem);
    overflow-y: auto;
  }
}

/* ── Mobile layout safeguards ──────────────────────────────────────
   Browsers below 640px get a few global guardrails that prevent the
   most common overflow + crowding patterns we found during the
   chunk-Q audit. Desktop styles stay untouched.
*/
@media (max-width: 639px) {
  /* Every table in a card/section becomes horizontally scrollable
     instead of squashing column text together. Wraps the table in
     a swipeable region without touching markup. */
  section table {
    display: block;
    overflow-x: auto;
    max-width: 100%;
  }
  /* Sub-nav button rows (Dispatch, Forms, Billing, Vessels sub-tabs,
     Maintenance sub-tabs) — make sure they wrap rather than overflow
     the viewport on phone-width screens. */
  section nav.flex,
  section .billing-sub-btn,
  section .vessels-tab-btn,
  section .maint-sub-btn,
  section .disp-sub-btn,
  section .forms-sub-btn {
    flex-wrap: wrap;
  }
}

/* Billing → Kanban List: hover highlight on the interactive barge /
   service rows. Every row is clickable (open card) and draggable (move
   between buckets). The purged Tailwind build ships no hover:bg-slate-*
   utilities, so the row affordance lives here instead. */
.billing-list-row {
  transition: background-color 0.1s ease;
}
.billing-list-row:hover {
  background-color: #f8fafc; /* slate-50 */
}

/* Kanban List declutter: group + row action buttons stay invisible until
   the pointer is over their group/row (or a button inside has focus, so
   keyboard users still reach them). Hover-capable pointers only — the
   iPad has no hover, so buttons stay always-visible there. */
@media (hover: hover) and (pointer: fine) {
  #billing-list .billing-group-actions {
    opacity: 0;
    transition: opacity 0.12s ease;
  }
  /* Row actions collapse to ZERO width when idle (not just transparent),
     so the narrow grid cells give their full width to the barge number /
     service label instead of reserving space for invisible buttons.
     max-width (not display:none) keeps the buttons tabbable so
     focus-within can reveal them for keyboard users. */
  #billing-list .billing-row-acts {
    max-width: 0;
    opacity: 0;
    overflow: hidden;
    transition: opacity 0.12s ease, max-width 0.12s ease;
  }
  #billing-list .billing-customer-group:hover .billing-group-actions,
  #billing-list .billing-customer-group:focus-within .billing-group-actions {
    opacity: 1;
  }
  #billing-list .billing-list-row:hover .billing-row-acts,
  #billing-list .billing-list-row:focus-within .billing-row-acts {
    max-width: 10rem;
    opacity: 1;
  }
}

/* Kanban List rows wrap into a 2-3 wide grid per customer group when the
   bucket has the width (auto-fit re-flows: 3 across on a wide bucket,
   down to 2 then 1 as space shrinks). Hairline top/left borders replace
   the old single-column divide-y separators. */
#billing-list .billing-list-rowgrid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
}
#billing-list .billing-list-rowgrid > .billing-list-row {
  border-top: 1px solid #f1f5f9;  /* slate-100 */
  border-left: 1px solid #f1f5f9;
  margin-left: -1px;              /* collapse doubled column borders */
}

/* Kanban List customer headers fold/expand on click. */
#billing-list .billing-group-hd {
  cursor: pointer;
}
#billing-list .billing-group-hd:hover {
  background-color: #f8fafc; /* slate-50 */
}

/* Kanban List collapsed empty bucket: slim vertical rail. Still a
   drag-drop target; the label reads top-to-bottom. */
#billing-list .billing-list-rail {
  cursor: pointer;
  align-items: center;
}
#billing-list .billing-rail-label {
  writing-mode: vertical-rl;
  padding: 0.6rem 0;
  white-space: nowrap;
}

/* The "$ shown / $ hidden" toolbar chip flips dark when amounts are
   hidden so the muted state is obvious at a glance. */
.billing-list-money-btn.is-money-off {
  background-color: #0f172a; /* slate-900 */
  border-color: #0f172a;
  color: #fff;
}


#table-view.hide-col-lock .col-lock,
#table-view.hide-col-queued .col-queued,
#table-view.hide-col-locking .col-locking,
#table-view.hide-col-refreshed .col-refreshed,
#table-view.hide-col-delay .col-delay,
#table-view.hide-col-single .col-single,
#table-view.hide-col-double .col-double,
#table-view.hide-col-notes .col-notes {
  display: none !important;
}

#map { height: calc(100vh - 220px); min-height: 320px; }

/* Leaflet paints its panes and controls at z-index 400–1000. The map
   container is only position:relative (z-index auto), so it does NOT
   trap those layers — they compete with the sticky global header
   (z-40) in the page root and win, bleeding tiles/markers/zoom
   controls through the header (search bar included) as the map scrolls
   up beneath it. `isolation: isolate` gives the container its own
   stacking context so all of Leaflet's internal z-indexes stay local
   and the whole map sits under the header. */
.leaflet-container { isolation: isolate; }

.lock-marker {
  border-radius: 9999px;
  border: 2px solid white;
  box-shadow: 0 1px 4px rgba(0,0,0,0.4);
  font-weight: 700;
  font-size: 11px;
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  text-shadow: 0 0 2px rgba(0,0,0,0.6);
}

/* Rake barges have a clipped lower-left corner to suggest the angled rake end. */

/* Flipped rake: same notch mirrored to the lower-RIGHT corner, for barges whose
   raked end is shown on the right (toggled via "Flip rake" in the barge editor). */


/* 200'+ rake flag: an asterisk seated in the BOTTOM-LEFT corner of the tile
   rectangle, marking the longer-than-standard (195') rake barges. It's rendered
   on the un-clipped wrapper (see bargeSelectionWrap), so it shows over the
   cut-away rake notch instead of being clipped. The '*' glyph's ink sits high in
   its em box (it ends ~47% down), so bottom:-8px pulls that ink down flush to
   the rectangle's bottom edge at this size; the empty lower part of the line box
   overflows harmlessly below. White halo keeps the dark glyph legible over any
   background; pointer-events:none so it never blocks tile clicks. */

/* Flipped rake → asterisk seats in the BOTTOM-RIGHT corner instead. */


/* Partial-load barges: yellow and gray diagonal stripes. Colors are yellow-400
   and slate-400 (matching the solid Loaded and Empty/clean swatches). */


/* Selected barge highlight — an amber perimeter that traces the tile's
   silhouette. We use stacked drop-shadow() filters instead of box-shadow:
   box-shadow gets clipped away by clip-path, but drop-shadow follows the
   rendered (clipped) shape, so the outline hugs a rake barge's clipped
   corner instead of forcing the tile back to a full rectangle. The rake
   clip-path is now KEPT when selected. */
.barge-selected {
  filter:
    drop-shadow( 2px 0 0 #f59e0b) drop-shadow(-2px 0 0 #f59e0b)
    drop-shadow(0  2px 0 #f59e0b) drop-shadow(0 -2px 0 #f59e0b)
    drop-shadow(0 0 3px #f59e0b);
  position: relative;
  z-index: 20;
}
.barge-selected-targeted {
  filter:
    drop-shadow( 2px 0 0 #d97706) drop-shadow(-2px 0 0 #d97706)
    drop-shadow(0  2px 0 #d97706) drop-shadow(0 -2px 0 #d97706)
    drop-shadow(0 0 3px #b45309);
  position: relative;
  z-index: 20;
}
/* Dock-order-due-soon highlight — a RED perimeter, half the thickness of the
   amber selection ring (1px offsets vs 2px), flagging a barge that has an open
   dock order scheduled within the next 12 hours (see bargeHasImminentDockOrder).
   Same drop-shadow technique as .barge-selected so it traces a rake barge's
   clipped silhouette and survives clip-path. When a due-soon barge is ALSO
   selected, this ring sits on the OUTER wrapper (see bargeSelectionWrap) so the
   thin red line shows just outside the amber selection ring. */
.barge-dock-due {
  filter:
    drop-shadow( 1px 0 0 #dc2626) drop-shadow(-1px 0 0 #dc2626)
    drop-shadow(0  1px 0 #dc2626) drop-shadow(0 -1px 0 #dc2626)
    drop-shadow(0 0 1.5px #dc2626);
  position: relative;
  z-index: 19;
}

/* Tow-order list barge tiles (board-style grid): the cell wraps a live board
   tile, stays draggable onto another order's card, and reveals the ⋮ move
   handle on hover. The red "D" badge flags a DAMAGED barge without needing a
   hover; full damage/cover detail stays in the tooltip. Badges sit just
   outside the tile rectangle, so the cell must not clip overflow. */
.tow-tile-cell { position: relative; display: inline-flex; cursor: grab; }

.tow-tile-move {
  position: absolute; top: -6px; left: -5px; z-index: 50;
  width: 16px; height: 16px; line-height: 13px; text-align: center;
  background: #fff; color: #475569; border: 1px solid #cbd5e1;
  border-radius: 9999px; font-size: 11px; font-weight: 700;
  cursor: pointer; padding: 0; opacity: 0; transition: opacity .12s;
}
.tow-tile-cell:hover .tow-tile-move,
.tow-tile-move:focus-visible { opacity: 1; }
/* Tow-order "Cancel Order" row button — rose outline with a hover tint the
   purged Tailwind build doesn't carry (no rose hover utilities exist). */
.disp-tow-cancelorder:hover { background: #fff1f2; }

/* Drag-to-reorder barges within a vessel / tow-order card grid (app.js
   wireBargeGridReorder). Each tile is wrapped in a .barge-sort-item grid cell;
   display:flex keeps the fixed-size tile flush in the cell (no inline gap).
   touch-action:none lets the pointer drag work on the iPads instead of the
   browser stealing the gesture for a page scroll. Only items with a resolvable
   barge id (data-barge-rec-id) are draggable; pending external pickups aren't. */
.barge-sort-item { display: flex; }
.barge-sort-item[data-barge-rec-id] { cursor: grab; touch-action: none; }
.barge-sort-item.barge-sort-dragging { opacity: 0.4; cursor: grabbing; z-index: 40; }
.barge-sort-grid.barge-sort-active { cursor: grabbing; }

/* ── App-wide refinements: modern typography + softer surfaces ─────────── */

:root {
  --accent:        #0284c7;   /* sky-600 — refined water-themed accent */
  --accent-soft:   #38bdf8;   /* sky-400 */
  --accent-glow:   rgba(2, 132, 199, 0.18);
  --surface:       #ffffff;
  --surface-warm:  #fafaf9;   /* stone-50 */
  --surface-warm2: #f5f5f4;   /* stone-100 */
  --ink-strong:    #1e293b;   /* slate-800 */
  --ink:           #334155;   /* slate-700 */
  --ink-soft:      #64748b;   /* slate-500 */
  --hairline:      rgba(15, 23, 42, 0.06);
}

html {
  font-feature-settings: "cv02", "cv03", "cv04", "cv11", "tnum";
}

body {
  font-family: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  background:
    radial-gradient(900px  600px at  -5%   0%, rgba(56, 189, 248, 0.18), transparent 60%),  /* sky */
    radial-gradient(800px  600px at 105% 10%, rgba(139, 92, 246, 0.14), transparent 55%),  /* violet */
    radial-gradient(900px  700px at  50% 110%, rgba(16, 185, 129, 0.10), transparent 55%), /* emerald */
    linear-gradient(180deg, #fafaf9 0%, #fef3c7 200%);
  background-attachment: fixed;
}

.font-mono, code, pre,
[class*="font-mono"] {
  font-family: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
  font-feature-settings: "tnum", "zero", "ss01";
}

h1, h2, h3, h4 { letter-spacing: -0.01em; }
h1 { font-weight: 600; }
h2, h3 { font-weight: 600; }

/* Card surfaces: bigger radius, softer layered shadow, hairline edge. */
.bg-white.shadow.rounded,
.bg-white.shadow.rounded-lg,
.bg-white.shadow-xl.rounded-lg {
  border-radius: 14px;
  border: 1px solid var(--hairline);
  box-shadow:
    0 1px 2px rgba(15, 23, 42, 0.04),
    0 12px 32px -16px rgba(15, 23, 42, 0.12);
  background: var(--surface);
}
.bg-white.shadow {
  background: var(--surface);
}

/* Inner containers (forms, lists inside cards) feel a touch softer. */
input, select, textarea {
  border-radius: 8px !important;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent) !important;
  box-shadow: 0 0 0 3px var(--accent-glow) !important;
}

/* Buttons: more breathing room, gentle elevation. */
button,
a.rounded {
  transition:
    background-color 0.15s ease,
    border-color 0.15s ease,
    box-shadow 0.15s ease,
    transform 0.06s ease;
}
button.rounded,
a.rounded { border-radius: 10px; }

button:active:not(:disabled),
a.rounded:active { transform: translateY(0.5px) scale(0.99); }

/* Primary dark buttons get a subtle inner highlight. */
button.bg-slate-900,
a.bg-slate-900 {
  background-image: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(0,0,0,0));
  box-shadow:
    0 1px 0 rgba(255,255,255,0.06) inset,
    0 1px 2px rgba(15, 23, 42, 0.18);
}
button.bg-slate-900:hover,
a.bg-slate-900:hover {
  box-shadow:
    0 1px 0 rgba(255,255,255,0.08) inset,
    0 4px 12px -4px rgba(15, 23, 42, 0.22);
}

/* Accent-colored sky buttons (already used) — keep harmonious. */
button.bg-sky-600,
button.bg-sky-700,
a.bg-sky-600 {
  background-image: linear-gradient(180deg, rgba(255,255,255,0.08), rgba(0,0,0,0));
}

/* Sidebar nav items: smoother hover. */
.section-btn,
.su-sub-btn,
.disp-sub-btn,
.emp-sub-btn,
.locks-config-btn {
  transition: background-color 0.12s ease, color 0.12s ease, border-left-color 0.12s ease;
  border-radius: 8px !important;
  border-left: 3px solid transparent;
}
.section-btn:hover  { border-left-color: rgba(2, 132, 199, 0.3); }

/* Per-section accent — colored left bar + active-state tint. */
.section-btn[data-section="home"]            { border-left-color: rgba(2, 132, 199, 0.7);  } /* sky */
.section-btn[data-section="fleet-board"]     { border-left-color: rgba(16, 185, 129, 0.7); } /* emerald */
.section-btn[data-section="locks"]           { border-left-color: rgba(245, 158, 11, 0.7); } /* amber */
.section-btn[data-section="vessels"]         { border-left-color: rgba(99, 102, 241, 0.7); } /* indigo */
.section-btn[data-section="dispatch"]        { border-left-color: rgba(244, 63, 94, 0.7);  } /* rose */
.section-btn[data-section="employees"]       { border-left-color: rgba(139, 92, 246, 0.7); } /* violet */
.section-btn[data-section="system-utility"]  { border-left-color: rgba(20, 184, 166, 0.7); } /* teal */

/* Active section: switch background to that section's accent gradient. */
.section-btn[data-section="home"].bg-slate-900           { background: linear-gradient(135deg, #0284c7, #0369a1); }
.section-btn[data-section="fleet-board"].bg-slate-900    { background: linear-gradient(135deg, #10b981, #047857); }
.section-btn[data-section="locks"].bg-slate-900          { background: linear-gradient(135deg, #f59e0b, #b45309); }
.section-btn[data-section="vessels"].bg-slate-900        { background: linear-gradient(135deg, #6366f1, #4338ca); }
.section-btn[data-section="dispatch"].bg-slate-900       { background: linear-gradient(135deg, #f43f5e, #be123c); }
.section-btn[data-section="employees"].bg-slate-900      { background: linear-gradient(135deg, #8b5cf6, #6d28d9); }
.section-btn[data-section="system-utility"].bg-slate-900 { background: linear-gradient(135deg, #14b8a6, #0f766e); }
.section-btn.bg-slate-900 {
  box-shadow: 0 1px 0 rgba(255,255,255,0.1) inset, 0 4px 12px -4px currentColor;
}

/* Sub-nav active state gets a softer color tint. */
.su-sub-btn.bg-slate-200,
.disp-sub-btn.bg-slate-200,
.emp-sub-btn.bg-slate-200 {
  background: linear-gradient(90deg, rgba(2, 132, 199, 0.12), rgba(99, 102, 241, 0.08));
  color: #0c4a6e !important;
}

/* Slight glow under the header. */
header.shadow,
header.shadow-sm {
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 8px 24px -16px rgba(15, 23, 42, 0.4);
}

/* Smoother table-row hover. */
#rows td { transition: background-color 0.12s ease; }
#rows tr:hover td { background-color: rgba(2, 132, 199, 0.04); }

/* Pills + small badges feel softer. */
.delay-pill, .text-\[10px\].rounded {
  border-radius: 999px;
}

/* Empty/idle text feels a hair lighter for visual hierarchy. */
.text-slate-500 { color: var(--ink-soft); }
.text-slate-400 { color: rgba(100, 116, 139, 0.7); }

/* ── Colorful module accents ─────────────────────────────────────────── */

/* Section cards get a colored top stripe matched to their module. */
#fleet-board-section .bg-white.shadow.rounded:first-child {
  background-image:
    linear-gradient(90deg, #10b981 0%, #10b981 100%),
    none;
  background-size: 100% 3px, auto;
  background-repeat: no-repeat;
  background-position: top left, 0 0;
}
#locks-section .bg-white.shadow.rounded:first-child,
#table-view {
  background-image: linear-gradient(90deg, #f59e0b 0%, #f59e0b 100%);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: top left;
}
#vessels-section .bg-white.shadow.rounded:first-child {
  background-image: linear-gradient(90deg, #6366f1 0%, #6366f1 100%);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: top left;
}
#dispatch-section .bg-white.shadow.rounded {
  background-image: linear-gradient(90deg, #f43f5e 0%, #fb7185 100%);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: top left;
}
#employees-section .bg-white.shadow.rounded:first-child {
  background-image: linear-gradient(90deg, #8b5cf6 0%, #8b5cf6 100%);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: top left;
}
#system-utility-section .bg-white.shadow.rounded {
  background-image: linear-gradient(90deg, #14b8a6 0%, #14b8a6 100%);
  background-size: 100% 3px;
  background-repeat: no-repeat;
  background-position: top left;
}

/* Delay pills get more saturation. */
.delay-green  {
  background: linear-gradient(135deg, #d1fae5, #a7f3d0);
  color: #065f46;
  box-shadow: inset 0 0 0 1px rgba(5, 150, 105, 0.18);
}
.delay-yellow {
  background: linear-gradient(135deg, #fef3c7, #fde68a);
  color: #92400e;
  box-shadow: inset 0 0 0 1px rgba(180, 83, 9, 0.18);
}
.delay-red    {
  background: linear-gradient(135deg, #fee2e2, #fecaca);
  color: #991b1b;
  box-shadow: inset 0 0 0 1px rgba(185, 28, 28, 0.18);
}
.delay-none   {
  background: linear-gradient(135deg, #f1f5f9, #e2e8f0);
  color: #475569;
}

/* Sub-headers within sections get tinted background tags. */
[id^="su-card-"] h2,
[id^="disp-card-"] h2 {
  display: inline-block;
  background: linear-gradient(135deg, rgba(2, 132, 199, 0.10), rgba(99, 102, 241, 0.08));
  color: #0c4a6e;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  margin-bottom: 0.25rem;
}

/* Primary buttons stay dark but get a subtle blue under-glow. */
button.bg-slate-900,
a.bg-slate-900 {
  background-image: linear-gradient(135deg, #1e293b 0%, #0f172a 100%);
  box-shadow:
    0 1px 0 rgba(255,255,255,0.08) inset,
    0 2px 6px -1px rgba(2, 132, 199, 0.25);
}
button.bg-slate-900:hover,
a.bg-slate-900:hover {
  background-image: linear-gradient(135deg, #334155 0%, #1e293b 100%);
  box-shadow:
    0 1px 0 rgba(255,255,255,0.12) inset,
    0 6px 18px -4px rgba(2, 132, 199, 0.35);
}

/* Status/kind pill chips throughout — bump saturation. */
.bg-emerald-100 { background: linear-gradient(135deg, #d1fae5, #a7f3d0) !important; }
.bg-sky-100     { background: linear-gradient(135deg, #e0f2fe, #bae6fd) !important; }
.bg-amber-100   { background: linear-gradient(135deg, #fef3c7, #fde68a) !important; }
.bg-rose-100    { background: linear-gradient(135deg, #ffe4e6, #fecdd3) !important; }
.bg-purple-100  { background: linear-gradient(135deg, #ede9fe, #ddd6fe) !important; }

/* Header subtle shimmer line at the bottom. */
header.shadow,
header.shadow-sm {
  border-bottom: 1px solid rgba(56, 189, 248, 0.25);
}

/* Invoice preview: force a page break between per-barge sections so a
   single Print dialog produces one printed page per invoice. */
.print-page-break {
  break-after: page;
  page-break-after: always;
  height: 0;
}
@media print {
  /* Hide everything by default; reveal only the invoice / statement /
     supply-request modal contents. Without this every part of the app
     (sidebar, header, kanban, etc.) prints alongside the document. */
  body * { visibility: hidden !important; }
  #invoice-preview-modal,
  #invoice-preview-modal *,
  #statement-modal,
  #statement-modal *,
  body.printing-supply-request #supply-request-modal,
  body.printing-supply-request #supply-request-modal *,
  body.printing-supply-request #first-aid-request-modal,
  body.printing-supply-request #first-aid-request-modal *,
  body.printing-supply-request #spill-kit-request-modal,
  body.printing-supply-request #spill-kit-request-modal *,
  body.printing-crew-schedule #crew-sched-print-modal,
  body.printing-crew-schedule #crew-sched-print-modal * { visibility: visible !important; }

  /* Lift the modal out of its fixed-position overlay so it occupies
     the full printable area. Drop the dark backdrop + max-width so
     the document fills the page edge-to-edge. */
  #invoice-preview-modal,
  #statement-modal,
  body.printing-supply-request #supply-request-modal,
  body.printing-supply-request #first-aid-request-modal,
  body.printing-supply-request #spill-kit-request-modal,
  body.printing-crew-schedule #crew-sched-print-modal {
    position: absolute !important;
    inset: 0 !important;
    background: white !important;
    padding: 0 !important;
    overflow: visible !important;
  }
  #invoice-preview-modal > div,
  #statement-modal > div,
  body.printing-supply-request #supply-request-modal > div,
  body.printing-supply-request #first-aid-request-modal > div,
  body.printing-supply-request #spill-kit-request-modal > div,
  body.printing-crew-schedule #crew-sched-print-modal > div {
    box-shadow: none !important;
    max-width: none !important;
    margin: 0 !important;
    border-radius: 0 !important;
  }
  /* Hide the modal's chrome (header buttons, picker inputs) when
     printing — only the generated calendar pages should make it to
     paper. Each calendar page wrap also forces a page break so the
     next month / next schedule starts on a fresh sheet. */
  body.printing-crew-schedule .no-print { display: none !important; }
  body.printing-crew-schedule .crew-print-page { page-break-after: always; }
  body.printing-crew-schedule .crew-print-page:last-child { page-break-after: auto; }
  /* Letter-landscape page sizing + tight cells so a full month fits
     on one sheet. The @page rule (size: letter landscape, 0.3in
     margins) is injected by JS right before window.print() so it
     doesn't interfere with the invoice / statement / supply print
     paths that want portrait letter. Math at 0.3" margins:
       usable area  ≈ 10.4" × 7.9"
       page title   ≈ 0.25"
       day-of-week  ≈ 0.16"
       grid (6 rows) ≈ 1.20" × 6 = 7.20"
       total         ≈ 7.61" (fits with margin)
     Each day cell holds: day# + 3 shift blocks (D/N/Off). Each
     shift block is 1 captain line + 0–N deckhand lines (pair packed
     per line). Typical 4-person crew → 1 captain + 2 deckhand lines
     = 3 lines × 3 blocks = 9 lines + day# = 10 lines per cell.
     At 7pt with 1.1 line-height ≈ 0.10" per line → 1.0" of text +
     0.05" padding × 2 = ~1.10", fits the 1.20" cell with breathing
     room. */
  body.printing-crew-schedule #crew-sched-print-body { padding: 0 !important; }
  body.printing-crew-schedule .crew-print-page { margin: 0 !important; padding: 0 !important; }
  /* Only the actual day cells get a fixed height — the day-of-week
     header (.crew-print-dow) stays auto-height. */
  body.printing-crew-schedule .crew-print-grid > .cell-day {
    min-height: 0 !important;
    height: 1.20in;
    overflow: hidden;
    padding: 2pt 3pt !important;
  }
  body.printing-crew-schedule .crew-print-page { font-size: 7pt; line-height: 1.15; }
  body.printing-crew-schedule .crew-print-page h3 { font-size: 11pt !important; }
  body.printing-crew-schedule .crew-print-page .text-\[10px\] { font-size: 7pt !important; }
  body.printing-crew-schedule .crew-print-page .text-\[9px\]  { font-size: 6.5pt !important; }
  body.printing-crew-schedule .crew-print-page .shift-block { margin-top: 1pt; }
  /* Screen-mode preview — give day cells a comfortable height so the
     modal's preview reads, but not so tall the user thinks the print
     output will overflow. */
  body:not(.printing-crew-schedule) .crew-print-grid > .cell-day {
    min-height: 100px;
  }
  /* Hide the chrome of the supply-request modal — header buttons +
     action buttons. The body stays so the printed sheet matches the
     paper form: vessel/status header, item table, other-items table,
     notes, and the signoff stamps. */
  body.printing-supply-request .supply-print-hide { display: none !important; }
  body.printing-supply-request .supply-print-scope input,
  body.printing-supply-request .supply-print-scope select,
  body.printing-supply-request .supply-print-scope textarea {
    border: none !important;
    background: transparent !important;
    -webkit-appearance: none !important;
    appearance: none !important;
    padding: 0 !important;
  }

}

/* Dock-order grid cards — each row produced by makeCrudModule sits in
   one cell of the responsive grid set on #disp-dockorder-list. Give
   the cells a border + padding so they read as discrete cards
   instead of a tabular row. The override here is scoped to the
   dock-order list so the other CRUD lists (which still use
   divide-y) keep their current look. */
#disp-dockorder-list > div {
  border: 1px solid rgb(226 232 240); /* slate-200 */
  border-radius: 0.375rem;            /* rounded */
  padding: 0.5rem 0.75rem;
  background: white;
}
/* Vessels list: per-boat shift-start mode (deck log required or not). */
.vsl-shift-pill { font-size: 10px; font-weight: 600; padding: 1px 8px; border-radius: 999px; background: rgb(204 251 241); color: rgb(15 118 110); }
.vsl-shift-pill.off { background: rgb(254 243 199); color: rgb(146 64 14); }

/* Permissions → Library documents: who can see each Library document. */
.plv-scroll { overflow-x: auto; border: 1px solid rgb(226 232 240); border-radius: 0.375rem; }
.plv-table { border-collapse: separate; border-spacing: 0; font-size: 12px; min-width: 100%; }
.plv-table th, .plv-table td { padding: 4px 6px; border-bottom: 1px solid rgb(241 245 249); text-align: center; vertical-align: middle; background: white; }
.plv-table .plv-doc { text-align: left; position: sticky; left: 0; z-index: 1; min-width: 14rem; max-width: 18rem; border-right: 1px solid rgb(226 232 240); }
.plv-table thead th { position: sticky; top: 0; z-index: 2; vertical-align: bottom; background: rgb(248 250 252); }
.plv-table thead th.plv-doc { z-index: 3; }
.plv-colhd span { display: inline-block; writing-mode: vertical-rl; transform: rotate(180deg); max-height: 150px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; font-size: 10px; font-weight: 600; color: rgb(71 85 105); }
.plv-colbtn { background: none; border: 0; padding: 0; cursor: pointer; }
.plv-colbtn:hover span { color: rgb(15 23 42); text-decoration: underline; }
.plv-docname { background: none; border: 0; padding: 0; cursor: pointer; font-weight: 600; color: rgb(30 41 59); text-align: left; }
.plv-docname:hover { text-decoration: underline; }
.plv-who { font-size: 10px; color: rgb(100 116 139); }
.plv-sec td { background: rgb(241 245 249) !important; text-align: left !important; font-size: 10px; letter-spacing: .06em; text-transform: uppercase; font-weight: 700; color: rgb(71 85 105); }
.plv-row.dirty td { background: rgb(255 251 235); }
.plv-cell { width: 22px; height: 22px; border-radius: 5px; border: 1px solid rgb(203 213 225); background: white; cursor: pointer; font-size: 12px; line-height: 1; color: white; }
.plv-cell.on { background: rgb(15 118 110); border-color: rgb(15 118 110); }
.plv-cell.inherit { background: rgb(204 251 241); border-color: rgb(153 246 228); }
.plv-cell.every.on { background: rgb(2 132 199); border-color: rgb(2 132 199); }
.plv-cell:hover { outline: 2px solid rgb(148 163 184); outline-offset: 1px; }

/* Locks page: Refresh + feed age at the right end of the view tab row. */
#locks-subnav { flex-wrap: wrap; align-items: flex-end; }
#locks-subnav .locks-refresh-bar {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding-bottom: 0.25rem;
}
#locks-subnav .locks-feed-age { font-size: 0.75rem; color: rgb(203 213 225); white-space: nowrap; }
#locks-subnav .locks-feed-age.is-stale { color: rgb(253 186 116); }
#locks-refresh[disabled] { opacity: 0.6; cursor: progress; }
#locks-refresh[disabled] svg { animation: locks-refresh-spin 0.9s linear infinite; }
@keyframes locks-refresh-spin { to { transform: rotate(360deg); } }

/* By-dock layout: dock header rows between the order cards. */
#disp-dockorder-list > div.do-dock-group {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 0.5rem;
  background: rgb(241 245 249);       /* slate-100 */
  font-size: 0.875rem;
  font-weight: 600;
  color: rgb(30 41 59);               /* slate-800 */
  margin-top: 0.5rem;
}
#disp-dockorder-list > div.do-dock-group:first-child { margin-top: 0; }

/* Invoice header row: BILL TO (left) + EQUIPMENT list (right). Bill To
   keeps its natural width (never below a readable floor); the equipment
   column is capped and its comma list wraps, so a 30-barge invoice no
   longer runs off the right edge or squeezes Bill To to one word a line.
   Short lists are narrower than the cap and render exactly as before. */
.inv-hdr-row {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 24px;
}
.inv-hdr-billto {
  flex: 1 1 auto;
  min-width: 14rem;
}
.inv-hdr-equip {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 55%;
}
.inv-equip-list { overflow-wrap: anywhere; }
/* Break only after the commas — never inside "ART 2433". */
.inv-equip-num { white-space: nowrap; }

@media print {
  /* Keep each per-barge invoice on its own page; never split a single
     invoice's table across pages mid-row. */
  .invoice-section {
    page-break-inside: avoid;
    padding-top: 0.25in;
  }
  table { page-break-inside: auto; }
  tr    { page-break-inside: avoid; page-break-after: auto; }

  /* Letter-size page margins. The browser dialog also offers margin
     controls; these are sensible defaults if the user accepts them. */
  @page { size: letter; margin: 0.5in; }
}

/* ── Dark mode overrides ──────────────────────────────────────────────
   The CDN build of Tailwind doesn't ship `dark:` variants for the
   thousands of existing class strings in this app, and retrofitting
   them would mean touching ~every template. Instead, we flip the
   highest-frequency utility colors via CSS overrides scoped under
   html.dark. Covers ~90% of the UI; specific elements that look off
   in dark mode get one-off rules added below.

   Boot order: index.html's <head> script reads localStorage['theme']
   and sets <html class="dark"> BEFORE first paint, so there's no
   white-flash on a dark-mode reload. The header toggle in app.js
   flips the class + persists the choice.

   Color palette mapping (light → dark):
     bg-white      → slate-900     (page-card background)
     bg-stone-50   → slate-950     (body background)
     bg-slate-50   → slate-800     (subtle panels, table headers)
     bg-slate-100  → slate-800
     bg-slate-200  → slate-700
     text-slate-900→ slate-100     (main text)
     text-slate-800→ slate-200
     text-slate-700→ slate-300
     text-slate-600→ slate-400
     text-slate-500→ slate-400     (mid stays mid)
     text-slate-400→ slate-500
     border-slate-200/300 → slate-700
   Accent colors (emerald/amber/rose/sky/indigo) stay as-is — they
   read fine on a dark background. The header gradient also stays as-
   is (it was already dark in light mode).
   ────────────────────────────────────────────────────────────────── */

html.dark body                          { background-color: rgb(2 6 23);    color: rgb(203 213 225); }   /* slate-950, slate-300 */

html.dark .bg-white                     { background-color: rgb(15 23 42) !important; }                  /* slate-900 */
html.dark .bg-stone-50                  { background-color: rgb(2 6 23) !important; }                    /* slate-950 */
html.dark .bg-slate-50                  { background-color: rgb(30 41 59) !important; }                  /* slate-800 */
html.dark .bg-slate-100                 { background-color: rgb(30 41 59) !important; }                  /* slate-800 */
html.dark .bg-slate-200                 { background-color: rgb(51 65 85) !important; }                  /* slate-700 */
html.dark .bg-emerald-50                { background-color: rgb(6 78 59 / 0.4) !important; }
html.dark .bg-amber-50                  { background-color: rgb(120 53 15 / 0.4) !important; }
html.dark .bg-rose-50                   { background-color: rgb(136 19 55 / 0.4) !important; }
html.dark .bg-sky-50                    { background-color: rgb(7 89 133 / 0.4) !important; }
html.dark .bg-indigo-50                 { background-color: rgb(49 46 129 / 0.4) !important; }

html.dark .text-slate-900               { color: rgb(241 245 249) !important; }                          /* slate-100 */
html.dark .text-slate-800               { color: rgb(226 232 240) !important; }                          /* slate-200 */
html.dark .text-slate-700               { color: rgb(203 213 225) !important; }                          /* slate-300 */
html.dark .text-slate-600               { color: rgb(148 163 184) !important; }                          /* slate-400 */
html.dark .text-slate-500               { color: rgb(148 163 184) !important; }
html.dark .text-slate-400               { color: rgb(100 116 139) !important; }                          /* slate-500 */
html.dark .text-black                   { color: rgb(241 245 249) !important; }

html.dark .border-slate-100             { border-color: rgb(51 65 85) !important; }                      /* slate-700 */
html.dark .border-slate-200             { border-color: rgb(51 65 85) !important; }
html.dark .border-slate-300             { border-color: rgb(71 85 105) !important; }                     /* slate-600 */

/* Cards (the universal `.shadow.rounded` pattern from earlier in this
   file) get a softer dark background + a subtle slate border so they
   don't blend into the body. */
html.dark .shadow.rounded               { background-color: rgb(15 23 42); border-color: rgb(51 65 85); }
html.dark .shadow-lg                    { box-shadow: 0 10px 15px -3px rgba(0,0,0,0.4), 0 4px 6px -4px rgba(0,0,0,0.4); }
html.dark .shadow                       { box-shadow: 0 4px 6px -1px rgba(0,0,0,0.4), 0 2px 4px -2px rgba(0,0,0,0.4); }

/* Form inputs: light-mode default is white with slate-300 border, which
   inverts poorly. Give inputs a clear dark surface so the user can see
   them against the card background. */
html.dark input[type="text"],
html.dark input[type="search"],
html.dark input[type="email"],
html.dark input[type="password"],
html.dark input[type="number"],
html.dark input[type="date"],
html.dark input[type="datetime-local"],
html.dark input[type="time"],
html.dark input[type="tel"],
html.dark input[type="url"],
html.dark textarea,
html.dark select {
  background-color: rgb(30 41 59);
  border-color: rgb(71 85 105);
  color: rgb(241 245 249);
}
html.dark input::placeholder,
html.dark textarea::placeholder         { color: rgb(100 116 139); }

/* Barge Cleaning form: Date + Start time + Stop time share one row on
   >= sm. A dedicated rule because the static Tailwind build doesn't ship
   sm:grid-cols-3 (only sm:grid-cols-2 is used elsewhere, so only that one
   got compiled). Mirrors `grid grid-cols-1 sm:grid-cols-3 gap-3`. */
.bcf-datetime-row { display: grid; grid-template-columns: 1fr; gap: 0.75rem; }
@media (min-width: 640px) {
  .bcf-datetime-row { grid-template-columns: repeat(3, 1fr); }
}

/* The popover dropdowns (vessel search, dock-order barge picker, etc.)
   have inline white-card styling that needs a dark equivalent. */
html.dark .sp-panel                    { background-color: rgb(30 41 59); border-color: rgb(71 85 105); color: rgb(226 232 240); }
html.dark .sp-item:hover               { background-color: rgb(51 65 85); }
html.dark .sp-item.bg-slate-100        { background-color: rgb(51 65 85) !important; }

/* Pills + status dots — the .pill-* helpers in this file's earlier
   block use light-mode pastel backgrounds. Knock the saturation down
   and shift the text to a lighter shade so they read on dark. */
html.dark .pill-dot                     { background-color: rgba(255,255,255,0.06); border-color: rgba(255,255,255,0.10); }
html.dark .pill-amber                   { color: rgb(252 211 77); }    /* amber-300 */
html.dark .pill-emerald                 { color: rgb(110 231 183); }   /* emerald-300 */
html.dark .pill-rose                    { color: rgb(253 164 175); }   /* rose-300 */
html.dark .pill-sky                     { color: rgb(125 211 252); }   /* sky-300 */
html.dark .pill-slate                   { color: rgb(203 213 225); }   /* slate-300 */
html.dark .pill-indigo                  { color: rgb(165 180 252); }   /* indigo-300 */

/* Print should always render in light mode regardless of toggle state
   — paper is white. Force the body + cards back to light values so
   the invoice PDF preview / print path doesn't go dark-on-dark. */
@media print {
  html.dark body                        { background-color: white; color: black; }
  html.dark .bg-white,
  html.dark .bg-slate-50,
  html.dark .bg-slate-100               { background-color: white !important; }
  html.dark .text-slate-900,
  html.dark .text-slate-800,
  html.dark .text-slate-700             { color: black !important; }
}

/* ── Action buttons (Edit / Delete / Duplicate / Archive / Reactivate) ──
   Renderer functions across the app produce small action buttons in the
   footer of entity cards / rows. Historically these were styled as text
   links; this gives them a real-button look. Add `.btn-act` plus a kind
   modifier (`.btn-act--edit`, etc.) to any button to opt in. */
.btn-act {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.75rem;
  line-height: 1rem;
  font-weight: 500;
  padding: 0.25rem 0.625rem;
  border-radius: 0.3125rem;
  border: 1px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 90ms ease, border-color 90ms ease, color 90ms ease;
}
.btn-act:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 1px; }

.btn-act--edit       { background:#f1f5f9; color:#1e293b; border-color:#cbd5e1; }
.btn-act--edit:hover { background:#e2e8f0; color:#0f172a; border-color:#64748b; }

.btn-act--del       { background:#fef2f2; color:#be123c; border-color:#fda4af; }
.btn-act--del:hover { background:#fecaca; color:#9f1239; border-color:#f43f5e; }

.btn-act--dup       { background:#f0f9ff; color:#075985; border-color:#7dd3fc; }
.btn-act--dup:hover { background:#bae6fd; color:#0c4a6e; border-color:#0284c7; }

.btn-act--archive       { background:#fffbeb; color:#92400e; border-color:#fcd34d; }
.btn-act--archive:hover { background:#fde68a; color:#78350f; border-color:#d97706; }

.btn-act--unarchive       { background:#ecfdf5; color:#065f46; border-color:#6ee7b7; }
.btn-act--unarchive:hover { background:#a7f3d0; color:#064e3b; border-color:#059669; }

/* Cancel — subdued ghost button so it visibly reads as a button without
   competing with the primary submit action it sits next to. */
.btn-act--cancel       { background:#ffffff; color:#475569; border-color:#cbd5e1; }
.btn-act--cancel:hover { background:#f1f5f9; color:#1e293b; border-color:#94a3b8; }

/* Dark-mode variants — pair each surface with its dark counterpart so the
   buttons stay legible on dark cards. */
html.dark .btn-act--edit       { background:#334155; color:#e2e8f0; border-color:#475569; }
html.dark .btn-act--edit:hover { background:#475569; color:#f8fafc; border-color:#64748b; }
html.dark .btn-act--del       { background:#3f1d24; color:#fecaca; border-color:#9f1239; }
html.dark .btn-act--del:hover { background:#5a232c; color:#fee2e2; border-color:#e11d48; }
html.dark .btn-act--dup       { background:#0c2a3d; color:#bae6fd; border-color:#075985; }
html.dark .btn-act--dup:hover { background:#0e3553; color:#e0f2fe; border-color:#0284c7; }
html.dark .btn-act--archive       { background:#3a2410; color:#fde68a; border-color:#92400e; }
html.dark .btn-act--archive:hover { background:#4a2e15; color:#fef3c7; border-color:#d97706; }
html.dark .btn-act--unarchive       { background:#0d2e22; color:#a7f3d0; border-color:#065f46; }
html.dark .btn-act--unarchive:hover { background:#11402f; color:#d1fae5; border-color:#059669; }
html.dark .btn-act--cancel       { background:#1e293b; color:#cbd5e1; border-color:#475569; }
html.dark .btn-act--cancel:hover { background:#334155; color:#f1f5f9; border-color:#64748b; }

/* ── Barge quick-edit popover (Fleet Diagram) — modernized card ────────────
   Colors live here (not Tailwind classes) because tailwind.css is a purged
   ahead-of-time build; arbitrary shades/variants wouldn't survive the purge.
   The card is always white (it doesn't follow dark mode), so light fills are
   safe in both modes. Controls are plain checkboxes (2×2 groups). */
#barge-hover-popover.bhp-card { border-radius:14px; overflow:hidden; }
.bhp-header { background:#b5d4f4; padding:10px 14px; }
.bhp-title-input { font-family:"JetBrains Mono",ui-monospace,monospace; font-weight:600; font-size:17px; color:#042c53; background:transparent; border:0; padding:0; width:100%; outline:none; }
.bhp-title-input::placeholder { color:#185fa5; opacity:.55; }
.bhp-subtitle { font-size:11px; color:#185fa5; line-height:1.25; min-height:13px; }
.bhp-body { padding:12px 14px 14px; }
.bhp-lab { display:block; font-size:10px; text-transform:uppercase; letter-spacing:.04em; color:#94a3b8; margin-bottom:5px; }
.bhp-input { width:100%; padding:7px 9px; font-size:13px; color:#0f172a; background:#fff; border:1px solid #cbd5e1; border-radius:8px; outline:none; transition:border-color .13s,box-shadow .13s; }
.bhp-input:focus { border-color:#185fa5; box-shadow:0 0 0 2px rgba(24,95,165,.18); }
.bhp-si-add-opt:hover { background:#f1f5f9; }
/* Fleet-board filter: non-matching barge tiles dim out (visual only). */
.barge-filtered-out { opacity:.25; transition:opacity .12s; }
/* Tow orders: highlight the card a dragged barge is hovering over. */
.tow-drop-hot { outline:2px dashed #2563eb; outline-offset:2px; box-shadow:0 0 0 4px rgba(37,99,235,.12); }
/* Barge search: flash a ring around the tile you jumped to. */
.barge-search-flash { position:relative; z-index:60; animation:bargeSearchFlash .7s ease-in-out 3; }
@keyframes bargeSearchFlash {
  0%,100% { box-shadow:0 0 0 2px #2563eb, 0 0 0 6px rgba(37,99,235,.30); }
  50%     { box-shadow:0 0 0 3px #2563eb, 0 0 0 11px rgba(37,99,235,.45); }
}
.bhp-iconin { position:relative; display:block; }
.bhp-iconin > .bhp-ico { position:absolute; left:9px; top:50%; transform:translateY(-50%); color:#94a3b8; pointer-events:none; display:flex; }
.bhp-iconin > .bhp-input { padding-left:30px; }
.bhp-save { display:inline-flex; align-items:center; gap:6px; background:#185fa5; color:#e6f1fb; font-size:12px; font-weight:500; padding:6px 14px; border-radius:8px; border:0; cursor:pointer; transition:background .13s; }
.bhp-save:hover { background:#0c447c; }
.bhp-fulllink { font-size:12px; color:#475569; text-decoration:underline; cursor:pointer; background:none; border:0; padding:0; }
.bhp-fulllink:hover { color:#0f172a; }
.bhp-dockbtn { display:inline-flex; align-items:center; gap:5px; background:#fff; color:#185fa5; font-size:12px; font-weight:500; padding:6px 12px; border-radius:8px; border:1px solid #b6d2ea; cursor:pointer; transition:background .13s, border-color .13s; }
.bhp-dockbtn:hover { background:#eef5fc; border-color:#185fa5; }
/* "Flip rake" toggle in the Hull cell — small outline button; fills in when the
   barge is currently flipped (clipped end on the right). Disabled for non-rakes. */
.bhp-fliprake { display:inline-flex; align-items:center; gap:4px; margin-top:5px; background:#fff; color:#185fa5; font-size:11px; font-weight:500; padding:3px 8px; border-radius:7px; border:1px solid #b6d2ea; cursor:pointer; transition:background .13s, border-color .13s, color .13s; }
.bhp-fliprake:hover:not(:disabled) { background:#eef5fc; border-color:#185fa5; }
.bhp-fliprake.is-flipped { background:#185fa5; color:#fff; border-color:#185fa5; }
.bhp-fliprake:disabled { opacity:.45; cursor:default; }
.bhp-fliprake-state { display:block; margin-top:3px; font-size:10px; color:#94a3b8; }

/* ── Fleet Board sticky toolbar + barge legend ────────────────────────────
   The toolbar card (title + search + zoom + Refresh + legend) sticks just
   below the global app header while the diagram scrolls. --app-header-h is
   kept in sync with the (flex-wrapping, variable-height) header in app.js;
   the fallback covers first paint before JS runs. Sticky/position styling
   lives here rather than in Tailwind utilities because the purged ahead-of-
   time build can't be relied on for arbitrary position/top values. */
.fleet-board-sticky {
  position: sticky;
  top: var(--app-header-h, 64px);
  /* Must sit ABOVE barge-tile content (strip z-30, status icon z-36, number
     text z-40), which isn't isolated in its own stacking context, so tiles
     scrolling underneath don't bleed through the toolbar/legend. Still below
     modals (z-2000) + the barge hover popover (z-2100). Spatially never
     overlaps the global header, so exceeding its z-40 is fine. */
  z-index: 50;
}
/* The Fleet Board vessel-status / "show hidden" summary. Its white sticky
   toolbar wrapper was removed; the line now sits inline above the diagram and
   disappears entirely (no leftover margin) whenever renderFleetBoard leaves it
   empty — so there's no blank bar in states with nothing to summarise.
   (.fleet-board-sticky above is now unused but kept for reference/rollback.) */
#fleet-board-summary:empty { display: none; }
/* Barge legend — horizontal inline row inside the toolbar card. Swatch
   colors come from utility classes already used by the live tiles; only
   layout lives here. */
#fleet-board-legend {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  font-size: 0.75rem;
  line-height: 1rem;
  color: #475569;             /* slate-600 */
}
#fleet-board-legend .legend-row { display: inline-flex; align-items: center; gap: 0.375rem; white-space: nowrap; }
#fleet-board-legend .legend-sep { width: 0; align-self: stretch; border-left: 1px solid #e2e8f0; margin: 0 0.125rem; }
#fleet-board-legend .legend-head { font-size: 0.625rem; text-transform: uppercase; letter-spacing: 0.04em; color: #64748b; }

/* "Save View" button next to the Fleet Board section toggles. Emerald accent
   so it reads as an action (not a 7th toggle); emerald-600 isn't fully in the
   purged Tailwind build (no border/hover shades) so the colors live here. */
.fleet-view-save {
  background-color: #059669;   /* emerald-600 */
  border-color: #059669;
  color: #fff;
  white-space: nowrap;
  cursor: pointer;
}
.fleet-view-save:hover    { background-color: #047857; border-color: #047857; }  /* emerald-700 */
.fleet-view-save.is-saved { background-color: #047857; border-color: #047857; }
.fleet-view-save.is-error { background-color: #e11d48; border-color: #e11d48; }  /* rose-600 */

/* Section toggle rows (Fleet Board sub-menu) — tap to show/hide, press-and-drag
   to reorder. Pointer events drive the drag (works on touch); touch-action:none
   keeps the gesture from scrolling the page mid-drag, user-select:none stops
   text selection. */
.fleet-section-row {
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: none;
}
.fleet-section-row .fleet-chip-grip {
  opacity: 0.4;
  font-size: 0.85em;
  line-height: 1;
  letter-spacing: -0.1em;
  flex: 0 0 auto;
  color: #94a3b8;              /* slate-400 */
}
/* Faux checkbox — filled slate when the section is on, empty outline when off. */
.fleet-section-row .fsr-box {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 3px;
  border: 1.5px solid #cbd5e1; /* slate-300 */
  background: #fff;
  position: relative;
}
.fleet-section-row .fsr-box.is-on {
  background: #334155;         /* slate-700 */
  border-color: #334155;
}
.fleet-section-row .fsr-box.is-on::after {
  content: "";
  position: absolute;
  left: 3.5px;
  top: 0.5px;
  width: 4px;
  height: 8px;
  border: solid #fff;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}
.fleet-section-row .fsr-label { flex: 1 1 auto; min-width: 0; }
.fleet-section-row.chip-dragging {
  cursor: grabbing;
  background: #f8fafc;         /* slate-50 */
  opacity: 0.95;
  box-shadow: 0 2px 8px rgba(15, 23, 42, 0.25);
}
/* Settle the non-dragged rows as they shift to make room. */
#fleet-section-toggles.chips-reordering .fleet-section-row:not(.chip-dragging) {
  transition: transform 0.12s ease;
}

/* ── "VERIFY" pill — dispatch order cards ─────────────────────────────────
   Shown next to a customer towboat's name when our catalog record disagrees
   with the USACE lock feed (name or vessel number). Click opens the reconcile
   dialog. Amber = "needs a look", matching the N/B / S/B tags. Colors live
   here (not Tailwind utilities) so the purged build can't drop them. */
.verify-vessel-pill {
  display: inline-flex;
  align-items: center;
  margin-left: 0.25rem;
  padding: 0.0625rem 0.375rem;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #92400e;             /* amber-800 */
  background: #fef3c7;        /* amber-100 */
  border: 1px solid #fcd34d;  /* amber-300 */
  border-radius: 9999px;
  cursor: pointer;
  transition: background-color 0.12s ease, box-shadow 0.12s ease;
}
.verify-vessel-pill:hover { background: #fde68a; }   /* amber-200 */
.verify-vessel-pill:focus-visible { outline: none; box-shadow: 0 0 0 2px #ffffff, 0 0 0 4px rgba(217, 119, 6, 0.5); }

/* Import-verify badge on a TowWorks-imported tow order whose line boat
   wasn't matched to a vessel in the catalog. Same amber pill as
   .verify-vessel-pill but non-interactive (informational marker). */
.tw-verify-pill {
  display: inline-flex;
  align-items: center;
  margin-left: 0.25rem;
  padding: 0.0625rem 0.375rem;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: #92400e;             /* amber-800 */
  background: #fef3c7;        /* amber-100 */
  border: 1px solid #fcd34d;  /* amber-300 */
  border-radius: 9999px;
}

/* ── Restored grid utility ────────────────────────────────────────────────
   The purged Tailwind build (vendor/tailwind.css) ships sm:col-span-5 but NOT
   the base .col-span-5. The Trip Card billable row uses a 12-col grid as
   col-span-3 (time) + col-span-2 (load) + col-span-5 (event) + col-span-2
   (actions); without this rule the event cell falls back to a single track,
   so its text wraps one word per line. Restore the base utility (same output
   Tailwind would emit) so the event column gets its intended ~5/12 width. */
.col-span-5 { grid-column: span 5 / span 5; }

/* Shift-order entry modal — half the shared CRUD width (max-w-3xl = 48rem → 24rem).
   The shared #crud-modal-host panel is wide for big forms (vessels, crew); the
   shift-order form's condensed Option-2 layout reads better narrow. Scope it
   with :has() so ONLY the panel currently holding #disp-dockorder-form shrinks —
   when any other form is shown, that id isn't a descendant and the panel keeps
   its normal width. (The form lives in its dispatch-card home otherwise.) */
#crud-modal-host > div:has(#disp-dockorder-form) { max-width: 24rem; }

/* Deck-log "Yes"/"Tightened" red segmented buttons. The purged Tailwind
   build (vendor/tailwind.css is generated ahead-of-time, no CLI) only
   carries peer-checked:*-emerald-600; the rose-600 peer-checked variants
   weren't in any markup at build time, so we hand-add them here mirroring
   Tailwind's compiled rules (rose-600 = rgb(225 29 72)). */
.peer:checked ~ .peer-checked\:bg-rose-600 { --tw-bg-opacity: 1; background-color: rgb(225 29 72 / var(--tw-bg-opacity, 1)); }
.peer:checked ~ .peer-checked\:border-rose-600 { --tw-border-opacity: 1; border-color: rgb(225 29 72 / var(--tw-border-opacity, 1)); }

/* ── Header action toolbar (Idea 2: icon-only, color-coded) ──────────────
   Compact square icon buttons in the top banner, replacing the wide labeled
   pills. The icon inherits the button's `color` (SVGs use stroke=currentColor),
   set per-button to a semantic hue inline. Hover lifts a subtle white wash on
   the dark banner. Each button keeps its title + aria-label for the tooltip /
   screen readers since the text label is gone. */
.hdr-act {
  display: inline-flex; align-items: center; justify-content: center; gap: 3px;
  min-width: 30px; height: 30px; padding: 0 6px;
  border-radius: 7px; background: rgba(255,255,255,0.07); color: #cbd5e1;
  transition: background .12s ease; flex-shrink: 0; cursor: pointer;
}
.hdr-act:hover { background: rgba(255,255,255,0.18); }
.hdr-act svg { width: 16px; height: 16px; }
.hdr-act .hdr-act-mono { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 11px; font-weight: 700; }
.hdr-act .hdr-act-badge { font-size: 10px; font-weight: 700; opacity: .9; }
/* Word labels (2026-09-29, option A): each button reads icon + word, the
   icon keeping its color and the word in light slate. Phones (<768px) drop
   back to icon-only squares so the toolbar still fits on one line; the
   title/aria-label carry the name there. */
.hdr-act .hdr-act-label {
  font-size: 12px; font-weight: 600; color: #e2e8f0; white-space: nowrap; line-height: 1;
}
.hdr-act:has(.hdr-act-label) { gap: 6px; padding: 0 10px; border: 1px solid rgba(255,255,255,0.10); }
/* The strip needs room to lay its buttons out in rows. Without a basis it
   was squeezed to one button wide between the brand and the right-hand
   controls and stacked every button vertically (already true on phones
   before the labels). With one, it drops to its own full-width line when
   the space beside the brand is too narrow, and wraps sideways there. */
#hdr-actions { flex: 1 1 560px; }
@media (max-width: 767px) {
  #hdr-actions { flex-basis: 100%; padding-left: 0; border-left: 0; }
  .hdr-act .hdr-act-label { display: none; }
  .hdr-act:has(.hdr-act-label) { gap: 3px; padding: 0 6px; border-color: transparent; }
}

/* Stat strip chips (Idea 2): each metric in its own pill instead of a long
   pipe-separated run. */
.hdr-stat-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: rgba(255,255,255,0.06); border-radius: 999px;
  padding: 2px 9px; white-space: nowrap;
}
.hdr-stat-chip .k { color: #94a3b8; font-weight: 600; }
.hdr-stat-chip .v { color: #e2e8f0; }

/* Tailwater readings sit in the banner, right-aligned in the band just below
   the zoom/Refresh controls (above the Barges strip). Plain text on the dark
   banner; visibility gated independently of the Barges strip. */
#header-tail-strip > div { justify-content: flex-end; }

/* Trip Card billable row — modal layout: date · load · action · route · on-invoice.
   The route column is capped so the on-invoice checkbox aligns in a column, and
   the whole row is vertically centered (align-items:center) so a single-line
   action label sits centered against a two-line route / vessel block. */
.trip-billable-modal{display:grid;grid-template-columns:94px 46px 142px minmax(0,16rem) max-content;align-items:center;column-gap:10px;row-gap:1px}
.trip-billable-modal.tbm-selectable{grid-template-columns:22px 94px 46px 142px minmax(0,16rem) max-content}
.trip-billable-modal .tbm-chk{display:flex;align-items:center;justify-content:center}
.trip-billable-modal .tbm-chk input{cursor:pointer;width:14px;height:14px}
.trip-billable-modal .tbm-chk-locked{opacity:.35;font-size:10px}
.trip-billable-modal.tbm-selected{background:rgba(99,102,241,.12)}
.trip-billable-modal.tbm-frozen{opacity:.6}
/* Billing board Combine select mode */
.billing-combine-mode .billing-tile{cursor:pointer}
.billing-tile-combine-selected{outline:2px solid #7c3aed;outline-offset:1px;box-shadow:0 0 0 3px rgba(124,58,237,.25);border-radius:4px}
/* Violet + slate-500 utilities the purged Tailwind build dropped — used by the
   Combine button / bar / multi-barge tile. Defined here so they actually render
   (novel Tailwind classes don't exist in the purged vendor build). */
.bg-violet-50{background-color:#f5f3ff}
.bg-violet-600{background-color:#7c3aed}
.bg-violet-700{background-color:#6d28d9}
.hover\:bg-violet-700:hover{background-color:#6d28d9}
.border-violet-200{border-color:#ddd6fe}
.border-violet-300{border-color:#c4b5fd}
.text-violet-600{color:#7c3aed}
.text-violet-700{color:#6d28d9}
.text-violet-900{color:#4c1d95}
.bg-slate-500{background-color:#64748b}
/* Hover shades the purged build dropped — used by Extract / Attach buttons. */
.hover\:bg-indigo-700:hover{background-color:#4338ca}
.hover\:bg-amber-700:hover{background-color:#b45309}
.hover\:bg-sky-800:hover{background-color:#075985}
.hover\:bg-slate-600:hover{background-color:#475569}
.trip-billable-modal .trip-rt-from{display:block;padding-left:15px}
.trip-billable-modal .trip-rt-to{display:block}
.trip-billable-modal .trip-rt-arr{display:inline-block;width:15px}
.trip-billable-modal .trip-rt-v{display:block}
.trip-billable-modal .tbm-inv{justify-self:end;white-space:nowrap}
.trip-billable-modal .tbm-ld b{display:block}

/* ── Shipyard module ─────────────────────────────────────────────────
   Modal frame + time-grid cells in plain CSS because vendor/tailwind.css
   is a purged build — novel utility classes won't exist at runtime. */
.sy-modal{position:fixed;inset:0;background:rgba(15,23,42,.45);display:none;align-items:flex-start;justify-content:center;overflow:auto;z-index:60;padding:2rem 1rem}
.sy-modal.open{display:flex}
.sy-modal-card{background:#fff;border-radius:.5rem;box-shadow:0 10px 30px rgba(0,0,0,.25);width:100%;max-width:56rem;margin-bottom:2rem}
.sy-time-table{border-collapse:collapse;width:100%}
.sy-time-table th,.sy-time-table td{padding:2px 4px;white-space:nowrap}
.sy-time-table td.sy-cell input{width:3.4rem;text-align:center;border:1px solid #cbd5e1;border-radius:.25rem;padding:2px 3px;font-size:.75rem}
.sy-time-table td.sy-cell input:focus{outline:2px solid #64748b;outline-offset:0}
.sy-emp-row{background:#f1f5f9;border-top:2px solid #cbd5e1}
.sy-asn-row{border-top:1px solid #e2e8f0}
.sy-asn-row.sy-house td:first-child{color:#92400e}
.sy-board-cols{display:flex;gap:.75rem;align-items:flex-start;min-width:max-content}
.sy-board-col{background:#f8fafc;border:1px solid #e2e8f0;border-radius:.375rem;padding:.5rem;width:15rem;flex:none}
.sy-board-card{background:#fff;border:1px solid #e2e8f0;border-radius:.375rem;padding:.5rem;margin-bottom:.5rem;cursor:pointer;box-shadow:0 1px 2px rgba(0,0,0,.06)}
.sy-board-card:hover{border-color:#94a3b8}
/* Vertical accordion board: statuses stack + each collapses (2026-09) —
   replaces the horizontal kanban lanes so wide status sets no longer scroll
   sideways. Cards reuse .sy-board-card inside a wrapping grid. */
.sy-acc-sec{border:1px solid #e2e8f0;border-radius:.5rem;background:#fff;margin-bottom:.5rem;overflow:hidden}
.sy-acc-hd{display:flex;align-items:center;gap:.5rem;padding:.6rem .75rem;cursor:pointer;user-select:none}
.sy-acc-hd:hover{background:#f8fafc}
.sy-acc-chev{color:#94a3b8;font-size:.8rem;line-height:1;width:.9rem;text-align:center;flex:none;transition:transform .15s}
.sy-acc-dot{width:9px;height:9px;border-radius:50%;flex:none}
.sy-acc-nm{font-weight:600;font-size:.8125rem;color:#334155}
.sy-acc-cnt{margin-left:auto;font-size:.6875rem;color:#64748b;background:#f1f5f9;border:1px solid #e2e8f0;border-radius:9999px;padding:.05rem .5rem}
.sy-acc-sec.collapsed .sy-acc-body{display:none}
.sy-acc-sec.collapsed .sy-acc-chev{transform:rotate(-90deg)}
.sy-acc-cards{display:grid;grid-template-columns:repeat(auto-fill,minmax(13rem,1fr));gap:.5rem;padding:0 .75rem .75rem}
.sy-acc-cards .sy-board-card{margin-bottom:0}
.sy-acc-empty{padding:0 .75rem .75rem;font-size:.6875rem;color:#94a3b8}

/* ── Permission matrix (System Utility → Permissions) ─────────────────────
   Role × permission grid. Sticky permission column + sticky role header so
   both survive scrolling in either axis; pips are the toggle affordance
   (green = granted, hollow = denied, grey square = SysAdmin locked). */
.perm-mx-scroll{overflow:auto;max-height:65vh;border:1px solid #e2e8f0;border-radius:.375rem}
.perm-mx{border-collapse:separate;border-spacing:0;width:100%;font-size:.8125rem}
.perm-mx th,.perm-mx td{border-bottom:1px solid #f1f5f9}
.perm-mx thead th{position:sticky;top:0;z-index:3;background:#f8fafc;border-bottom:2px solid #cbd5e1;padding:.375rem .5rem;vertical-align:bottom}
.perm-mx thead tr.perm-mx-deptrow th.perm-mx-depth{height:1.5rem;line-height:1.4375rem;padding:0 .5rem;vertical-align:middle;text-align:center;font-size:.625rem;text-transform:uppercase;letter-spacing:.08em;font-weight:700;color:#475569;background:#e2e8f0;border-bottom:1px solid #cbd5e1;white-space:nowrap}
.perm-mx thead tr.perm-mx-namerow th{top:1.5rem}
.perm-mx-grpstart{border-left:2px solid #cbd5e1}
.perm-mx-rowh{position:sticky;left:0;z-index:2;background:#fff;text-align:left;min-width:14rem;max-width:19rem;padding:.3125rem .625rem;color:#334155}
.perm-mx thead .perm-mx-corner{z-index:4;background:#f8fafc;font-size:.6875rem;text-transform:uppercase;letter-spacing:.06em;color:#64748b}
.perm-mx-colh{text-align:center;min-width:6.5rem}
.perm-mx-rolebtn{display:block;width:100%;background:none;border:none;cursor:pointer;font:inherit;padding:.125rem .25rem;border-radius:.25rem;color:#0f172a}
.perm-mx-rolebtn:hover{background:#e2e8f0}
.perm-mx-rolebtn:focus-visible{outline:2px solid #64748b;outline-offset:0}
.perm-mx-rolename{display:block;font-weight:600;line-height:1.15}
.perm-mx-crewcnt{display:block;font-weight:400;font-size:.6563rem;color:#94a3b8;margin-top:.125rem}
.perm-mx-grp td{position:sticky;left:0;z-index:1;background:#f1f5f9;font-size:.6875rem;text-transform:uppercase;letter-spacing:.06em;font-weight:700;color:#64748b;padding:.3125rem .625rem;border-bottom:1px solid #e2e8f0;text-align:left}
.perm-mx tbody tr:hover td{background:#f8fafc}
.perm-mx tbody tr.perm-mx-grp:hover td{background:#f1f5f9}
.perm-mx-cell{text-align:center;padding:.125rem .25rem}
.perm-mx-cell.perm-col-sel,.perm-mx thead th.perm-col-sel{background:#eef2f7}
.perm-mx-toggle{background:none;border:none;cursor:pointer;padding:.3125rem;border-radius:.375rem;display:inline-grid;place-items:center;line-height:0}
.perm-mx-toggle:hover{background:#e2e8f0}
.perm-mx-toggle:focus-visible{outline:2px solid #64748b;outline-offset:0}
.perm-mx-toggle--dirty{box-shadow:inset 0 0 0 2px #f59e0b;background:#fffbeb}
.perm-pip{display:inline-block;width:.75rem;height:.75rem;border-radius:9999px}
.perm-pip--on{background:#059669}
.perm-pip--off{background:transparent;border:2px solid #cbd5e1}
.perm-pip--lock{background:#94a3b8;border-radius:.1875rem;width:.625rem;height:.625rem}
.perm-mx-empty{padding:1rem .75rem;color:#94a3b8;font-style:italic;text-align:left}

/* Permission matrix v2 — column kind tags + effective-access inspector */
.perm-mx-tags{display:block;margin-top:.125rem}
.perm-mx-tag{display:inline-block;font-size:.5625rem;text-transform:uppercase;letter-spacing:.06em;font-weight:700;border-radius:.25rem;padding:0 .3125rem;margin:0 .0625rem}
.perm-mx-tag--role{background:#e0e7ff;color:#3730a3}
.perm-mx-tag--pos{background:#d1fae5;color:#065f46}
.perm-mx-tag--orphan{background:#fef3c7;color:#92400e}
.perm-insp{border:1px solid #e2e8f0;border-radius:.375rem;padding:.625rem .75rem;background:#f8fafc}
.perm-insp-src{white-space:nowrap}
.perm-insp-cols{column-width:16rem;column-gap:1.25rem;margin-top:.5rem}
.perm-insp-grp{break-inside:avoid;margin-bottom:.625rem}
.perm-insp-grp-title{font-size:.6875rem;text-transform:uppercase;letter-spacing:.06em;font-weight:700;color:#64748b;margin-bottom:.1875rem}
.perm-insp-grp ul{list-style:none;margin:0;padding:0}
.perm-insp-grp li,.perm-insp-blocked li{font-size:.75rem;color:#334155;padding:.0625rem 0}
.perm-insp-attr-chip{display:inline-block;font-size:.5625rem;text-transform:uppercase;letter-spacing:.05em;font-weight:700;border-radius:.25rem;padding:0 .25rem;margin-left:.25rem;background:#e2e8f0;color:#475569;vertical-align:1px}
.perm-insp-attr-chip--role{background:#e0e7ff;color:#3730a3}
.perm-insp-attr-chip--position{background:#d1fae5;color:#065f46}
.perm-insp-blocked{margin-top:.5rem;border-top:1px dashed #e2e8f0;padding-top:.5rem}
.perm-insp-blocked li{color:#92400e}
.perm-insp-blocked ul{list-style:none;margin:0;padding:0}

/* Fleet Board — VIEW ONLY (fleet-board:view-only restrictive feature).
   The section becomes a pure display: barge tiles, slots, cards and
   every button inside the board go inert. Scrolling still works (the
   containers themselves keep pointer events); only interactive children
   are switched off. Buttons dim so the state is visible at a glance. */
#fleet-board-section.fb-viewonly #fleet-board-diagram *,
#fleet-board-section.fb-viewonly [data-barge-id],
#fleet-board-section.fb-viewonly [draggable] {
  pointer-events: none !important;
}
#fleet-board-section.fb-viewonly button,
#fleet-board-section.fb-viewonly input,
#fleet-board-section.fb-viewonly select,
#fleet-board-section.fb-viewonly a {
  pointer-events: none !important;
  opacity: 0.45;
}

/* Permissions matrix — collapsible department bands + profile tag. */
.perm-mx-depth[data-grp] { cursor: pointer; user-select: none; }
.perm-mx-depth[data-grp]:hover { background: #e2e8f0; }
.perm-mx-depth--clps { white-space: nowrap; color: #475569; }
.perm-mx-clpscnt { font-weight: 400; color: #94a3b8; }
.perm-mx-clpscol { width: 18px; min-width: 18px; max-width: 18px; padding: 0 !important;
  background: repeating-linear-gradient(135deg, #f8fafc, #f8fafc 4px, #f1f5f9 4px, #f1f5f9 8px);
  cursor: pointer; }
.perm-mx-tag--prof { background: #ede9fe; color: #6d28d9; }

/* Permissions matrix — department chips (Option B). Hidden departments
   read struck-through, mirroring the Fleet Board section chips. */
.perm-mx-chip { font-size: 11px; padding: 3px 10px; border-radius: 999px;
  border: 1px solid #bfdbfe; background: #eff6ff; color: #1d4ed8; cursor: pointer; }
.perm-mx-chip:hover { background: #dbeafe; }
.perm-mx-chip--off { border-color: #e2e8f0; background: #f8fafc; color: #94a3b8; text-decoration: line-through; }
.perm-mx-chip--all { border-color: #cbd5e1; background: #fff; color: #475569; text-decoration: none; font-weight: 600; }

/* Permissions — Simple view level chips. Colors follow the mockup:
   None gray, View blue, Use green, Manage purple; dirty cells get the
   same amber ring the advanced toggles use. */
.perm-lv { font-size: 11px; font-weight: 600; padding: 2px 10px; border-radius: 999px;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap; }
.perm-lv--none   { background: #f1f5f9; color: #94a3b8; }
.perm-lv--view   { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.perm-lv--use    { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.perm-lv--manage { background: #ede9fe; color: #6d28d9; border-color: #ddd6fe; }
.perm-lv--dirty  { box-shadow: 0 0 0 2px #fcd34d; }
.perm-lv:hover   { filter: brightness(0.95); }

/* Permissions Simple view — nav-style sub-item rows under each module. */
.perm-sub-rowh { padding-left: 22px !important; color: #64748b; font-weight: 400; font-size: 11px; }
.perm-sub-row td { border-bottom-color: #f1f5f9; }
.perm-tool { font-size: 10px; font-weight: 600; padding: 1px 8px; border-radius: 999px;
  border: 1px solid transparent; cursor: pointer; white-space: nowrap; }
.perm-tool--inherit { background: #f0fdf4; color: #86bfa0; border-color: #dcfce7; }   /* on via module default — soft */
.perm-tool--on      { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.perm-tool--off     { background: #fef2f2; color: #b91c1c; border-color: #fecaca; }
.perm-tool--na      { background: transparent; color: #cbd5e1; border: none; cursor: default; }

/* Permissions Simple view — module fold toggles (▸/▾ sub-item rows). */
.perm-mod-fold { background: none; border: none; padding: 0; font: inherit; font-weight: 600;
  color: inherit; cursor: pointer; white-space: nowrap; }
.perm-mod-fold:hover { color: #1d4ed8; }
.perm-fold-cnt { font-weight: 400; color: #94a3b8; font-size: 10px; }

/* Per-tab View lock — the tab opens but its card is a pure display.
   Same pattern as the Fleet Board wall display: interactive children
   lose pointer events and dim; containers keep events so wheel
   scrolling still works. Applied by applyToolCardLock() when the
   active tool carries tool:<module>:<tab>:view. */
.tool-viewonly button,
.tool-viewonly input,
.tool-viewonly select,
.tool-viewonly textarea,
.tool-viewonly [draggable] {
  pointer-events: none !important;   /* controls die — but rows/cards stay clickable so
                                        records still OPEN (read-only) from a View tab */
  opacity: 0.55;
}
.tool-viewonly .sy-vo-keep {
  pointer-events: auto !important;
  opacity: 1;
}
/* Simple view — View chip for sub-items. */
.perm-tool--view { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }

/* Shipyard Time — real day headers: weekday over MM/DD, today highlighted. */
.sy-day-date { font-size: 10px; color: #94a3b8; font-weight: 400; }
th.sy-day-today { background: #eff6ff; border-radius: 6px 6px 0 0; }
th.sy-day-today > div:first-child { color: #1d4ed8; font-weight: 700; }
th.sy-day-today .sy-day-date { color: #3b82f6; }

/* ── Emulate User (Admin → Emulate User) ─────────────────────────────
   Fixed bottom banner shown for the whole emulation session; rendered
   by renderEmulationBanner() in app.js. Amber = "caution, you are not
   yourself". body.emulating pads the page bottom so the banner never
   hides content (same trick as the vessel-log ticker padding). */
#emulation-banner {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 95;
  display: flex; align-items: center; justify-content: center;
  gap: 0.75rem; padding: 0.5rem 0.75rem;
  background: #b45309; color: #fff;
  font-size: 0.8125rem; line-height: 1.25rem;
  box-shadow: 0 -2px 8px rgba(15, 23, 42, 0.35);
}
#emulation-banner .emu-dot {
  width: 0.5rem; height: 0.5rem; border-radius: 9999px;
  background: #fef3c7; flex: none;
  animation: emu-pulse 1.6s ease-in-out infinite;
}
@keyframes emu-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }
#emulation-banner button {
  background: rgba(255, 255, 255, 0.15);
  border: 1px solid rgba(255, 255, 255, 0.55);
  color: #fff; border-radius: 0.25rem;
  padding: 0.2rem 0.65rem; font-size: 0.75rem; white-space: nowrap;
  cursor: pointer;
}
#emulation-banner button:hover { background: rgba(255, 255, 255, 0.3); }
body.emulating { padding-bottom: 2.75rem; }

/* Start button on the Emulate User card (hover:bg-amber-700 isn't in
   the purged Tailwind build, hence the custom class). */
.emu-start-btn { background: #d97706; }
.emu-start-btn:hover { background: #b45309; }

/* Sandbox banner — a thin hazard-tape strip down the far LEFT edge of EVERY
   screen (including login) when the server runs in sandbox mode
   (start-sandbox.js / FLEET_SANDBOX=1). Was a full-width strip across the
   top; moved to an 11px vertical strip 2026-09-28 to give the header its row
   back. The words run bottom-to-top in tiny type; body.sandboxing pads the
   page right so nothing starts underneath it. Sits above toasts (z 3000). */
#sandbox-banner {
  position: fixed; top: 0; bottom: 0; left: 0; width: 11px; z-index: 4000;
  background: repeating-linear-gradient(45deg, #f59e0b, #f59e0b 7px, #1f2937 7px, #1f2937 14px);
  color: #fff; font-weight: 700; font-size: 7px; line-height: 11px; letter-spacing: 0.08em;
  writing-mode: vertical-rl; transform: rotate(180deg);
  white-space: nowrap; overflow: hidden; text-align: center;
  text-shadow: 0 0 2px #000, 0 0 2px #000;
  pointer-events: none;
}
body.sandboxing { padding-left: 11px; }

/* ── Weather module ─────────────────────────────────────────────────────
   Alert banners, per-location cards, and the drill-in dashboard (hourly
   wind bars + river-gauge flood-stage bar). All custom because most of
   these color/layout combos aren't in the purged Tailwind build. */
.wx-cards {
  display: grid; gap: 0.75rem;
  grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
}
.wx-card {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 0.5rem;
  padding: 0.75rem 1rem; cursor: pointer;
  transition: box-shadow 120ms, border-color 120ms;
}
.wx-card:hover { border-color: #94a3b8; box-shadow: 0 1px 4px rgba(15, 23, 42, 0.08); }
.wx-card-top { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.wx-card-name { font-size: 0.875rem; font-weight: 600; color: #1e293b; }
.wx-card-now { display: flex; align-items: center; gap: 0.6rem; margin: 0.5rem 0 0.25rem; }
.wx-card-temp { font-size: 1.75rem; font-weight: 600; color: #0f172a; line-height: 1; }
.wx-card-temp-lg { font-size: 2.25rem; }
.wx-card-desc { font-size: 0.8125rem; color: #475569; }
.wx-card-stats {
  display: flex; flex-wrap: wrap; gap: 0.35rem 1rem;
  font-size: 0.75rem; color: #64748b; margin-bottom: 0.6rem;
}
.wx-strip {
  display: grid; grid-template-columns: repeat(5, 1fr); gap: 0.25rem;
  border-top: 1px solid #f1f5f9; padding-top: 0.5rem; text-align: center;
}
.wx-strip-name { font-size: 0.6875rem; color: #94a3b8; }
.wx-strip-temp { font-size: 0.75rem; color: #1e293b; }
.wx-strip-temp span { color: #94a3b8; }

.wx-chip {
  font-size: 0.6875rem; padding: 0.1rem 0.5rem; border-radius: 9999px;
  white-space: nowrap; flex: none;
}
.wx-chip-ok     { background: #ecfdf5; color: #047857; }
.wx-chip-warn   { background: #fffbeb; color: #b45309; }
.wx-chip-severe { background: #fef2f2; color: #b91c1c; }

.wx-alert {
  display: flex; gap: 0.6rem; align-items: flex-start;
  border-radius: 0.5rem; border: 1px solid; padding: 0.6rem 0.85rem;
  margin-bottom: 0.5rem;
}
.wx-alert-severe   { background: #fef2f2; border-color: #fecaca; color: #b91c1c; }
.wx-alert-moderate { background: #fffbeb; border-color: #fde68a; color: #b45309; }
.wx-alert-minor    { background: #f0f9ff; border-color: #bae6fd; color: #0369a1; }
.wx-alert-icn { flex: none; margin-top: 0.1rem; }
.wx-alert-main { flex: 1; min-width: 0; }
.wx-alert-top { display: flex; justify-content: space-between; gap: 0.5rem; align-items: baseline; }
.wx-alert-event { font-size: 0.8125rem; font-weight: 600; }
.wx-alert-until { font-size: 0.6875rem; white-space: nowrap; }
.wx-alert-area { font-size: 0.75rem; opacity: 0.85; margin-top: 0.1rem; }
.wx-alert-details summary { font-size: 0.6875rem; cursor: pointer; margin-top: 0.25rem; }
.wx-alert-details pre {
  font: inherit; font-size: 0.75rem; white-space: pre-wrap;
  margin: 0.35rem 0 0; opacity: 0.9;
}

.wx-detail-head { display: flex; align-items: center; gap: 0.6rem; margin-bottom: 0.75rem; }
.wx-detail-name { font-size: 0.9375rem; font-weight: 600; color: #1e293b; }
.wx-detail-station { font-size: 0.6875rem; color: #94a3b8; margin-left: auto; }
.wx-detail-grid {
  display: grid; gap: 0.75rem; margin-bottom: 0.75rem;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}
.wx-panel {
  background: #fff; border: 1px solid #e2e8f0; border-radius: 0.5rem;
  padding: 0.75rem 1rem; margin-bottom: 0.75rem;
}
.wx-detail-grid .wx-panel { margin-bottom: 0; }
.wx-panel-title { font-size: 0.8125rem; font-weight: 600; color: #334155; margin-bottom: 0.5rem; }
.wx-panel-sub { font-weight: 400; color: #94a3b8; font-size: 0.6875rem; }
.wx-stat-grid {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem;
  border-top: 1px solid #f1f5f9; padding-top: 0.6rem; margin-top: 0.6rem;
}
.wx-stat-grid div { display: flex; flex-direction: column; }
.wx-stat-grid span { font-size: 0.6875rem; color: #94a3b8; }
.wx-stat-grid b { font-size: 0.8125rem; color: #1e293b; font-weight: 600; }
.wx-detail-text { font-size: 0.8125rem; color: #475569; margin: 0.6rem 0 0; }

.wx-gauge-now { display: flex; align-items: baseline; gap: 0.75rem; flex-wrap: wrap; }
.wx-gauge-stage { font-size: 1.5rem; font-weight: 600; color: #0f172a; }
.wx-gauge-fc { font-size: 0.75rem; color: #64748b; }
.wx-gaugebar {
  position: relative; height: 0.5rem; border-radius: 9999px;
  background: #f1f5f9; border: 1px solid #e2e8f0; margin: 0.75rem 0 0.4rem;
}
.wx-gaugebar-fill {
  position: absolute; left: 0; top: 0; bottom: 0;
  background: #0d9488; border-radius: 9999px;
}
.wx-gaugebar-fc {
  position: absolute; top: -0.3rem; width: 0; height: 1rem;
  border-left: 2px dotted #0f766e;
}
.wx-gaugebar-mark { position: absolute; top: -0.2rem; width: 2px; height: 0.85rem; }
.wx-gaugebar-action   { background: #eab308; }
.wx-gaugebar-minor    { background: #f97316; }
.wx-gaugebar-moderate { background: #dc2626; }
.wx-gaugebar-major    { background: #a21caf; }
.wx-gaugebar-legend {
  display: flex; flex-wrap: wrap; gap: 0.25rem 0.85rem;
  font-size: 0.6875rem; color: #64748b;
}
.wx-gaugebar-legend .wx-dot {
  display: inline-block; width: 0.5rem; height: 0.5rem;
  border-radius: 9999px; margin-right: 0.25rem; vertical-align: baseline;
}
.wx-gauge-flow { margin-left: auto; }

.wx-bars {
  display: grid; grid-template-columns: repeat(12, 1fr); gap: 0.3rem;
  align-items: end;
}
.wx-bar-col { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; }
.wx-bar { width: 100%; max-width: 2rem; border-radius: 3px 3px 0 0; }
.wx-bar-lo  { background: #7dd3fc; }
.wx-bar-mid { background: #0284c7; }
.wx-bar-hi  { background: #b91c1c; }
.wx-bar-val { font-size: 0.6875rem; color: #475569; }
.wx-bar-lbl { font-size: 0.625rem; color: #94a3b8; }

.wx-day-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 0.4rem; text-align: center;
}
.wx-day-cell { padding: 0.35rem 0.2rem; border-radius: 0.375rem; }
.wx-day-cell:hover { background: #f8fafc; }
.wx-day-meta { font-size: 0.625rem; color: #94a3b8; }

.wx-ic { display: inline-flex; color: #64748b; }
.wx-ic-sun      { color: #d97706; }
.wx-ic-moon     { color: #6366f1; }
.wx-ic-cloudsun { color: #d97706; }
.wx-ic-cloud    { color: #94a3b8; }
.wx-ic-rain     { color: #0284c7; }
.wx-ic-snow     { color: #7dd3fc; }
.wx-ic-storm    { color: #b91c1c; }
.wx-ic-wind     { color: #0d9488; }
.wx-ic-fog      { color: #94a3b8; }

.wx-errors { font-size: 0.6875rem; color: #b45309; margin: 0; }

/* Default-location star (per-user; starred location opens on entry). */
.wx-card-top-right { display: flex; align-items: center; gap: 0.4rem; flex: none; }
.wx-star {
  display: inline-flex; align-items: center; justify-content: center;
  padding: 0.15rem; border: none; background: none; cursor: pointer;
  color: #cbd5e1; border-radius: 0.25rem;
}
.wx-star:hover { color: #f59e0b; background: #f8fafc; }
.wx-star-on { color: #f59e0b; }

/* Invoice send-history chips (ledger Sent column + preview bar). */
.inv-sent-chip {
  display: inline-block; font-size: 0.625rem; font-weight: 700;
  border-radius: 9999px; padding: 0.1rem 0.5rem; border: 1px solid;
  white-space: nowrap; line-height: 1.3;
}
.inv-sent-mail   { background: #ecfdf5; color: #047857; border-color: #a7f3d0; }
.inv-sent-print  { background: #eff6ff; color: #1d4ed8; border-color: #bfdbfe; }
.inv-sent-manual { background: #f0fdf4; color: #15803d; border-color: #bbf7d0; }
.inv-sent-gl     { background: #f5f3ff; color: #6d28d9; border-color: #ddd6fe; }
.inv-sent-none   { background: #fff7ed; color: #c2410c; border-color: #fed7aa; }
.inv-sent-fail   { background: #fef2f2; color: #b91c1c; border-color: #fecaca; }

/* "Anywhere" row under the fleet cards: city search + Follow Me + saved
   place chips (per-user, max 8). */
.wx-anywhere {
  display: flex; align-items: center; gap: 0.6rem; flex-wrap: wrap;
  margin-top: 0.9rem; padding-top: 0.9rem; border-top: 1px dashed #e2e8f0;
}
.wx-anywhere-lbl {
  font-size: 0.6875rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.03em; color: #64748b;
}
.wx-geo-wrap { position: relative; }
.wx-geo-input {
  width: 15rem; font-size: 0.8125rem; padding: 0.4rem 0.6rem;
  border: 1px solid #cbd5e1; border-radius: 0.5rem; background: #fff;
}
.wx-geo-input:focus { outline: 2px solid #0ea5e9; outline-offset: -1px; }
.wx-geo-results {
  position: absolute; top: 2.3rem; left: 0; min-width: 17rem; z-index: 40;
  background: #fff; border: 1px solid #cbd5e1; border-radius: 0.5rem;
  box-shadow: 0 8px 22px rgba(15, 23, 42, 0.12); overflow: hidden;
}
.wx-geo-hit {
  display: block; width: 100%; text-align: left; font-size: 0.8125rem;
  padding: 0.45rem 0.75rem; border: none; background: none; cursor: pointer;
  border-bottom: 1px solid #f1f5f9; color: #0f172a;
}
.wx-geo-hit:last-child { border-bottom: none; }
.wx-geo-hit:hover { background: #f0f9ff; }
.wx-geo-none { font-size: 0.8125rem; color: #94a3b8; padding: 0.45rem 0.75rem; }
.wx-follow-btn {
  font-size: 0.8125rem; padding: 0.4rem 0.85rem; cursor: pointer;
  border: 1px solid #0ea5e9; color: #0369a1; background: #f0f9ff;
  border-radius: 0.5rem;
}
.wx-follow-btn:hover { background: #e0f2fe; }
.wx-follow-btn:disabled { opacity: 0.6; cursor: default; }
.wx-place-chip {
  display: inline-flex; align-items: center; gap: 0.35rem; cursor: pointer;
  font-size: 0.75rem; color: #0369a1; background: #f0f9ff;
  border: 1px solid #bae6fd; border-radius: 9999px; padding: 0.25rem 0.4rem 0.25rem 0.7rem;
}
.wx-place-chip:hover { background: #e0f2fe; }
.wx-place-del {
  border: none; background: none; cursor: pointer; color: #0369a1;
  opacity: 0.55; font-size: 0.6875rem; padding: 0 0.25rem; border-radius: 9999px;
}
.wx-place-del:hover { opacity: 1; background: #bae6fd; }
.wx-adhoc-chip {
  font-size: 0.625rem; font-weight: 700; letter-spacing: 0.03em;
  color: #0369a1; background: #f0f9ff; border: 1px solid #bae6fd;
  border-radius: 9999px; padding: 0.15rem 0.6rem; flex: none;
}
/* River-stage gauge selector on ad-hoc dashboards. */
.wx-gauge-pick { flex: none; }
.wx-gauge-select {
  font-size: 0.8125rem; padding: 0.35rem 0.5rem; max-width: 100%;
  border: 1px solid #cbd5e1; border-radius: 0.375rem; background: #fff;
}

/* Weather radar map (MapLibre GL, lazy-loaded). Fixed height so the panel
   doesn't jump while tiles stream in; canvas inherits the rounded corners. */
.wx-radar-map {
  height: 380px; border-radius: 0.375rem; overflow: hidden;
  background: #e2e8f0; position: relative;
}
.wx-radar-fallback {
  display: flex; align-items: center; justify-content: center; height: 100%;
  font-size: 0.8125rem; color: #64748b;
}

/* Radar animation timeline (play/pause + scrubber under the map). */
.wx-radar-ctl { display: flex; align-items: center; gap: 0.6rem; margin-top: 0.5rem; }
.wx-radar-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.75rem; height: 1.75rem; flex: none; cursor: pointer;
  border: 1px solid #cbd5e1; border-radius: 0.375rem;
  background: #fff; color: #334155;
}
.wx-radar-btn:hover { background: #f8fafc; }
.wx-radar-ctl input[type="range"] { flex: 1; accent-color: #0d9488; min-width: 0; }
.wx-radar-time {
  font-size: 0.75rem; color: #334155; flex: none; min-width: 7.5rem;
  text-align: right; font-variant-numeric: tabular-nums;
}
.wx-radar-fc-badge {
  font-size: 0.625rem; text-transform: uppercase; letter-spacing: 0.03em;
  background: #fffbeb; color: #b45309; border: 1px solid #fde68a;
  padding: 0 0.3rem; border-radius: 9999px; margin-left: 0.25rem;
}

/* Radar intensity key in the panel header (after the subtitle). */
.wx-panel-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 0.25rem 1rem; margin-bottom: 0.5rem;
}
.wx-panel-head .wx-panel-title { margin-bottom: 0; }
.wx-radar-key {
  display: flex; flex-wrap: wrap; gap: 0.2rem 0.75rem;
  margin-left: auto; font-size: 0.6875rem; color: #475569;
}
.wx-radar-key-item { display: inline-flex; align-items: center; gap: 0.3rem; white-space: nowrap; }
.wx-radar-key-item i {
  width: 0.625rem; height: 0.625rem; border-radius: 3px; flex: none;
}

/* Weather alert popup — site-wide, bottom-right, permission-scoped.
   z-index 90 sits under the emulation banner (95); body.emulating lifts
   the stack clear of it. Red = Severe/Extreme, amber = advisories. */
#wx-alert-popups {
  position: fixed; right: 0.875rem; bottom: 0.875rem; z-index: 90;
  width: 330px; max-width: calc(100vw - 1.75rem);
  display: flex; flex-direction: column; gap: 0.5rem;
}
body.emulating #wx-alert-popups { bottom: 3.5rem; }
.wx-popup {
  background: #fff; border: 2px solid; border-radius: 0.625rem;
  overflow: hidden; box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
}
.wx-popup-warn { border-color: #dc2626; }
.wx-popup-adv  { border-color: #f59e0b; }
.wx-popup-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.45rem 0.75rem; color: #fff;
  font-size: 0.75rem; font-weight: 600;
}
.wx-popup-warn .wx-popup-head { background: #dc2626; }
.wx-popup-adv  .wx-popup-head { background: #d97706; }
.wx-popup-count { margin-left: auto; font-size: 0.625rem; font-weight: 400; opacity: 0.85; }
.wx-popup-body { padding: 0.6rem 0.75rem; }
.wx-popup-event { font-size: 0.8125rem; font-weight: 600; }
.wx-popup-warn .wx-popup-event { color: #991b1b; }
.wx-popup-adv  .wx-popup-event { color: #92400e; }
.wx-popup-meta { font-size: 0.6875rem; color: #475569; margin-top: 0.15rem; }
.wx-popup-desc { font-size: 0.6875rem; color: #64748b; margin-top: 0.4rem; }
.wx-popup-actions { display: flex; gap: 0.5rem; margin-top: 0.6rem; }
.wx-popup-ack {
  flex: 1; border: none; color: #fff; cursor: pointer;
  font-size: 0.75rem; font-weight: 600;
  padding: 0.45rem 0.6rem; border-radius: 0.375rem;
}
.wx-popup-warn .wx-popup-ack { background: #dc2626; }
.wx-popup-warn .wx-popup-ack:hover { background: #b91c1c; }
.wx-popup-adv .wx-popup-ack { background: #d97706; }
.wx-popup-adv .wx-popup-ack:hover { background: #b45309; }
.wx-popup-open {
  background: #fff; border: 1px solid #cbd5e1; color: #475569; cursor: pointer;
  font-size: 0.6875rem; padding: 0.45rem 0.6rem; border-radius: 0.375rem;
}
.wx-popup-open:hover { background: #f8fafc; }
.wx-popup-next {
  display: flex; align-items: center; gap: 0.5rem;
  background: #fff; border: 1.5px solid #f59e0b; border-radius: 0.625rem;
  padding: 0.5rem 0.75rem; font-size: 0.6875rem; color: #92400e;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
}
.wx-popup-next-warn { border-color: #dc2626; color: #991b1b; }
.wx-popup-next span { margin-left: auto; font-size: 0.625rem; color: #94a3b8; }

/* ── Customer-request popup — the weather alert's twin, for portal
   requests. Same geometry and rules; sits ABOVE the weather stack so a
   warning always keeps the bottom corner. Blue = checks clear,
   amber = the request tripped a validation check. ── */
#pr-request-popups {
  position: fixed; right: 0.875rem; bottom: 0.875rem; z-index: 89;
  width: 330px; max-width: calc(100vw - 1.75rem);
  display: flex; flex-direction: column; gap: 0.5rem;
}
/* When weather alerts are up too, the request stack rides above them. */
body:has(#wx-alert-popups) #pr-request-popups { bottom: 14rem; }
body.emulating #pr-request-popups { bottom: 3.5rem; }
body.emulating:has(#wx-alert-popups) #pr-request-popups { bottom: 17rem; }
.pr-popup {
  background: #fff; border: 2px solid; border-radius: 0.625rem;
  overflow: hidden; box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
}
.pr-popup-ok   { border-color: #0284c7; }
.pr-popup-flag { border-color: #d97706; }
.pr-popup-head {
  display: flex; align-items: center; gap: 0.5rem;
  padding: 0.45rem 0.75rem; color: #fff;
  font-size: 0.75rem; font-weight: 600;
}
.pr-popup-ok   .pr-popup-head { background: #0284c7; }
.pr-popup-flag .pr-popup-head { background: #d97706; }
.pr-popup-count { margin-left: auto; font-size: 0.625rem; font-weight: 400; opacity: 0.85; }
.pr-popup-body { padding: 0.6rem 0.75rem; }
.pr-popup-title { font-size: 0.8125rem; font-weight: 600; }
.pr-popup-ok   .pr-popup-title { color: #075985; }
.pr-popup-flag .pr-popup-title { color: #92400e; }
.pr-popup-meta { font-size: 0.6875rem; color: #475569; margin-top: 0.15rem; }
.pr-popup-barges {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6875rem; color: #64748b; margin-top: 0.35rem;
}
.pr-popup-flagline {
  font-size: 0.6875rem; font-weight: 600; color: #92400e;
  background: #fef3c7; border-radius: 0.3125rem;
  padding: 0.2rem 0.45rem; margin-top: 0.4rem; display: inline-block;
}
.pr-popup-actions { display: flex; gap: 0.5rem; margin-top: 0.6rem; }
.pr-popup-go {
  flex: 1; border: none; color: #fff; cursor: pointer;
  font-size: 0.75rem; font-weight: 600;
  padding: 0.45rem 0.6rem; border-radius: 0.375rem;
}
.pr-popup-ok   .pr-popup-go { background: #0284c7; }
.pr-popup-ok   .pr-popup-go:hover { background: #0369a1; }
.pr-popup-flag .pr-popup-go { background: #d97706; }
.pr-popup-flag .pr-popup-go:hover { background: #b45309; }
.pr-popup-x {
  background: #fff; border: 1px solid #cbd5e1; color: #475569; cursor: pointer;
  font-size: 0.6875rem; padding: 0.45rem 0.6rem; border-radius: 0.375rem;
}
.pr-popup-x:hover { background: #f8fafc; }
.pr-popup-next {
  display: flex; align-items: center; gap: 0.5rem;
  background: #fff; border: 1.5px solid #0284c7; border-radius: 0.625rem;
  padding: 0.5rem 0.75rem; font-size: 0.6875rem; color: #075985;
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.12);
}
.pr-popup-next span { margin-left: auto; font-size: 0.625rem; color: #94a3b8; }
/* Row the popup sent you to — fades after a few seconds. */
tr.or-focus > td { background: #e0f2fe !important; transition: background 1.2s ease-out; }
#or-chips .or-chip + .or-chip { border-left: 1px solid #e2e8f0; }

/* ── Sales Log table ─────────────────────────────────────────────────── */
/* Item columns share a uniform narrow width; a long item-type header
   (e.g. "Engine Room Trash (Yellow Bag)") wraps onto extra lines instead
   of stretching its column wide. Mirrored inline in the print window
   (salesLogPrint) since that popup doesn't load this stylesheet. */
#sales-log-table th.sl-item-col {
  width: 5.5rem;
  min-width: 3.5rem;
  white-space: normal;
  overflow-wrap: break-word;
}

/* ── TowWorks Pending Review (Import Center) ─────────────────────────
   Full-screen review of every difference between the TowWorks pending
   list and Peep Light's unbilled charges. TowWorks columns are warm
   (amber), Peep Light columns are cool (blue), so the systems read apart. */
.twr-overlay { --twr-tw: #92400e; --twr-tw-bg: #fdf3e2; --twr-inv-bg: #fefaf2; --twr-pl: #1d4ed8; --twr-pl-bg: #eaf1fd;
  position: fixed; inset: 0; z-index: 1000; background: rgba(15, 23, 42, 0.45); display: flex; padding: 12px; }
.twr-overlay[hidden] { display: none; }
.twr-shell { background: var(--page); color: var(--ink); border-radius: 10px; width: 100%; max-width: 1400px; margin: 0 auto;
  display: flex; flex-direction: column; min-height: 0; box-shadow: 0 20px 50px rgba(15, 23, 42, 0.3); }
.twr-top { display: flex; gap: 12px; align-items: flex-start; justify-content: space-between; padding: 14px 18px; border-bottom: 1px solid var(--hairline-firm); background: var(--surface); border-radius: 10px 10px 0 0; }
.twr-top h2 { font-size: 17px; font-weight: 700; color: var(--ink-strong); margin: 0; }
.twr-top p { font-size: 12px; color: var(--ink-soft); margin: 2px 0 0; }
.twr-top a { color: var(--accent); }
.twr-body { flex: 1; min-height: 0; overflow: auto; padding: 14px 18px 18px; display: grid; gap: 12px; align-content: start; }
.twr-muted { color: var(--ink-soft); font-size: 12px; }
.twr-card { background: var(--surface); border: 1px solid var(--hairline-firm); border-radius: var(--radius); padding: 14px 16px; display: grid; gap: 10px; min-width: 0; }
.twr-card h3 { font-size: 14px; font-weight: 700; color: var(--ink-strong); margin: 0; }
.twr-card h4, .twr-detail h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-soft); font-weight: 600; margin: 0 0 4px; }
.twr-home { display: grid; gap: 12px; grid-template-columns: minmax(min(360px, 100%), 1fr) minmax(min(420px, 100%), 2fr); align-items: start; }
@media (max-width: 900px) { .twr-home { grid-template-columns: minmax(0, 1fr); } }
.twr-upload { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.twr-btn { font: inherit; font-size: 13px; font-weight: 600; padding: 7px 14px; min-height: 36px; border-radius: 6px; border: 1px solid var(--hairline-firm); background: var(--surface); color: var(--ink-strong); cursor: pointer; }
.twr-btn.primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.twr-btn:disabled { opacity: .5; cursor: default; }
.twr-tbl { overflow-x: auto; max-width: 100%; min-width: 0; }
.twr-tbl table { border-collapse: collapse; width: 100%; font-size: 12px; }
.twr-tbl th { text-align: left; font-weight: 600; color: var(--ink-soft); font-size: 11px; padding: 5px 7px; border-bottom: 1px solid var(--hairline-firm); white-space: nowrap; }
.twr-tbl td { padding: 5px 7px; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.twr-tbl .n { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.twr-tbl .w { white-space: nowrap; font-variant-numeric: tabular-nums; }
.twr-tbl tr.hit td { background: rgba(2, 132, 199, 0.1); font-weight: 600; }
.twr-tbl tr.zero td { color: var(--ink-faint); }
.twr-click { cursor: pointer; }
.twr-click:hover td, .twr-click:focus td { background: var(--surface-2); }
.twr-summary { display: flex; flex-wrap: wrap; gap: 10px 28px; background: var(--surface); border: 1px solid var(--hairline-firm); border-radius: var(--radius); padding: 12px 16px; }
.twr-summary > div, .twr-amounts > div { display: grid; gap: 1px; min-width: 120px; }
.twr-summary .lab, .twr-amounts .lab, .twr-read .lab { font-size: 11px; text-transform: uppercase; letter-spacing: .06em; color: var(--ink-soft); font-weight: 600; }
.twr-overlay .lab.tw { color: var(--twr-tw); }
.twr-overlay .lab.pl { color: var(--twr-pl); }
.twr-overlay .big { font-size: 18px; font-weight: 600; color: var(--ink-strong); font-variant-numeric: tabular-nums; }
.twr-bar { display: block; height: 6px; background: var(--surface-2); border: 1px solid var(--hairline); border-radius: 99px; overflow: hidden; margin-top: 4px; }
.twr-bar > i { display: block; height: 100%; width: 0; background: var(--accent); transition: width .2s; }
.twr-main { display: grid; grid-template-columns: minmax(280px, 360px) minmax(0, 1fr); gap: 12px; align-items: start; min-height: 0; }
@media (max-width: 900px) { .twr-main { grid-template-columns: minmax(0, 1fr); } }
.twr-list { background: var(--surface); border: 1px solid var(--hairline-firm); border-radius: var(--radius); display: grid; grid-template-rows: auto minmax(0, 1fr); max-height: calc(100vh - 230px); position: sticky; top: 0; min-width: 0; }
@media (max-width: 900px) { .twr-list { position: static; max-height: 45vh; } }
.twr-filters { display: flex; flex-wrap: wrap; gap: 6px; padding: 8px; border-bottom: 1px solid var(--hairline-firm); }
.twr-filters select { font: inherit; font-size: 12px; padding: 4px 6px; border: 1px solid var(--hairline-firm); border-radius: 6px; background: var(--surface); flex: 1 1 130px; min-width: 0; }
.twr-rows { overflow-y: auto; }
.twr-row { display: grid; grid-template-columns: 10px minmax(0, 1fr) auto; gap: 8px; align-items: center; width: 100%; text-align: left; padding: 8px 10px; min-height: 40px; border: 0; border-bottom: 1px solid var(--hairline); background: transparent; font: inherit; color: inherit; cursor: pointer; }
.twr-row:hover { background: var(--surface-2); }
.twr-row[aria-current="true"] { background: rgba(2, 132, 199, 0.1); }
.twr-row .dot { width: 10px; height: 10px; border-radius: 50%; border: 2px solid var(--hairline-firm); }
.twr-row .dot.done { background: var(--accent); border-color: var(--accent); }
.twr-row .txt { min-width: 0; }
.twr-row .t1 { display: block; font-weight: 600; font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-strong); }
.twr-row .t2 { display: block; font-size: 11px; color: var(--ink-soft); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.twr-row .amt { text-align: right; font-size: 13px; font-variant-numeric: tabular-nums; }
.twr-detail { display: grid; gap: 12px; min-width: 0; }
.twr-head { display: flex; flex-wrap: wrap; gap: 8px 20px; justify-content: space-between; align-items: flex-start; }
.twr-title { font-size: 20px; font-weight: 700; color: var(--ink-strong); }
.twr-amounts { display: flex; flex-wrap: wrap; gap: 12px 22px; }
.twr-read { background: var(--surface-2); border: 1px solid var(--hairline); border-radius: var(--radius); padding: 10px 12px; display: grid; gap: 4px; }
.twr-read p { margin: 0; font-size: 13px; color: var(--ink-strong); }
table.twr-cmp { table-layout: fixed; min-width: 720px; }
table.twr-cmp th:first-child, table.twr-cmp td:first-child { width: 88px; }
table.twr-cmp th.h-tw, table.twr-cmp td.x-tw { background: var(--twr-tw-bg); }
table.twr-cmp th.h-inv, table.twr-cmp td.x-inv { background: var(--twr-inv-bg); }
table.twr-cmp th.h-pl, table.twr-cmp td.x-pl { background: var(--twr-pl-bg); }
table.twr-cmp th.h-tw, table.twr-cmp th.h-inv { color: var(--twr-tw); }
table.twr-cmp th.h-pl { color: var(--twr-pl); }
table.twr-cmp td { padding: 7px 8px; border-bottom: 1px solid var(--hairline-firm); }
table.twr-cmp tr.focus td { box-shadow: inset 0 2px 0 var(--accent), inset 0 -2px 0 var(--accent); }
table.twr-cmp tr.focus td:first-child { box-shadow: inset 2px 2px 0 var(--accent), inset 0 -2px 0 var(--accent); font-weight: 700; }
table.twr-cmp tr.focus td:last-child { box-shadow: inset -2px 2px 0 var(--accent), inset 0 -2px 0 var(--accent); }
.twr-cmp .what { display: block; font-weight: 600; font-size: 12px; color: var(--ink-strong); }
.twr-cmp .sub { display: block; font-size: 11px; color: var(--ink-soft); overflow-wrap: anywhere; }
.twr-cmp .sub-i { font-weight: 400; font-size: 11px; color: var(--ink-soft); }
.twr-cmp .amt { display: block; font-size: 13px; margin-top: 2px; font-variant-numeric: tabular-nums; }
.twr-cmp .none { font-size: 12px; color: var(--ink-faint); font-style: italic; }
.twr-cmp .item + .item { margin-top: 6px; padding-top: 6px; border-top: 1px dashed var(--hairline-firm); }
.twr-overlay .st { display: inline-block; margin-top: 2px; font-size: 11px; padding: 1px 7px; border-radius: 99px; background: var(--surface-2); }
.twr-overlay .st-invoiced { background: var(--good-bg); color: var(--good); }
.twr-overlay .st-pending, .twr-overlay .st-this { background: var(--warn-bg); color: var(--warn); }
.twr-overlay .st-writtenoff { background: var(--bad-bg); color: var(--bad); }
.twr-legend { margin: 0; }
.twr-more { border-top: 1px solid var(--hairline); padding-top: 8px; }
.twr-more > summary { cursor: pointer; font-size: 13px; font-weight: 600; color: var(--accent); }
.twr-sides { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-top: 10px; }
@media (max-width: 1100px) { .twr-sides { grid-template-columns: minmax(0, 1fr); } }
.twr-empty { font-style: italic; }
.twr-seg { display: flex; flex-wrap: wrap; gap: 6px; }
.twr-seg button { font: inherit; font-size: 13px; padding: 7px 12px; min-height: 38px; border-radius: 6px; border: 1px solid var(--hairline-firm); background: var(--surface); color: var(--ink-strong); cursor: pointer; }
.twr-seg button[aria-pressed="true"] { background: var(--accent); border-color: var(--accent); color: #fff; }
.twr-decide textarea { font: inherit; width: 100%; min-height: 60px; padding: 8px; border: 1px solid var(--hairline-firm); border-radius: 6px; resize: vertical; }
.twr-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; justify-content: space-between; }
.twr-actions > span:last-child { display: flex; gap: 8px; }
.twr-overlay button:focus-visible, .twr-overlay select:focus-visible, .twr-overlay textarea:focus-visible, .twr-click:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .twr-bar > i { transition: none; } }

/* ── Import Center: "What are you importing?" picker ─────────────────
   Opened by a Setup Data category card; picking a type starts the usual
   column-mapping import. */
.imp-pick { position: fixed; inset: 0; z-index: 1000; background: rgba(15, 23, 42, 0.45); display: flex; align-items: flex-start; justify-content: center; padding: 8vh 16px 16px; }
.imp-pick[hidden] { display: none; }
.imp-pick-box { background: var(--surface); color: var(--ink); border-radius: 10px; width: 100%; max-width: 560px; padding: 16px 18px 18px; display: grid; gap: 12px; box-shadow: 0 20px 50px rgba(15, 23, 42, 0.3); max-height: 84vh; overflow-y: auto; }
.imp-pick-top { display: flex; gap: 12px; justify-content: space-between; align-items: flex-start; }
.imp-pick-top h3 { font-size: 16px; font-weight: 700; color: var(--ink-strong); margin: 0; }
.imp-pick-top p { font-size: 12px; color: var(--ink-soft); margin: 3px 0 0; }
.imp-pick-close { font-size: 22px; line-height: 1; border: 0; background: transparent; color: var(--ink-soft); cursor: pointer; min-width: 38px; min-height: 38px; border-radius: 6px; }
.imp-pick-close:hover { background: var(--surface-2); }
.imp-pick-box h4 { font-size: 11px; text-transform: uppercase; letter-spacing: .07em; color: var(--ink-soft); font-weight: 600; margin: 4px 0 -4px; }
.imp-pick-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(200px, 100%), 1fr)); gap: 8px; }
.imp-pick-opt { display: grid; gap: 2px; text-align: left; padding: 10px 12px; min-height: 44px; border: 1px solid var(--hairline-firm); border-radius: var(--radius); background: var(--surface); font: inherit; color: inherit; cursor: pointer; }
.imp-pick-opt:hover { border-color: var(--accent); background: var(--surface-2); }
.imp-pick-opt .t { font-weight: 600; font-size: 13px; color: var(--ink-strong); }
.imp-pick-opt .h { font-size: 11px; color: var(--ink-soft); }
.imp-pick-opt:focus-visible, .imp-pick-close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
