:root {
  /* Brand red, split out from --danger so a theme can recolour the topbar
     without turning error text, overdue markers and unread badges the same
     colour. --danger stays semantic: red means something is wrong. */
  --brand: #b91c1c;
  --blue: #1d4ed8;
  --blue-dark: #1e3a8a;
  --bg: #f5f7fa;
  --border: #d8dee8;
  --text: #1f2430;
  --muted: #5b6472;
  --danger: #b91c1c;
  --danger-bg: #fdecec;
  /* Subtle fill (Directory extension buttons, Grid totals row, Stats tab
     hover, menu hover...). Was never defined, so its light fallback showed in
     dark mode too - dark mode now points it at --surface-2 (below). */
  --bg-alt: #f3f4f6;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--app-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif);
  background: var(--bg);
  color: var(--text);
  position: relative;
}

/* Poke reaction (see partials/header.ejs's pollPokes()/pokeShake()) - a
   quick decaying side-to-side shake, like the whole window got bumped.
   Amplitude halves each swing (40 -> 20 -> 10 -> 4px) so it reads as a
   single settling jolt rather than a sustained wobble. overflow-x:hidden
   only while shaking avoids a momentary horizontal scrollbar. */
body.poke-shaking { overflow-x: hidden; animation: poke-shake 0.7s ease-in-out; }
@keyframes poke-shake {
  0%   { transform: translateX(0); }
  10%  { transform: translateX(-40px); }
  20%  { transform: translateX(40px); }
  30%  { transform: translateX(-20px); }
  40%  { transform: translateX(20px); }
  50%  { transform: translateX(-10px); }
  60%  { transform: translateX(10px); }
  70%  { transform: translateX(-4px); }
  80%  { transform: translateX(4px); }
  100% { transform: translateX(0); }
}

/* Background photo behind every page - a single full-viewport image
   (not tiled/repeated like the earlier logo watermark, since repeating
   small rotated crops of a photograph creates visible seams and
   duplicated scenery in a way a simple icon mark doesn't).
   A fixed-position pseudo-element (rather than background-attachment:fixed
   on body) keeps it anchored to the viewport reliably across browsers,
   including mobile Safari, which has long had quirks with fixed
   backgrounds on scrollable pages. Sits at z-index:-1 so it paints behind
   the topbar/content without needing every view's markup to opt in. */
body::before {
  content: '';
  position: fixed;
  inset: 0;
  /* My preferences -> Background: --bg-image / --bg-opacity set on <html> (partials/header.ejs). */
  background-image: var(--bg-image, url('/bg-photo.jpg'));
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center;
  opacity: var(--bg-opacity, 0.1);
  pointer-events: none;
  z-index: -1;
}

.container {
  max-width: none;
  margin: 0;
  padding: 24px 1in 60px;
}

.topbar {
  background: var(--brand);
  color: #fff;
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 1000;
  transition: transform 0.25s ease;
}
/* Slid up out of view on scroll-down - see the scroll listener in
   partials/header.ejs, which removes this class the instant the user
   scrolls back up even slightly. */
.topbar.topbar-hidden {
  transform: translateY(-100%);
}
.topbar-inner {
  max-width: none;
  margin: 0;
  padding: 14px 1in;
  display: flex;
  align-items: center;
  gap: 24px;
}
.brand { color: #fff; font-weight: 700; text-decoration: none; font-size: 1.1rem; display: flex; align-items: center; }
.brand-logo { height: 28px; width: auto; display: block; }
.brand-text { margin-left: 10px; }
.topbar nav { display: flex; align-items: center; justify-content: center; gap: 16px; flex: 1; }
.topbar nav a { color: #fde3e3; text-decoration: none; }
.topbar nav a:hover { color: #fff; font-weight: 700; }
.topbar nav a.nav-link-end { margin-left: auto; }
.topbar-user { display: flex; align-items: center; gap: 12px; font-size: 0.9rem; color: #fde3e3; }
.topbar-user .link-button:hover { font-weight: 700; }
/* Top bar never wraps a label onto two lines (2026-10-02): "Truck Board",
   "Truck Offers 1", "Toll Routes" and the name stay on one line each, and the
   bar keeps one row while it fits. Narrower screens first tighten spacing,
   shrink the search box and drop the " · role" after the name; if it still
   doesn't fit, the search/online/name group moves to a second row on the
   right - never overlapping, never splitting a word. */
.brand { flex: none; }
.topbar-inner { flex-wrap: wrap; row-gap: 8px; }
.topbar nav { flex: 1 0 auto; }
.topbar nav a, .topbar-user .link-button, .user-menu-name { white-space: nowrap; }
.topbar-user { flex: none; margin-left: auto; }
.online-users-widget { display: flex; align-items: center; gap: 14px; }
@media (max-width: 1700px) {
  .topbar-inner { padding-left: 20px; padding-right: 20px; gap: 16px; }
  .topbar nav { gap: 12px; }
  .topbar-user { gap: 10px; }
  .online-users-widget { gap: 12px; }
  .user-role-suffix { display: none; }
  .topbar #header-search-input { width: 130px; }
}
@media (max-width: 1450px) {
  .topbar nav, .topbar-user { font-size: 0.88rem; }
  .topbar nav { gap: 12px; }
  .topbar-user { gap: 10px; }
  .topbar #header-search-input { width: 120px; }
}
/* The menu grew (Photos, 2026-10-02) and wrapped to two rows at 1440px and
   even 1920px: the name never shows the " · role" any more, and below 1500px
   the logo goes without the "Smart Haul" text. */
.user-role-suffix { display: none; }
@media (max-width: 1500px) {
  .brand-text { display: none; }
}
@media (max-width: 1250px) {
  .brand-text { display: none; }
  .topbar-inner { padding-left: 16px; padding-right: 16px; gap: 14px; }
  .topbar nav { gap: 10px; }
}
/* Only meaningful below the mobile breakpoint (see @media max-width:768px),
   where it replaces the full nav - hidden on desktop. */
.hamburger-btn { display: none; }
/* Phone-only Grid bits (see the phone section at the end of this file). */
.grid-legend .grid-m-legend-toggle, .grid-m-sub { display: none; }

/* "Who's online" hover dropdown - see partials/header.ejs. */
.online-users-widget { position: relative; }
.online-users-dropdown {
  display: none; position: absolute; top: 100%; right: 0; margin-top: 8px;
  background: #fff; color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  min-width: 256px; max-height: 340px; overflow-y: auto; padding: 10px 12px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.18); z-index: 1100;
}
.online-users-dropdown.open { display: block; }
.online-users-count { font-weight: 700; font-size: 0.85rem; padding-bottom: 6px; margin-bottom: 6px; border-bottom: 1px solid var(--border); }
.online-user-row { padding: 6px 0; border-bottom: 1px solid var(--border); }
.online-user-row:last-child { border-bottom: none; }
.online-user-row strong { display: block; font-size: 0.9rem; }
.online-user-kick { display: block; margin-top: 2px; }
/* Who's-online grouped boxes: one per office, plus Carriers and Drivers
   (loads via header-app.js). Border-only so they read the same in dark mode. */
.online-box { border: 1px solid var(--border); border-radius: 8px; padding: 3px 8px 2px; margin-bottom: 8px; }
.online-box:last-of-type { margin-bottom: 2px; }
.online-box-title { display: flex; align-items: center; gap: 6px; font-size: 0.7rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); padding: 3px 0 5px; }
.online-box-count { margin-left: auto; font-size: 0.7rem; font-weight: 700; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 0 7px; text-transform: none; letter-spacing: 0; }
.online-box .online-user-row:last-child { border-bottom: none; }
.online-box-empty { font-size: 0.78rem; color: var(--muted); padding: 2px 0 4px; }
/* Clicking a name reveals "Play"/"Poke"/"Quick text" (toggles the .expanded
   class on its wrap below) - hidden the rest of the time so the
   online-users list doesn't look cluttered with three buttons next to
   every single person. Source order in partials/header.ejs (play btn,
   then name, then poke btn, then quick-text btn) plus this inline-flex
   wrap is what puts them on the correct side of the name. */
.online-user-name-wrap { position: relative; display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.online-user-name { cursor: pointer; }
.online-user-play-btn,
.online-user-poke-btn,
.online-user-quick-text-btn {
  display: none;
  color: #fff; border: none; border-radius: 6px;
  padding: 4px 10px; font-size: 0.78rem; font-weight: 600; cursor: pointer;
  white-space: nowrap; box-shadow: 0 4px 10px rgba(0,0,0,0.2);
}
.online-user-play-btn { background: var(--blue); }
.online-user-poke-btn { background: var(--navy, #1f2430); }
.online-user-quick-text-btn { background: var(--green, #1a7f45); }
/* "View as" sits next to the name and is always shown (unlike Play/Poke),
   like Kick out - a small purple pill. */
.online-user-viewas {
  border: 1px solid #4c1d95; background: #f3effc; color: #4c1d95;
  border-radius: 999px; padding: 1px 9px; font-size: 0.74rem; font-weight: 600;
  cursor: pointer; white-space: nowrap;
}
.online-user-viewas:hover { background: #4c1d95; color: #fff; }
.online-user-viewas:disabled { opacity: 0.6; cursor: default; }
.online-user-name-wrap.expanded .online-user-play-btn,
.online-user-name-wrap.expanded .online-user-poke-btn,
.online-user-name-wrap.expanded .online-user-quick-text-btn { display: inline-block; }
.online-user-play-btn:disabled,
.online-user-poke-btn:disabled,
.online-user-quick-text-btn:disabled { opacity: 0.8; cursor: default; }
.online-users-footer {
  margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border);
  display: flex; justify-content: center; gap: 14px; flex-wrap: wrap;
}
.online-users-footer a { font-size: 0.82rem; }

/* Hover dropdown on the username in the topbar - currently just links out
   to the Dispatcher Guide (src/public/dispatcher-guide.html), same
   hover-open/delayed-close shape as .online-users-widget above. */
.user-menu-widget { position: relative; }
.user-menu-dropdown {
  display: none; position: absolute; top: 100%; right: 0; margin-top: 8px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  min-width: 200px; padding: 6px; box-shadow: 0 6px 16px rgba(0,0,0,0.18); z-index: 1100;
}
.user-menu-dropdown.open { display: block; }
.user-menu-link {
  display: flex; align-items: center; gap: 8px; padding: 9px 10px; border-radius: 6px;
  color: var(--text); text-decoration: none; font-size: 0.9rem; font-weight: 600;
}
.user-menu-link:hover { background: var(--bg); }
/* "Theme" in the name menu (a button that opens the theme panel). */
button.user-menu-link { width: 100%; border: 0; background: none; font: inherit; font-size: 0.9rem; font-weight: 600; text-align: left; cursor: pointer; white-space: nowrap; }
/* Same colour as the links beside it (dark mode paints links blue). */
:root[data-theme="dark"] button.user-menu-link { color: var(--blue); }
/* Name menu extras (2026-10-04): my week, status, Do not disturb, photo, log out. */
.user-menu-dropdown { min-width: 270px; }
.user-menu-week:empty { display: none; }
.my-week { display: block; margin: 2px 2px 6px; padding: 8px 10px; border-radius: 8px; background: var(--bg); color: var(--text); text-decoration: none; }
.my-week:hover { outline: 1px solid var(--border); }
.my-week-head { display: block; font-size: 0.72rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); margin-bottom: 4px; }
.my-week-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 4px 12px; }
.my-week-cell b { display: block; font-size: 0.98rem; font-variant-numeric: tabular-nums; }
.my-week-cell small { color: var(--muted); font-size: 0.72rem; }
.my-week-cell i { font-style: normal; font-weight: 700; }
.my-week-cell i.up { color: #15803d; }
.my-week-cell i.down { color: #b91c1c; }
.user-menu-status, .user-menu-dnd { display: block; padding: 6px 10px 8px; border-bottom: 1px solid var(--border); }
.user-menu-dnd { margin-bottom: 4px; }
.user-menu-label { display: block; font-size: 0.75rem; font-weight: 700; color: var(--muted); margin-bottom: 5px; }
.user-menu-dnd-state { font-weight: 600; color: var(--text); }
.user-menu-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.status-chip { display: inline-flex; align-items: center; gap: 5px; padding: 3px 9px; border: 1px solid var(--border); border-radius: 999px; background: none; color: var(--text); font: inherit; font-size: 0.78rem; font-weight: 600; cursor: pointer; }
.status-chip:hover { background: var(--bg); }
.status-chip[aria-pressed="true"] { border-color: currentColor; background: var(--bg); box-shadow: inset 0 0 0 1px currentColor; }
.status-swatch { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
.status-available { --st: #22c55e; } .status-busy { --st: #ef4444; } .status-lunch { --st: #f59e0b; } .status-away { --st: #94a3b8; }
.status-swatch { background: var(--st); }
.status-pill { display: inline-block; padding: 0 7px; border-radius: 999px; font-size: 0.72rem; font-weight: 700; color: #fff; background: var(--st); vertical-align: middle; }
/* "View as" (routes/viewAs.js): the bar on the admin's own screen, and the
   small button in the Directory. */
.viewas-bar { position: sticky; top: 0; z-index: 2000; display: flex; align-items: center; justify-content: center; gap: 14px; padding: 6px 14px; background: #4c1d95; color: #fff; font-size: 0.9rem; font-weight: 600; }
.viewas-bar .viewas-ro { opacity: 0.8; font-weight: 500; }
.viewas-bar form { margin: 0; }
.viewas-bar button { border: 1px solid rgba(255, 255, 255, 0.6); background: rgba(255, 255, 255, 0.12); color: #fff; font: inherit; font-weight: 700; padding: 2px 12px; border-radius: 999px; cursor: pointer; }
.viewas-bar button:hover { background: rgba(255, 255, 255, 0.24); }
.dir-viewas { display: inline; margin: 0; }
.dir-viewas button { border: 1px solid var(--border); background: var(--bg); color: var(--text); font: inherit; font-size: 0.74rem; font-weight: 600; padding: 1px 8px; border-radius: 999px; cursor: pointer; vertical-align: middle; }
.dir-viewas button:hover { border-color: #4c1d95; color: #4c1d95; }
.status-pill.status-lunch { color: #422006; }
.user-menu-dnd .user-menu-dnd-on { display: none; }
.user-menu-dnd.is-on .user-menu-dnd-on { display: flex; }
.user-menu-dnd.is-on .user-menu-dnd-off { display: none; }
.user-menu-photo-form { margin: 0; }
.user-menu-photo-form label { cursor: pointer; }
.user-menu-photo-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.user-menu-logout { margin: 4px 0 0; border-top: 1px solid var(--border); padding-top: 4px; }
/* Log out lives in the name menu now; the separate top-bar link stays only with the side bar. */
@media (min-width: 769px) { :root:not([data-nav="side"]) .topbar .logout-btn { display: none; } }
:root[data-nav="side"] .user-menu-logout { display: none; }
/* Phones keep the visible Log out link (no hover there). */
@media (max-width: 768px) { .user-menu-logout { display: none; } }
/* The dot (status) and moon (Do not disturb) on your photo / the yellow button. */
.my-status-dot { position: absolute; right: -2px; bottom: -2px; width: 11px; height: 11px; border-radius: 50%; background: var(--st); border: 2px solid #fff; box-sizing: content-box; }
.my-dnd-moon { display: none; position: absolute; left: -7px; bottom: -5px; font-size: 13px; line-height: 1; filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.5)); }
:root[data-dnd="on"] .my-dnd-moon { display: block; }
/* Do not disturb: pop-ups that arrive stay hidden (and are dropped when it ends). */
:root[data-dnd="on"] #chat-toast-stack { display: none; }
.user-menu-theme-now { margin-left: auto; padding-left: 10px; font-weight: 500; font-size: 0.8rem; color: var(--muted); white-space: nowrap; }
.theme-toggle.theme-picker-btn { display: none; }
:root[data-nav="side"][data-nav-collapsed="on"] .theme-toggle.theme-picker-btn { display: inline-flex; }

.header-search { position: relative; }
.header-search-input, #header-search-input {
  border: 1px solid rgba(255,255,255,0.4); border-radius: 6px; background: rgba(255,255,255,0.12);
  color: #fff; padding: 5px 10px; font-size: 0.85rem; width: 180px;
}
#header-search-input::placeholder { color: rgba(255,255,255,0.75); }
#header-search-input:focus { outline: none; background: rgba(255,255,255,0.2); }
.header-search-results {
  display: none; position: absolute; top: 100%; right: 0; margin-top: 8px;
  background: #fff; color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  min-width: 280px; max-height: 360px; overflow-y: auto;
  box-shadow: 0 6px 16px rgba(0,0,0,0.18); z-index: 1100;
}
.header-search-results.open { display: block; }
.header-search-section-label {
  font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted);
  padding: 8px 12px 2px;
}
.header-search-item { display: block; padding: 6px 12px; color: var(--text); text-decoration: none; font-size: 0.9rem; }
.header-search-item:hover { background: var(--bg); }

.loads-summary-box {
  display: flex; gap: 24px; background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 12px 20px; margin-bottom: 16px;
}
.loads-summary-item { display: flex; flex-direction: column; }
.loads-summary-value { font-size: 1.3rem; font-weight: 700; }
.loads-summary-label { font-size: 0.78rem; color: var(--muted); }

.inline-form { display: inline; }
.link-button {
  background: none; border: none; color: #fde3e3; text-decoration: underline;
  cursor: pointer; font-size: 0.9rem; padding: 0;
}
.link-button:hover { color: #fff; }

h1 { font-size: 1.5rem; margin: 0 0 18px; }
h2 { font-size: 1.15rem; margin: 28px 0 10px; }

.card {
  background: #fff;
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 24px;
  max-width: 420px;
  margin: 60px auto;
}

.login-footer {
  max-width: 420px;
  margin: -40px auto 24px;
  text-align: center;
  color: var(--muted);
  font-size: 0.78rem;
}

.app-footer {
  text-align: center;
  color: var(--muted);
  font-size: 0.72rem;
  padding: 16px 0 8px;
}

table { width: 100%; border-collapse: collapse; background: #fff; border-radius: 8px; overflow: hidden; }
th, td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 0.92rem; }
th { background: #eef1f6; font-weight: 600; color: var(--muted); }
tr:last-child td { border-bottom: none; }

/* Drag-to-resize columns (src/public/column-resize.js) - opt-in per table
   via class="resizable" + a unique id. table-layout:fixed is set by the JS
   once it builds the <colgroup>; overflow/ellipsis here keeps a narrowed
   column's content from spilling into its neighbor instead of wrapping. */
table.resizable th, table.resizable td { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.col-resize-handle {
  position: absolute; top: 0; right: 0; width: 6px; height: 100%;
  cursor: col-resize; user-select: none;
}
.col-resize-handle:hover { background: rgba(0, 0, 0, 0.15); }

/* Show/hide columns (src/public/column-visibility.js) - opt-in per table via
   class="col-toggleable" + a unique id, same convention as .resizable above. */
.col-visually-hidden { display: none !important; }
.col-toggle-wrap { position: relative; display: inline-block; }
.col-toggle-panel {
  position: absolute; top: calc(100% + 4px); right: 0; z-index: 20;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); padding: 8px 4px; min-width: 170px;
  max-height: 320px; overflow-y: auto;
}
.col-toggle-row { display: flex; align-items: center; gap: 6px; padding: 5px 10px; font-size: 0.86rem; cursor: pointer; white-space: nowrap; }
.col-toggle-row:hover { background: #f5f7fa; }
.col-toggle-row input { margin: 0; }

/* All Loads has 14+ columns - a squeezed column (e.g. "Jun 29" wrapping to
   "Jun" / "29" on its own lines) makes every row unnecessarily tall.
   Smaller text + no wrapping keeps every value on one line; the .grid-
   scroll wrapper (loads/all-loads.ejs, same one grid.ejs uses) lets the
   table scroll horizontally instead of squeezing columns to fit. */
/* The table's own min-width is the load-bearing part here, not just a size
   preference - column-resize.js (src/public/column-resize.js)
   unconditionally sets table-layout:fixed on every .resizable table (for
   drag-to-resize) and inserts an empty <colgroup> with no explicit <col>
   widths until a user manually resizes something. With table-layout:fixed
   and an empty colgroup, browsers size columns by dividing the TABLE's own
   width evenly - per-cell min-width on th/td is not enough to stop that
   (verified in-browser: it renders far narrower than its min-width once
   the colgroup is in play). Forcing min-width on the <table> itself is
   what actually keeps the table wider than a phone's viewport, which is
   what lets .grid-scroll's horizontal scroll (plus the floating
   scrollbar) kick in instead of squeezing all 16 columns unreadably thin.
   Scoped to the #all-loads-table id, not the .all-loads-table class - that
   class is reused by admin/audit-log.ejs and games/ttt-stats.ejs for their
   own (3-4 column, non-.resizable, never actually squeezed) tables, which
   would end up absurdly wide for no reason if this applied class-wide. */
#all-loads-table { min-width: 1400px; }
.all-loads-table th, .all-loads-table td { white-space: nowrap; font-size: 0.82rem; padding: 7px 10px; min-width: 100px; }
/* Squeezes columns that never need much room (truck #, dispatcher first
   name, 2-letter state codes) so they don't eat into the horizontal
   scroll budget the wider columns (carrier/city names) actually need. */
.all-loads-table th.col-tight, .all-loads-table td.col-tight { padding-left: 6px; padding-right: 6px; min-width: 65px; max-width: 90px; overflow: hidden; text-overflow: ellipsis; }
/* Click-to-call driver name (tel: link - see telHref() in all-loads.ejs).
   The phone glyph makes it obvious the name is callable, not just styled
   like every other plain-text cell. */
.driver-tel-link { color: var(--blue); text-decoration: none; }
.driver-tel-link:hover { text-decoration: underline; }
.driver-tel-link::before { content: "\260E"; margin-right: 4px; font-size: 0.85em; }
.badge { display: inline-block; padding: 2px 8px; border-radius: 999px; font-size: 0.78rem; font-weight: 600; }
.badge-active { background: #dcfce7; color: #166534; }
.badge-inactive { background: #f1f1f1; color: #6b7280; }
/* Carrier compliance status (admin/carriers/list.ejs + view.ejs) - amber
   for "needs attention" (expiring soon or missing paperwork), red for
   already-expired insurance. */
.badge-warning { background: #fef3c7; color: #92400e; }
.badge-danger { background: #fee2e2; color: #991b1b; }
/* Owner Operator vs Company Driver (admin/drivers, customer/drivers) - blue
   so it doesn't get confused with the green/grey Active/Inactive badge
   sitting right next to it in the same table row. */
.badge-info { background: #dbeafe; color: #1e40af; }

/* Generate Invoice picker (invoices/select.ejs) - a load already on a
   prior invoice of the currently-selected type is greyed out and its
   checkbox disabled, so accounting can't double-bill it by accident. */
.invoice-load-row-locked { background: #f1f1f1; color: #9ca3af; }
.invoice-load-row-locked td { color: #9ca3af; }
.invoice-billed-cell .badge { margin-right: 4px; }

.actions-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
/* Global "← Back" above every signed-in page (partials/header.ejs). */
.page-back-row { display: flex; justify-content: flex-end; margin: 0 0 8px; }
/* Pages with a title line: footer.ejs moves Back onto it - hide the row from the start so nothing jumps while a big page loads. */
main:has(.actions-bar) .page-back-row { display: none; }
@media print { .page-back-row { display: none; } }

/* Total-count next to an admin list heading (Carriers (42), Users (13), etc.)
   - always the full list length since these pages aren't paginated. */
.list-count { font-weight: 400; font-size: 1.1rem; color: var(--muted); }

/* Groups a list heading with an inline filter (e.g. the office dropdown on
   Admin > Users) as one flex item, so .actions-bar's space-between still
   only has two things to split: this group and the page's action button. */
.actions-bar-left { display: flex; align-items: center; gap: 12px; }

/* Same pairing on the other side, for pages with more than one right-side
   button (All Loads/Grid view: Grid/Map/Columns + New Load) - without this,
   .actions-bar's space-between spreads every one of those buttons apart
   individually across the bar's full width instead of clustering them. */
.actions-bar-right { display: flex; align-items: center; gap: 8px; }
/* "Page name on the right" (personal choice, menu under your name): the page
   name - with the office next to it, office first - moves to the right and
   the buttons to the left. */
@media (min-width: 769px) {
  :root[data-header="title-right"] .actions-bar { flex-direction: row-reverse; }
  :root[data-header="title-right"] .actions-bar-left { flex-direction: row-reverse; }
}

.btn {
  display: inline-block; background: var(--blue); color: #fff; border: none;
  padding: 9px 16px; border-radius: 6px; text-decoration: none; font-size: 0.92rem;
  cursor: pointer;
}
.btn:hover { background: var(--blue-dark); }
.btn-secondary { background: #fff; color: var(--text); border: 1px solid var(--border); }
.btn-secondary:hover { background: #eef1f6; }

/* "This delivered load has no documents on file" mark, sitting next to the
   load's broker load number in All Loads (see utils/loadPaperwork.js for
   when it appears). A filled circle rather than a bare "!" so it reads as a
   deliberate marker at a glance down a dense column, and it's a link - it
   opens that load's Documents section. Sized in em so it tracks the row's
   font size wherever the table is used. */
.doc-warning {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.35em; height: 1.35em; margin-left: 5px;
  border-radius: 50%; background: var(--danger); color: #fff;
  font-size: 0.78rem; font-weight: 700; line-height: 1;
  text-decoration: none; vertical-align: middle; cursor: pointer;
}
.doc-warning:hover { filter: brightness(1.15); text-decoration: none; }
/* Same red as the mark, on the optional Docs column's zero. */
.doc-count-missing { color: var(--danger); font-weight: 700; }

form.stacked label { display: block; font-weight: 600; font-size: 0.88rem; margin: 14px 0 5px; }
/* datetime-local and textarea were missing from this list, so both fell back
   to their intrinsic browser size while every field around them stretched -
   a notes box came out ~215px wide next to an 866px input. box-sizing keeps
   the padding inside that 100% so nothing overflows its column. */
form.stacked input[type=text], form.stacked input[type=email], form.stacked input[type=password],
form.stacked input[type=number], form.stacked input[type=date], form.stacked input[type=tel],
form.stacked input[type=datetime-local],
form.stacked select, form.stacked textarea {
  width: 100%; box-sizing: border-box;
  padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.95rem;
}
/* Inherit the UI font - a bare <textarea> otherwise renders in the
   browser's monospace default, which is why the driver-notes placeholder
   looked like code. */
form.stacked textarea { font-family: inherit; resize: vertical; }
form.stacked .checkbox-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; }
form.stacked .checkbox-row label { margin: 0; font-weight: 500; }
form.stacked .hint { color: var(--muted); font-size: 0.82rem; margin-top: 4px; }
.form-actions { margin-top: 24px; display: flex; gap: 10px; }

/* Searchable dropdown widget (src/public/searchable-select.js) - wraps a
   <select class="searchable">. Base rules give it sane sizing anywhere;
   the form.stacked/.filter-row overrides below mirror those contexts'
   existing plain-select sizing exactly, so swapping a select to searchable
   doesn't change its footprint on the page. */
.ss-wrapper { position: relative; display: inline-block; min-width: 160px; }
.ss-wrapper select.searchable { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; z-index: 0; }
.ss-input { position: relative; z-index: 1; width: 100%; box-sizing: border-box; font: inherit; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.9rem; background: #fff; }
.ss-input:disabled { background: var(--bg); color: var(--muted); cursor: not-allowed; }
/* z-index 200: above the Grid's sticky legend (.grid-legend-sticky, 50), which
   used to cover the carrier dropdown; still below the fixed topbar (1000). */
.ss-menu {
  display: none; position: absolute; top: 100%; left: 0; right: 0; z-index: 200; margin-top: 2px;
  background: #fff; border: 1px solid var(--border); border-radius: 6px; max-height: 240px; overflow-y: auto;
  box-shadow: 0 4px 14px rgba(0,0,0,0.14);
}
.ss-menu.open { display: block; }
.ss-option { padding: 8px 10px; cursor: pointer; font-size: 0.9rem; }
.ss-option:hover, .ss-option.highlighted { background: var(--bg); }
.ss-option-empty { color: var(--muted); font-style: italic; }
.ss-no-results { padding: 8px 10px; color: var(--muted); font-size: 0.85rem; }

form.stacked .ss-wrapper { display: block; width: 100%; }
form.stacked .ss-input { padding: 9px 10px; font-size: 0.95rem; }
.filter-row .ss-wrapper { display: inline-block; }
.filter-row .ss-input { padding: 7px 9px; font-size: 0.88rem; }

.alert-error {
  background: var(--danger-bg); color: var(--danger); border: 1px solid #f5b5b5;
  padding: 10px 14px; border-radius: 6px; font-size: 0.9rem; margin-bottom: 16px;
}
.alert-success {
  background: #dcfce7; color: #166534; border: 1px solid #86efac;
  padding: 10px 14px; border-radius: 6px; font-size: 0.9rem; margin-bottom: 16px;
}
.alert-info {
  background: #dbeafe; color: #1e40af; border: 1px solid #93c5fd;
  padding: 10px 14px; border-radius: 6px; font-size: 0.9rem; margin-bottom: 16px;
}

.admin-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; margin-top: 20px; }
.admin-tile {
  display: block; background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 20px; text-decoration: none; color: var(--text); font-weight: 600;
}
.admin-tile:hover { border-color: var(--blue); }
.admin-tile span { display: block; font-weight: 400; color: var(--muted); font-size: 0.82rem; margin-top: 4px; }

.empty-state { color: var(--muted); padding: 30px 0; text-align: center; }

.filter-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin-bottom: 18px; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 12px 14px; }
.filter-row input, .filter-row select { padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; font-size: 0.88rem; }
.filter-row label { font-size: 0.82rem; color: var(--muted); margin-right: -4px; }

.btn-sm { padding: 5px 10px; font-size: 0.82rem; }

/* "Ask Smart Haul" (loads/all-loads.ejs + routes/loads.js POST /all/ask) -
   a separate, additive lookup above the real filter form, styled distinctly
   (a soft gradient-tinted card) so it doesn't get mistaken for another plain
   filter field. */
.ask-smart-haul { margin-bottom: 10px; }
.ask-smart-haul-bar {
  display: flex; align-items: center; gap: 8px;
  background: linear-gradient(135deg, #eef2ff, #f5f3ff);
  border: 1px solid #ddd6fe; border-radius: 10px; padding: 10px 14px;
}
.ask-smart-haul-icon { font-size: 1.05rem; color: var(--blue-dark); }
.ask-smart-haul-bar input {
  flex: 1; border: 1px solid #ddd6fe; border-radius: 8px; padding: 9px 12px;
  font-size: 0.95rem; background: #fff;
}
.ask-smart-haul-bar input::placeholder { color: #7c6fd9; font-weight: 600; }
.ask-smart-haul-hint { margin: 4px 0 10px 4px; font-size: 0.78rem; }
.ask-smart-haul-results {
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 14px 16px; margin-bottom: 12px;
}
.ask-smart-haul-understood { font-style: italic; color: var(--muted); margin: 0 0 8px; }
.ask-smart-haul-notes { margin: 0 0 8px; padding-left: 18px; color: var(--danger); font-size: 0.85rem; }
.ask-smart-haul-count { font-size: 1.6rem; font-weight: 700; margin: 4px 0; }
.ask-smart-haul-summary { font-weight: 600; margin: 0 0 10px; }
.ask-smart-haul-error { color: var(--danger); margin: 0; }
.ask-smart-haul-table { width: 100%; border-collapse: collapse; font-size: 0.85rem; }
.ask-smart-haul-table th, .ask-smart-haul-table td { padding: 6px 10px; border-bottom: 1px solid var(--border); text-align: left; white-space: nowrap; }

/* Stats page trailer-type filter - a <details> dropdown (same "click to
   reveal" pattern as the per-truck/per-day drill-downs elsewhere on this
   page) holding one checkbox per trailer type, so a user can
   check off e.g. Reefer + Dry Van together before hitting Apply. */
.trailer-type-dropdown { position: relative; }
.trailer-type-dropdown summary { list-style: none; }
.trailer-type-dropdown summary::-webkit-details-marker { display: none; }
.trailer-type-dropdown[open] summary { background: #eef1f6; }
.trailer-type-options {
  position: absolute; top: calc(100% + 4px); left: 0; z-index: 20;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 12px; box-shadow: 0 4px 14px rgba(0,0,0,0.1);
  display: flex; flex-direction: column; gap: 6px; min-width: 160px;
}
.trailer-type-options label { display: flex; align-items: center; gap: 6px; font-size: 0.88rem; text-transform: capitalize; cursor: pointer; }
.trailer-type-options .btn { margin-top: 4px; align-self: flex-start; }

/* "Trailer type snapshot" card (stats/index.ejs) - built to be screenshot
   and sent straight to a prospect, so the highlight boxes lean bigger/
   bolder than the rest of the Stats page rather than matching its usual
   dense-table density. */
.sales-snapshot { border-color: var(--blue); border-width: 2px; }
.best-load-row { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 16px; }
.best-load-box { flex: 1 1 260px; background: var(--bg); border: 1px solid var(--border); border-radius: 8px; padding: 14px 16px; }
.best-load-label { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.03em; color: var(--muted); font-weight: 600; }
.best-load-figure { font-size: 1.8rem; font-weight: 700; color: var(--blue-dark); margin: 4px 0; }
.best-load-route { font-weight: 600; }
.best-load-detail { color: var(--muted); font-size: 0.85rem; margin-top: 2px; }

.status-booked { background: #e0e7ff; color: #3730a3; }
.status-picked_up { background: #fef3c7; color: #92400e; }
.status-delivered { background: #dcfce7; color: #166534; }
.status-ready_for_payment { background: #ccfbf1; color: #115e59; }
.status-not_invoiced { background: #fef3c7; color: #92400e; }
.status-invoiced { background: #dbeafe; color: #1e40af; }
.status-ready_to_be_factored { background: #fae8ff; color: #86198f; }
.status-factored { background: #ede9fe; color: #5b21b6; }
.status-invoiced_directly { background: #e0f2fe; color: #075985; }
.status-paid { background: #d1fae5; color: #065f46; }
/* Accounting "not invoiced" (empty accounting_status) - a quiet neutral badge
   so an un-invoiced load reads as "nothing happened yet on the money side". */
.status-none { background: #f1f5f9; color: #64748b; }
/* Admin sees both tracks stacked in the one Status column. */
.status-both { display: flex; flex-direction: column; gap: 3px; align-items: flex-start; }
.status-both .status-select { width: 100%; }
/* Status control(s) at the top of the load edit page (loads/form.ejs). */
.load-status-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin: 0 0 16px; }
.load-status-bar .inline-form { display: inline-flex; margin: 0; }
.load-status-label { font-size: 0.8rem; font-weight: 700; color: var(--muted); text-transform: uppercase; letter-spacing: 0.04em; }
/* Accounting-side flag: dispatch marked the load ready for payment and it
   hasn't been invoiced yet (loads/_status-cell.ejs, My Loads, Ask results). */
.ready-pay-flag {
  display: inline-block; margin-top: 3px; padding: 1px 7px; border-radius: 999px;
  font-size: 0.7rem; font-weight: 700; white-space: nowrap;
  background: #ccfbf1; color: #115e59; border: 1px solid #5eead4;
}
:root[data-theme="dark"] .ready-pay-flag { background: rgba(20, 184, 166, 0.18); color: #5eead4; border-color: rgba(94, 234, 212, 0.45); }

/* Turns the plain status badge in All Loads into a clickable in-place
   status changer - keeps the same badge colors/shape, just strips the
   native <select> chrome so it still reads as a badge until clicked. */
/* text-align-last is what actually centres the *closed* value of a <select>;
   plain text-align alone is ignored for that by several browsers, so both are
   set. The pill is as wide as the longest option ("ready to be factored"), so
   left-aligned short values like "booked" looked stranded against one edge. */
.status-select {
  border: none; appearance: none; -webkit-appearance: none; cursor: pointer;
  text-align: center; text-align-last: center;
}

/* Invoice-only status (invoices/list.ejs, invoices/detail.ejs) - a distinct
   color per status so draft/sent/partial/overdue aren't visually confused
   with each other (they used to share colors with the load-status set
   above, e.g. draft and sent both rendered as status-booked). */
.invoice-status-draft { background: #f1f5f9; color: #475569; }
.invoice-status-sent { background: #e0e7ff; color: #3730a3; }
.invoice-status-partial { background: #fef3c7; color: #92400e; }
.invoice-status-paid { background: #d1fae5; color: #065f46; }
.invoice-status-overdue { background: #fee2e2; color: #991b1b; }
/* Invoices list (2026-10-08): click a status badge to change it, tick boxes
   for a bulk change (views/invoices/list.ejs). */
button.inv-status-btn { border: 1px solid transparent; font: inherit; font-size: 0.75rem; cursor: pointer; white-space: nowrap; }
button.inv-status-btn:hover, button.inv-status-btn[aria-expanded="true"] { border-color: currentColor; }
button.inv-status-btn:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 1px; }
.inv-status-menu .csm-item .badge { pointer-events: none; }
.inv-partial { padding: 6px 8px 4px; border-top: 1px solid var(--border); margin-top: 4px; }
.inv-partial label { display: block; font-size: 0.78rem; color: var(--muted); margin-bottom: 4px; }
.inv-partial-row { display: flex; gap: 6px; }
.inv-partial-row input { width: 110px; }
.inv-pick-col { width: 28px; text-align: center; }
.inv-pick-col input { width: 16px; height: 16px; cursor: pointer; }
.inv-bulk-bar {
  position: fixed; left: 50%; bottom: 18px; transform: translateX(-50%); z-index: 900;
  display: flex; align-items: center; flex-wrap: wrap; gap: 10px; padding: 10px 14px; max-width: calc(100vw - 32px);
  background: var(--surface, #fff); color: var(--text); border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.25);
}
.inv-bulk-bar[hidden] { display: none; }
.inv-bulk-bar label { margin: 0; font-weight: 600; }
.inv-bulk-bar select { width: auto; }
.inv-bulk-sep { width: 1px; align-self: stretch; background: var(--border); }
/* Email invoices review page (views/invoices/bulk-email.ejs). */
.be-group { padding: 12px 14px; margin-bottom: 12px; }
.be-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 6px 14px; }
.be-on, form.stacked .be-on { display: inline-flex; align-items: center; gap: 8px; margin: 0; cursor: pointer; font-size: 1rem; }
.be-on input { width: 16px; height: 16px; }
.be-to-label { margin-top: 8px; }
.be-to { max-width: 460px; }
.be-table { margin-top: 10px; font-variant-numeric: tabular-nums; }
.be-blocked { opacity: 0.8; }
.be-warn { color: #b45309; }
.be-error { color: var(--danger, #b91c1c); font-weight: 600; }
.be-result { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline; padding: 10px 14px; margin-bottom: 8px; }
.be-result .hint { flex-basis: 100%; }
.be-ok { border-left: 4px solid #16a34a; }
.be-fail { border-left: 4px solid #dc2626; }

.stats-table td.num, .stats-table th.num { text-align: right; }
.stats-table summary { cursor: pointer; font-weight: 600; }
.section-card { background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 20px; margin-bottom: 20px; }

/* CRM pipeline (crm/pipeline.ejs) - a "Sales Pipeline" overview (stage
   cards + summary tiles), a "Follow-ups Due" table, and a working Kanban
   board (native HTML5 drag-and-drop) further down the same page. */
.crm-header { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; margin-bottom: 18px; }
.crm-header-actions { display: flex; gap: 8px; flex-shrink: 0; }

.crm-stage-row { display: flex; align-items: stretch; gap: 4px; overflow-x: auto; padding-bottom: 4px; }
.crm-stage-card {
  flex: 1 1 0; min-width: 120px; display: flex; flex-direction: column; align-items: center; gap: 6px;
  padding: 14px 10px 12px; border-radius: 8px; text-decoration: none; color: var(--text);
  background: var(--stage-bg); border-bottom: 3px solid var(--stage-color);
}
.crm-stage-label { font-size: 0.72rem; font-weight: 700; color: var(--stage-color); text-align: center; }
.crm-stage-icon {
  width: 40px; height: 40px; border-radius: 8px; background: #fff; color: var(--stage-color);
  display: flex; align-items: center; justify-content: center;
}
.crm-stage-count { font-size: 1.3rem; font-weight: 700; color: var(--stage-color); }
.crm-stage-sub { font-size: 0.75rem; color: var(--muted); margin-top: -6px; }
.crm-stage-chevron { align-self: center; color: var(--muted); font-size: 1.3rem; flex-shrink: 0; }

.crm-summary-row { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--border); }
.crm-summary-tile { display: flex; align-items: center; gap: 10px; flex: 1 1 200px; }
.crm-summary-icon {
  width: 36px; height: 36px; border-radius: 8px; flex-shrink: 0;
  background: var(--tile-bg); color: var(--tile-color); display: flex; align-items: center; justify-content: center;
}
.crm-summary-text { display: flex; flex-direction: column; }
.crm-summary-label { font-size: 0.78rem; color: var(--muted); }
.crm-summary-text strong { font-size: 1.15rem; }

.crm-followups-table th, .crm-followups-table td { vertical-align: middle; }
.crm-cell-company { display: flex; align-items: center; gap: 10px; }
.crm-avatar {
  width: 32px; height: 32px; border-radius: 50%; background: var(--avatar-bg); color: var(--avatar-color);
  display: flex; align-items: center; justify-content: center; font-size: 0.78rem; font-weight: 700; flex-shrink: 0;
}
.crm-avatar-sm { width: 24px; height: 24px; font-size: 0.68rem; margin-right: 6px; }
.crm-company-name { font-weight: 600; text-decoration: none; color: var(--text); display: block; }
.crm-company-name:hover { text-decoration: underline; }
.crm-contact-name { display: block; }
.crm-next-action { display: inline-flex; align-items: center; gap: 6px; font-size: 0.88rem; }
.crm-stage-badge { background: var(--badge-bg); color: var(--badge-color); }
.crm-due { display: inline-flex; align-items: center; gap: 5px; font-size: 0.85rem; }
.crm-due.overdue { color: var(--danger); font-weight: 600; }
.crm-owner { display: inline-flex; align-items: center; font-size: 0.88rem; }
/* Must be display:inline-flex on this inner span, never display:flex (or
   any non table-cell/-row/-*) directly on the <td> itself - a table cell
   with its display overridden away from table-cell stops participating
   correctly in border-collapse row-height sizing in Chrome, which was
   exactly why this column's border-bottom rendered ~20px above its
   sibling cells' borders in every row (and doubled to ~40px on a row with
   no phone/email at all, i.e. an empty cell) instead of lining up. */
.crm-row-actions { display: inline-flex; gap: 8px; }
.crm-row-actions a { color: var(--muted); }
.crm-row-actions a:hover { color: var(--blue); }
.crm-followups-table th:last-child, .crm-followups-table td.crm-row-actions-cell,
.crm-followups-table th.crm-col-quick-note, .crm-followups-table td.crm-col-quick-note {
  width: 1%; white-space: nowrap;
}

/* column-resize.js (src/public/column-resize.js) sets table-layout:fixed
   and inserts an empty <colgroup> - with no <col> width yet (before a user
   first drags a handle), a fixed-layout table falls back to its header
   row's own CSS width instead of equal-dividing, so these give it sane
   starting proportions (Company/Contact needs much more room than Stage
   or Quick Note) until someone drags a column to their own preference. */
#crm-followups-table th:nth-child(1) { width: 28%; }
#crm-followups-table th:nth-child(2) { width: 20%; }
#crm-followups-table th:nth-child(3) { width: 12%; }
#crm-followups-table th:nth-child(4) { width: 10%; }
#crm-followups-table th:nth-child(5) { width: 16%; }
#crm-followups-table th:nth-child(6) { width: 10%; }
#crm-followups-table th:nth-child(7) { width: 4%; }

.crm-quick-note-btn {
  background: none; border: 1px solid var(--border); border-radius: 6px; padding: 4px 10px;
  font-size: 0.78rem; color: var(--muted); cursor: pointer; white-space: nowrap;
}
.crm-quick-note-btn:hover { color: var(--blue); border-color: var(--blue); }
.crm-quick-note-backdrop {
  position: fixed; inset: 0; z-index: 10050; background: rgba(0,0,0,0.5);
  display: flex; align-items: center; justify-content: center;
}
/* [hidden] must win over the display:flex above - an author stylesheet
   rule of equal specificity always beats the browser's default
   `[hidden] { display: none }`, so without this the modal would render
   open on every page load regardless of the hidden attribute. */
.crm-quick-note-backdrop[hidden] { display: none; }
.crm-quick-note-modal {
  background: #fff; border-radius: 12px; padding: 20px 24px; width: 360px; max-width: 92vw;
  box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.crm-quick-note-modal h3 { margin: 0 0 12px; font-size: 1.05rem; }
.crm-quick-note-modal textarea { width: 100%; box-sizing: border-box; }

.crm-board { display: flex; gap: 14px; overflow-x: auto; padding-bottom: 8px; align-items: flex-start; }
.crm-column {
  flex: 0 0 240px; background: var(--col-bg, #eef1f6); border: 1px solid var(--border); border-top: 3px solid var(--col-color, var(--border)); border-radius: 8px;
  display: flex; flex-direction: column; max-height: 75vh;
}
.crm-column.drag-over { background: #e0e7ff; }
.crm-column-header {
  display: flex; align-items: center; gap: 6px;
  padding: 10px 12px; border-bottom: 1px solid var(--border); font-size: 0.88rem;
}
.crm-column-header strong { flex: 1; }
.crm-column-icon { color: var(--col-color); display: flex; }
.crm-column-count { background: #fff; border-radius: 999px; padding: 1px 8px; font-size: 0.78rem; font-weight: 700; color: var(--muted); }
.crm-column-body { flex: 1; overflow-y: auto; padding: 8px; display: flex; flex-direction: column; gap: 8px; min-height: 60px; }
.crm-card {
  background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 8px 10px;
  cursor: grab; display: flex; flex-direction: column; gap: 2px;
}
.crm-card.dragging { opacity: 0.4; }
.crm-card-name { font-weight: 600; text-decoration: none; color: var(--text); }
.crm-card-name:hover { text-decoration: underline; }
.crm-card-contact { font-size: 0.85rem; }

.crm-activity-list { list-style: none; margin: 0; padding: 0; }
.crm-activity-list li { padding: 6px 0; border-bottom: 1px solid var(--border); font-size: 0.92rem; }
.crm-activity-list li:last-child { border-bottom: none; }

@media (max-width: 900px) {
  .crm-header { flex-direction: column; }
  .crm-stage-row { flex-wrap: nowrap; }
}

/* Internal chat (src/views/chat/index.ejs) - two-pane layout: conversation
   list on the left, the open thread on the right. */
.chat-layout { display: flex; gap: 16px; align-items: flex-start; }
.chat-sidebar { width: 280px; flex-shrink: 0; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 14px; }
.chat-sidebar-actions { display: flex; gap: 8px; margin-bottom: 12px; }
.chat-sidebar-actions .btn { flex: 1; padding: 7px 10px; font-size: 0.85rem; }
.chat-new-panel { margin-bottom: 14px; padding: 10px; border: 1px solid var(--border); border-radius: 6px; background: var(--bg); }
.chat-new-panel select, .chat-new-panel input[type=text] { width: 100%; margin-bottom: 8px; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; }
.chat-people-picker { max-height: 160px; overflow-y: auto; margin-bottom: 8px; border: 1px solid var(--border); border-radius: 6px; padding: 6px; background: #fff; }
.chat-people-picker-item { display: block; padding: 3px 0; font-size: 0.9rem; }
.chat-conversation-list { list-style: none; margin: 0; padding: 0; }
.chat-conversation-item a { display: block; padding: 10px 8px; border-radius: 6px; text-decoration: none; color: var(--text); }
.chat-conversation-item a:hover { background: var(--bg); }
.chat-conversation-item.active a { background: #e0e7ff; }
.chat-conversation-name { display: block; font-weight: 600; }
.chat-conversation-preview { display: block; font-size: 0.82rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.chat-unread-badge { display: inline-block; background: var(--danger); color: #fff; font-size: 0.7rem; font-weight: 700; border-radius: 999px; padding: 1px 7px; margin-left: 6px; }

.chat-thread { flex: 1; background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 14px; display: flex; flex-direction: column; min-height: 480px; max-height: 70vh; }
.chat-thread-title { margin: 0 0 10px; }
.chat-messages { flex: 1; overflow-y: auto; display: flex; flex-direction: column; gap: 10px; padding-right: 6px; }
.chat-message { max-width: 70%; background: var(--bg); border-radius: 8px; padding: 8px 12px; align-self: flex-start; }
.chat-message.own { align-self: flex-end; background: #e0e7ff; }
.chat-message-meta { font-size: 0.78rem; margin-bottom: 3px; }
.chat-message-body { margin: 0; white-space: pre-wrap; word-break: break-word; }

/* Quoted preview of the message being replied to (see reply_to_message_id,
   chatModel.listMessages) - a thin left border like a blockquote, sitting
   between the sender/time meta and the actual message body. */
.chat-reply-preview {
  display: flex; flex-direction: column; gap: 1px; border-left: 3px solid var(--border);
  padding: 3px 8px; margin-bottom: 5px; font-size: 0.8rem; opacity: 0.85;
}
.chat-message.own .chat-reply-preview { border-left-color: rgba(255,255,255,0.5); }
.chat-reply-preview-name { font-weight: 700; }
.chat-reply-preview-snippet { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Reply/Like row under every message - small plain-text buttons, only
   really noticeable on hover, so they don't visually compete with the
   message content itself. */
.chat-message-actions { display: flex; gap: 12px; margin-top: 4px; }
.chat-message-actions button {
  background: none; border: none; padding: 0; font-size: 0.76rem; color: var(--muted);
  cursor: pointer; display: flex; align-items: center; gap: 3px;
}
.chat-message-actions button:hover { color: var(--text); text-decoration: underline; }
.chat-like-btn.liked { color: var(--danger); font-weight: 700; }
.chat-like-btn.liked:hover { color: var(--danger); }

/* Indicator bar shown above the compose box while replying to a specific
   message - see startReply()/cancelReply() in chat/index.ejs and the FAB
   thread in partials/header.ejs. */
.chat-replying-indicator {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--bg); border: 1px solid var(--border); border-left: 3px solid var(--danger);
  border-radius: 6px; padding: 6px 10px; margin-bottom: 8px; font-size: 0.85rem;
}
.chat-replying-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.chat-replying-cancel { background: none; border: none; font-size: 1.1rem; line-height: 1; cursor: pointer; color: var(--muted); padding: 0 2px; flex-shrink: 0; }
.chat-replying-cancel:hover { color: var(--text); }
/* Wraps into two rows rather than one cramped one - the text box gets a
   row to itself (flex-basis: 100% forces everything else after it onto
   the next line, since flex-wrap has nowhere to put it but there), then
   the attach/emoji/GIF buttons and Send sit together below it. Matters
   most in the quick-chat FAB panel (only 320px wide - see .chat-fab-panel)
   where a single row for textarea + 4 buttons left almost nothing for
   actual typing. */
.chat-compose { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; align-items: center; }
.chat-compose textarea { flex: 1 1 100%; resize: none; padding: 10px 12px; border: 1px solid var(--border); border-radius: 6px; font-family: inherit; min-height: 52px; font-size: 0.95rem; }
.chat-attach-btn { flex-shrink: 0; padding: 8px 10px; }
.chat-compose button[type="submit"] { margin-left: auto; }
.chat-attach-name { flex-shrink: 0; max-width: 120px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; align-self: center; }
.chat-attachment-link { display: inline-block; margin-top: 4px; color: inherit; font-size: 0.9rem; }
.chat-attachment-image { display: block; margin-top: 4px; max-width: 240px; max-height: 240px; border-radius: 8px; }

.chat-emoji-wrap, .chat-gif-wrap { position: relative; flex-shrink: 0; }
.chat-emoji-popover, .chat-gif-popover {
  display: none; position: absolute; bottom: 100%; left: 0; margin-bottom: 8px;
  background: #fff; border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 6px 16px rgba(0,0,0,0.18); z-index: 1100; padding: 8px;
}
.chat-emoji-popover.open, .chat-gif-popover.open { display: block; }
.chat-emoji-popover { width: 260px; }
.chat-emoji-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.chat-emoji-tab {
  border: 1px solid var(--border); background: var(--bg); border-radius: 4px;
  font-size: 0.72rem; padding: 3px 6px; cursor: pointer;
}
.chat-emoji-tab:hover { background: #fff; }
.chat-emoji-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; max-height: 320px; overflow-y: auto; }
.chat-emoji-item { font-size: 1.2rem; text-align: center; padding: 4px; cursor: pointer; border-radius: 4px; }
.chat-emoji-item:hover { background: var(--bg); }
.chat-gif-popover { width: 280px; }
.chat-gif-popover input { width: 100%; margin-bottom: 6px; }
.chat-gif-suggestions { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.chat-gif-suggestion-chip {
  border: 1px solid var(--border); background: var(--bg); border-radius: 12px;
  font-size: 0.72rem; padding: 3px 9px; cursor: pointer;
}
.chat-gif-suggestion-chip:hover { background: #fff; }
.chat-gif-results { display: grid; grid-template-columns: repeat(2, 1fr); gap: 6px; max-height: 440px; overflow-y: auto; }
.chat-gif-result { width: 100%; border-radius: 4px; cursor: pointer; }
.chat-gif-result:hover { outline: 2px solid var(--danger); }

/* New Load form (loads/form.ejs) - paired sections (Equipment/Broker,
   Pickup/Delivery) side by side instead of one long stacked sequence, same
   responsive collapse-to-one-column pattern as .lead-page-layout (CRM
   redesign), so a dispatcher scrolls a lot less to fill one out. */
.load-two-col-row { display: flex; gap: 20px; align-items: flex-start; margin: 20px 0; }
.load-two-col { flex: 1; min-width: 0; }
@media (max-width: 900px) {
  .load-two-col-row { flex-direction: column; }
}

/* Tighter field spacing than the shared form.stacked default, specific to
   this form since it has far more fields on one page than anywhere else -
   the goal is less scrolling, not a redesign of every other form's
   spacing. */
/* New/Edit Load is by far the longest form in the app and dispatchers fill
   it in many times a day, so it's tuned for density: tighter rows, smaller
   hints, and short related fields sitting side by side rather than stacked.
   Everything here is scoped to #load-form, so no other form in the app
   changes shape. */
#load-form label { margin: 7px 0 2px; font-size: 0.85rem; }
#load-form .hint { margin-top: 2px; font-size: 0.78rem; line-height: 1.35; }
#load-form .checkbox-row { margin-top: 6px; }
#load-form .section-card { padding: 14px 16px; margin-bottom: 14px; }
#load-form h2 { font-size: 1.05rem; margin-bottom: 6px; }
#load-form input[type=text], #load-form input[type=tel], #load-form input[type=number],
#load-form input[type=email], #load-form input[type=date], #load-form input[type=datetime-local],
#load-form select, #load-form textarea { padding: 6px 9px; font-size: 0.9rem; }
#load-form textarea { line-height: 1.35; }
#load-form .ss-input { padding: 6px 9px; }

/* Puts short, related fields on one line - ZIP / city / state, contact name
   + phone, the two scheduling bars - instead of three stacked label+input
   pairs each. This is where most of the removed scrolling comes from.
   .narrow is for fixed-size fields (state, ZIP) that shouldn't take an
   equal share of the row. */
#load-form .field-row { display: flex; gap: 10px; align-items: flex-start; }
#load-form .field-row > div { flex: 1 1 0; min-width: 0; }
#load-form .field-row > div.narrow { flex: 0 0 86px; }
#load-form .field-row label { margin-top: 0; }
/* searchable-select.js wraps its <select> in an inline-block with a 160px
   floor - inside a flex cell that would blow the row's width out. */
#load-form .field-row .ss-wrapper { display: block; min-width: 0; width: 100%; }
@media (max-width: 700px) {
  #load-form .field-row { flex-direction: column; gap: 0; }
  #load-form .field-row > div.narrow { flex: 1 1 auto; }
}

/* Document quick-look overlay (src/public/doc-preview.js) - opens an
   uploaded PDF or image over the page the user is already on, so checking
   a rate confirmation doesn't cost them their place in the load. */
.doc-preview-overlay {
  position: fixed; inset: 0; z-index: 4000; display: flex; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.6); padding: 24px;
}
.doc-preview-panel {
  background: var(--card, #fff); border-radius: 10px; overflow: hidden;
  width: min(1100px, 100%); height: min(90vh, 100%); display: flex; flex-direction: column;
  box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
}
.doc-preview-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 10px 14px; border-bottom: 1px solid var(--border); flex-shrink: 0;
}
.doc-preview-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.doc-preview-actions { display: flex; gap: 8px; flex-shrink: 0; }
/* The file fills whatever room is left; --bg behind it so a PDF's own
   grey viewer chrome and a transparent PNG both sit on something sane. */
.doc-preview-body { flex: 1; min-height: 0; background: var(--bg); display: flex; }
.doc-preview-body iframe { border: 0; width: 100%; height: 100%; }
.doc-preview-body img { max-width: 100%; max-height: 100%; margin: auto; object-fit: contain; }
.doc-preview-fallback { margin: auto; padding: 24px; color: var(--muted); }
@media (max-width: 700px) {
  .doc-preview-overlay { padding: 0; }
  .doc-preview-panel { width: 100%; height: 100%; border-radius: 0; }
  .doc-preview-bar { flex-wrap: wrap; }
}

.rpm-risk-card {
  background: #fffbeb; border: 1px solid var(--warning, #d97706); color: #92400e;
  border-radius: 8px; padding: 10px 14px; margin: 4px 0 16px; font-size: 0.88rem;
}

.history-summary-result {
  background: var(--bg); border: 1px solid var(--border); border-radius: 8px;
  padding: 10px 14px; margin: 10px 0 16px; font-size: 0.9rem; font-style: italic;
}

#carrier-form label { margin: 9px 0 4px; }
#carrier-form .hint { margin-top: 2px; }
#carrier-form .checkbox-row { margin-top: 8px; }

/* Date fields default to form.stacked's full-width rule (sized for a
   dropdown or a broker name), which stretches a date input into a long
   empty bar with the picker icon stranded far to the right. Cap it to a
   normal date-field width here instead. */
#pay-statement-form input[type=date] { width: auto; max-width: 220px; }

/* Chat nav badge (unread count next to the "Chat" link in the topbar) */
.chat-nav-badge {
  display: inline-block; background: #fff; color: var(--danger); font-size: 0.7rem; font-weight: 700;
  border-radius: 999px; padding: 0 6px; margin-left: 4px; min-width: 16px; text-align: center;
}

/* Chat/Calendar sub-nav, shown at the top of both pages (partials/blog-nav.ejs)
   now that Calendar isn't a separate top-nav item - same tab look as
   .lead-tabs/.lead-tab. */
.blog-subnav { display: flex; gap: 4px; border-bottom: 1px solid var(--border); }
.blog-subnav-tab {
  background: none; border: none; border-bottom: 2px solid transparent; padding: 10px 14px;
  font-size: 0.92rem; font-weight: 600; color: var(--muted); cursor: pointer; margin-bottom: -1px;
  text-decoration: none;
}
.blog-subnav-tab:hover { color: var(--text); }
.blog-subnav-tab.active { color: var(--blue); border-bottom-color: var(--blue); }

/* Quick-chat FAB (partials/header.ejs) - a small green launcher fixed to
   the bottom-right corner of every page, plus its popup panel and the
   incoming-message toast stack. Reuses the .chat-message / .chat-compose
   styling above so the panel's thread view looks like the full chat page. */
.chat-fab {
  position: fixed; bottom: 20px; right: 20px; width: 52px; height: 52px; border-radius: 50%;
  background: var(--danger); border: none; box-shadow: 0 4px 14px rgba(0,0,0,0.25); cursor: pointer;
  display: flex; align-items: center; justify-content: center; z-index: 2000;
}
.chat-fab:hover { background: #991b1b; }
.chat-fab-badge {
  position: absolute; top: -4px; right: -4px; background: var(--danger); color: #fff;
  font-size: 0.7rem; font-weight: 700; border-radius: 999px; padding: 1px 6px; min-width: 16px; text-align: center;
}

.chat-fab-panel {
  position: fixed; bottom: 82px; right: 20px; width: 320px; max-height: min(800px, 82vh);
  background: #fff; color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.22); z-index: 1990;
  display: flex; flex-direction: column; overflow: hidden;
}
.chat-fab-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; background: var(--danger); color: #fff; font-size: 0.9rem;
}
.chat-fab-panel-actions { display: flex; align-items: center; gap: 10px; }
.chat-fab-panel-actions a { color: #fff; text-decoration: underline; }
.chat-fab-close { background: none; border: none; color: #fff; font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0; }
.chat-fab-panel-body { flex: 1; overflow-y: auto; padding: 10px 12px; min-height: 160px; max-height: min(720px, 72vh); display: flex; flex-direction: column; }
.chat-fab-new-select { width: 100%; margin-bottom: 10px; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; }
.chat-fab-conv { padding: 8px 4px; border-bottom: 1px solid var(--border); cursor: pointer; }
.chat-fab-conv:last-child { border-bottom: none; }
.chat-fab-conv:hover { background: var(--bg); }
.chat-fab-thread-header { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.chat-fab-messages { max-height: min(520px, 50vh); }
.chat-fab-compose { margin-top: 8px; }
.chat-fab-panel .chat-message { font-size: 0.85rem; }

.chat-toast-stack {
  position: fixed; bottom: 82px; right: 20px; z-index: 2010;
  display: flex; flex-direction: column-reverse; gap: 8px;
}
.chat-toast {
  width: 280px; background: #fff; border: 1px solid var(--border); border-left: 4px solid var(--danger);
  border-radius: 8px; box-shadow: 0 6px 18px rgba(0,0,0,0.2); padding: 10px 12px;
}
.chat-toast-header { display: flex; align-items: center; justify-content: space-between; margin-bottom: 4px; }
.chat-toast-name { cursor: pointer; }
.chat-toast-name:hover { text-decoration: underline; }
.chat-toast-close { background: none; border: none; color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer; padding: 0; }
.chat-toast-preview { margin: 0 0 8px; font-size: 0.85rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }
.chat-toast-reply { display: flex; gap: 6px; }
.chat-toast-reply textarea { flex: 1; resize: none; padding: 6px 8px; border: 1px solid var(--border); border-radius: 6px; font-family: inherit; font-size: 0.85rem; }
.chat-toast-reply .btn { padding: 6px 10px; font-size: 0.85rem; }

/* Text-messaging FAB - sits beside the Quick chat FAB (same row, to its
   left) rather than stacked above it, so each button's own panel opens
   directly above that button without the other button/panel overlapping
   it. Chat FAB is at right:20px, 52px wide, so this one sits at
   20+52+12=84px from the right. */
.text-fab {
  position: fixed; bottom: 20px; right: 84px; width: 52px; height: 52px; border-radius: 50%;
  background: var(--blue); border: none; box-shadow: 0 4px 14px rgba(0,0,0,0.25); cursor: pointer;
  display: flex; align-items: center; justify-content: center; z-index: 2000;
}
.text-fab:hover { filter: brightness(0.9); }
.text-fab-panel {
  position: fixed; bottom: 82px; right: 84px; width: 320px; max-height: min(800px, 82vh);
  background: #fff; color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0,0,0,0.22); z-index: 1990;
  display: flex; flex-direction: column; overflow: hidden;
}
.text-fab-panel-header {
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 12px; background: var(--blue); color: #fff; font-size: 0.9rem;
}
.text-fab-panel-actions { display: flex; align-items: center; gap: 10px; }
.text-fab-close { background: none; border: none; color: #fff; font-size: 1.3rem; line-height: 1; cursor: pointer; padding: 0; }
.text-fab-panel-body { flex: 1; overflow-y: auto; padding: 10px 12px; min-height: min(460px, 62vh); max-height: min(720px, 72vh); display: flex; flex-direction: column; }
.text-fab-new-select { width: 100%; margin-bottom: 8px; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; }
.text-fab-manual-row { display: flex; gap: 6px; margin-bottom: 10px; }
.text-fab-manual-input { flex: 1; padding: 7px 9px; border: 1px solid var(--border); border-radius: 6px; }
.text-fab-conv { padding: 8px 4px; border-bottom: 1px solid var(--border); cursor: pointer; display: flex; flex-direction: column; }
.text-fab-conv:last-child { border-bottom: none; }
.text-fab-conv:hover { background: var(--bg); }
.text-fab-conv-name { font-weight: 600; }
.text-fab-conv-preview { font-size: 0.85rem; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.text-fab-conv-time { font-size: 0.75rem; color: var(--muted); }
.text-fab-thread-header { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.text-fab-messages { flex: 1; overflow-y: auto; max-height: min(520px, 50vh); display: flex; flex-direction: column; gap: 6px; }
.text-fab-msg { max-width: 85%; padding: 6px 10px; border-radius: 10px; font-size: 0.85rem; }
.text-fab-msg p { margin: 0; }
.text-fab-msg.outbound { align-self: flex-end; background: var(--blue); color: #fff; }
.text-fab-msg.inbound { align-self: flex-start; background: var(--bg); border: 1px solid var(--border); }
.text-fab-meta { display: block; margin-top: 3px; font-size: 0.7rem; opacity: 0.8; }
/* A text that never reached the phone (status failed) - no longer looks like a normal blue bubble. */
.text-fab-msg.outbound.failed { background: #fee2e2; color: #7f1d1d; border: 1px solid #fca5a5; }
.text-fab-failed { display: block; margin-top: 3px; font-size: 0.72rem; font-weight: 700; color: #b91c1c; }
.text-fab-back { color: var(--blue) !important; }
.text-fab-back:hover { color: var(--blue-dark) !important; }
.text-fab-suggest { margin-top: 8px; }
.text-fab-suggest-toggle { color: var(--blue) !important; font-size: 0.82rem; }
.text-fab-suggest-toggle:hover { color: var(--blue-dark) !important; }
.text-fab-suggest-panel { margin-top: 6px; padding: 8px; background: var(--bg); border: 1px solid var(--border); border-radius: 6px; }
.text-fab-suggest-langs { display: flex; gap: 6px; }
.text-fab-suggest-langs .btn { flex: 1; padding: 5px 8px; font-size: 0.82rem; }
.text-fab-suggest-list { display: flex; flex-direction: column; gap: 4px; margin-top: 6px; max-height: 180px; overflow-y: auto; }
.text-fab-suggest-item { text-align: left; padding: 6px 8px; font-size: 0.8rem; line-height: 1.3; border: 1px solid var(--border); border-radius: 6px; background: #fff; cursor: pointer; }
.text-fab-suggest-item:hover { background: var(--bg); border-color: var(--blue); }
.text-fab-compose { display: flex; gap: 8px; margin-top: 8px; }
.text-fab-compose textarea { flex: 1; resize: none; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font-family: inherit; min-height: 44px; }
.text-fab-send-error { color: var(--danger); }

/* Big centered notification (currently just "You were poked by X" - see
   showPokeToast in partials/header.ejs) - deliberately not a corner toast
   like chat's, since the whole point is to be impossible to miss. The
   stack wrapper has pointer-events:none so it never blocks clicks on the
   page underneath except where a box actually is. */
.center-overlay-stack {
  position: fixed; inset: 0; z-index: 10000; pointer-events: none;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 16px;
}
.center-overlay-box {
  pointer-events: auto; position: relative; background: #fff; border-radius: 20px;
  padding: 40px 70px; max-width: 90vw; text-align: center;
  box-shadow: 0 20px 60px rgba(0,0,0,0.35); animation: center-overlay-pop 0.3s ease-out;
}
@keyframes center-overlay-pop {
  0% { transform: scale(0.7); opacity: 0; }
  100% { transform: scale(1); opacity: 1; }
}
.center-overlay-close {
  position: absolute; top: 8px; right: 14px; background: none; border: none;
  font-size: 1.5rem; line-height: 1; color: var(--muted); cursor: pointer; padding: 0;
}
.poke-overlay-emoji { font-size: 4rem; line-height: 1; margin-bottom: 10px; white-space: nowrap; }
.poke-overlay-box h2 { margin: 0; font-size: 2.2rem; }

/* Tic-Tac-Toe modal (see the tttShow*/tttStartInvite functions in
   partials/header.ejs) - a real modal (dimmed, blocking backdrop) rather
   than a toast, since it needs actual input (symbol choice, board clicks)
   rather than just being glanced at. Sized to roughly the "5-10 inch"
   popup window the feature was requested as. */
.ttt-backdrop {
  position: fixed; inset: 0; z-index: 10050; background: rgba(0,0,0,0.5);
  display: flex; align-items: center; justify-content: center;
}
.ttt-modal {
  background: #fff; border-radius: 16px; padding: 28px 32px; width: 480px; max-width: 92vw;
  text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.4);
}
.ttt-modal h2 { margin: 0 0 10px; font-size: 1.3rem; }
.ttt-symbol-choice { display: flex; gap: 12px; justify-content: center; margin-top: 12px; }
.ttt-turn-banner { font-weight: 700; margin: 10px 0 16px; font-size: 1.05rem; }
.ttt-board {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px;
  width: 100%; max-width: 340px; margin: 0 auto;
}
.ttt-cell {
  aspect-ratio: 1 / 1; font-size: 2.4rem; font-weight: 800; color: var(--text);
  border: 2px solid var(--border); border-radius: 10px; background: var(--bg); cursor: pointer;
}
.ttt-cell:disabled { cursor: default; }
.ttt-cell:not(:disabled):hover { background: #eef1f6; }

/* Unscheduled-loads nag bar (header.ejs, filled by header-app.js). Sits
   directly under the topbar on every page, so it's deliberately shallow -
   it has to be impossible to miss without stealing a row of the board on
   the pages people actually work in. Red rather than amber: this is a rule
   being broken, not a heads-up. Same palette as .badge-danger elsewhere. */
.unscheduled-banner {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  flex-wrap: wrap; padding: 8px 16px;
  background: #fee2e2; color: #991b1b;
  border-bottom: 1px solid #fca5a5;
  font-size: 0.88rem; font-weight: 600;
}
.unscheduled-banner a { color: #7f1d1d; text-decoration: underline; white-space: nowrap; }
:root[data-theme="dark"] .unscheduled-banner {
  background: #450a0a; color: #fecaca; border-bottom-color: #7f1d1d;
}
:root[data-theme="dark"] .unscheduled-banner a { color: #fecaca; }

/* Hauly Runner (games/runner.ejs) - the <hauly-runner> element samples
   these --color-* custom properties for its canvas palette (it can't read
   --bg/--text directly; that naming is the widget's own contract, kept
   generic so the same file drops into non-Smart-Haul pages). Mapped to the
   app palette here, with the brand red left as the accent because the
   sprites - the logo tile especially - are drawn in it. The dark override
   further down keeps the canvas in step with the topbar toggle. */
.runner-stage {
  border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: #fff;
}
.runner-stage hauly-runner {
  --color-bg: #ffffff;
  --color-text: #1f2430;
  --color-accent: #ec3013;
  --color-accent-700: #ae1800;
  --color-neutral-300: #e6ebf2;
  --color-neutral-500: #5b6472;
  --color-neutral-700: #3a4150;
  --color-neutral-900: #1f2430;
  outline: none;
}

/* Truck Status grid view (loads/grid.ejs) - dense, spreadsheet-like layout.
   Wider than the standard .container, so it scrolls horizontally on its
   own rather than forcing the whole page wide. */
.grid-scroll { overflow-x: auto; max-width: 100%; }

/* Floating horizontal scrollbar (loads/grid.ejs) - fixed to the bottom of
   the viewport so it's reachable without scrolling the whole page down to
   the real one below a tall grid. Same fixed-position + slide
   show/hide pattern as .topbar above. */
.grid-floating-scrollbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 999;
  background: #fff; border-top: 1px solid var(--border);
  overflow-x: auto; overflow-y: hidden;
  padding: 8px 1in;
  transition: transform 0.25s ease;
}
.grid-floating-scrollbar.grid-floating-scrollbar-hidden {
  transform: translateY(100%);
}
.grid-floating-scrollbar-spacer { height: 1px; }
/* overflow:visible overrides the generic `table` rule's overflow:hidden
   (used elsewhere just to round table corners) - that overflow:hidden
   makes the table itself the nearest clipping ancestor for the sticky
   Carrier/Driver/Truck/Trailer columns below, which silently neutralizes
   their position:sticky (it needs .grid-scroll, the actual horizontally
   scrolling element, to be the nearest one instead). */
.truck-grid { width: auto; min-width: 100%; table-layout: fixed; font-size: 0.78rem; overflow: visible; }
.truck-grid th, .truck-grid td { white-space: nowrap; padding: 3px 7px; line-height: 1.25; }
/* Week mode's day columns are labeled by weekday name alone (Monday,
   Tuesday...) - this is the actual calendar date underneath, so it's
   clear at a glance which Monday/Tuesday is being looked at. Not bold,
   unlike the weekday name above it, so it reads as secondary. */
.grid-day-date { display: block; font-weight: 400; font-size: 0.85em; opacity: 0.75; }
/* Centers the weekday name and the date line under it on top of each other
   (both were left-aligned before, so the shorter date line sat flush left
   under the first letter of the day name instead of centered beneath it). */
.truck-grid-day-header { text-align: center; }
.truck-grid-carrier, .truck-grid-truck, .truck-grid-driver, .truck-grid-trailer {
  font-weight: 600; position: sticky;
  /* Sit above the day cells so the load chips scroll UNDER these frozen
     columns instead of bleeding over them during horizontal scroll. Kept low
     (2) so it stays well under tooltips (500) and modals. */
  z-index: 2;
  /* Flat, calm background regardless of truck stage - the red/amber/green
     status now lives on the load chips themselves (see .load-chip-*
     below), so this column doesn't need to double up as a status light.
     Color is a CSS variable, set per-dispatcher-group table (see
     .grid-dispatcher-group-title's table in loads/grid.ejs) so each
     dispatcher's box can have its own color; unset groups fall back to
     the original flat light green. */
  background: var(--truck-grid-bg, #dcfce7);
  /* Fixed dark fallback, NOT inherit: the default background is a hardcoded
     light green in BOTH themes, so inheriting the page text colour turned the
     carrier/trailer names light-on-light-green (invisible) in dark mode for any
     dispatcher group without a custom colour. A dispatcher group WITH a colour
     still sets --truck-grid-fg and wins. */
  color: var(--truck-grid-fg, #14532d);
}
/* Column order (left to right): Carrier, Driver, Truck, Trailer - each
   sticky column's `left` offset stacks on the ones before it. */
/* Long carrier/driver names wrap onto a second line instead of being cut
   off. The board toggle + copy icons live in the Trailer cell (after the
   trailer number), so the Truck column only holds the number. Widths match
   the week view's colgroup in loads/grid.ejs (150/100/64/110). */
.truck-grid-carrier { left: 0; min-width: 176px; max-width: 176px; white-space: normal; overflow-wrap: anywhere; line-height: 1.25; }
.truck-grid-driver {
  left: 176px; min-width: 96px; max-width: 96px;
  white-space: normal; overflow-wrap: anywhere; line-height: 1.25; font-weight: 500;
}
.truck-grid-truck { left: 272px; min-width: 56px; max-width: 56px; overflow-wrap: anywhere; }
.truck-grid-trailer {
  left: 328px; min-width: 104px; max-width: 104px; border-right: 2px solid var(--border);
  overflow-wrap: anywhere; font-weight: 500;
}
/* Beats the grid-wide .truck-grid td { white-space: nowrap } so these four
   label cells can wrap. */
.truck-grid td.truck-grid-carrier, .truck-grid td.truck-grid-driver,
.truck-grid td.truck-grid-truck, .truck-grid td.truck-grid-trailer { white-space: normal; }
.grid-row-actions { display: inline-flex; align-items: center; white-space: nowrap; }
.grid-row-actions form { display: inline-flex; }
/* Inside the Carrier and Trailer cells: one row, everything centred
   vertically. Carrier = handle | fixed board-icon slot | name (names line up);
   Trailer = number | copy icon pinned right (copy icons line up). */
.truck-grid td.truck-grid-carrier, .truck-grid td.truck-grid-driver,
.truck-grid td.truck-grid-truck, .truck-grid td.truck-grid-trailer { vertical-align: middle; }
.grid-label-flex { display: flex; align-items: center; gap: 4px; min-width: 0; }
.grid-label-flex .truck-row-drag { flex: 0 0 auto; }
.grid-board-slot { flex: 0 0 20px; width: 20px; display: inline-flex; justify-content: center; }
.grid-board-slot form { display: inline-flex; }
.grid-board-slot .grid-post-btn { margin-left: 0; }
.grid-label-text { flex: 1 1 auto; min-width: 0; }
.grid-trailer-num { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.truck-grid-trailer .grid-row-actions { margin-left: auto; flex: 0 0 auto; }
.truck-grid-trailer .grid-copy-btn { margin-left: 0; }
/* No underline on the names (Yaro's call) - hover still underlines so they
   read as clickable. */
.truck-grid-carrier a, .truck-grid-truck a, .truck-grid-trailer a, .truck-grid-driver a { color: inherit; text-decoration: none; }

/* "Post to board" button in the truck cell (see loads/grid.ejs). A small
   inline icon next to the truck number - muted until the truck is actually on
   the public Available Trucks board, then green. No underline (it is not a
   text link) and it stops the row's default link decoration bleeding in. */
.grid-post-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; margin-left: 4px; vertical-align: middle;
  border-radius: 5px; color: var(--muted); text-decoration: none !important;
  opacity: 0.55; transition: opacity 0.12s, color 0.12s, background 0.12s;
  background: none; border: 0; padding: 0; cursor: pointer; font: inherit;
}
.grid-post-btn:hover { opacity: 1; background: rgba(127,127,127,0.14); }
.grid-post-btn.on { color: #0f7d3d; opacity: 1; }
/* Copy driver/phone/truck/trailer button (loads/grid.ejs) - same shape as the
   board toggle beside it; flashes green on success. */
.grid-copy-btn {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; margin-left: 2px; vertical-align: middle;
  border-radius: 5px; color: inherit; opacity: 0.55; cursor: pointer;
  background: none; border: 0; padding: 0; font: inherit;
  transition: opacity 0.12s, color 0.12s, background 0.12s;
}
.grid-copy-btn:hover { opacity: 1; background: rgba(127,127,127,0.14); }
.grid-copy-btn.copied { color: #22c55e; opacity: 1; }
.grid-copy-btn.copy-failed { color: #ef4444; opacity: 1; }
.grid-post-btn.on:hover { background: rgba(15,125,61,0.14); }
.truck-grid-carrier a:hover, .truck-grid-truck a:hover, .truck-grid-trailer a:hover, .truck-grid-driver a:hover { text-decoration: underline; }

/* Custom hover tooltip for the Carrier/Driver/Truck/Trailer columns (one
   shared instance, see loads/grid.ejs) - a real element rather than a
   title attribute so it stays open when the mouse moves into it and its
   text can be selected/copied. */
.grid-hover-tooltip {
  display: none; position: fixed; z-index: 500; max-width: 280px;
  background: #fff; color: var(--text); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 4px 16px rgba(0,0,0,0.18); padding: 10px 12px; font-size: 0.82rem;
}
.grid-hover-tooltip-hint { margin: 0 0 6px; color: var(--muted); font-style: italic; }
.grid-hover-tooltip-text { white-space: pre-line; user-select: text; margin-bottom: 8px; line-height: 1.4; }
.grid-hover-tooltip-copy { font-size: 0.78rem; padding: 3px 10px; }
.grid-hover-tooltip-rows { display: flex; flex-direction: column; gap: 6px; }
.grid-hover-tooltip-rows:empty { display: none; }
.grid-hover-tooltip-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; white-space: nowrap; }
.grid-hover-tooltip-row .grid-hover-tooltip-copy { margin: 0; flex: none; }
/* A long value (an email) wraps inside the box instead of pushing its Copy button out (2026-10-03). */
.grid-hover-tooltip-row > span { min-width: 0; white-space: normal; overflow-wrap: anywhere; }
.grid-hover-tooltip:has(.grid-hover-tooltip-row) { max-width: 340px; }

.grid-legend { display: flex; flex-direction: column; gap: 8px; margin-bottom: 14px; font-size: 0.85rem; color: var(--muted); }
.grid-legend-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 18px; }
/* Wraps the two legend rows (folds away on phones) - same 8px spacing as before. */
.grid-legend-more { display: flex; flex-direction: column; gap: 8px; }
.grid-legend-markers { gap: 6px; }
.grid-legend-label { font-size: 0.78rem; margin-right: 4px; }
/* Follows the fixed top bar: sits right under it, and slides away with it on
   scroll-down / comes back with it on scroll-up (body.topbar-is-hidden is
   toggled next to .topbar-hidden in header-app.js; --topbar-h is the bar's
   measured height). Lets a dispatcher reach the drag chips from a truck at
   the bottom of a long board. */
.grid-legend-sticky {
  position: sticky; top: var(--topbar-h, 56px); z-index: 50;
  margin-left: -12px; margin-right: -12px; padding: 8px 12px;
  background: color-mix(in srgb, var(--bg) 94%, transparent);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  border-bottom: 1px solid var(--border);
  transition: transform 0.25s ease;
}
body.topbar-is-hidden .grid-legend-sticky { transform: translateY(calc(-1 * var(--topbar-h, 56px) - 100%)); }
/* The Grid's filter bar (carrier / view / week / Show grid) lives at the top
   of the sticky bar (loads/grid.ejs) - flat, no card of its own. */
.grid-legend-sticky .grid-legend-filters { margin: 0; padding: 0 0 2px; background: none; border: 0; border-radius: 0; box-shadow: none; }
/* Click-to-sort headers (public/table-sort.js). */
th.sortable-th { cursor: pointer; user-select: none; }
th.sortable-th:hover { color: var(--text); }
th.sortable-th::after { content: "\2195"; margin-left: 4px; opacity: 0.3; font-size: 0.85em; }
th.sortable-th.sorted-asc::after { content: "\25B2"; opacity: 0.8; }
th.sortable-th.sorted-desc::after { content: "\25BC"; opacity: 0.8; }
/* ‹ calendar › in the Grid filter bar. */
.grid-week-nav { display: inline-flex; align-items: stretch; gap: 4px; }
.grid-week-step {
  display: inline-flex; align-items: center; justify-content: center; min-width: 32px; padding: 0 7px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--surface, #fff); color: var(--text); cursor: pointer;
}
.grid-week-step:hover { background: var(--surface-2, #eef2f7); }
.grid-week-step:focus-visible { outline: 2px solid var(--blue, #2563eb); outline-offset: 1px; }
/* The week box: shows "09/21 – 09/27/2026"; the real date input sits
   invisibly underneath so the browser's calendar opens there
   (public/week-nav.js). */
[data-week-nav] [hidden] { display: none !important; }
.week-nav-field { position: relative; display: inline-flex; }
.week-nav-range {
  display: inline-flex; align-items: center; gap: 8px; padding: 7px 10px;
  border: 1px solid var(--border); border-radius: 6px; background: var(--surface, #fff); color: var(--text);
  font: inherit; font-size: 0.88rem; font-variant-numeric: tabular-nums; white-space: nowrap; cursor: pointer;
}
.week-nav-range:hover { background: var(--surface-2, #eef2f7); }
.week-nav-range:focus-visible { outline: 2px solid var(--blue, #2563eb); outline-offset: 1px; }
.week-nav-range svg { color: var(--muted); flex: none; }
.week-nav-input { position: absolute; left: 0; bottom: 0; width: 100%; height: 100%; opacity: 0; pointer-events: none; }
/* No showPicker() (old browser): fall back to the plain date box. */
.week-nav-plain .week-nav-range { display: none; }
.week-nav-plain .week-nav-input { position: static; opacity: 1; pointer-events: auto; width: auto; height: auto; }
/* The day/date header row (Carrier ... Monday 09/21 ... Total) follows the
   scroll too (2026-09-27): it parks right under the top bar + markers bar
   (--grid-legend-h is measured in loads/grid.ejs), and moves up to the very
   top when those two slide away on scroll-down. Each dispatcher group's table
   keeps its own header, so it hands over to the next group's as you scroll.
   Week view on a computer does it in CSS: the week always fits the screen, so
   .grid-scroll can drop its horizontal-scroll box (a scroll box would pin the
   sticky cells to itself instead of the page). Month view and phones keep the
   scroll box, so there loads/grid.ejs slides the header down in JS instead.
   z-index 3 = above the frozen label columns (2), below the markers bar (50).
   The bottom line is a shadow because collapsed-table borders don't travel
   with a sticky cell. */
.truck-grid thead th { box-shadow: inset 0 -1px 0 var(--border); }
@media (min-width: 761px) {
  .grid-scroll:has(.truck-grid-week) { overflow: visible; }
  .truck-grid-week thead th {
    position: sticky; z-index: 3;
    top: calc(var(--topbar-h, 56px) + var(--grid-legend-h, 0px));
    transition: top 0.25s ease;
  }
  body.topbar-is-hidden .truck-grid-week thead th { top: 0; }
}
.legend-swatch { display: inline-block; width: 12px; height: 12px; border-radius: 3px; border: 1px solid var(--border); margin-right: 5px; vertical-align: middle; }
/* Team lead's combined team total, shown above the grid (loads/grid.ejs). */
.grid-team-total {
  display: inline-flex; align-items: baseline; flex-wrap: wrap; gap: 4px 14px;
  padding: 10px 16px; margin: 0 0 16px; border-radius: 10px;
  background: var(--surface, #fff); border: 1px solid var(--border); border-left: 4px solid var(--brand, #b91c1c);
}
.grid-team-total .gtt-label { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; }
.grid-team-total .gtt-period { font-weight: 400; text-transform: none; letter-spacing: 0; }
.grid-team-total .gtt-gross { font-size: 1.4rem; font-weight: 800; color: #0f7d3d; font-variant-numeric: tabular-nums; }
.grid-team-total .gtt-sub { font-size: 0.82rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Admin's per-team gross breakdown, shown above the grid (loads/grid.ejs). */
.grid-team-breakdown { margin: 0 0 16px; }
.grid-team-breakdown .gtb-title { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; margin-bottom: 7px; }
.grid-team-breakdown .gtb-cards { display: flex; flex-wrap: wrap; gap: 10px; }
.gtb-card {
  display: flex; flex-direction: column; gap: 1px; min-width: 150px;
  padding: 9px 14px; border-radius: 10px; background: var(--surface, #fff);
  border: 1px solid var(--border); border-left: 4px solid var(--brand, #b91c1c);
}
.gtb-card.gtb-indep { border-left-color: var(--muted); }
/* "All teams" total: pushed to the far right of the row, a touch stronger than a team box. */
.gtb-card.gtb-all { margin-left: auto; border: 2px solid #0f7d3d; border-left-width: 5px; min-width: 190px; }
.gtb-card.gtb-all .gtb-gross { font-size: 1.3rem; }
/* "My preferences" (preferences/index.ejs) + what the Grid options hide. */
:root[data-grid-rpm="off"] .chip-rpm { display: none; }
:root[data-grid-markers="off"] .grid-legend-markers { display: none; }
:root[data-grid-teamtotals="off"] .grid-team-total, :root[data-grid-teamtotals="off"] .grid-team-breakdown { display: none; }
.theme-picker-more { display: block; margin-top: 8px; padding-top: 8px; border-top: 1px solid var(--border); font-size: 0.85rem; font-weight: 600; text-decoration: none; }
.pref-intro { margin: -6px 0 14px; }
.pref-saved { color: #0f7d3d; font-weight: 600; margin: 0 0 12px; }
.pref-form { display: flex; flex-direction: column; gap: 0; max-width: 820px; }
.pref-section { max-width: 820px; }
.pref-section h2 { margin: 0 0 4px; font-size: 1.1rem; }
.pref-select { min-width: 260px; margin-top: 6px; }
.pref-choices { display: flex; flex-direction: column; gap: 8px; margin-top: 8px; }
.pref-choices.pref-inline { flex-direction: row; flex-wrap: wrap; gap: 8px 18px; margin-top: 0; }
.pref-choice { display: flex; align-items: flex-start; gap: 8px; cursor: pointer; }
.pref-choice input { margin-top: 3px; }
.pref-choice .hint { display: block; font-weight: 400; }
.pref-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; flex-wrap: wrap; padding: 10px 0; border-top: 1px solid var(--border); }
.pref-row:first-of-type { border-top: 0; }
.pref-label { font-weight: 600; }
.pref-actions { margin: 4px 0 22px; }
.pref-bg-upload { display: flex; align-items: center; flex-wrap: wrap; gap: 10px; margin: 12px 0 4px; }
.pref-bg-group { margin: 14px 0 6px; font-size: 0.78rem; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; opacity: 0.7; }
.pref-bg-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; max-width: 820px; }
.pref-bg-tile { position: relative; display: flex; flex-direction: column; gap: 5px; cursor: pointer; }
.pref-bg-tile input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.pref-bg-img { display: block; aspect-ratio: 16 / 9; border-radius: 8px; border: 2px solid var(--border); background: var(--surface, #fff) center / cover no-repeat; transition: border-color 0.15s, box-shadow 0.15s; }
.pref-bg-name { font-size: 0.85rem; font-weight: 600; }
.pref-bg-tile:hover .pref-bg-img { border-color: var(--brand); }
.pref-bg-tile input:checked + .pref-bg-img { border-color: var(--brand); box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand) 35%, transparent); }
.pref-bg-tile input:checked ~ .pref-bg-name::before { content: "\2713  "; color: var(--brand); }
.pref-bg-tile input:focus-visible + .pref-bg-img { outline: 2px solid var(--brand); outline-offset: 2px; }
.pref-bg-tile.is-disabled { cursor: default; opacity: 0.55; }
.pref-bg-pick { cursor: pointer; position: relative; }
.pref-bg-pick input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.pref-bg-pick:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }
.pref-bg-opacity { margin-top: 10px; border-top: 1px solid var(--border); }
.pref-range-wrap { display: flex; align-items: center; gap: 10px; flex: 1 1 260px; max-width: 460px; }
.pref-range-wrap input[type=range] { flex: 1; accent-color: var(--brand); }
.pref-range-wrap output { min-width: 3.2em; text-align: right; font-variant-numeric: tabular-nums; font-weight: 600; }

/* Company Directory (directory/index.ejs). */
.directory-link { color: inherit; }
.dir-intro { margin: -6px 0 14px; }
.dir-top { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 16px; align-items: start; }
@media (max-width: 860px) { .dir-top { grid-template-columns: 1fr; } }
.dir-top h2 { margin: 0 0 4px; font-size: 1.1rem; }
.dir-lookup input[type="search"], .dir-filter input { width: 100%; padding: 10px 12px; font-size: 1rem; }
.dir-lookup-results { margin-top: 10px; display: flex; flex-direction: column; gap: 10px; }
.dir-hit { border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
.dir-hit-head { display: flex; align-items: center; gap: 8px; }
.dir-hit-kind { font-size: 0.68rem; text-transform: uppercase; letter-spacing: 0.06em; font-weight: 700; padding: 2px 6px; border-radius: 4px; background: var(--bg-alt, #f3f4f6); color: var(--muted); }
.dir-hit-person { display: flex; align-items: center; flex-wrap: wrap; gap: 4px 10px; margin-top: 6px; }
.dir-hit-name { font-weight: 600; }
.dir-me-form { display: flex; flex-wrap: wrap; gap: 8px 12px; align-items: flex-end; }
.dir-me-form label { display: flex; flex-direction: column; gap: 3px; font-size: 0.85rem; font-weight: 600; }
.dir-me-form input { width: 160px; }
.dir-saved { color: #0f7d3d; font-weight: 600; margin: 0 0 8px; }
.dir-filter { margin: 4px 0 6px; display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.dir-filter input { flex: 1 1 320px; max-width: 520px; }
.dir-office-tabs { display: flex; gap: 6px; flex-wrap: wrap; }
.dir-office-tab { font: inherit; font-weight: 600; padding: 7px 14px; border-radius: 999px; border: 1px solid var(--border); background: var(--surface, #fff); color: var(--text); cursor: pointer; }
.dir-office-tab:hover { border-color: var(--brand, #b91c1c); }
.dir-office-tab.active { background: var(--brand, #b91c1c); border-color: var(--brand, #b91c1c); color: #fff; }
.dir-office-tab:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; }
.dir-scope { margin: 2px 0 8px; }
.dir-view-toggle { display: inline-flex; border: 1px solid var(--border); border-radius: 999px; overflow: hidden; margin-left: auto; }
.dir-view-btn { font: inherit; font-weight: 600; padding: 7px 14px; border: 0; background: var(--surface, #fff); color: var(--text); cursor: pointer; }
.dir-view-btn + .dir-view-btn { border-left: 1px solid var(--border); }
.dir-view-btn.active { background: var(--text); color: var(--surface, #fff); }
.dir-view-btn:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: -2px; }
#dir-teams .dir-office-title:first-child { margin-top: 6px; }
.dir-other-title { margin: 6px 0 4px; font-size: 0.95rem; }
.dir-list-card { padding: 6px 14px 10px; overflow-x: auto; }
.dir-list-card .dir-table th { text-align: left; font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); padding: 8px 6px; }
.dir-list-card .dir-table .dir-office-cell, .dir-list-card .dir-table .dir-team { font-size: 0.86rem; white-space: nowrap; }
.dir-office-title { margin: 22px 0 10px; }
.dir-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(420px, 1fr)); gap: 14px; }
@media (max-width: 520px) { .dir-cards { grid-template-columns: 1fr; } }
.dir-card { margin: 0; padding: 12px 14px; }
.dir-card h3 { margin: 0 0 6px; font-size: 1rem; }
.dir-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.dir-table td { padding: 7px 6px; border-top: 1px solid var(--border); vertical-align: middle; }
.dir-table .dir-name .hint { font-size: 0.78rem; margin-left: 16px; }
.dir-table .dir-email { word-break: break-all; font-size: 0.82rem; }
.dir-table .dir-phone, .dir-hit-person a { white-space: nowrap; }
.dir-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: #cbd5e1; margin-right: 6px; vertical-align: middle; }
.dir-dot.on { background: #16a34a; box-shadow: 0 0 0 2px rgba(22, 163, 74, 0.2); }
.dir-badge { font-size: 0.66rem; text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700; padding: 1px 6px; border-radius: 999px; background: #fef3c7; color: #92400e; }
.dir-ext-btn { font: inherit; font-weight: 800; font-size: 1rem; font-variant-numeric: tabular-nums; padding: 3px 9px; border-radius: 6px; border: 1px solid var(--border); background: var(--bg-alt, #f3f4f6); color: var(--text); cursor: pointer; white-space: nowrap; }
.dir-ext-btn:hover { border-color: var(--brand, #b91c1c); }
.dir-ext-btn:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; }
.dir-ext-btn.copied { background: #dcfce7; border-color: #16a34a; color: #14532d; }
:root[data-theme="dark"] .dir-badge { background: rgba(251, 191, 36, 0.15); color: #fbbf24; }
:root[data-theme="dark"] .dir-ext-btn.copied { background: rgba(74, 222, 128, 0.15); color: #4ade80; }

/* Stats tabs + Overview top-5 panels (stats/index.ejs). */
.stats-tabs { display: flex; flex-wrap: wrap; gap: 4px; margin: 4px 0 16px; border-bottom: 2px solid var(--border); }
.stats-tab { padding: 8px 14px; border-radius: 8px 8px 0 0; color: var(--muted); font-weight: 600; text-decoration: none; margin-bottom: -2px; border-bottom: 2px solid transparent; }
.stats-tab:hover { color: var(--text); background: var(--bg-alt, #f3f4f6); }
.stats-tab.active { color: var(--brand, #b91c1c); border-bottom-color: var(--brand, #b91c1c); }
.stats-tab:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; }
.stats-top-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; margin: 16px 0 24px; }
.stats-top-panel { background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; }
.stats-top-head { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.stats-top-head h3 { margin: 0 0 6px; font-size: 1rem; }
.stats-top-head a { font-size: 0.82rem; }
.stats-top-list { margin: 0; padding-left: 20px; }
.stats-top-list li { display: grid; grid-template-columns: 1fr auto; column-gap: 8px; padding: 4px 0; border-bottom: 1px solid var(--border); }
.stats-top-list li:last-child { border-bottom: 0; }
.stats-top-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-top-value { font-weight: 700; font-variant-numeric: tabular-nums; }
.stats-top-sub { grid-column: 1 / -1; font-size: 0.78rem; }

/* Dispatcher scorecard (stats/_scorecard.ejs). Group edges are a left rule;
   green/red compare a row with the Company row. */
.sc-intro { margin: -4px 0 10px; }
.sc-wrap { overflow-x: auto; margin-bottom: 8px; }
.sc-table { font-variant-numeric: tabular-nums; }
.sc-table th, .sc-table td { white-space: nowrap; padding: 8px 9px; }
.sc-table thead tr:first-child th { white-space: normal; min-width: 58px; line-height: 1.2; vertical-align: bottom; }
.sc-table .sc-group { border-left: 2px solid var(--border); }
/* The small detail ("3 of 21", broker name) sits under the number, so the
   14 columns fit a desktop screen; long broker names are cut short. */
.sc-table td .hint { display: block; font-size: 0.76em; font-weight: 400; margin-top: 1px; }
.sc-table td:last-child .hint { max-width: 150px; overflow: hidden; text-overflow: ellipsis; }

.sc-table tr.sc-company td { background: var(--bg-alt, #f3f4f6); font-weight: 600; border-bottom: 2px solid var(--border); }
.sc-table td.sc-good { color: #0f7d3d; font-weight: 700; }
.sc-table td.sc-bad { color: #b42318; font-weight: 700; }
.sc-trend { color: var(--muted); }
.sc-trend.sc-good, .sc-trend.sc-bad { font-weight: 700; }
.sc-trend .sc-spark { vertical-align: middle; }
.sc-how { margin: 4px 0 22px; font-size: 0.88rem; }
/* Clickable Discipline counts - look like the number, act like a link. */
.sc-drill { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; text-align: inherit; text-decoration: underline dotted; text-underline-offset: 3px; }
.sc-drill:hover { text-decoration-style: solid; }
.sc-drill:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; border-radius: 3px; }
.sc-drill .hint { text-decoration: none; }
.gtb-dialog.sc-dialog { width: min(1040px, calc(100% - 32px)); }
.sc-dialog-hint { margin: 2px 0 8px; }
.sc-dialog td.sc-days { white-space: normal; }
.sc-dialog .gtb-table a { color: var(--link, #1d4ed8); text-decoration: underline; }
.sc-dialog .gtb-dialog-body { max-height: 65vh; overflow: auto; }
.sc-how summary { cursor: pointer; color: var(--muted); }
.sc-how ul { margin: 6px 0 0; padding-left: 20px; line-height: 1.5; }
:root[data-theme="dark"] .sc-table td.sc-good { color: #4ade80; }
:root[data-theme="dark"] .sc-table td.sc-bad { color: #f87171; }

/* Load page: carrier we bill, no BOL yet (loads/form.ejs). */
.bol-required-note { margin: -4px 0 12px; padding: 8px 12px; border-radius: 8px; border-left: 4px solid #d97706; background: rgba(217, 119, 6, 0.08); }

/* Dashboard "Needs attention" card (partials/attention-card.ejs). */
.attention-card { background: var(--surface, #fff); border: 1px solid var(--border); border-left: 4px solid #d97706; border-radius: 10px; padding: 14px 18px; margin: 4px 0 22px; }
.attention-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 14px; }
.attention-head h2 { margin: 0; font-size: 1.2rem; }
.attention-sub { margin: 16px 0 2px; font-size: 1rem; display: flex; align-items: center; gap: 8px; }
.attention-count { display: inline-block; min-width: 22px; padding: 1px 8px; border-radius: 999px; background: #d97706; color: #fff; font-size: 0.8rem; text-align: center; font-variant-numeric: tabular-nums; }
.attention-why { margin: 0 0 6px; }
.attention-more-line { margin: 8px 0 0; display: flex; align-items: center; gap: 10px; }
.attention-table-wrap { overflow-x: auto; }
.attention-table { width: 100%; border-collapse: collapse; font-size: 0.88rem; }
.attention-table th { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); text-align: left; }
.attention-table th, .attention-table td { padding: 6px 8px; border-bottom: 1px solid var(--border); white-space: nowrap; }
.attention-table a { color: var(--link, #1d4ed8); font-weight: 600; }
.attention-table td.attention-actions { display: flex; gap: 6px; }
.attention-actions form { margin: 0; }
.attention-actions label.btn { cursor: pointer; margin: 0; }
.attention-actions label.disabled { opacity: 0.6; pointer-events: none; }
.attention-clear { margin: 4px 0 18px; padding: 8px 12px; border-radius: 8px; background: rgba(15, 125, 61, 0.08); color: #0f7d3d; font-weight: 600; }
:root[data-theme="dark"] .attention-clear { color: #4ade80; background: rgba(74, 222, 128, 0.08); }

/* Market Board (market/index.ejs) - the trailer-type cards are filter links. */
.market-intro { margin: -6px 0 12px; }
.market-filters label { display: inline-flex; align-items: center; gap: 6px; }
.market-cards { display: flex; flex-wrap: wrap; gap: 10px; margin: 4px 0 16px; }
a.market-card { color: inherit; text-decoration: none; transition: box-shadow 0.12s, transform 0.12s; }
a.market-card:hover { box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); transform: translateY(-1px); }
a.market-card:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; }
a.market-card.active { box-shadow: 0 0 0 2px var(--brand, #b91c1c); }
.market-table-wrap { overflow-x: auto; }
.market-table td.num, .market-table th.num { text-align: right; font-variant-numeric: tabular-nums; }
.market-table td.nowrap, .market-table td.num { white-space: nowrap; }
.market-table td.market-state { font-weight: 600; }
.market-note { margin-top: 10px; }
.gtb-card .gtb-name { font-size: 0.82rem; font-weight: 700; }
.gtb-card .gtb-tag { font-size: 0.62rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); font-weight: 700; margin-left: 3px; }
.gtb-card .gtb-gross { font-size: 1.15rem; font-weight: 800; color: #0f7d3d; font-variant-numeric: tabular-nums; }
.gtb-card .gtb-sub { font-size: 0.74rem; color: var(--muted); font-variant-numeric: tabular-nums; }
/* Team boxes are buttons now (click = per-dispatcher breakdown). */
button.gtb-card, button.grid-team-total { font: inherit; color: inherit; text-align: left; cursor: pointer; transition: box-shadow 0.12s, transform 0.12s; }
button.gtb-card:hover, button.grid-team-total:hover { box-shadow: 0 3px 12px rgba(0, 0, 0, 0.12); transform: translateY(-1px); }
button.gtb-card:focus-visible, button.grid-team-total:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; }
.gtb-dialog { border: 1px solid var(--border); border-radius: 12px; padding: 16px 18px; width: min(720px, calc(100% - 32px)); background: var(--surface, #fff); color: var(--text); }
.gtb-dialog::backdrop { background: rgba(15, 23, 42, 0.45); }
.gtb-dialog-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.gtb-dialog-head h3 { margin: 0; font-size: 1.1rem; }
.gtb-dialog-close { background: none; border: 0; font-size: 1.6rem; line-height: 1; cursor: pointer; color: var(--muted); padding: 0 4px; }
.gtb-dialog-close:hover { color: var(--text); }
.gtb-dialog-body { overflow-x: auto; margin: 6px 0 4px; }
.gtb-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.gtb-table th { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted); text-align: left; }
.gtb-table th, .gtb-table td { padding: 7px 8px; border-bottom: 1px solid var(--border); font-size: 0.9rem; white-space: nowrap; }
.gtb-table .num { text-align: right; }
.gtb-table tfoot td { font-weight: 800; border-bottom: 0; border-top: 2px solid var(--border); }
.gtb-table a { color: inherit; font-weight: 600; text-decoration: none; }
.gtb-table a:hover { text-decoration: underline; }
.truck-grid-cell { min-width: 130px; vertical-align: top; padding: 3px !important; }

/* Week/month summary rows at the bottom of each dispatcher's table
   (loads/grid.ejs's <tfoot>) - matches the totals row the original Google
   Sheets Truck Status layout always ended with. Bold + a top border to set
   it apart from the last truck row; the label cell isn't sticky like the
   Carrier/Driver/Truck/Trailer columns above it, since it spans all four
   and would otherwise need its own left-offset math. */
.truck-grid-totals-row td { font-weight: 700; border-top: 2px solid var(--border); background: var(--bg-alt, #f3f4f6); }
/* Per-truck weekly total column (loads/grid.ejs) - a light left border
   separates it from the day columns, same idea as .truck-grid-trailer's
   right border marking the end of the sticky label columns. Centered
   (rather than left-aligned like every other column) since it's a single
   standalone figure, not part of a left-to-right reading line - centering
   it, and the rate/miles/RPM stacked underneath, reads more like a small
   summary card than a stray number floating in the row. */
.truck-grid-total, .truck-grid-total-col { text-align: center; }
.truck-grid-total { font-weight: 600; border-left: 2px solid var(--border); padding-top: 5px; padding-bottom: 5px; }
.truck-grid-total-rate { display: block; font-size: 1.05em; }
.truck-grid-total .hint { display: block; margin-top: 2px; color: var(--muted); font-weight: 400; font-size: 0.88em; }
.truck-grid-total .hint.truck-grid-total-rpm { margin-top: 0; }

/* Grid view dispatcher grouping (loads/grid.ejs) - each dispatcher's
   trucks sit in their own .section-card box; title pinned top-left. */
.grid-dispatcher-group { padding: 14px; }
.grid-dispatcher-group-title { margin: 0 0 10px; font-size: 1rem; }

/* Load chips - color reflects that load's OWN status, shown right on the
   calendar day rather than only in the far-left column:
   - in-transit (amber): picked up but not yet delivered.
   - booked (green): booked, delivered, invoiced, or paid - once a load is
     booked it stays this color through the rest of its own lifecycle
     rather than flipping color based on whether the truck has since been
     rebooked (that used to make an already-delivered-and-invoiced load
     look identical to a truck sitting empty with nothing lined up).
   - self-covered (dark blue): the carrier booked this themselves - not
     Smart Haul's load to manage, always this color regardless of status. */
.load-chip {
  display: block; border: 1px solid transparent; border-radius: 6px;
  padding: 2px 5px; margin-bottom: 2px; font-size: 0.7rem; line-height: 1.2;
  color: #fff; text-decoration: none; white-space: normal;
}
.load-chip-self-covered { background: #1e3a8a; border-color: #1e3a8a; }
.load-chip-self-covered:hover { background: #1e40af; }
/* Lighter/softer red than a solid alarm-red - light background with dark
   red text reads as "needs attention" without being visually harsh. */
.load-chip-open { background: #fca5a5; border-color: #f87171; color: #7f1d1d; }
.load-chip-open:hover { background: #f87171; }
.load-chip-in-transit { background: #b45309; border-color: #b45309; }
.load-chip-in-transit:hover { background: #92400e; }
.load-chip-booked { background: #15803d; border-color: #15803d; }
.load-chip-booked:hover { background: #166534; }
/* Grid chips by dispatch status (2026-09-27): the same colours as the status
   dropdown / badges (.status-* above), so a chip reads like the status it's
   in. A coloured stripe down the left edge sets load chips apart from the
   pastel day markers (Vacation, In Transit...) and keeps the six apart at a
   glance. Not invoiced is a touch more orange than Picked up (the badges
   share one amber) so the two don't blur together on the board.
   The legend swatches reuse the same classes. */
.load-chip-st-booked            { --chip-bg: #e0e7ff; --chip-bar: #4f46e5; --chip-fg: #312e81; }
.load-chip-st-picked_up         { --chip-bg: #fef3c7; --chip-bar: #d97706; --chip-fg: #78350f; }
.load-chip-st-delivered         { --chip-bg: #dcfce7; --chip-bar: #16a34a; --chip-fg: #14532d; }
.load-chip-st-ready_for_payment { --chip-bg: #ccfbf1; --chip-bar: #0d9488; --chip-fg: #134e4a; }
.load-chip-st-not_invoiced      { --chip-bg: #ffedd5; --chip-bar: #ea580c; --chip-fg: #7c2d12; }
.load-chip-st-invoiced          { --chip-bg: #dbeafe; --chip-bar: #2563eb; --chip-fg: #1e3a8a; }
.load-chip[class*="load-chip-st-"] {
  background: var(--chip-bg); color: var(--chip-fg);
  border-color: color-mix(in srgb, var(--chip-bar) 35%, transparent); border-left: 4px solid var(--chip-bar);
}
.load-chip[class*="load-chip-st-"]:hover { background: color-mix(in srgb, var(--chip-bg) 82%, var(--chip-bar)); }
/* Billed line (2026-10-08): the right edge once accounting has sent the bill
   (invoiced / invoiced directly / factored / paid - routes/loads.js). Purple
   unless the person picked another colour or hid it (My preferences -> Grid;
   partials/header.ejs sets --billed-line / data-billed-line). */
:root:not([data-billed-line="off"]) .load-chip.load-chip-billed { border-right: 4px solid var(--billed-line, #7c3aed); }
.legend-swatch.legend-swatch-billed { background: linear-gradient(to left, var(--billed-line, #7c3aed) 0 4px, var(--surface, #fff) 4px); border-color: var(--billed-line, #7c3aed); }
:root[data-billed-line="off"] .legend-billed { display: none; }
/* "Copied: CITY, ST" note after right-clicking an Open box (loads/grid.ejs). */
.copy-flash { position: absolute; z-index: 1001; padding: 5px 10px; border-radius: 6px; background: #14532d; color: #fff; font-size: 0.82rem; font-weight: 600; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2); pointer-events: none; white-space: nowrap; }
.copy-flash[hidden] { display: none; }

/* Grid quick status (loads/grid.ejs): the ▾ on a load box + its menu. */
.load-chip { position: relative; }
.chip-status-btn { position: absolute; top: 2px; right: 2px; width: 18px; height: 18px; display: inline-flex; align-items: center; justify-content: center; border-radius: 4px; font-size: 11px; line-height: 1; color: var(--chip-fg, inherit); background: rgba(255, 255, 255, 0.7); border: 1px solid rgba(0, 0, 0, 0.12); opacity: 0; transition: opacity 0.12s; cursor: pointer; }
.load-chip:hover .chip-status-btn, .chip-status-btn:focus-visible, .chip-status-btn[aria-expanded="true"] { opacity: 1; }
.chip-status-btn:focus-visible { outline: 2px solid var(--brand, #b91c1c); outline-offset: 1px; }
@media (hover: none) { .chip-status-btn { opacity: 0.85; } }
.chip-status-saved { animation: chipSaved 0.9s ease-out; }
@keyframes chipSaved { 0% { box-shadow: 0 0 0 3px rgba(22, 163, 74, 0.55); } 100% { box-shadow: 0 0 0 0 rgba(22, 163, 74, 0); } }
@media (prefers-reduced-motion: reduce) { .chip-status-saved { animation: none; } }
.chip-status-menu { position: absolute; z-index: 1000; min-width: 190px; padding: 6px; border-radius: 10px; background: var(--surface, #fff); color: var(--text); border: 1px solid var(--border); box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22); }
.chip-status-menu .csm-copy { font-weight: 600; border-bottom: 1px solid var(--border); margin-bottom: 2px; }
.chip-status-menu .csm-copy-icon { display: inline-block; width: 12px; text-align: center; margin-right: 6px; opacity: 0.75; }
.chip-status-menu .csm-title { font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--muted); font-weight: 700; padding: 4px 8px 6px; }
.chip-status-menu .csm-item { display: flex; align-items: center; gap: 8px; width: 100%; padding: 7px 8px; border: 0; border-radius: 6px; background: none; font: inherit; font-size: 0.9rem; color: inherit; text-align: left; text-decoration: none; cursor: pointer; }
.chip-status-menu .csm-item:hover, .chip-status-menu .csm-item:focus-visible { background: var(--bg-alt, #f3f4f6); outline: none; }
.chip-status-menu .csm-item.current { font-weight: 700; }
.chip-status-menu .csm-item:disabled { opacity: 0.6; cursor: default; }
.chip-status-menu .csm-dot { width: 10px; height: 10px; border-radius: 50%; flex: none; }
.chip-status-menu .csm-booked .csm-dot { background: #4f46e5; }
.chip-status-menu .csm-picked_up .csm-dot { background: #d97706; }
.chip-status-menu .csm-delivered .csm-dot { background: #16a34a; }
.chip-status-menu .csm-ready_for_payment .csm-dot { background: #0d9488; }
.chip-status-menu .csm-check { margin-left: auto; color: #16a34a; }
.chip-status-menu .csm-open { border-top: 1px solid var(--border); border-radius: 0 0 6px 6px; margin-top: 4px; padding-top: 9px; color: var(--link, #1d4ed8); }
.chip-status-menu .csm-locked { padding: 4px 8px 8px; font-size: 0.85rem; color: var(--muted); }
.chip-status-menu .csm-msg { font-size: 0.8rem; color: #b42318; padding: 0 8px; }
.chip-status-menu .csm-msg:empty { display: none; }
.legend-swatch[class*="load-chip-st-"] { background: linear-gradient(to right, var(--chip-bar) 0 4px, var(--chip-bg) 4px); border-color: var(--chip-bar); }
/* Per-day quick note scratchpad on the grid (loads/grid.ejs): a two-field box
   at the bottom of each dated cell - free-text note on the left, rate on the
   right. Kept visually quiet when empty so noteless cells don't shout, and
   tinted like a sticky note once something's typed. */
.grid-note { display: flex; margin: 4px 0 0; }
/* A day's note is just this tag (2026-09-27); the text opens in the pop-up
   (loads/grid.ejs #grid-note-dialog). Sticky-note yellow, full width - the
   same box as the day markers (Vacation, Stuck at DEL...). */
.grid-note-pill {
  flex: 1 1 auto; width: 100%; padding: 3px 6px; border: 1px solid #f0e3a8; border-radius: 4px; background: #fff8dc; color: #6b5a12;
  font: inherit; font-size: 0.68rem; font-weight: 600; line-height: 1.25; text-align: left; cursor: pointer;
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.grid-note-pill:hover { background: #fdefb2; border-color: #e6cf6b; }
.grid-note-pill:focus-visible { outline: 2px solid #d4a300; outline-offset: 1px; }
.grid-note-dialog { width: min(520px, calc(100% - 32px)); }
.grid-note-dialog textarea { width: 100%; box-sizing: border-box; margin: 4px 0 12px; padding: 10px 12px; font: inherit; font-size: 0.95rem; line-height: 1.45; border: 1px solid var(--border); border-radius: 8px; background: var(--surface, #fff); color: var(--text); resize: vertical; }
.grid-note-dialog textarea:read-only { background: var(--surface-2, #f6f7f9); }

/* Week view fits the viewport with no horizontal scroll: the table is exactly
   the container width and its own <colgroup> (loads/grid.ejs) sizes the four
   frozen label columns + Total, leaving the day columns to share the rest.
   Comes after the base .truck-grid rule so width:100% wins. Month view keeps
   the .resizable drag-columns + horizontal scroll (30+ days can't fit). */
.truck-grid-week { width: 100%; min-width: 0; table-layout: fixed; }
.truck-grid-week .truck-grid-cell { min-width: 0; }
/* Saturday/Sunday rarely carry loads - narrower, so the weekdays get the room. */
.truck-grid-week col.grid-col-weekend { width: 7%; }
/* Clip any minor content overflow so the fixed-width columns never force the
   grid to scroll horizontally in week view (the whole point). Load chips wrap,
   the frozen columns already ellipsis, so nothing important is cut. */
.truck-grid-week td, .truck-grid-week th { overflow: hidden; }

/* Drag handle for reordering truck rows on the grid (per user). */
.truck-row-drag {
  cursor: grab; user-select: none; margin-right: 5px;
  color: var(--muted, #5b6472); opacity: 0.45; font-size: 0.95em; line-height: 1;
}
.truck-row-drag:hover { opacity: 1; }
.truck-row-drag:active { cursor: grabbing; }
.truck-row-dragging td { opacity: 0.45; }
tr.truck-row-drop-before td { box-shadow: inset 0 2px 0 0 var(--brand, #d32020); }
tr.truck-row-drop-after td { box-shadow: inset 0 -2px 0 0 var(--brand, #d32020); }

/* Grid "Open" box (loads/grid.ejs, openBoxFor in routes/loads.js): the truck
   is - or will be - empty at this city with nothing booked next. Dashed and
   unfilled so it reads as "needs a load", not as a booked load; replaced by
   the next load's green box on its pickup day once that load is added. */
.grid-open-box {
  display: block; border: 1.5px dashed #64748b; border-radius: 6px;
  padding: 2px 5px; margin-bottom: 2px; font-size: 0.7rem; line-height: 1.25;
  color: #334155; text-decoration: none; white-space: normal; background: rgba(255, 255, 255, 0.6);
}
a.grid-open-box:hover { border-color: var(--blue); color: var(--blue); }
.grid-open-box-sub { font-size: 0.64rem; opacity: 0.8; }
:root[data-theme="dark"] .grid-open-box { color: #cbd5e1; border-color: #94a3b8; background: transparent; }

.legend-swatch.load-chip-self-covered-swatch { background: #1e3a8a; border-color: #1e3a8a; }
.legend-swatch.load-chip-open-swatch { background: #fca5a5; border-color: #f87171; }
.legend-swatch.load-chip-in-transit-swatch { background: #b45309; border-color: #b45309; }
.legend-swatch.load-chip-booked-swatch { background: #15803d; border-color: #15803d; }

/* A dispatcher explicitly marked this truck unavailable/idle this day for
   a specific reason (see truckVacationModel/loads/vacations.ejs) - each
   reason gets its own color so they're distinguishable at a glance. */
.vacation-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #fdba74; border-radius: 4px; background: #ffedd5; color: #c2410c;
  font-size: 0.68rem; font-weight: 600;
}
.repair-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #c4b5fd; border-radius: 4px; background: #ede9fe; color: #5b21b6;
  font-size: 0.68rem; font-weight: 600;
}
.went-home-empty-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #f9a8d4; border-radius: 4px; background: #fce7f3; color: #9d174d;
  font-size: 0.68rem; font-weight: 600;
}
/* TONU (truck order not used, see migration 110) - amber rather than the
   plain grey/green status badges it sits next to, because it's the reason a
   row shows money but no rate per mile. */
.badge-tonu { background: #fef3c7; color: #92400e; }

/* Marks a load that shares one physical route with another (married freight)
   in the Stats per-truck day breakdown. Muted on purpose - it is a footnote
   pointing at the explanation under the table, not a status to scan for. */
.combo-mark { margin-left: 4px; color: var(--muted); font-size: 0.85em; cursor: help; }

/* Pending - a lighter, cooler blue than the co-dispatch marker below, which
   is the only other blue on the board. The other three markers say a truck
   definitely isn't running; this one says the day is still being worked. */
.pending-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #7dd3fc; border-radius: 4px; background: #e0f2fe; color: #0369a1;
  font-size: 0.68rem; font-weight: 600;
}
.co-dispatch-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #93c5fd; border-radius: 4px; background: #dbeafe; color: #1d4ed8;
  font-size: 0.68rem; font-weight: 600;
}

/* The three reason markers above double as drag handles in the grid legend,
   and every empty day cell is a drop target for them (see loads/grid.ejs) -
   marking a driver off used to mean leaving the board for the truck's own
   profile form. .truck-grid-drop is only rendered for roles allowed to set
   markers, so scoping the click affordances to it keeps a read-only
   viewer's markers looking (and behaving) inert. */
/* Rate con drop pop-up on the Grid (loads/grid.ejs). */
.ratecon-drop-dialog { border: 1px solid var(--border); border-radius: 12px; padding: 18px 20px; max-width: 420px; width: calc(100% - 32px); background: var(--surface, #fff); color: var(--text); }
.ratecon-drop-dialog::backdrop { background: rgba(15, 23, 42, 0.45); }
.ratecon-drop-dialog h3 { margin: 0 0 10px; font-size: 1.05rem; }
.ratecon-drop-dialog p { margin: 0 0 8px; word-break: break-word; }
.ratecon-drop-status { font-weight: 600; min-height: 1.2em; }
.ratecon-drop-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 12px; }

/* Legend handle for quick notes - looks like a filled day note. */
/* Four more day markers (migration 135). Same box as the ones above. */
.in-transit-marker, .off-marker, .stuck-pu-marker, .stuck-del-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid; border-radius: 4px; font-size: 0.68rem; font-weight: 600;
}
.in-transit-marker { border-color: #5eead4; background: #ccfbf1; color: #0f766e; }
.off-marker { border-color: #94a3b8; background: #e2e8f0; color: #334155; }
.stuck-pu-marker { border-color: #fca5a5; background: #fee2e2; color: #b91c1c; }
.stuck-del-marker { border-color: #f87171; background: #fecaca; color: #7f1d1d; }
/* Restarts (migration 137): green = home, indigo = on the road. */
.restart-home-marker, .restart-road-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid; border-radius: 4px; font-size: 0.68rem; font-weight: 600;
}
.restart-home-marker { border-color: #a3e635; background: #ecfccb; color: #3f6212; }
.restart-road-marker { border-color: #a5b4fc; background: #e0e7ff; color: #3730a3; }
/* Self covered (migration 140): the same dark blue as a self-covered load box. */
.self-covered-marker {
  display: block; text-align: center; margin: 4px auto; padding: 3px 6px;
  border: 1px solid #1e3a8a; border-radius: 4px; font-size: 0.68rem; font-weight: 600;
  background: #1e3a8a; color: #fff;
}
/* Open box controls (loads/grid.ejs, migration 142): an x on the automatic
   box, a hand-set box (dashed, blue-grey), the legend chip and the pop-up. */
.grid-open-wrap { position: relative; }
.grid-open-hide {
  position: absolute; top: 0; right: 0; z-index: 1; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 3px;
  background: transparent; color: #8a93a0; font-size: 0.8rem; line-height: 16px; cursor: pointer;
}
.grid-open-hide:hover { background: #fee2e2; color: #b91c1c; }
.grid-open-manual { border-color: #64748b; color: #334155; background: #f1f5f9; }
.grid-open-manual.editable { cursor: pointer; }
.grid-open-manual.editable:hover { background: #e2e8f0; }
.legend-chip.open-marker-chip { border: 1px dashed #64748b; background: #fff; color: #334155; }
.grid-open-fields { display: grid; grid-template-columns: 1fr 70px 120px; gap: 10px; margin: 6px 0 4px; }
.grid-open-fields label { display: flex; flex-direction: column; gap: 4px; font-size: 0.8rem; color: var(--muted); }
.grid-open-fields input { padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; font: inherit; font-size: 0.95rem; color: var(--text); background: var(--surface, #fff); }
.grid-open-fields input[name="state"] { text-transform: uppercase; }
.grid-open-error { color: #b91c1c; font-size: 0.85rem; margin: 4px 0; }
/* A load box under the dragged Self covered chip. */
.load-chip.load-chip-drop-over { outline: 2px solid #1e3a8a; outline-offset: 1px; }

/* In the legend every drag chip is the same size, so the row reads evenly. */
.grid-legend .legend-chip {
  display: inline-flex; align-items: center; justify-content: center;
  width: 118px; height: 24px; margin: 0; padding: 0 6px; box-sizing: border-box;
  font-size: 0.72rem; font-weight: 600; line-height: 1; white-space: nowrap;
}
.note-marker {
  display: inline-block; padding: 3px 8px; border: 1px solid #f0e3a8; border-radius: 4px;
  background: #fff8dc; color: #4a3f12; font-size: 0.68rem; font-weight: 600;
}
:root[data-theme="dark"] .note-marker { background: rgba(250, 204, 21, 0.16); border-color: rgba(250, 204, 21, 0.35); color: #fde68a; }
.marker-draggable { cursor: grab; -webkit-user-select: none; user-select: none; }
.marker-draggable:active { cursor: grabbing; }
/* Only while a chip is in flight - a permanent outline on every empty cell
   would turn the whole board into a dotted grid. */
body.grid-marker-dragging .truck-grid-drop { outline: 1px dashed var(--border); outline-offset: -2px; }
.truck-grid-cell.truck-grid-drop-over { background: #fef3c7; outline: 2px solid #f59e0b; outline-offset: -2px; }
.truck-grid-drop .day-marker { cursor: pointer; }
.truck-grid-drop .day-marker:hover { filter: brightness(0.94); text-decoration: line-through; }
/* Draggable markers (move between days) - grab affordance; click still clears */
.truck-grid-drop .day-marker[draggable="true"] { cursor: grab; }
.truck-grid-drop .day-marker[draggable="true"]:hover { text-decoration: none; }
.truck-grid-drop .day-marker.day-marker-moving { opacity: 0.4; cursor: grabbing; }
/* Right-click marker menu (reuses .chip-status-menu) + the "Copied" toast */
.grid-marker-menu .gmm-remove { border-top: 1px solid var(--border); border-radius: 0 0 6px 6px; margin-top: 4px; padding-top: 9px; color: #b42318; }
.grid-marker-toast { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 1100; max-width: calc(100% - 32px); padding: 9px 14px; border-radius: 8px; background: #1f2937; color: #fff; font-size: 0.9rem; box-shadow: 0 8px 24px rgba(15, 23, 42, 0.3); }
.grid-marker-toast[hidden] { display: none; }

/* Company suggestion dropdown (pickup/delivery "we've seen this place
   before" autocomplete) - sits directly under the company name input. */
.company-suggest-wrap { position: relative; }
.company-suggest-list {
  display: none; position: absolute; z-index: 20; left: 0; right: 0; top: 100%;
  background: #fff; border: 1px solid var(--border); border-top: none;
  border-radius: 0 0 6px 6px; max-height: 220px; overflow-y: auto;
  box-shadow: 0 4px 10px rgba(0,0,0,0.08);
}
.company-suggest-list.open { display: block; }
.company-suggest-item { padding: 8px 10px; cursor: pointer; border-bottom: 1px solid var(--border); }
.company-suggest-item:last-child { border-bottom: none; }
.company-suggest-item:hover, .company-suggest-item.active { background: var(--bg); }
.company-suggest-item .name { font-weight: 600; }
.company-suggest-item .addr { color: var(--muted); font-size: 0.85rem; }

/* Mobile/tablet support - the rest of the sheet above is written for
   desktop widths (the 1in container padding especially), so phones and
   tablets need these overrides to avoid a horizontally-scrolling page and
   cramped forms. Tables are the main structural problem: rather than
   rewrite every view's markup, any plain <table> becomes its own
   horizontally-scrollable strip below the tablet breakpoint (the same
   trick .grid-scroll already uses on desktop for the wide Truck Status
   grid - .truck-grid is excluded here since it already manages its own
   scrolling and sticky columns via .grid-scroll). */
@media (max-width: 768px) {
  .container { padding: 16px 16px 40px; }
  .topbar-inner { padding: 10px 16px; flex-wrap: wrap; row-gap: 10px; }
  .hamburger-btn { display: inline-flex; align-items: center; justify-content: center; margin-left: auto; background: none; border: none; padding: 6px; cursor: pointer; }

  /* Collapsed by default - only the logo + hamburger show. Tapping the
     hamburger adds .mobile-nav-open to .topbar (see the toggle script in
     partials/header.ejs), which reveals the nav links and the who's-online/
     logout block as a full-width panel that wraps onto its own lines below
     the logo row, instead of letting them wrap into a cramped multi-row nav
     next to the logo. Kept in normal flow (not position:absolute) so the two
     panels stack under each other rather than overlapping, and so the fixed
     topbar's real height - used to offset page content below it, see
     syncBodyOffset() in partials/header.ejs - grows/shrinks correctly. */
  .topbar nav, .topbar-user { display: none; width: 100%; order: 3; }
  .topbar nav a.nav-link-end { margin-left: 0; }
  .topbar-user { order: 4; }
  .topbar.mobile-nav-open nav, .topbar.mobile-nav-open .topbar-user {
    display: flex; flex-direction: column; align-items: stretch; gap: 10px;
  }
  .topbar.mobile-nav-open .topbar-user { padding-top: 10px; border-top: 1px solid rgba(255,255,255,0.2); }
  .card { max-width: 100%; margin: 24px auto; }

  /* .all-loads-table is excluded here too - like .truck-grid, it already
     scrolls via its own .grid-scroll wrapper + floating scrollbar (see
     loads/all-loads.ejs). Letting this rule also make the <table> itself
     display:block/overflow-x:auto would create a second, independent
     scroll container nested inside .grid-scroll, so the floating bar
     (which only tracks .grid-scroll's scroll position) would stop
     matching what the user actually sees on mobile. */
  table:not(.truck-grid):not(.all-loads-table) { display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; }
  table:not(.truck-grid):not(.all-loads-table) th, table:not(.truck-grid):not(.all-loads-table) td { white-space: nowrap; }

  .actions-bar { flex-wrap: wrap; gap: 10px; }
  .form-actions { flex-wrap: wrap; }
  .admin-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }

  /* Prevents iOS Safari's automatic zoom-in when a form field with a
     smaller font size receives focus - very disorienting on a login or
     load-intake form if left at the desktop 0.88-0.95rem sizes.
     !important is needed here since form.stacked's own type+attribute
     selectors (e.g. "form.stacked input[type=email]") are more specific
     than a bare "input" selector and would otherwise win. */
  input, select, textarea { font-size: 16px !important; }
}

@media (max-width: 480px) {
  .container { padding: 12px 10px 32px; }
  .topbar-inner { padding: 8px 10px; }
  h1 { font-size: 1.3rem; }
  .card { padding: 18px; }

  /* The invoice-email form (input + button on one line via .inline-form)
     is the one place a fixed min-width would force horizontal overflow on
     a narrow phone - let it wrap instead. */
  .inline-form { display: inline-flex; flex-wrap: wrap; gap: 8px; }
  .inline-form input { min-width: 0; width: 100%; }
}

/* CRM lead form/detail redesign (crm/lead-form.ejs, lead-detail.ejs,
   _lead-form-fields.ejs, _lead-sidebar.ejs) - a two-column page (form +
   sidebar), tabbed sections, and the handful of input widgets the
   reference layout needed that nothing else in the app used yet: a
   multi-column form grid, checkbox pills, a tag-chip input, star ratings,
   and a circular "health" progress ring. */
.lead-page-layout { display: flex; align-items: flex-start; gap: 20px; }
.lead-page-main { flex: 1; min-width: 0; }
.lead-sidebar { width: 300px; flex-shrink: 0; display: flex; flex-direction: column; gap: 16px; }

.lead-top-bar { display: flex; justify-content: space-between; align-items: center; margin-bottom: 16px; }
.lead-top-bar-title { display: flex; align-items: center; gap: 10px; }
.lead-back { color: var(--muted); text-decoration: none; font-size: 1.3rem; line-height: 1; }
.lead-back:hover { color: var(--text); }
.lead-top-bar h1 { margin: 0; }
.lead-top-bar-actions { display: flex; gap: 8px; }

.lead-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); margin-bottom: 20px; flex-wrap: wrap; }
.lead-tab {
  background: none; border: none; border-bottom: 2px solid transparent; padding: 10px 14px;
  font-size: 0.92rem; font-weight: 600; color: var(--muted); cursor: pointer; margin-bottom: -1px;
}
.lead-tab:hover { color: var(--text); }
.lead-tab.active { color: var(--blue); border-bottom-color: var(--blue); }
.lead-tab-panel[hidden] { display: none; }

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 20px; }
.form-grid-full { grid-column: 1 / -1; }
.form-grid label { display: block; font-weight: 600; font-size: 0.88rem; margin: 14px 0 5px; }
.form-grid input[type=text], .form-grid input[type=email], .form-grid input[type=tel],
.form-grid input[type=number], .form-grid input[type=date], .form-grid select, .form-grid textarea {
  width: 100%; padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 0.95rem; font-family: inherit;
}
.form-grid .hint { color: var(--muted); font-size: 0.82rem; margin-top: 4px; }
.form-grid .checkbox-row { display: flex; align-items: center; gap: 8px; margin-top: 16px; }
.form-grid .checkbox-row label { margin: 0; font-weight: 500; }

@media (max-width: 900px) {
  .lead-page-layout { flex-direction: column; }
  .lead-sidebar { width: 100%; }
  .form-grid { grid-template-columns: 1fr; }
}

.checkbox-group { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 6px; }
.checkbox-pill {
  display: flex; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 999px;
  padding: 6px 12px; font-size: 0.85rem; cursor: pointer; background: #fff;
}
.checkbox-pill:has(input:checked) { border-color: var(--blue); background: #eff6ff; color: var(--blue); font-weight: 600; }
.checkbox-pill input { margin: 0; }

.tag-input-wrap {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px; border: 1px solid var(--border);
  border-radius: 6px; padding: 6px 8px; min-height: 42px;
}
.tag-chip { display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-radius: 999px; font-size: 0.82rem; font-weight: 600; }
.tag-chip button { background: none; border: none; cursor: pointer; font-size: 0.9rem; line-height: 1; color: inherit; opacity: 0.7; padding: 0; }
.tag-chip button:hover { opacity: 1; }
.tag-input-swatches { display: flex; gap: 4px; margin-right: 4px; }
.tag-swatch { width: 16px; height: 16px; border-radius: 50%; cursor: pointer; border: 2px solid transparent; padding: 0; }
.tag-swatch.selected { border-color: var(--text); }
.tag-input-text { border: none; outline: none; flex: 1; min-width: 100px; font-size: 0.9rem; padding: 4px; }

.star-rating { display: inline-flex; align-items: center; gap: 2px; }
.star-rating .star { color: #d8dee8; font-size: 1.1rem; }
.star-rating .star.filled { color: #f59e0b; }
.star-rating.input .star { cursor: pointer; }
.star-rating-score { color: var(--muted); font-size: 0.85rem; margin-left: 6px; }

.health-ring {
  --pct: 0;
  width: 96px; height: 96px; border-radius: 50%; margin: 0 auto 10px;
  background: conic-gradient(var(--blue) calc(var(--pct) * 1%), #eef1f6 0);
  display: flex; align-items: center; justify-content: center;
}
.health-ring-inner {
  width: 74px; height: 74px; border-radius: 50%; background: #fff;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.health-ring-score { font-size: 1.3rem; font-weight: 700; line-height: 1; }
.health-ring-label { font-size: 0.72rem; color: var(--muted); margin-top: 2px; }

.lead-sidebar-panel { background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 16px; }
.lead-sidebar-panel h3 { margin: 0 0 12px; font-size: 0.95rem; }
.lead-health-rows { display: flex; flex-direction: column; gap: 8px; }
.lead-health-row { display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem; }
.lead-health-row .label { color: var(--muted); }
.lead-quick-actions { display: flex; flex-direction: column; gap: 8px; }
.lead-quick-actions .btn, .lead-quick-actions button { width: 100%; text-align: left; }
.lead-activity-feed { display: flex; flex-direction: column; gap: 10px; margin: 0; padding: 0; list-style: none; }
.lead-activity-feed-item { font-size: 0.85rem; }
.lead-activity-feed-item .meta { color: var(--muted); font-size: 0.78rem; }
.lead-documents-drop {
  border: 2px dashed var(--border); border-radius: 8px; padding: 20px; text-align: center;
  color: var(--muted); font-size: 0.85rem; cursor: pointer;
}
.lead-documents-drop.dragover { border-color: var(--blue); background: #eff6ff; }
.lead-documents-list { margin-top: 10px; display: flex; flex-direction: column; gap: 6px; }

/* Generic drag-and-drop file zone (src/public/file-drop.js) - same visual
   language as .lead-documents-drop above, reusable anywhere a file input
   wants drop support alongside its existing click-to-choose. */
.file-drop-zone {
  border: 2px dashed var(--border); border-radius: 8px; padding: 16px; text-align: center;
  color: var(--muted); font-size: 0.85rem; cursor: pointer;
}
.file-drop-zone.dragover { border-color: var(--blue); background: #eff6ff; }
.file-drop-selected-name { margin-top: 6px; font-size: 0.85rem; }
.file-drop-selected-name:empty { display: none; }
.lead-documents-list-item { display: flex; justify-content: space-between; align-items: center; font-size: 0.85rem; }
.lead-placeholder { color: var(--muted); font-size: 0.85rem; text-align: center; padding: 10px 0; }

/* Calendar (day-off marking + announcements) - src/views/calendar/index.ejs */
.calendar-controls { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap; gap: 10px; margin-bottom: 14px; }
.calendar-office-tabs { display: flex; gap: 4px; border-bottom: 1px solid var(--border); }
.calendar-office-tab {
  background: none; border: none; border-bottom: 2px solid transparent; padding: 10px 14px;
  font-size: 0.92rem; font-weight: 600; color: var(--muted); cursor: pointer; margin-bottom: -1px;
}
.calendar-office-tab:hover { color: var(--text); }
.calendar-office-tab.active { color: var(--blue); border-bottom-color: var(--blue); }
.calendar-month-nav { display: flex; align-items: center; gap: 10px; }
.calendar-legend { display: flex; flex-wrap: wrap; gap: 18px; margin-bottom: 14px; font-size: 0.85rem; color: var(--muted); }
.calendar-swatch-dayoff { background: #eef1f6; border-color: var(--border); }
.calendar-swatch-announcement { background: var(--danger); border-color: var(--danger); }

/* Fills most of the viewport, per the "calendar visible full-screen, log
   requires a scroll" request - the activity log section below it sits in
   normal document flow, so reaching it always requires scrolling past
   this. */
.calendar-grid {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 6px;
  min-height: calc(100vh - 260px);
}
.calendar-day-header { font-size: 0.78rem; font-weight: 700; color: var(--muted); text-align: center; padding-bottom: 4px; }
.calendar-day-cell {
  background: #fff; border: 1px solid var(--border); border-radius: 8px; padding: 6px;
  min-height: 90px; cursor: pointer; display: flex; flex-direction: column; gap: 4px;
}
.calendar-day-cell:hover { border-color: var(--blue); }
.calendar-day-empty { background: none; border: none; cursor: default; }
.calendar-day-today { border-color: var(--blue); border-width: 2px; }
.calendar-day-num { font-size: 0.82rem; font-weight: 700; color: var(--muted); }
.calendar-pill {
  font-size: 0.72rem; padding: 2px 6px; border-radius: 4px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap;
}
.calendar-pill-dayoff { background: #eef1f6; color: var(--text); }
.calendar-pill-announcement { background: var(--danger); color: #fff; font-weight: 600; }

.calendar-modal-backdrop {
  position: fixed; inset: 0; background: rgba(0,0,0,0.4); z-index: 3000;
  display: flex; align-items: center; justify-content: center;
}
.calendar-modal {
  background: #fff; border-radius: 8px; padding: 24px; width: 100%; max-width: 440px;
  max-height: 85vh; overflow-y: auto;
}
.calendar-modal label { display: block; font-weight: 600; font-size: 0.88rem; margin: 14px 0 5px; }
.calendar-modal input[type=text], .calendar-modal input[type=date], .calendar-modal textarea {
  width: 100%; padding: 9px 10px; border: 1px solid var(--border); border-radius: 6px;
  font-size: 0.95rem; font-family: inherit;
}

/* ============================================================
   DARK MODE
   ============================================================
   Opt-in via data-theme="dark" on <html>, set by the toggle in the topbar
   (see partials/header.ejs) and persisted in localStorage. An inline
   script in <head> applies the saved choice before first paint, so the
   page never flashes white on its way to dark.

   Everything below is additive - it only appends `:root[data-theme="dark"]
   <selector>` rules, which outrank the plain element/class rules above on
   specificity. Light mode is byte-for-byte unchanged, so this cannot
   regress the default look.

   The palette is deliberately NOT neutral grey: every dark surface carries
   a slight red/magenta bias so it sits under Smart Haul's red brand bar as
   though chosen for it, rather than inherited from a generic dark
   template. Accent colours are lifted several steps lighter than their
   light-mode values - those are tuned for contrast against white and go
   muddy on a dark ground. */
/* Every dark palette sets --surface-2, so the subtle fill follows it. */
:root[data-theme="dark"] { --bg-alt: var(--surface-2); }
:root[data-theme="dark"] {
  --bg: #0c0a0c;
  --surface: #17131a;      /* cards, tables, dropdowns, modals */
  --surface-2: #211b25;    /* table headers, hover states, wells */
  --border: #322936;
  --text: #f2ecf0;
  --muted: #a3939f;
  --blue: #7d9bff;
  --blue-dark: #a3b8ff;
  --danger: #ff5a5a;
  --danger-bg: #2b1114;
  --glow: rgba(239, 68, 68, 0.55);
}

/* Ambient red bloom behind the whole app - three big, very soft radials
   pinned to the viewport. This is the "coloured shadow in the background":
   at these alphas over a near-black base it reads as a faint warm haze in
   the corners rather than a visible gradient, and it keeps large empty
   areas (long tables, the Grid board) from looking like flat charcoal.
   Non-interactive, at z-index -2 - one layer under the existing photo
   watermark at -1. */
:root[data-theme="dark"] body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -2;
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(220, 38, 38, 0.20), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(147, 22, 33, 0.16), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(190, 24, 60, 0.13), transparent 65%);
}
/* The photo watermark is tuned for a light page; at 0.1 over near-black it
   turns into grey noise. Dropped and desaturated so it stays a texture. */
:root[data-theme="dark"] body::before {
  opacity: var(--bg-opacity, 0.05);
  filter: grayscale(0.4) brightness(0.7);
}

/* Brand bar: in dark mode the company red is demoted from a filled slab to
   an accent. A solid red bar reads as a glaring stripe across the top of a
   near-black page - here the bar itself becomes graphite (a step lighter
   than --surface so it still separates from the page) and the red survives
   as the hairline underneath plus the glow spilling down onto the content.
   Light mode keeps the filled red bar exactly as it is. */
:root[data-theme="dark"] .topbar {
  background: linear-gradient(180deg, #1e1926 0%, #14111b 100%);
  border-bottom: 1px solid rgba(239, 68, 68, 0.35);
  box-shadow: 0 12px 40px -18px var(--glow), 0 1px 0 rgba(255, 255, 255, 0.05) inset;
}

/* --- Surfaces -------------------------------------------------------- */
:root[data-theme="dark"] table,
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .section-card,
:root[data-theme="dark"] .loads-summary-box,
:root[data-theme="dark"] .filter-row,
:root[data-theme="dark"] .admin-tile,
:root[data-theme="dark"] .online-users-dropdown,
:root[data-theme="dark"] .user-menu-dropdown,
:root[data-theme="dark"] .header-search-results,
:root[data-theme="dark"] .col-toggle-panel,
:root[data-theme="dark"] .ss-input,
:root[data-theme="dark"] .ss-menu,
:root[data-theme="dark"] .ask-smart-haul-bar input,
:root[data-theme="dark"] .ask-smart-haul-results,
:root[data-theme="dark"] .trailer-type-options,
:root[data-theme="dark"] .crm-quick-note-modal,
:root[data-theme="dark"] .crm-card,
:root[data-theme="dark"] .chat-sidebar,
:root[data-theme="dark"] .chat-people-picker,
:root[data-theme="dark"] .chat-thread,
:root[data-theme="dark"] .chat-emoji-popover,
:root[data-theme="dark"] .chat-gif-popover,
:root[data-theme="dark"] .chat-fab-panel,
:root[data-theme="dark"] .chat-toast,
:root[data-theme="dark"] .text-fab-panel,
:root[data-theme="dark"] .text-fab-suggest-item,
:root[data-theme="dark"] .center-overlay-box,
:root[data-theme="dark"] .ttt-modal,
:root[data-theme="dark"] .grid-floating-scrollbar,
:root[data-theme="dark"] .grid-hover-tooltip,
:root[data-theme="dark"] .company-suggest-list,
:root[data-theme="dark"] .checkbox-pill,
:root[data-theme="dark"] .lead-sidebar-panel,
:root[data-theme="dark"] .calendar-day-cell,
:root[data-theme="dark"] .calendar-modal,
:root[data-theme="dark"] .runner-stage,
:root[data-theme="dark"] .file-drop-zone {
  background: var(--surface);
  color: var(--text);
  border-color: var(--border);
}

/* The canvas can't inherit the swap above - it paints from these values,
   and views/games/runner.ejs calls refreshTheme() on the toggle to make it
   re-read them. Accent stays the brand red in both themes. */
:root[data-theme="dark"] .runner-stage hauly-runner {
  --color-bg: #17131a;
  --color-text: #f2ecf0;
  --color-neutral-300: #322936;
  --color-neutral-500: #a3939f;
  --color-neutral-700: #6b5c68;
  --color-neutral-900: #211b25;
}

/* Wells / header rows / hover states - one step up from the base surface,
   so a table header still separates from its own body. */
:root[data-theme="dark"] th,
:root[data-theme="dark"] .btn-secondary:hover,
:root[data-theme="dark"] .trailer-type-dropdown[open] summary,
:root[data-theme="dark"] .ttt-cell:not(:disabled):hover,
:root[data-theme="dark"] .calendar-swatch-dayoff,
:root[data-theme="dark"] .calendar-pill-dayoff,
:root[data-theme="dark"] .col-toggle-row:hover,
:root[data-theme="dark"] .user-menu-link:hover,
:root[data-theme="dark"] .header-search-item:hover,
:root[data-theme="dark"] .chat-emoji-tab:hover,
:root[data-theme="dark"] .chat-gif-suggestion-chip:hover {
  background: var(--surface-2);
  color: var(--text);
}
:root[data-theme="dark"] th { color: var(--muted); }

/* --- Buttons and inputs ---------------------------------------------- */
/* The accent inverts between themes: --blue is a deep navy on white, but a
   light periwinkle on near-black (and --blue-dark, the hover state, is
   lighter still). White ink that works in light mode only reaches 2.6:1 on
   the dark-mode button, so the primary button takes dark ink instead - 7.5:1
   on the default background, better on hover. Must stay ABOVE the
   .btn-secondary block below: both are (0,2,0), so the later rule wins for
   a button carrying both classes, which is what secondary needs. */
:root[data-theme="dark"] .btn { color: var(--bg); }
:root[data-theme="dark"] .btn-secondary {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border);
}
/* select:not(.badge) - All Loads' status cell is a <select> wearing the badge
   styling (see .status-select), and a bare `select` behind a :root[...]
   prefix is (0,2,1), which outranks the (0,1,0) .status-* colour rules and
   flattened every status pill to the same grey. Same specificity trap as the
   topbar links and the buttons; excluding .badge here keeps real form
   controls dark without repainting anything shaped like a badge. */
:root[data-theme="dark"] input,
:root[data-theme="dark"] select:not(.badge),
:root[data-theme="dark"] textarea {
  background: var(--surface-2);
  color: var(--text);
  border-color: var(--border);
}
/* Native date/time pickers draw their own glyph, which renders black on
   black without this. */
:root[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator,
:root[data-theme="dark"] input[type="datetime-local"]::-webkit-calendar-picker-indicator,
:root[data-theme="dark"] input[type="time"]::-webkit-calendar-picker-indicator {
  filter: invert(0.85);
}
:root[data-theme="dark"] ::placeholder { color: var(--muted); }
:root[data-theme="dark"] input:focus,
:root[data-theme="dark"] select:focus,
:root[data-theme="dark"] textarea:focus {
  outline: none;
  border-color: rgba(239, 68, 68, 0.6);
  box-shadow: 0 0 0 3px rgba(239, 68, 68, 0.16);
}
/* The topbar's own search sits ON the red bar, so it keeps its
   light-on-red treatment instead of picking up the dark-surface rule. */
:root[data-theme="dark"] #header-search-input {
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  border-color: rgba(255, 255, 255, 0.28);
}

/* --- Depth ------------------------------------------------------------
   A red-tinted drop shadow plus a 1px warm top highlight, so cards read as
   lit from above by the same red the background is glowing with, rather
   than floating on a generic black shadow. */
:root[data-theme="dark"] .card,
:root[data-theme="dark"] .section-card,
:root[data-theme="dark"] .loads-summary-box,
:root[data-theme="dark"] .admin-tile,
:root[data-theme="dark"] .lead-sidebar-panel,
:root[data-theme="dark"] table {
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.04) inset,
              0 10px 30px -18px rgba(239, 68, 68, 0.35),
              0 4px 18px -12px rgba(0, 0, 0, 0.8);
}
:root[data-theme="dark"] .admin-tile:hover {
  border-color: rgba(239, 68, 68, 0.45);
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.06) inset,
              0 14px 34px -16px rgba(239, 68, 68, 0.5);
}
/* Floating layers sit above the page, so they take a deeper, tighter
   shadow than the in-flow cards above. */
:root[data-theme="dark"] .online-users-dropdown,
:root[data-theme="dark"] .user-menu-dropdown,
:root[data-theme="dark"] .header-search-results,
:root[data-theme="dark"] .col-toggle-panel,
:root[data-theme="dark"] .ss-menu,
:root[data-theme="dark"] .chat-fab-panel,
:root[data-theme="dark"] .chat-toast,
:root[data-theme="dark"] .text-fab-panel,
:root[data-theme="dark"] .ttt-modal,
:root[data-theme="dark"] .calendar-modal,
:root[data-theme="dark"] .crm-quick-note-modal,
:root[data-theme="dark"] .center-overlay-box,
:root[data-theme="dark"] .grid-hover-tooltip {
  box-shadow: 0 18px 50px -12px rgba(0, 0, 0, 0.85),
              0 0 30px -10px rgba(239, 68, 68, 0.28);
}

/* --- Text and badges -------------------------------------------------- */
/* Buttons are excluded: this rule is a bare element selector behind a
   :root[...] prefix (0,2,1), so it outranks any single-class component rule
   like .btn (0,1,0) and repaints the label of every <a class="btn">. In dark
   mode --blue is the button's own background, so the text vanished entirely
   until hover. Excluding .btn here fixes it at the source rather than
   patching one button at a time - .btn-secondary always ships alongside
   .btn, so this covers both. The missing-paperwork mark is excluded for the
   same reason: it's an <a>, but it's a filled red circle whose label has to
   stay readable against that fill, not a blue link. */
:root[data-theme="dark"] a:not(.btn):not(.doc-warning) { color: var(--blue); }
/* Dark mode's --danger is a much lighter red than the light theme's, so the
   mark switches to dark text on it - white would leave a bold glyph sitting
   at roughly 3:1 against its own background. */
:root[data-theme="dark"] .doc-warning { color: #2a0b0b; }
/* The topbar is its own colour world - light text on the graphite bar - and
   the generic link colour above outranks .brand/.topbar nav a on
   specificity, so without these the nav links and the wordmark turn blue up
   there. Neutral rather than tinted: the bar is no longer red, so a pink
   cast would read as a leftover. */
:root[data-theme="dark"] .brand { color: #fff; }
:root[data-theme="dark"] .topbar nav a { color: #d5cdd8; }
:root[data-theme="dark"] .topbar nav a:hover { color: #fff; }
:root[data-theme="dark"] .hint,
:root[data-theme="dark"] .empty-state,
:root[data-theme="dark"] .app-footer,
:root[data-theme="dark"] .login-footer { color: var(--muted); }
:root[data-theme="dark"] .user-menu-link,
:root[data-theme="dark"] .header-search-item { color: var(--text); }
/* Badges are dark text on pale pastel fills in light mode; the fills become
   translucent tints of the same hue so the label can stay light. */
:root[data-theme="dark"] .badge-active { background: rgba(34, 197, 94, 0.18); color: #86efac; }
:root[data-theme="dark"] .badge-inactive { background: rgba(148, 163, 184, 0.18); color: #cbd5e1; }
/* Load-status pills: the light theme's pastel fills would glare as near-white
   blocks on a dark page, so each keeps its hue but becomes a translucent tint
   with light text of the same family - the colour coding survives, which is
   the whole point of the column.
   Deliberately scoped to .badge.status-*, NOT bare .status-*: the <option>
   elements inside the native dropdown carry the same status-* class but no
   .badge, and their popup is drawn by the OS on a light background, where
   light text would be unreadable. They keep the light pastels. */
:root[data-theme="dark"] .badge.status-none { background: rgba(148, 163, 184, 0.18); color: #cbd5e1; }
:root[data-theme="dark"] .badge.status-booked { background: rgba(99, 102, 241, 0.22); color: #c7d2fe; }
:root[data-theme="dark"] .badge.status-picked_up { background: rgba(245, 158, 11, 0.20); color: #fcd34d; }
:root[data-theme="dark"] .badge.status-delivered { background: rgba(34, 197, 94, 0.18); color: #86efac; }
:root[data-theme="dark"] .badge.status-ready_for_payment { background: rgba(20, 184, 166, 0.20); color: #5eead4; }
:root[data-theme="dark"] .badge.status-not_invoiced { background: rgba(245, 158, 11, 0.20); color: #fcd34d; }
:root[data-theme="dark"] .badge.status-invoiced { background: rgba(59, 130, 246, 0.22); color: #93c5fd; }
:root[data-theme="dark"] .badge.status-ready_to_be_factored { background: rgba(217, 70, 239, 0.20); color: #f0abfc; }
:root[data-theme="dark"] .badge.status-factored { background: rgba(139, 92, 246, 0.22); color: #c4b5fd; }
:root[data-theme="dark"] .badge.status-invoiced_directly { background: rgba(14, 165, 233, 0.22); color: #7dd3fc; }
:root[data-theme="dark"] .badge.status-paid { background: rgba(16, 185, 129, 0.20); color: #6ee7b7; }
:root[data-theme="dark"] .badge-warning { background: rgba(245, 158, 11, 0.18); color: #fcd34d; }
:root[data-theme="dark"] .badge-danger { background: rgba(239, 68, 68, 0.2); color: #fca5a5; }
:root[data-theme="dark"] .badge-info { background: rgba(59, 130, 246, 0.2); color: #93c5fd; }
:root[data-theme="dark"] .alert-error {
  background: var(--danger-bg);
  color: #fca5a5;
  border-color: rgba(239, 68, 68, 0.4);
}
:root[data-theme="dark"] .chat-nav-badge { background: #ff5a5a; color: #2b0b0d; }

/* The Grid board's per-dispatcher box colours are set inline from
   DISPATCHER_GRID_COLORS (see routes/loads.js) and stay exactly as they
   are - that colour coding is how staff recognise whose box is whose.
   Only the neutral scaffolding around them is re-skinned. */
:root[data-theme="dark"] .truck-grid td { border-color: var(--border); }
:root[data-theme="dark"] .grid-dispatcher-group { border-color: var(--border); }

/* --- The toggle button ------------------------------------------------ */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, 0.35);
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: #fff;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.18s ease, border-color 0.18s ease, transform 0.18s ease;
}
.theme-toggle:hover {
  background: rgba(255, 255, 255, 0.24);
  border-color: rgba(255, 255, 255, 0.6);
  transform: translateY(-1px);
}
.theme-toggle:active { transform: translateY(0); }
.theme-toggle svg { display: block; }
/* Exactly one icon shows, decided purely by the current theme - no JS class
   juggling, so the icon cannot drift out of sync with the theme actually
   applied. */
.theme-toggle .theme-icon-moon { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-icon-sun { display: none; }
:root[data-theme="dark"] .theme-toggle .theme-icon-moon { display: block; }
:root[data-theme="dark"] .theme-toggle {
  border-color: rgba(255, 190, 190, 0.5);
  box-shadow: 0 0 14px -2px rgba(239, 68, 68, 0.6);
}

@media (prefers-reduced-motion: reduce) {
  .theme-toggle { transition: none; }
  .theme-toggle:hover, .theme-toggle:active { transform: none; }
}

/* Logged-out pages (login, 2FA) render no topbar, so the theme toggle floats
   in the corner instead. It can't inherit the topbar version's white-on-red
   treatment - there's no coloured bar under it - so it gets colours that read
   against the page background in each theme. Scoped under
   .theme-toggle-floating so the topbar button is untouched. */
.theme-toggle-floating { position: fixed; top: 14px; right: 14px; z-index: 1200; }
/* Both themes are pinned with :root[...] so they sit at the same specificity
   as the topbar's own `:root[data-theme="dark"] .theme-toggle` rule and
   can't be outranked by it, and the :not() makes light/dark mutually
   exclusive rather than relying on source order. Literal colours, not
   var(--surface-2)/var(--surface): those tokens only exist in the dark
   block, so in light mode they resolve to nothing. */
/* Targeted by id, not class. The topbar's own theme-toggle rules are
   class-based, and this button sits outside the topbar on a plain page
   background where their white-on-red treatment is unreadable - an id
   selector (1,0,0) settles it outright instead of me having to keep score
   against every class rule that might touch .theme-toggle. Literal colours
   rather than var(--surface-2)/var(--surface): those tokens are defined
   only inside the dark block, so they resolve to nothing in light mode. */
#theme-toggle-anon {
  background: #ffffff;
  border-color: #d7dbe3;
  color: #1f2430;
  box-shadow: 0 2px 10px rgba(0, 0, 0, 0.18);
}
#theme-toggle-anon:hover { background: #eef1f6; border-color: #1d4ed8; }
:root[data-theme="dark"] #theme-toggle-anon {
  background: #211b25;
  border-color: #322936;
  color: #f2ecf0;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.5);
}
:root[data-theme="dark"] #theme-toggle-anon:hover { background: #17131a; border-color: #7d9bff; }

/* === Theme palettes =====================================================
   Ten themes, chosen per person from the palette button in the topbar, and
   every one of them has BOTH a light and a dark version. So `data-palette`
   picks the colour family and `data-theme` still picks light or dark inside
   it - the sun/moon button stays a plain light/dark flip and never moves
   anyone off the theme they chose. Classic is the pair that ships with no
   palette attribute at all (`:root` and `:root[data-theme="dark"]` above),
   which is why it is not listed here.

   Deliberately additive and stacked on top of the existing two-theme setup
   rather than replacing it. `data-theme` still drives all ~125 existing
   dark-mode component rules untouched; a palette only recolours tokens on
   top of them. So every theme inherits a component layer already known to
   work, Classic renders byte-identical to what shipped before, and a bad
   palette can only shift colours - it cannot break layout or contrast rules
   that live in the component rules.

   Each palette sets surface and accent tokens only. --danger and --danger-bg
   are never overridden: red has to keep meaning "wrong" in all twenty
   combinations.
   ==================================================================== */

/* --- Sand ------------------------------------------------------------
   Warm paper - a cream ground and a taupe bar. The least screen-like of the set. */
:root:not([data-theme="dark"])[data-palette="sand"] {
  --brand: #8a6a4f;
  --bg: #f6f1e9;
  --border: #ddd2c2;
  --text: #2a231c;
  --muted: #6b5f51;
  --blue: #7a5a3c;
  --blue-dark: #59422b;
}
:root[data-theme="dark"][data-palette="sand"] {
  --brand: #5c463a;
  --bg: #0c0906;
  --surface: #191410;
  --surface-2: #241d17;
  --border: #372c22;
  --text: #f4ebe0;
  --muted: #ab9b8c;
  --blue: #c8ab8e;
  --blue-dark: #e0c9b2;
  --glow: rgba(150, 120, 90, 0.34);
}
:root[data-theme="dark"][data-palette="sand"] .topbar {
  background: linear-gradient(180deg, #33291f 0%, #221b14 100%);
  border-bottom: 1px solid rgba(180, 150, 120, 0.28);
}
:root[data-theme="dark"][data-palette="sand"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(150, 120, 90, 0.16), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(120, 95, 70, 0.13), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(200, 171, 142, 0.10), transparent 65%);
}

/* --- Ember -----------------------------------------------------------
   Amber. The closest in spirit to the warmth of Classic, without the red. */
:root:not([data-theme="dark"])[data-palette="ember"] {
  --brand: #b5651d;
  --bg: #fdf4ea;
  --border: #eed9c0;
  --text: #2b2119;
  --muted: #6f6155;
  --blue: #b06010;
  --blue-dark: #7d4409;
}
:root[data-theme="dark"][data-palette="ember"] {
  --brand: #8a4a15;
  --bg: #0d0a07;
  --surface: #1a1410;
  --surface-2: #251d16;
  --border: #372a1f;
  --text: #f6eee4;
  --muted: #ab9a88;
  --blue: #f0a35e;
  --blue-dark: #f8c48f;
  --glow: rgba(217, 119, 6, 0.45);
}
:root[data-theme="dark"][data-palette="ember"] .topbar {
  background: linear-gradient(180deg, #3a2410 0%, #26170a 100%);
  border-bottom: 1px solid rgba(217, 119, 6, 0.35);
}
:root[data-theme="dark"][data-palette="ember"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(217, 119, 6, 0.18), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(180, 83, 9, 0.15), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(251, 146, 60, 0.11), transparent 65%);
}

/* --- Sage ------------------------------------------------------------
   Soft olive. Reads as a working surface rather than a screen. */
:root:not([data-theme="dark"])[data-palette="sage"] {
  --brand: #56693c;
  --bg: #f2f4ea;
  --border: #d6dcc4;
  --text: #23281a;
  --muted: #5f6552;
  --blue: #5a7a2e;
  --blue-dark: #40591e;
}
:root[data-theme="dark"][data-palette="sage"] {
  --brand: #3f4d2a;
  --bg: #080a06;
  --surface: #141810;
  --surface-2: #1d2318;
  --border: #2b3324;
  --text: #eef2e6;
  --muted: #a3a993;
  --blue: #a9c98c;
  --blue-dark: #c5dcae;
  --glow: rgba(132, 168, 90, 0.34);
}
:root[data-theme="dark"][data-palette="sage"] .topbar {
  background: linear-gradient(180deg, #26301a 0%, #181f10 100%);
  border-bottom: 1px solid rgba(132, 168, 90, 0.30);
}
:root[data-theme="dark"][data-palette="sage"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(132, 168, 90, 0.16), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(101, 133, 65, 0.13), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(169, 201, 140, 0.10), transparent 65%);
}

/* --- Forest ----------------------------------------------------------
   Deep emerald - the saturated green, where Sage is the muted one. */
:root:not([data-theme="dark"])[data-palette="forest"] {
  --brand: #26603f;
  --bg: #ecf4ef;
  --border: #c7dcd0;
  --text: #16241c;
  --muted: #506159;
  --blue: #157f5c;
  --blue-dark: #0e5b41;
}
:root[data-theme="dark"][data-palette="forest"] {
  --brand: #24583f;
  --bg: #070d0a;
  --surface: #111a15;
  --surface-2: #1a251f;
  --border: #27362d;
  --text: #e8f2ec;
  --muted: #94a89c;
  --blue: #63c7a4;
  --blue-dark: #8fdcbf;
  --glow: rgba(16, 185, 129, 0.42);
}
:root[data-theme="dark"][data-palette="forest"] .topbar {
  background: linear-gradient(180deg, #16301f 0%, #0e2016 100%);
  border-bottom: 1px solid rgba(16, 185, 129, 0.32);
}
:root[data-theme="dark"][data-palette="forest"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(16, 185, 129, 0.18), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(5, 150, 105, 0.14), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(52, 211, 153, 0.11), transparent 65%);
}

/* --- Teal ------------------------------------------------------------
   Cool teal - the calmest of the cool half. */
:root:not([data-theme="dark"])[data-palette="teal"] {
  --brand: #0f6d68;
  --bg: #ecf4f4;
  --border: #c6dcdc;
  --text: #16262a;
  --muted: #52666a;
  --blue: #0d8079;
  --blue-dark: #095c57;
}
:root[data-theme="dark"][data-palette="teal"] {
  --brand: #12525c;
  --bg: #060c0d;
  --surface: #0f1a1c;
  --surface-2: #172526;
  --border: #233537;
  --text: #e6f3f4;
  --muted: #8fa8ab;
  --blue: #5ec8d4;
  --blue-dark: #8fdde6;
  --glow: rgba(20, 184, 200, 0.40);
}
:root[data-theme="dark"][data-palette="teal"] .topbar {
  background: linear-gradient(180deg, #0f3238 0%, #0a2126 100%);
  border-bottom: 1px solid rgba(20, 184, 200, 0.32);
}
:root[data-theme="dark"][data-palette="teal"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(20, 184, 200, 0.17), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(13, 148, 160, 0.14), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(94, 200, 212, 0.10), transparent 65%);
}

/* --- Harbor ----------------------------------------------------------
   Steel blue. The default choice for anyone who just wants the red gone. */
:root:not([data-theme="dark"])[data-palette="harbor"] {
  --brand: #1e4f7c;
  --bg: #eef2f6;
  --border: #ccd6e0;
  --text: #16212b;
  --muted: #55636f;
  --blue: #1a5f9c;
  --blue-dark: #124470;
}
:root[data-theme="dark"][data-palette="harbor"] {
  --brand: #1b4257;
  --bg: #070b0e;
  --surface: #101820;
  --surface-2: #18232c;
  --border: #24323d;
  --text: #e6eef5;
  --muted: #91a3b0;
  --blue: #6fb3d9;
  --blue-dark: #9bcde8;
  --glow: rgba(56, 160, 200, 0.40);
}
:root[data-theme="dark"][data-palette="harbor"] .topbar {
  background: linear-gradient(180deg, #143242 0%, #0d212c 100%);
  border-bottom: 1px solid rgba(56, 160, 200, 0.32);
}
:root[data-theme="dark"][data-palette="harbor"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(56, 160, 200, 0.17), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(30, 110, 150, 0.14), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(111, 179, 217, 0.10), transparent 65%);
}

/* --- Midnight --------------------------------------------------------
   Deep indigo - the darkest of the cool themes, and the coolest of the light ones. */
:root:not([data-theme="dark"])[data-palette="midnight"] {
  --brand: #2a3f7a;
  --bg: #eef0f8;
  --border: #ccd2e6;
  --text: #1a1f2e;
  --muted: #565e75;
  --blue: #3b52b0;
  --blue-dark: #29397d;
}
:root[data-theme="dark"][data-palette="midnight"] {
  --brand: #24486e;
  --bg: #080b12;
  --surface: #121826;
  --surface-2: #1b2333;
  --border: #28324a;
  --text: #e9eef8;
  --muted: #93a1bb;
  --blue: #7fa8ff;
  --blue-dark: #a8c4ff;
  --glow: rgba(59, 130, 246, 0.45);
}
:root[data-theme="dark"][data-palette="midnight"] .topbar {
  background: linear-gradient(180deg, #16253c 0%, #0f1a2b 100%);
  border-bottom: 1px solid rgba(59, 130, 246, 0.35);
}
:root[data-theme="dark"][data-palette="midnight"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(37, 99, 235, 0.20), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(29, 78, 216, 0.16), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(56, 189, 248, 0.12), transparent 65%);
}

/* --- Amethyst --------------------------------------------------------
   Purple. */
:root:not([data-theme="dark"])[data-palette="amethyst"] {
  --brand: #5b3a8a;
  --bg: #f3eff9;
  --border: #d8cce8;
  --text: #241d31;
  --muted: #5f5772;
  --blue: #6d3fb5;
  --blue-dark: #4e2a86;
}
:root[data-theme="dark"][data-palette="amethyst"] {
  --brand: #4c2d75;
  --bg: #0a0810;
  --surface: #171327;
  --surface-2: #211b33;
  --border: #322847;
  --text: #efeaf8;
  --muted: #a397bd;
  --blue: #a78bfa;
  --blue-dark: #c4b5fd;
  --glow: rgba(139, 92, 246, 0.45);
}
:root[data-theme="dark"][data-palette="amethyst"] .topbar {
  background: linear-gradient(180deg, #2c1d47 0%, #1d1330 100%);
  border-bottom: 1px solid rgba(139, 92, 246, 0.35);
}
:root[data-theme="dark"][data-palette="amethyst"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(139, 92, 246, 0.20), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(109, 40, 217, 0.16), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(167, 139, 250, 0.12), transparent 65%);
}

/* --- Graphite --------------------------------------------------------
   No colour bias at all, for anyone who finds a tinted app distracting. */
:root:not([data-theme="dark"])[data-palette="graphite"] {
  --brand: #4a4a4f;
  --bg: #f2f2f4;
  --border: #d5d5da;
  --text: #1f1f22;
  --muted: #5e5e66;
  --blue: #4a5568;
  --blue-dark: #333c4d;
}
:root[data-theme="dark"][data-palette="graphite"] {
  --brand: #3a3a3d;
  --bg: #0b0b0c;
  --surface: #171719;
  --surface-2: #212124;
  --border: #313134;
  --text: #eeeef0;
  --muted: #9b9ba1;
  --blue: #8ab4f8;
  --blue-dark: #adc9fb;
  --glow: rgba(148, 163, 184, 0.30);
}
:root[data-theme="dark"][data-palette="graphite"] .topbar {
  background: linear-gradient(180deg, #232326 0%, #161618 100%);
  border-bottom: 1px solid rgba(148, 163, 184, 0.25);
}
:root[data-theme="dark"][data-palette="graphite"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(148, 163, 184, 0.10), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(100, 116, 139, 0.09), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(148, 163, 184, 0.07), transparent 65%);
}

/* --- GAY -------------------------------------------------------------
   The fun one (2026-09-26): a pride-flag rainbow top bar, violet accents.
   Light: the whole bar is the rainbow, deepened a little (and a soft text
   shadow) so the white nav text stays readable over orange and yellow.
   Dark: the usual dark bar with the flag as a stripe along its bottom edge. */
:root:not([data-theme="dark"])[data-palette="gay"] {
  --brand: #6b2c91;
  --bg: #f7f3fa;
  --border: #ddd0e8;
  --text: #221a2b;
  --muted: #625870;
  --blue: #7b2cbf;
  --blue-dark: #5a1f8f;
}
:root:not([data-theme="dark"])[data-palette="gay"] .topbar {
  background: linear-gradient(90deg, #d12229 0%, #ee6a13 20%, #d39a00 40%, #13843a 60%, #1f55c0 80%, #6b2c91 100%);
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.55);
}
:root[data-theme="dark"][data-palette="gay"] {
  --brand: #5b2a7e;
  --bg: #0b0810;
  --surface: #17121f;
  --surface-2: #21192c;
  --border: #33283f;
  --text: #f1ecf7;
  --muted: #a598b6;
  --blue: #c084fc;
  --blue-dark: #d8b4fe;
  --glow: rgba(192, 132, 252, 0.40);
}
:root[data-theme="dark"][data-palette="gay"] .topbar {
  background: linear-gradient(180deg, #1d1726 0%, #130f1a 100%);
  border-bottom: 4px solid transparent;
  border-image: linear-gradient(90deg, #e40303, #ff8c00, #ffed00, #008026, #24408e, #732982) 1;
}
:root[data-theme="dark"][data-palette="gay"] body::after {
  background:
    radial-gradient(60rem 40rem at 8% -10%, rgba(228, 3, 3, 0.12), transparent 60%),
    radial-gradient(50rem 38rem at 105% 8%, rgba(36, 64, 142, 0.18), transparent 62%),
    radial-gradient(70rem 50rem at 50% 115%, rgba(115, 41, 130, 0.16), transparent 65%);
}

/* --- The picker itself ------------------------------------------------ */
.theme-picker { position: relative; display: inline-flex; }
.theme-picker-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 120;
  background: var(--surface, #fff); color: var(--text);
  border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 12px 32px -10px rgba(0, 0, 0, 0.45);
  padding: 8px; min-width: 210px; display: none;
}
.theme-picker-panel[data-open="true"] { display: block; }
.theme-picker-panel h4 {
  margin: 4px 8px 8px; font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); font-weight: 700;
}
.theme-option {
  display: flex; align-items: center; gap: 9px; width: 100%;
  padding: 7px 8px; border: 0; border-radius: 7px; cursor: pointer;
  background: transparent; color: var(--text); font-size: 13.5px; text-align: left;
  font-family: inherit;
}
.theme-option:hover { background: var(--surface-2, #eef2f7); }
.theme-option[aria-checked="true"] { font-weight: 700; }
.theme-option[aria-checked="true"]::after { content: "✓"; margin-left: auto; opacity: 0.75; }
.theme-swatch {
  width: 22px; height: 16px; border-radius: 4px; flex: none;
  border: 1px solid rgba(127, 127, 127, 0.45);
  display: inline-block; position: relative; overflow: hidden;
}
.theme-swatch i { position: absolute; inset: 0 0 0 55%; display: block; }
.theme-sep { border: 0; border-top: 1px solid var(--border); margin: 6px 8px; }
/* Light / Dark at the top of the theme panel. */
.theme-mode { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; padding: 2px 6px 4px; }
.theme-mode-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 7px 8px; border: 1px solid var(--border); border-radius: 8px;
  background: transparent; color: var(--text); font: inherit; font-size: 0.88rem; cursor: pointer;
}
.theme-mode-btn:hover { background: var(--surface-2, #eef2f7); }
.theme-mode-btn[aria-pressed="true"] { background: var(--brand); border-color: var(--brand); color: #fff; font-weight: 700; }
.theme-mode-btn:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.theme-picker-hint {
  margin: 6px 8px 2px; padding-top: 7px; border-top: 1px solid var(--border);
  font-size: 11px; line-height: 1.35; color: var(--muted);
}

/* "What's new" badge + panel in the top bar (partials/header.ejs,
   src/data/whatsNew.js). Reuses the round .theme-toggle button; unread turns
   it bright yellow with a count so it stands out on the red top bar. */
.whats-new { position: relative; display: inline-flex; }
.whats-new-btn { position: relative; }
.whats-new-mark { font-weight: 900; font-size: 16px; line-height: 1; font-family: Georgia, 'Times New Roman', serif; }
.whats-new-btn.has-unread {
  background: #fde047; border-color: #fde047; color: #7f1d1d;
  animation: whats-new-pulse 1.8s ease-in-out infinite;
}
.whats-new-btn.has-unread:hover { background: #facc15; border-color: #facc15; }
.whats-new-count {
  position: absolute; top: -6px; right: -7px; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: #fff; color: #b91c1c; border: 1px solid #b91c1c;
  font-size: 10.5px; font-weight: 800; line-height: 15px; text-align: center;
}
/* Top-bar menu counts (Truck Offers, CRM, Carriers, My Loads, portal Admin)
   look like the "!" count above (2026-10-02): a small bubble on the word's
   top-right corner instead of a pill beside it. Dashboard tiles keep theirs. */
#topbar-nav a { position: relative; }
#topbar-nav .chat-nav-badge {
  position: absolute; top: -9px; right: -13px; margin: 0; min-width: 17px; height: 17px; padding: 0 4px;
  border-radius: 999px; background: #fff; color: #b91c1c; border: 1px solid #b91c1c;
  font-size: 10.5px; font-weight: 800; line-height: 15px; text-align: center; box-sizing: border-box;
}
#topbar-nav a:has(> .chat-nav-badge:not([style*="none"])) { margin-right: 10px; }
@keyframes whats-new-pulse {
  0%, 100% { box-shadow: 0 0 0 0 rgba(253, 224, 71, 0.65); }
  50% { box-shadow: 0 0 0 6px rgba(253, 224, 71, 0); }
}
@media (prefers-reduced-motion: reduce) { .whats-new-btn.has-unread { animation: none; } }
/* Load changes (accounting): the same round button and yellow count as What's
   new, with a "$" (partials/header.ejs, routes/loadChanges.js). */
a.load-changes-btn { text-decoration: none; margin-right: 6px; }
.load-changes-mark { font-weight: 900; font-size: 15px; line-height: 1; }
/* The list page (views/load-changes.ejs). */
.lc-item { padding: 12px 14px; margin-bottom: 10px; border-left: 4px solid #7c3aed; }
.lc-item.lc-kind-documents { border-left-color: #0d9488; }
.lc-head { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 12px; }
.lc-kind { font-weight: 700; }
.lc-load { font-weight: 700; }
.lc-billed { padding: 1px 8px; border-radius: 999px; background: #fee2e2; color: #991b1b; font-size: 0.78rem; font-weight: 700; }
.lc-status { padding: 1px 8px; border-radius: 999px; background: var(--bg-alt, #f3f4f6); font-size: 0.78rem; }
.lc-meta { margin-top: 2px; }
.lc-rate { display: flex; flex-wrap: wrap; gap: 4px 18px; margin: 8px 0 4px; font-variant-numeric: tabular-nums; }
.lc-rate s { color: var(--muted); }
.lc-up { color: #15803d; font-weight: 700; }
.lc-down { color: #b91c1c; font-weight: 700; }
.lc-files { margin: 8px 0 4px; padding-left: 20px; }
.lc-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; margin-top: 6px; }
.lc-done-form { margin: 0; }
.lc-history { margin-top: 18px; }
.lc-history summary { cursor: pointer; font-weight: 600; margin-bottom: 10px; }
.lc-history .lc-item { opacity: 0.75; }
/* The person's photo as the What's new button (2026-10-04): bigger than the
   old 22px avatar, a yellow ring while there is news, and the yellow count
   flickering on the photo's top-right. */
.whats-new-btn.has-face { width: 34px; height: 34px; padding: 0; border: 2px solid rgba(255, 255, 255, 0.75); background: none; margin-right: 2px; }
.whats-new-btn.has-face:hover { border-color: #fff; background: none; }
/* Round no matter what else styles the button or images. */
.whats-new-btn.has-face { border-radius: 50% !important; }
.whats-new-face { display: block; width: 100%; height: 100%; border-radius: 50% !important; clip-path: circle(50%); object-fit: cover; }
.whats-new-btn.has-face.has-unread { background: none; border-color: #fde047; }
.whats-new-btn.has-face.has-unread:hover { background: none; border-color: #facc15; }
.whats-new-btn.has-face .whats-new-count {
  top: -7px; right: -8px; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px; line-height: 18px; font-size: 11px; font-weight: 800;
  background: #fde047; color: #7f1d1d; border: 1px solid #a16207; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
  animation: whats-new-flicker 1.4s ease-in-out infinite;
}
@keyframes whats-new-flicker {
  0%, 100% { opacity: 1; transform: scale(1); }
  45% { opacity: 1; transform: scale(1.08); }
  60% { opacity: 0.35; transform: scale(0.96); }
  75% { opacity: 1; transform: scale(1.04); }
}
@media (prefers-reduced-motion: reduce) { .whats-new-btn.has-face .whats-new-count { animation: none; } }
:root[data-motion="calm"] .whats-new-btn.has-face .whats-new-count,
:root[data-motion="calm"] .whats-new-btn.has-unread { animation: none; }
.whats-new-panel {
  position: absolute; top: calc(100% + 8px); right: 0; z-index: 130;
  width: 360px; max-width: calc(100vw - 24px); max-height: min(70vh, 560px); overflow-y: auto;
  background: var(--surface, #fff); color: var(--text);
  border: 1px solid var(--border); border-radius: 12px;
  box-shadow: 0 14px 36px -10px rgba(0, 0, 0, 0.45);
  padding: 12px 14px 14px; display: none; text-align: left;
}
.whats-new-panel[data-open="true"] { display: block; }
.whats-new-panel h4 {
  margin: 0 0 6px; font-size: 10.5px; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--muted); font-weight: 700;
}
.whats-new-date {
  margin: 12px 0 6px; font-size: 11.5px; font-weight: 700; color: var(--muted);
  border-bottom: 1px solid var(--border); padding-bottom: 3px;
}
.whats-new-item { padding: 8px 10px; border-radius: 8px; margin-bottom: 6px; }
.whats-new-item.unread { background: var(--surface-2, #f4f6f9); }
.whats-new-title { font-weight: 700; font-size: 13.5px; display: flex; align-items: center; gap: 7px; line-height: 1.3; }
.whats-new-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: #dc2626; }
.whats-new-item p { margin: 4px 0 6px; font-size: 12.8px; line-height: 1.45; color: var(--text); }
.whats-new-item a { font-size: 12.5px; font-weight: 700; color: var(--brand, #b91c1c); text-decoration: none; }
.whats-new-item a:hover { text-decoration: underline; }
/* Driver shared location (Send Pin): Grid button, its preview dialog, the
   alert toast and the Map view pin. */
.grid-pin-btn { background: none; border: 0; padding: 0 2px; cursor: pointer; font-size: 0.95rem; line-height: 1; vertical-align: middle; }
.grid-pin-btn:hover { transform: scale(1.15); }
.driver-pin-map { position: relative; border-radius: 8px; overflow: hidden; border: 1px solid var(--border); margin: 6px 0 10px; aspect-ratio: 560 / 300; background: var(--surface-2, #f4f6f9); }
.driver-pin-map img { width: 100%; height: 100%; object-fit: cover; display: block; }
.driver-pin-marker { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -92%); font-size: 30px; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35)); }
.pin-toast-actions { display: flex; gap: 12px; margin-top: 4px; }
.pin-toast-actions a { font-size: 0.82rem; font-weight: 700; color: var(--brand, #b91c1c); text-decoration: none; }
.pin-toast-actions a:hover { text-decoration: underline; }
.driver-pin-icon { font-size: 26px; line-height: 28px; text-align: center; filter: drop-shadow(0 2px 2px rgba(0,0,0,0.35)); background: none; border: 0; }

/* Tiered pay (payroll/tiers.ejs, _tier-rows.ejs, _tier-detail.ejs). */
.pay-tier-card { border: 1px solid var(--border); border-radius: 10px; padding: 12px 14px; margin: 8px 0 14px; background: var(--surface, #fff); }
.pay-tier-table { border-collapse: collapse; margin: 6px 0 8px; }
.pay-tier-table th { font-size: 0.74rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); text-align: left; padding: 4px 8px 4px 0; }
.pay-tier-table td { padding: 4px 8px 4px 0; white-space: nowrap; }
.pay-tier-table input { width: 110px; }
.pay-tier-table input[readonly] { background: var(--surface-2, #f4f6f9); }
.pay-tier-lines tfoot td { font-weight: 800; }
.whats-new-all { display: block; text-align: center; padding: 9px 0 3px; margin-top: 4px; border-top: 1px solid var(--border); font-size: 12.8px; font-weight: 700; color: var(--brand, #b91c1c); text-decoration: none; }
.whats-new-all:hover { text-decoration: underline; }
/* Full history page (views/whats-new.ejs). */
.whats-new-page { max-width: 760px; }
.whats-new-page .whats-new-month { margin: 26px 0 6px; font-size: 1.05rem; }
.whats-new-page .whats-new-date { margin-top: 14px; }
.whats-new-page .whats-new-item { background: var(--surface, #fff); border: 1px solid var(--border); padding: 10px 14px; margin-bottom: 8px; }
.whats-new-page .whats-new-item.unread { border-left: 3px solid var(--brand, #b91c1c); }
.whats-new-page .whats-new-item p { font-size: 0.92rem; }
.whats-new-page .whats-new-title { font-size: 0.98rem; }

/* Photo library (photos/index.ejs). */
.ph-upload-btn { position: relative; cursor: pointer; }
.ph-upload-btn input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.ph-upload-btn:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }
.ph-crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: -6px 0 14px; font-size: 0.92rem; }
.ph-crumbs a { text-decoration: none; }
.ph-inline-form { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 0 0 14px; }
.ph-inline-form[hidden] { display: none; }
.ph-inline-form input[type=text] { flex: 1 1 260px; max-width: 420px; padding: 8px 10px; border: 1px solid var(--border); border-radius: 6px; }
.ph-inline { display: inline-flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 0; }
.ph-folder-tools { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 14px; }
.ph-folders { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 12px; margin-bottom: 18px; }
.ph-folder { display: flex; flex-direction: column; gap: 3px; padding: 8px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface, #fff); color: var(--text); text-decoration: none; }
.ph-folder:hover, .ph-folder:focus-visible { border-color: var(--brand); }
.ph-folder-cover { display: flex; align-items: center; justify-content: center; aspect-ratio: 4 / 3; border-radius: 6px; background: var(--surface-2, #eef2f7) center / cover no-repeat; color: var(--muted); }
.ph-folder-name { font-weight: 600; overflow-wrap: anywhere; }
.ph-folder-count { font-size: 0.78rem; }
.ph-select-bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin: 0 0 10px; }
.ph-select-actions { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ph-select-actions[hidden] { display: none; }
.ph-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 8px; }
.ph-thumb { position: relative; display: block; padding: 0; border: 1px solid var(--border); border-radius: 8px; overflow: hidden; background: var(--surface-2, #eef2f7); cursor: zoom-in; aspect-ratio: 1; }
.ph-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.ph-thumb:focus-visible { outline: 3px solid var(--brand); outline-offset: 2px; }
.ph-thumb-caption { position: absolute; left: 0; right: 0; bottom: 0; padding: 4px 6px; font-size: 0.72rem; color: #fff; text-align: left; background: linear-gradient(transparent, rgba(0,0,0,0.65)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.ph-check { display: none; position: absolute; top: 6px; right: 6px; width: 22px; height: 22px; border-radius: 50%; border: 2px solid #fff; background: rgba(0,0,0,0.3); box-shadow: 0 1px 3px rgba(0,0,0,0.4); }
.ph-selecting .ph-thumb { cursor: pointer; }
.ph-selecting .ph-check { display: block; }
.ph-thumb.picked { outline: 3px solid var(--brand); outline-offset: -3px; }
.ph-thumb.picked .ph-check { background: var(--brand); }
.ph-thumb.picked .ph-check::after { content: ""; position: absolute; left: 6px; top: 2px; width: 5px; height: 10px; border: solid #fff; border-width: 0 2px 2px 0; transform: rotate(45deg); }
.ph-empty { max-width: 640px; }
.ph-rules { margin-top: 18px; }
.ph-status:not([hidden]) { font-weight: 600; }
.ph-viewer { width: min(1100px, 96vw); max-width: 96vw; max-height: 94vh; padding: 0; border: 0; border-radius: 12px; background: #111; color: #eee; }
.ph-viewer::backdrop { background: rgba(0,0,0,0.75); }
.ph-viewer-top { display: flex; justify-content: space-between; align-items: center; padding: 8px 12px; font-size: 0.85rem; }
.ph-viewer-close { background: none; border: 0; color: #fff; font-size: 1.8rem; line-height: 1; cursor: pointer; }
.ph-viewer-stage { position: relative; display: flex; align-items: center; justify-content: center; background: #000; }
.ph-viewer-stage img { display: block; max-width: 100%; max-height: 70vh; object-fit: contain; }
.ph-nav { position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 64px; border: 0; border-radius: 8px; background: rgba(0,0,0,0.45); color: #fff; font-size: 2rem; cursor: pointer; }
.ph-nav[hidden] { display: none; }
.ph-prev { left: 8px; }
.ph-next { right: 8px; }
.ph-viewer-info { display: flex; flex-direction: column; gap: 10px; padding: 10px 14px 14px; }
.ph-viewer-info .hint { color: #aaa; }
.ph-viewer-actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.ph-own-actions { display: contents; }
.ph-own-actions[hidden] { display: none; }
.ph-viewer input[type=text], .ph-viewer select { padding: 6px 8px; border-radius: 6px; border: 1px solid #444; background: #1d1d1d; color: #eee; max-width: 220px; }
.ph-viewer .btn-danger { background: #b91c1c; color: #fff; }
@media (max-width: 760px) {
  .ph-grid { grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 6px; }
  .ph-folders { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 8px; }
  .ph-viewer { width: 100vw; max-width: 100vw; max-height: 100vh; max-height: 100dvh; border-radius: 0; }
  .ph-viewer-stage img { max-height: 60vh; max-height: 60dvh; }
  .ph-viewer input[type=text], .ph-viewer select { max-width: 100%; flex: 1 1 100%; }
}

/* "Directory" in the top bar (it replaced the "Who's online" button) looks like
   that button did, in both themes - not like a blue page link. */
.topbar a.directory-link, :root[data-theme="dark"] .topbar a.directory-link { color: #fde3e3; }
.topbar a.directory-link:hover, :root[data-theme="dark"] .topbar a.directory-link:hover { color: #fff; }

/* Font (My preferences -> Font): <html data-font="...">. No attribute = the
   standard font above. Only fonts every Windows / Mac computer already has -
   nothing to download. Form fields and buttons follow the chosen font too. */
:root[data-font="arial"] { --app-font: Arial, "Helvetica Neue", Helvetica, sans-serif; }
:root[data-font="verdana"] { --app-font: Verdana, Geneva, Tahoma, sans-serif; }
:root[data-font="georgia"] { --app-font: Georgia, "Times New Roman", Times, serif; }
:root[data-font="trebuchet"] { --app-font: "Trebuchet MS", "Lucida Grande", "Lucida Sans", sans-serif; }
/* Just for fun (Yaro, 2026-10-02): playful + curvy handwriting. */
:root[data-font="comic"] { --app-font: "Comic Sans MS", "Comic Sans", "Chalkboard SE", "Comic Neue", cursive; }
:root[data-font="script"] { --app-font: "Segoe Script", "Segoe Print", "Bradley Hand", "Snell Roundhand", "Brush Script MT", cursive; }
/* Handwriting runs wide: the menu a touch smaller so the top bar keeps one row. */
@media (min-width: 769px) { :root[data-font="script"] .topbar nav, :root[data-font="script"] .topbar-user { font-size: 0.8rem; } }
:root[data-font] button, :root[data-font] input, :root[data-font] select, :root[data-font] textarea { font-family: inherit; }
.pref-font-fun { flex-basis: 100%; margin-top: 4px; font-weight: 600; }
.pref-cols { border: 1px solid var(--border); border-radius: 10px; padding: 8px 12px 12px; margin: 10px 0 0; }
.pref-cols legend { font-weight: 700; padding: 0 6px; }
.pref-cols-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px 14px; }
.pref-col { display: flex; align-items: center; gap: 6px; cursor: pointer; font-size: 0.92rem; }
.pref-cols-saved { font-weight: 600; margin-left: 6px; }
.pref-chip-row { border-top: 1px solid var(--border); }
.pref-chip-grid { margin: 2px 0 10px; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); }
.chip-broker { font-weight: 600; }

/* Carrier portal: the carrier's own logo in the top bar, on a small white
   tile so a dark or see-through logo still shows on the coloured bar. */
.carrier-logo-tile { display: inline-flex; align-items: center; height: 36px; padding: 3px 8px; border-radius: 7px; background: #fff; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25); }
.carrier-logo { display: block; max-height: 30px; max-width: 170px; width: auto; height: auto; object-fit: contain; }
:root[data-nav="side"] .brand-carrier { padding: 0 2px 6px; }
:root[data-nav="side"][data-nav-collapsed="on"] .carrier-logo { max-width: 36px; }
.carrier-logo-manage { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.carrier-logo-preview { display: inline-flex; align-items: center; padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px; background: #fff; }
.carrier-logo-preview img { display: block; max-height: 60px; max-width: 280px; }
.carrier-logo-form { margin: 0; }
.carrier-logo-pick { position: relative; cursor: pointer; }
.carrier-logo-pick input[type=file] { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.carrier-logo-pick:focus-within { outline: 2px solid var(--brand); outline-offset: 2px; }

/* Text size (My preferences): almost every size here is in rem, so scaling the
   root scales the app. Phones keep the 16px form fields (no iOS zoom-in). */
:root[data-text="small"] { font-size: 93.75%; }
:root[data-text="large"] { font-size: 109.375%; }
:root[data-text="xlarge"] { font-size: 118.75%; }
/* Row spacing (My preferences): the height of table rows everywhere except the
   Grid board, which keeps its own tight layout. Only top/bottom - columns keep
   their widths. */
:root[data-rows="compact"] table:not(.truck-grid) > thead > tr > th, :root[data-rows="compact"] table:not(.truck-grid) > tbody > tr > td { padding-top: 4px; padding-bottom: 4px; }
:root[data-rows="roomy"] table:not(.truck-grid) > thead > tr > th, :root[data-rows="roomy"] table:not(.truck-grid) > tbody > tr > td { padding-top: 15px; padding-bottom: 15px; }

/* Top-bar clocks (My preferences -> Clocks). */
.topbar-clocks { display: inline-flex; align-items: center; gap: 10px; font-size: 0.78rem; white-space: nowrap; font-variant-numeric: tabular-nums; }
.topbar-clock b { font-weight: 700; opacity: 0.8; margin-right: 2px; }
/* Make room for the clocks on the top bar: the logo goes without its text
   below 1800px, and the clocks tighten up on smaller screens. */
@media (max-width: 1800px) { :root:not([data-nav="side"]) .topbar:has(.topbar-clocks) .brand-text { display: none; } }
@media (max-width: 1450px) { .topbar-clocks { gap: 7px; font-size: 0.72rem; } }
:root[data-nav="side"] .topbar-clocks { flex: 1 1 100%; justify-content: space-between; }
:root[data-nav="side"][data-nav-collapsed="on"] .topbar-clocks { display: none; }

/* Colour-blind friendly load status colours (My preferences): the Okabe-Ito
   set - blue, orange, bluish green, yellow, vermillion, reddish purple - which
   stay apart for the common kinds of colour blindness. Grid boxes + legend
   (their --chip-* tokens) and the status badges. */
:root[data-status-colors="colorblind"] .load-chip-st-booked            { --chip-bg: #d6e8f5; --chip-bar: #0072b2; --chip-fg: #003a5c; }
:root[data-status-colors="colorblind"] .load-chip-st-picked_up         { --chip-bg: #fdefd0; --chip-bar: #e69f00; --chip-fg: #5c3d00; }
:root[data-status-colors="colorblind"] .load-chip-st-delivered         { --chip-bg: #d3f0e6; --chip-bar: #009e73; --chip-fg: #00513b; }
:root[data-status-colors="colorblind"] .load-chip-st-ready_for_payment { --chip-bg: #fbf6c4; --chip-bar: #c9b700; --chip-fg: #4d4500; }
:root[data-status-colors="colorblind"] .load-chip-st-not_invoiced      { --chip-bg: #f8dbc9; --chip-bar: #d55e00; --chip-fg: #612b00; }
:root[data-status-colors="colorblind"] .load-chip-st-invoiced          { --chip-bg: #f4deeb; --chip-bar: #cc79a7; --chip-fg: #5e2447; }
:root[data-status-colors="colorblind"] .status-booked { background: #d6e8f5; color: #003a5c; }
:root[data-status-colors="colorblind"] .status-picked_up { background: #fdefd0; color: #5c3d00; }
:root[data-status-colors="colorblind"] .status-delivered { background: #d3f0e6; color: #00513b; }
:root[data-status-colors="colorblind"] .status-ready_for_payment { background: #fbf6c4; color: #4d4500; }
:root[data-status-colors="colorblind"] .status-not_invoiced { background: #f8dbc9; color: #612b00; }
:root[data-status-colors="colorblind"] .status-invoiced { background: #f4deeb; color: #5e2447; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-booked { background: rgba(0, 114, 178, 0.3); color: #9ccbea; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-picked_up { background: rgba(230, 159, 0, 0.25); color: #f5cf73; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-delivered { background: rgba(0, 158, 115, 0.25); color: #7fd9bd; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-ready_for_payment { background: rgba(240, 228, 66, 0.2); color: #f0e442; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-not_invoiced { background: rgba(213, 94, 0, 0.28); color: #f0a874; }
:root[data-status-colors="colorblind"][data-theme="dark"] .badge.status-invoiced { background: rgba(204, 121, 167, 0.28); color: #eab3d2; }

/* Calmer screen (My preferences): no animations or sliding. */
:root[data-motion="calm"] *, :root[data-motion="calm"] *::before, :root[data-motion="calm"] *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}

/* ===== Side-bar menu (2026-10-02) ===============================================
   Optional, per person (My preferences -> Menu): <html data-nav="side">, plus
   data-nav-collapsed="on" when folded to icons. The SAME header markup as the
   top bar - this only rearranges it into a column on the left. Computers
   only; phones keep the top bar + menu button. Without data-nav="side"
   nothing here applies and the top bar is exactly as before (the icons and
   the fold button stay hidden). */
.topbar .nav-ico, .side-collapse-btn, .logout-btn .nav-ico { display: none; }
@media (min-width: 769px) {
  :root[data-nav="side"] { --side-w: 228px; }
  :root[data-nav="side"][data-nav-collapsed="on"] { --side-w: 66px; }
  :root[data-nav="side"] body { padding-left: var(--side-w); padding-top: 0 !important; }
  :root[data-nav="side"] .container { padding-left: 28px; padding-right: 28px; }

  :root[data-nav="side"] .topbar {
    top: 0; bottom: 0; left: 0; right: auto; width: var(--side-w);
    transform: none !important; overflow: visible;
    border-bottom: 0 !important; border-image: none !important;
    border-right: 1px solid rgba(0, 0, 0, 0.12);
    box-shadow: 2px 0 14px -8px rgba(0, 0, 0, 0.35);
  }
  :root[data-nav="side"] .topbar-inner {
    height: 100%; flex-direction: column; flex-wrap: nowrap; align-items: stretch;
    gap: 6px; padding: 12px 10px 12px; row-gap: 6px;
  }
  /* Logo + fold button on the first row. */
  :root[data-nav="side"] .brand { padding: 2px 6px 6px; }
  :root[data-nav="side"] .brand-text { display: inline; }
  :root[data-nav="side"] .side-collapse-btn {
    display: inline-flex; align-items: center; justify-content: center;
    position: absolute; top: 12px; right: 8px; width: 30px; height: 30px; padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.3); border-radius: 8px; background: transparent; color: #fff; cursor: pointer;
  }
  :root[data-nav="side"] .side-collapse-btn:hover { background: rgba(255, 255, 255, 0.14); }
  :root[data-nav="side"] .side-collapse-btn:focus-visible { outline: 2px solid #fff; outline-offset: 2px; }

  /* The links: one column, icon + name, scrolls on its own if it is long. */
  :root[data-nav="side"] .topbar nav {
    flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden;
    flex-direction: column; align-items: stretch; justify-content: flex-start; gap: 2px;
    margin-top: 4px; padding: 2px; font-size: 0.93rem;
  }
  :root[data-nav="side"] .topbar nav a {
    position: relative; display: flex; align-items: center; gap: 11px;
    padding: 8px 10px; border-radius: 8px; white-space: nowrap; margin: 0;
  }
  :root[data-nav="side"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.13); font-weight: inherit; color: #fff; }
  :root[data-nav="side"] .topbar nav a.is-current { background: rgba(255, 255, 255, 0.2); color: #fff; font-weight: 700; }
  :root[data-nav="side"] .topbar nav a:focus-visible { outline: 2px solid #fff; outline-offset: -2px; }
  :root[data-nav="side"] .topbar nav a.nav-link-end { margin-top: 10px; }
  :root[data-nav="side"] .topbar nav a.nav-link-end::before {
    content: ""; position: absolute; left: 10px; right: 10px; top: -6px; height: 1px; background: rgba(255, 255, 255, 0.2);
  }
  :root[data-nav="side"] .topbar .nav-ico { display: block; flex: none; opacity: 0.92; }
  :root[data-nav="side"] .nav-label { overflow: hidden; text-overflow: ellipsis; }
  :root[data-nav="side"] #topbar-nav .chat-nav-badge { position: static; margin-left: auto; }
  :root[data-nav="side"] #topbar-nav a:has(> .chat-nav-badge:not([style*="none"])) { margin-right: 0; }

  /* Bottom block: search, who's online / directory, name, then the icon buttons in one row. */
  :root[data-nav="side"] .topbar-user {
    flex: none; margin-left: 0; display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
    padding: 10px 4px 0; border-top: 1px solid rgba(255, 255, 255, 0.2); font-size: 0.86rem;
  }
  :root[data-nav="side"] .topbar-user .header-search,
  :root[data-nav="side"] .topbar-user .online-users-widget,
  :root[data-nav="side"] .topbar-user .user-menu-widget { flex: 1 1 100%; }
  :root[data-nav="side"] .topbar #header-search-input { width: 100%; box-sizing: border-box; }
  :root[data-nav="side"] .user-menu-name { display: block; overflow: hidden; text-overflow: ellipsis; font-weight: 600; color: #fff; }
  :root[data-nav="side"] .logout-btn { display: inline-flex; align-items: center; gap: 6px; margin-left: auto; }
  :root[data-nav="side"] .logout-btn .nav-ico { display: block; width: 18px; height: 18px; }

  /* Pop-ups open up and to the right of the bar instead of down/left off the screen. */
  :root[data-nav="side"] .header-search-results,
  :root[data-nav="side"] .online-users-dropdown,
  :root[data-nav="side"] .user-menu-dropdown,
  :root[data-nav="side"] .theme-picker-panel,
  :root[data-nav="side"] .whats-new-panel {
    top: auto; bottom: calc(100% + 8px); left: 0; right: auto; margin-top: 0;
  }
  :root[data-nav="side"] .whats-new-panel { max-height: min(75vh, 620px); }

  /* Folded: icons only (names show as a tooltip). */
  :root[data-nav="side"][data-nav-collapsed="on"] .brand-text,
  :root[data-nav="side"][data-nav-collapsed="on"] .nav-label,
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar-user .header-search,
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar-user .online-users-widget,
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar-user .user-menu-widget { display: none; }
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar-inner { padding: 12px 8px; align-items: center; }
  :root[data-nav="side"][data-nav-collapsed="on"] .brand { padding: 2px 0 4px; }
  :root[data-nav="side"][data-nav-collapsed="on"] .side-collapse-btn { position: static; transform: rotate(180deg); }
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar nav { align-self: stretch; }
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar nav a { justify-content: center; padding: 9px 0; }
  :root[data-nav="side"][data-nav-collapsed="on"] #topbar-nav .chat-nav-badge { position: absolute; top: 1px; right: 4px; }
  :root[data-nav="side"][data-nav-collapsed="on"] .topbar-user { flex-direction: column; flex-wrap: nowrap; padding: 10px 0 0; align-self: stretch; }
  :root[data-nav="side"][data-nav-collapsed="on"] .logout-btn { margin-left: 0; }
}

/* ===== Side-bar button looks (2026-10-02) ========================================
   My preferences -> Menu -> "Side bar buttons": <html data-nav-look="cards |
   badges | pills">. No attribute = "Simple" (the side bar as first built).
   Only ever applies with the side bar on a computer. */
@media (min-width: 769px) {
  /* Shared by the three new looks: the bottom tools sit in their own panel. */
  :root[data-nav="side"][data-nav-look] .topbar-user {
    margin: 4px 0 0; padding: 10px; border-top: 0; border-radius: 12px;
    background: rgba(0, 0, 0, 0.16); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.1);
  }
  :root[data-nav="side"][data-nav-look] .topbar nav a.nav-link-end { margin-top: 14px; }
  :root[data-nav="side"][data-nav-look] .topbar nav a.nav-link-end::before { top: -8px; }

  /* Cards: every item its own soft tile. */
  :root[data-nav="side"][data-nav-look="cards"] .topbar nav { gap: 6px; padding: 4px 2px; }
  :root[data-nav="side"][data-nav-look="cards"] .topbar nav a {
    padding: 9px 11px; border-radius: 10px;
    background: rgba(255, 255, 255, 0.08); border: 1px solid rgba(255, 255, 255, 0.14);
    box-shadow: 0 1px 2px rgba(0, 0, 0, 0.18);
  }
  :root[data-nav="side"][data-nav-look="cards"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.17); border-color: rgba(255, 255, 255, 0.3); }
  :root[data-nav="side"][data-nav-look="cards"] .topbar nav a.is-current { background: #fff; border-color: #fff; color: #1f2328; }

  /* Icon circles: each icon in a round badge; the current page's is solid white. */
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav { gap: 4px; }
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav a { padding: 5px 8px; gap: 12px; border-radius: 999px; }
  :root[data-nav="side"][data-nav-look="badges"] .topbar .nav-ico {
    box-sizing: content-box; width: 18px; height: 18px; padding: 7px; border-radius: 50%;
    background: rgba(255, 255, 255, 0.15); transition: background 0.15s, color 0.15s;
  }
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.08); }
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav a:hover .nav-ico { background: rgba(255, 255, 255, 0.3); }
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav a.is-current { background: transparent; }
  :root[data-nav="side"][data-nav-look="badges"] .topbar nav a.is-current .nav-ico { background: #fff; color: #1f2328; }

  /* Pills: outlined rounded buttons; the current page filled in. */
  :root[data-nav="side"][data-nav-look="pills"] .topbar nav { gap: 6px; padding: 4px 2px; }
  :root[data-nav="side"][data-nav-look="pills"] .topbar nav a {
    padding: 7px 13px; border-radius: 999px; border: 1px solid rgba(255, 255, 255, 0.38);
  }
  :root[data-nav="side"][data-nav-look="pills"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.12); border-color: #fff; }
  :root[data-nav="side"][data-nav-look="pills"] .topbar nav a.is-current { background: #fff; border-color: #fff; color: #1f2328; }

  /* Folded to icons: the same looks, as squares / circles. */
  :root[data-nav="side"][data-nav-collapsed="on"][data-nav-look] .topbar-user { padding: 8px 0; align-self: stretch; }
  :root[data-nav="side"][data-nav-collapsed="on"][data-nav-look="cards"] .topbar nav a { padding: 9px 0; }
  :root[data-nav="side"][data-nav-collapsed="on"][data-nav-look="badges"] .topbar nav a { padding: 3px 0; }
  :root[data-nav="side"][data-nav-collapsed="on"][data-nav-look="pills"] .topbar nav a {
    width: 42px; height: 42px; padding: 0; align-self: center; border-radius: 50%;
  }
}

/* The same looks on the regular top bar (computers; phones keep the menu
   button). Compact, so the bar still fits on one row where it did before. */
@media (min-width: 769px) {
  :root:not([data-nav="side"])[data-nav-look] .topbar nav { gap: 4px; }
  :root:not([data-nav="side"])[data-nav-look] .topbar nav a {
    position: relative; display: inline-flex; align-items: center; gap: 6px;
    padding: 5px 9px; border-radius: 8px; line-height: 1.2; border: 1px solid transparent;
  }
  :root:not([data-nav="side"])[data-nav-look] .topbar nav a:hover { font-weight: inherit; color: #fff; }
  :root:not([data-nav="side"])[data-nav-look] .topbar nav a.nav-link-end { margin-left: auto; }
  :root:not([data-nav="side"])[data-nav-look] .topbar nav a.is-current { background: #fff; border-color: #fff; color: #1f2328; }
  :root:not([data-nav="side"])[data-nav-look] #topbar-nav a:has(> .chat-nav-badge:not([style*="none"])) { margin-right: 6px; }

  :root:not([data-nav="side"])[data-nav-look="cards"] .topbar nav a { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.18); }
  :root:not([data-nav="side"])[data-nav-look="cards"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.2); border-color: rgba(255, 255, 255, 0.32); }

  :root:not([data-nav="side"])[data-nav-look="pills"] .topbar nav a { border-radius: 999px; border-color: rgba(255, 255, 255, 0.45); }
  :root:not([data-nav="side"])[data-nav-look="pills"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.12); border-color: #fff; }
  @media (max-width: 1450px) {
    :root:not([data-nav="side"])[data-nav-look="cards"] .topbar nav a,
    :root:not([data-nav="side"])[data-nav-look="pills"] .topbar nav a { padding: 4px 7px; }
    :root:not([data-nav="side"])[data-nav-look="cards"] .topbar nav,
    :root:not([data-nav="side"])[data-nav-look="pills"] .topbar nav { gap: 3px; }
  }

  /* Icon circles on the top bar: the circle above a small name, so it still fits one row. */
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav { gap: 2px; }
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav a {
    flex-direction: column; gap: 2px; padding: 2px 6px; border-radius: 10px; font-size: 0.74rem; line-height: 1.1;
  }
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav a:hover { background: rgba(255, 255, 255, 0.1); }
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav .nav-ico {
    display: block; box-sizing: content-box; width: 16px; height: 16px; padding: 5px; border-radius: 50%;
    background: rgba(255, 255, 255, 0.16);
  }
  :root:not([data-nav="side"])[data-nav-look="badges"] #topbar-nav .chat-nav-badge { top: -4px; right: -4px; }
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav a.is-current { background: transparent; border-color: transparent; color: #fff; font-weight: 700; }
  :root:not([data-nav="side"])[data-nav-look="badges"] .topbar nav a.is-current .nav-ico { background: #fff; color: #1f2328; }
}

/* The little previews on My preferences (preferences/index.ejs). */
.nav-look-demo { display: inline-flex; flex-direction: column; gap: 4px; width: 92px; padding: 7px; border-radius: 8px; background: var(--brand, #b91c1c); vertical-align: middle; flex: none; }
.nav-look-demo i { display: block; height: 11px; border-radius: 4px; background: rgba(255, 255, 255, 0.55); width: 70%; }
.nav-look-demo i.on { background: #fff; width: 82%; }
.nav-look-demo-cards i { height: 13px; width: 100%; background: rgba(255, 255, 255, 0.16); box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3); border-radius: 5px; }
.nav-look-demo-cards i.on { background: #fff; width: 100%; }
.nav-look-demo-badges i { position: relative; margin-left: 16px; width: 60%; }
.nav-look-demo-badges i::before { content: ""; position: absolute; left: -16px; top: -1px; width: 13px; height: 13px; border-radius: 50%; background: rgba(255, 255, 255, 0.4); }
.nav-look-demo-badges i.on { background: #fff; width: 66%; }
.nav-look-demo-badges i.on::before { background: #fff; }
.nav-look-demo-pills i { height: 13px; width: 100%; border-radius: 999px; background: transparent; box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.7); }
.nav-look-demo-pills i.on { background: #fff; width: 100%; }
.pref-look-choices { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px; margin-top: 10px; }
.pref-look-choices .pref-choice { align-items: center; padding: 8px; border: 1px solid var(--border); border-radius: 10px; }
.pref-look-choices .pref-choice:has(input:checked) { border-color: var(--brand); box-shadow: 0 0 0 1px var(--brand); }

/* ===== Phones (2026-10-02) =====================================================
   An iPhone is ~390px wide. Desktop stays exactly as it was - everything here
   is inside max-width media queries. */
@media (max-width: 760px) {
  /* --- Grid -------------------------------------------------------------
     Week view used to squeeze the whole table into the screen: the four
     pinned columns + Total need ~530px, so the seven day columns got ZERO
     width and every row turned into a tall empty block. On a phone: one
     pinned column (truck #, driver, carrier stacked), the days at a readable
     width scrolling sideways, opening on today (script in loads/grid.ejs). */
  .grid-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
  .truck-grid-week { width: 1px; min-width: 0; }
  /* !important: the label columns' widths are inline on the <col>s. */
  .truck-grid-week colgroup col { width: 150px; }
  .truck-grid-week colgroup col.grid-col-weekend { width: 110px; }
  .truck-grid-week colgroup col:last-child { width: 92px !important; }
  .truck-grid-week colgroup col:nth-child(1), .truck-grid-week colgroup col:nth-child(2), .truck-grid-week colgroup col:nth-child(4) { width: 0 !important; }
  .truck-grid-week colgroup col:nth-child(3) { width: 112px !important; }
  /* The carrier / driver / trailer cells stay in the table (it needs them)
     but take no room; their content shows inside the truck cell instead. */
  .truck-grid td.truck-grid-carrier, .truck-grid td.truck-grid-driver, .truck-grid td.truck-grid-trailer,
  .truck-grid thead th:nth-child(1), .truck-grid thead th:nth-child(2), .truck-grid thead th:nth-child(4) {
    width: 0; min-width: 0; max-width: 0; padding: 0; border-left: 0; border-right: 0; font-size: 0; overflow: hidden;
  }
  .truck-grid td.truck-grid-carrier *, .truck-grid td.truck-grid-driver *, .truck-grid td.truck-grid-trailer * { display: none; }
  .truck-grid-carrier, .truck-grid-driver, .truck-grid-trailer { left: 0; }
  .truck-grid-truck, .truck-grid thead th:nth-child(3) {
    left: 0; min-width: 112px; max-width: 112px; border-right: 2px solid var(--border);
    white-space: normal; line-height: 1.25;
  }
  .truck-grid thead th:nth-child(3) { position: sticky; z-index: 4; background: var(--surface, #fff); }
  .grid-m-sub { display: block; font-weight: 500; font-size: 0.72rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .grid-m-carrier { font-weight: 400; opacity: 0.8; }
  .grid-m-call { text-decoration: none; }
  /* Month view: same idea - its four pinned columns shrink to the one. */
  .truck-grid.resizable td.truck-grid-truck { min-width: 112px; }
  /* The sticky legend bar ate the top of the screen: on a phone it scrolls
     away with the page, and the colour legend + drag chips (dragging needs a
     mouse anyway) fold behind "Legend & tools". */
  .grid-legend-sticky { position: static; margin-left: 0; margin-right: 0; padding: 8px 0; }
  .grid-legend .grid-m-legend-toggle { display: inline-flex; align-self: flex-start; margin-top: 6px; }
  .grid-legend .grid-legend-more { display: none; }
  .grid-legend.m-legend-open .grid-legend-more { display: flex; }
  /* Each dispatcher box is as wide as its table, so its name can stay pinned
     on the left while the days scroll. */
  .grid-scroll .grid-dispatcher-group { padding: 10px 8px; width: max-content; min-width: 100%; }
  .grid-dispatcher-group-title { position: sticky; left: 8px; display: inline-block; z-index: 5; }
  /* Team totals: two small cards per row instead of one big card per screen. */
  .grid-team-breakdown .gtb-cards { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
  .gtb-card { min-width: 0; padding: 8px 10px; }
  .gtb-card .gtb-gross { font-size: 1.05rem; }
  .gtb-card .gtb-sub { font-size: 0.72rem; }
  .grid-team-total { width: 100%; }
  .truck-grid-cell { padding: 2px !important; }

  /* --- Menu --------------------------------------------------------------
     Two columns of big tap targets; scrolls inside itself when it is taller
     than the screen (a fixed bar can't be scrolled by the page). */
  .topbar.mobile-nav-open { max-height: 100vh; max-height: 100dvh; overflow-y: auto; -webkit-overflow-scrolling: touch; }
  .topbar.mobile-nav-open nav { display: grid; grid-template-columns: 1fr 1fr; gap: 2px 12px; }
  .topbar.mobile-nav-open nav a { padding: 10px 4px; font-size: 1rem; border-bottom: 1px solid rgba(255,255,255,0.12); }
  .topbar.mobile-nav-open .topbar-user { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px 16px; }
  .topbar.mobile-nav-open .topbar-user #header-search-input { width: 100%; }
  .topbar.mobile-nav-open .topbar-user > *:has(#header-search-input) { flex: 1 1 100%; }

  /* --- Everywhere ----------------------------------------------------------
     Smaller call/chat bubbles, and room under the page so they never sit on
     top of the last rows or the Save button. */
  .chat-fab, .text-fab { width: 44px; height: 44px; bottom: 14px; }
  .chat-fab { right: 12px; }
  .text-fab { right: 64px; }
  main.container { padding-bottom: 84px; }
  /* Button labels stay on one line ("+ New Load", "Table view"). */
  .btn { white-space: nowrap; }
  .actions-bar .btn { padding: 8px 12px; }
  .actions-bar-right, .actions-bar-left { flex-wrap: wrap; }
  /* Filter forms marked data-m-fold: only the week picker until "More filters"
     (button added by the script in partials/footer.ejs). */
  form[data-m-fold]:not(.m-open) > *:not(.grid-week-nav):not(.m-fold-btn):not([type=hidden]) { display: none !important; }
}

/* ==== Grid layout options (My preferences -> Grid view) ====================
   The hidden columns stay in the table at zero width (same trick as the
   phone layout) so every row keeps the same column count. */
.truck-grid.grid-hide-trailer colgroup col:nth-child(4),
.truck-grid.grid-hide-total colgroup col:last-child { width: 0 !important; }
.truck-grid.grid-hide-trailer td.truck-grid-trailer, .truck-grid.grid-hide-trailer thead th:nth-child(4),
.truck-grid.grid-hide-total td.truck-grid-total, .truck-grid.grid-hide-total .truck-grid-total-col {
  width: 0; min-width: 0; max-width: 0; padding: 0 !important; border-left: 0; border-right: 0; font-size: 0; overflow: hidden;
}
.truck-grid.grid-hide-trailer td.truck-grid-trailer *, .truck-grid.grid-hide-total td.truck-grid-total * { display: none; }
/* The truck cell takes the trailer cell's job: the divider line and the copy button. */
.truck-grid-week.grid-hide-trailer colgroup col:nth-child(3) { width: 84px !important; }
.truck-grid.grid-hide-trailer .truck-grid-truck { min-width: 84px; max-width: 84px; border-right: 2px solid var(--border); }
.grid-copy-in-truck { display: none; }
.truck-grid.grid-hide-trailer .grid-copy-in-truck { display: inline-flex; vertical-align: middle; margin-left: 4px; }
/* Compact truck rows: less padding in the cells and the load boxes. */
.truck-grid.grid-compact th, .truck-grid.grid-compact td { padding-top: 1px; padding-bottom: 1px; line-height: 1.15; }
.truck-grid.grid-compact .truck-grid-cell { padding: 1px 2px !important; }
.truck-grid.grid-compact .load-chip { padding: 1px 4px; margin-bottom: 1px; line-height: 1.1; }
.truck-grid.grid-compact .truck-grid-total { padding-top: 2px; padding-bottom: 2px; }
.truck-grid.grid-compact .truck-grid-total .hint { margin-top: 0; }
@media (max-width: 760px) {
  .truck-grid-week.grid-hide-trailer colgroup col:nth-child(3) { width: 112px !important; }
  .truck-grid.grid-hide-trailer .truck-grid-truck { min-width: 112px; max-width: 112px; }
  .truck-grid.grid-hide-trailer .grid-copy-in-truck { display: none; }
}

/* ==== My preferences -> Menu buttons / Dashboard tiles (reorder lists) ==== */
.pref-order-wrap { display: flex; flex-wrap: wrap; gap: 10px 32px; align-items: flex-start; }
.pref-order-list { list-style: none; margin: 6px 0 10px; padding: 0; min-width: 260px; }
.pref-order-cols { columns: 2 280px; column-gap: 32px; }
.pref-order-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 3px 6px; border-bottom: 1px solid var(--border); break-inside: avoid; }
.pref-order-row:hover { background: var(--bg-alt); }
.pref-order-btns { display: inline-flex; gap: 4px; flex: 0 0 auto; }
.pref-move { width: 26px; height: 24px; padding: 0; border: 1px solid var(--border); border-radius: 5px; background: var(--surface, #fff); color: inherit; cursor: pointer; line-height: 1; }
.pref-move:hover { border-color: var(--blue); }
.pref-order-list li:first-child .pref-move[data-dir="-1"], .pref-order-list li:last-child .pref-move[data-dir="1"] { opacity: 0.35; }
.dash-customize { margin-top: 14px; }
.dash-customize a { color: var(--muted); }

/* ==== Grid: favourite (starred) trucks ==================================== */
/* Stacked under the drag handle so the carrier name keeps its full width. */
.grid-row-tools { display: inline-flex; flex-direction: column; align-items: center; flex: 0 0 auto; gap: 2px; }
.grid-star { border: 0; background: none; padding: 0; margin: 0; width: 12px; font-size: 11px; line-height: 1; cursor: pointer; color: inherit; opacity: 0.35; }
.grid-star:hover, .grid-star:focus-visible { opacity: 0.9; }
.grid-star.on { opacity: 1; color: #fbbf24; text-shadow: 0 0 1px rgba(0, 0, 0, 0.5); }
.grid-starred-only.on { background: #fbbf24; border-color: #f59e0b; color: #422006; }
#pref-copy-list { margin-bottom: 12px; }

/* ==== Default views ("Make this my default view") / New Load defaults ==== */
.default-view { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; white-space: nowrap; }
.default-view .link-button, #save-load-defaults { color: var(--blue); opacity: 1; text-decoration: underline; background: none; border: 0; padding: 0; cursor: pointer; font: inherit; }
.default-view .link-button:hover, #save-load-defaults:hover { text-decoration: none; }
#save-load-defaults { margin-left: 10px; font-size: 0.85rem; }

/* ==== My links / keyboard shortcuts ===================================== */
.pref-links { display: grid; gap: 6px; max-width: 640px; }
.pref-link-row { display: grid; grid-template-columns: 180px 1fr; gap: 8px; }
@media (max-width: 760px) { .pref-link-row { grid-template-columns: 1fr; } }
.shortcut-help { position: fixed; z-index: 2000; top: 80px; right: 24px; min-width: 240px; padding: 14px 16px; border-radius: 10px;
  background: var(--surface, #fff); color: var(--text, #111); border: 1px solid var(--border); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.25); }
.shortcut-help table { margin: 8px 0 4px; border-collapse: collapse; }
.shortcut-help td { padding: 3px 10px 3px 0; }
.shortcut-help kbd { display: inline-block; min-width: 22px; text-align: center; padding: 1px 6px; border: 1px solid var(--border); border-bottom-width: 2px; border-radius: 5px; font: 600 0.85rem/1.3 ui-monospace, Consolas, monospace; background: var(--bg-alt); }

/* ==== Profile photos / Dashboard "this week" card ======================== */
.avatar { display: inline-block; width: 28px; height: 28px; border-radius: 50%; object-fit: cover; vertical-align: middle; margin-right: 6px; flex: 0 0 auto; }
.avatar-sm { width: 22px; height: 22px; margin-right: 5px; }
.avatar-lg { width: 72px; height: 72px; margin: 0; }
.avatar-empty { display: inline-flex; align-items: center; justify-content: center; background: var(--bg-alt); color: var(--muted); font-size: 1.6rem; font-weight: 700; border: 1px dashed var(--border); }
.user-menu-name .avatar { border: 1px solid rgba(255, 255, 255, 0.6); }
.pref-photo-row { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
.pref-photo-form { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.dash-stats { margin: 16px 0 4px; padding: 14px 16px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface, #fff); }
.dash-stats-head { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; margin-bottom: 10px; }
.dash-stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; }
.dash-stat { display: flex; flex-direction: column; gap: 2px; }
.dash-stat-val { font-size: 1.45rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.dash-stat-lbl { font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.dash-stat-prev { font-size: 0.8rem; color: var(--muted); font-variant-numeric: tabular-nums; }
.dash-stat-prev .up { color: #15803d; }
.dash-stat-prev .down { color: #b91c1c; }
:root[data-theme="dark"] .dash-stat-prev .up { color: #4ade80; }
:root[data-theme="dark"] .dash-stat-prev .down { color: #f87171; }

/* ==== My preferences on wide screens (2026-10-03): the cards flow into two
   columns instead of one narrow strip with empty space on the right. The form
   is display: contents so its cards and the ones after it share the columns. */
@media (min-width: 1200px) {
  main:has(> .pref-form) { columns: 2; column-gap: 20px; }
  main:has(> .pref-form) > .pref-form { display: contents; }
  main:has(> .pref-form) .pref-section { max-width: none; break-inside: avoid; margin-top: 0; margin-bottom: 20px; }
  main:has(> .pref-form) .pref-bg-tiles { max-width: none; }
  main:has(> .pref-form) > :is(.actions-bar, .pref-intro, .pref-saved, .pref-actions, .page-back-row) { column-span: all; }
}
@media (min-width: 2200px) { main:has(> .pref-form) { columns: 3; } }
.pref-actions-bottom { margin: 4px 0 30px; }

/* ==== New Load: second load of the day (combined trip, 2026-10-03) ===== */
.combo-card fieldset.combo-q { border: 1px solid var(--border); border-radius: 8px; padding: 6px 12px 10px; margin: 12px 0 4px; }
.combo-card fieldset.combo-q legend { font-weight: 600; padding: 0 4px; }
.combo-card .combo-opt { display: flex; align-items: center; gap: 8px; font-weight: 400; margin: 6px 0 0; }
.combo-card .combo-opt input { width: auto; margin: 0; }
.combo-wh-grid { display: grid; grid-template-columns: 120px 1fr 120px; gap: 0 12px; }
@media (max-width: 760px) { .combo-wh-grid { grid-template-columns: 1fr; } }
.combo-route-preview:not(:empty) { margin-top: 12px; padding: 8px 12px; border-radius: 8px; background: var(--bg-alt); font-weight: 600; }

/* ==== Poke with a message (2026-10-03) ==================================== */
.online-user-poke-msg-btn { display: none; color: #fff; background: var(--navy, #1f2430); border: none; border-radius: 6px; padding: 4px 8px; font-size: 0.85rem; cursor: pointer; box-shadow: 0 4px 10px rgba(0,0,0,0.2); }
.online-user-name-wrap.expanded .online-user-poke-msg-btn { display: inline-block; }
.poke-overlay-message { margin: 14px auto 0; max-width: 520px; font-size: 1.25rem; font-style: italic; overflow-wrap: anywhere; }
.poke-compose-box { padding: 30px 36px; width: min(460px, 92vw); }
.poke-compose-box h3 { margin: 0 0 12px; }
.poke-compose-box textarea { width: 100%; box-sizing: border-box; font: inherit; }
.poke-compose-actions { display: flex; gap: 10px; justify-content: center; margin-top: 12px; }

/* ==== Carrier portal Grid view (customer/grid.ejs, 2026-10-03) ============ */
.pgrid-filters { flex-wrap: wrap; align-items: center; gap: 8px; }
.pgrid-filters #pgrid-search { min-width: 200px; }
.pgrid-check { display: inline-flex; align-items: center; gap: 6px; font-size: 0.9rem; white-space: nowrap; }
.pgrid-check input { width: auto; margin: 0; }
.pgrid-summary { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin: 12px 0; }
.pgrid-summary > div { background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 10px; padding: 10px 14px; display: flex; flex-direction: column; }
.pgrid-sum-val { font-size: 1.3rem; font-weight: 800; font-variant-numeric: tabular-nums; }
.pgrid-sum-lbl { font-size: 0.78rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted); }
.pgrid-legend { display: flex; flex-wrap: wrap; gap: 6px 16px; margin: 6px 0 10px; font-size: 0.85rem; }
.pgrid-legend-item { display: inline-flex; align-items: center; gap: 6px; }
.pgrid-legend-item .legend-swatch { margin-right: 0; }
.pgrid-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; background: var(--surface, #fff); border: 1px solid var(--border); border-radius: 10px; }
.pgrid { width: 100%; border-collapse: collapse; font-size: 0.85rem; table-layout: fixed; min-width: 980px; }
/* The phone rule that makes every table scroll by itself would break the pinned truck column - this one scrolls inside .pgrid-scroll. */
.pgrid { display: table !important; overflow: visible !important; }
.pgrid-month { min-width: 2600px; }
.pgrid th, .pgrid td { border: 1px solid var(--border); padding: 4px 6px; vertical-align: top; }
.pgrid thead th { background: var(--bg-alt); position: sticky; top: 0; z-index: 2; text-align: center; }
.pgrid .pgrid-truck { width: 80px; position: sticky; left: 0; z-index: 3; background: var(--surface, #fff); font-weight: 700; }
.pgrid thead .pgrid-truck { z-index: 4; background: var(--bg-alt); }
.pgrid .pgrid-driver { width: 130px; } .pgrid .pgrid-trailer { width: 70px; } .pgrid .pgrid-total { width: 120px; }
.pgrid td.pgrid-driver, .pgrid td.pgrid-trailer { vertical-align: middle; }
.pgrid td.pgrid-total { text-align: right; vertical-align: middle; } .pgrid td.pgrid-total .hint { display: block; }
.pgrid-weekend { background: rgba(0,0,0,0.025); }
.pgrid th.pgrid-today { box-shadow: inset 0 -3px 0 var(--blue); } .pgrid td.pgrid-today { background: rgba(59,130,246,0.06); }
.pgrid .load-chip { display: block; margin: 0 0 3px; font-size: 0.72rem; }
.pgrid-loadno { opacity: 0.85; }
.pgrid-marker { display: inline-block; font-size: 0.7rem; font-weight: 700; padding: 1px 6px; border-radius: 4px; background: #fef3c7; color: #92400e; }
.pgrid-marker-repair { background: #ede9fe; color: #5b21b6; } .pgrid-marker-off { background: #e5e7eb; color: #374151; }
@media (max-width: 760px) { .pgrid .pgrid-driver, .pgrid .pgrid-trailer { display: none; } .pgrid { min-width: 860px; } }
@media print { .topbar, .pgrid-filters, .actions-bar-right, .pgrid-legend, .page-back-row, .fab, footer { display: none !important; } .pgrid-scroll { overflow: visible; border: 0; } .pgrid { min-width: 0; font-size: 0.7rem; } }

/* ==== Places map (places/*.ejs, 2026-10-03) =============================== */
.places-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin: 6px 0 12px; }
.places-chip { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; cursor: pointer; }
.places-chip input { width: auto; margin: 0; }
.places-dot { display: inline-block; width: 12px; height: 12px; border-radius: 50%; border: 2px solid #fff; box-shadow: 0 0 0 1px rgba(0,0,0,0.25); flex: 0 0 auto; }
.places-badge { display: inline-flex; align-items: center; justify-content: center; border-radius: 50%; flex: 0 0 auto; box-shadow: 0 1px 3px rgba(0,0,0,0.25); }
.places-item .places-badge { margin-top: 1px; }
.places-h1 { display: inline-flex; align-items: center; gap: 10px; }
#places-filter, #places-goto { min-width: 240px; }
gmp-place-autocomplete#places-goto { flex: 1 1 260px; max-width: 420px; color-scheme: light; }
:root[data-theme="dark"] gmp-place-autocomplete#places-goto { color-scheme: dark; }
.places-pin { display: block; }
.places-pin-bounce { animation: places-bounce 0.7s ease-out; }
@keyframes places-bounce { 0%, 100% { transform: translateY(0); } 30% { transform: translateY(-14px); } 55% { transform: translateY(0); } 75% { transform: translateY(-6px); } }
@media (prefers-reduced-motion: reduce) { .places-pin-bounce { animation: none; } }
#places-state, #places-city { width: auto; max-width: 100%; }
.places-truck { border: 1px solid var(--border); border-radius: 8px; padding: 8px 12px 12px; margin: 12px 0 4px; }
.places-truck[hidden] { display: none; }
.places-truck legend { font-weight: 600; padding: 0 4px; }
.places-amenity-checks { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 4px 12px; margin-top: 10px; }
.places-check { display: flex; align-items: center; gap: 6px; font-weight: normal; margin: 0; }
.places-check input { width: auto; margin: 0; }
.places-logo { width: 46px; height: 26px; object-fit: contain; background: #fff; border: 1px solid var(--border); border-radius: 6px; padding: 2px; flex: 0 0 auto; }
.places-logo-lg { width: 84px; height: 44px; }
.places-must { margin: -4px 0 12px; } .places-must summary { cursor: pointer; font-weight: 600; }
.places-must-list { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
.places-amen { display: inline-flex; align-items: center; gap: 5px; margin: 0; padding: 3px 10px; border: 1px solid var(--border); border-radius: 999px; font-weight: normal; font-size: 0.85rem; cursor: pointer; background: var(--surface, #fff); }
.places-amen input { width: auto; margin: 0; }
.places-amen:has(input:checked) { border-color: var(--blue, #2563eb); background: #eff6ff; color: #1e3a8a; }
.places-facts { color: var(--text, #111827) !important; opacity: 0.8; }
.places-list-count { margin-right: auto; }
.places-more { margin-top: 8px; width: 100%; }
.places-more[hidden] { display: none; }
.places-credit { margin-top: 10px; font-size: 0.78rem; }
.places-info-am { margin-top: 4px; color: #166534; }
.places-am-chips { display: flex; flex-wrap: wrap; gap: 5px; }
.places-am-chip { padding: 2px 9px; border-radius: 999px; background: #ecfdf5; color: #166534; font-size: 0.82rem; border: 1px solid #bbf7d0; }
/* [hidden] must beat display:flex/sticky above, or filtered places stay in the list. */
.places-item[hidden], .places-state-head[hidden] { display: none; }
.places-layout { display: grid; grid-template-columns: minmax(0, 1fr) 320px; gap: 14px; }
#places-map { height: 70vh; min-height: 420px; border-radius: 12px; border: 1px solid var(--border); }
.places-map-hint { margin: 6px 0 0; }
.places-pending { padding: 24px; border: 1px dashed var(--border); border-radius: 12px; background: var(--surface, #fff); }
.places-sort { display: flex; align-items: center; justify-content: flex-end; gap: 6px; margin-bottom: 6px; font-size: 13px; color: var(--text-muted, #6b7280); }
.places-sort select { width: auto; padding: 3px 8px; font-size: 13px; }
.places-state-head { position: sticky; top: 0; z-index: 1; padding: 4px 10px; margin-top: 4px; font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--text-muted, #6b7280); background: var(--bg, #f3f4f6); border-radius: 6px; }
.places-list { max-height: 70vh; overflow-y: auto; display: flex; flex-direction: column; gap: 4px; }
.places-item { display: flex; align-items: flex-start; gap: 8px; padding: 8px 10px; border-radius: 8px; border: 1px solid var(--border); background: var(--surface, #fff); color: inherit; text-decoration: none; }
.places-item:hover { border-color: var(--blue); } .places-item .hint { display: block; }
.places-item.is-pending, .places-item.is-rejected { opacity: 0.7; border-style: dashed; }
.places-count { display: inline-block; min-width: 18px; padding: 0 5px; border-radius: 999px; background: var(--danger, #b91c1c); color: #fff; font-size: 0.75rem; line-height: 18px; text-align: center; }
.places-info { max-width: 260px; font-size: 0.85rem; line-height: 1.35; } .places-info a { display: inline-block; margin-top: 6px; font-weight: 600; }
.places-form-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 20px; }
#places-form-map { height: 420px; border-radius: 10px; border: 1px solid var(--border); }
.places-addr-grid { display: grid; grid-template-columns: 1fr 90px 110px; gap: 0 10px; } .places-addr-grid.places-two { grid-template-columns: 1fr 1fr; }
.places-profile-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 10px; }
.places-kind-badge { color: #fff; font-weight: 700; font-size: 0.78rem; padding: 3px 10px; border-radius: 999px; }
.places-dl { display: grid; grid-template-columns: 160px 1fr; gap: 6px 14px; margin: 0 0 14px; } .places-dl dt { font-weight: 600; color: var(--muted); } .places-dl dd { margin: 0; }
.places-pre { white-space: pre-line; }
.places-links { display: flex; gap: 10px; flex-wrap: wrap; }
.places-status { padding: 10px 14px; border-radius: 8px; margin: 0 0 12px; display: flex; gap: 12px; align-items: center; flex-wrap: wrap; }
.places-status-pending { background: #fef3c7; color: #78350f; } .places-status-rejected { background: #fee2e2; color: #7f1d1d; }
.places-remove { margin-top: 14px; }
.places-review-card { margin-bottom: 12px; } .places-review-actions { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
.places-reject { display: inline-flex; gap: 6px; } .places-reject input { width: 220px; }
.mu-calc input { width: 90px; text-align: right; } .mu-calc td, .mu-calc th { vertical-align: middle; }
@media (max-width: 900px) { .places-layout, .places-form-grid { grid-template-columns: 1fr; } .places-list { max-height: none; } #places-map { height: 60vh; } }

/* My profile (routes/profile.js, migration 154) */
.profile-card { max-width: 860px; }
.profile-head { display: flex; gap: 18px; align-items: center; flex-wrap: wrap; margin-bottom: 14px; }
.profile-photo { width: 112px; height: 112px; border-radius: 50%; object-fit: cover; flex: 0 0 auto; }
.profile-photo-empty { display: inline-flex; align-items: center; justify-content: center; background: var(--border, #e5e7eb); color: var(--text-muted, #6b7280); font-size: 2.6rem; font-weight: 700; }
.profile-photo-row { display: flex; gap: 16px; align-items: center; flex-wrap: wrap; }
.profile-photo-row .profile-photo { width: 96px; height: 96px; }
.profile-name { margin: 0; }
.profile-role { font-weight: 600; margin-top: 2px; }
.profile-dl { display: grid; grid-template-columns: 190px 1fr; gap: 8px 14px; margin: 0; }
.profile-dl dt { font-weight: 600; color: var(--muted, #6b7280); }
.profile-dl dd { margin: 0; }
.profile-private { border-left: 4px solid #f59e0b; }
.profile-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 12px; }
.profile-grid-4 { grid-template-columns: 2fr 1.4fr 1fr 1.2fr; }
.profile-bday { display: flex; gap: 8px; flex-wrap: wrap; }
.profile-bday select, .profile-bday input { width: auto; }
.profile-sub { margin: 14px 0 4px; font-size: 1rem; }
.profile-cake { font-size: 1.1em; }
.dir-profile-link { color: inherit; text-decoration: none; } .dir-profile-link:hover strong { text-decoration: underline; }
.dash-bdays { margin: 12px 0; padding: 10px 14px; border: 1px solid var(--border); border-radius: 10px; background: var(--surface, #fff); }
.dash-bdays ul { list-style: none; margin: 6px 0 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px 18px; }
.dash-bdays li a { font-weight: 600; } .dash-bdays li.is-today a { color: #b45309; }
@media (max-width: 700px) { .profile-dl { grid-template-columns: 1fr; gap: 2px; } .profile-dl dd { margin-bottom: 8px; } .profile-grid, .profile-grid-4 { grid-template-columns: 1fr; } }

/* Top bar "More" (2026-10-04, public/nav-overflow.js): links that don't fit
   fold in here so the bar stays one row. */
/* Wide screens: 40px at each end instead of an inch - at 1920px the whole menu
   (with Warehouse) and the tools fit on one row again. */
@media (min-width: 1701px) { .topbar-inner { padding-left: 40px; padding-right: 40px; } }
.nav-more { position: relative; display: inline-flex; align-items: center; }
.nav-more[hidden] { display: none; }
.nav-more-btn { background: none; border: 0; color: #fde3e3; font: inherit; cursor: pointer; display: inline-flex; align-items: center; gap: 4px; padding: 0; white-space: nowrap; }
.nav-more-btn:hover { color: #fff; font-weight: 700; }
.nav-more-btn::after { content: ''; border: 4px solid transparent; border-top-color: currentColor; margin-left: 2px; margin-top: 4px; }
.nav-more-panel { display: none; position: absolute; top: calc(100% + 10px); right: 0; min-width: 220px; background: var(--card, #fff); color: var(--text, #1f2937); border: 1px solid var(--border, #e5e7eb); border-radius: 10px; box-shadow: 0 12px 28px rgba(0,0,0,.18); padding: 6px; z-index: 1100; }
.nav-more.open .nav-more-panel { display: block; }
.nav-more-items { display: flex; flex-direction: column; }
.topbar nav .nav-more-panel a { color: var(--text, #1f2937); display: flex; align-items: center; gap: 8px; padding: 8px 10px; border-radius: 7px; margin: 0; white-space: nowrap; }
.topbar nav .nav-more-panel a:hover { background: var(--hover, rgba(0,0,0,.05)); font-weight: 400; color: var(--text, #1f2937); }
.nav-more-panel .nav-more-customize { border-top: 1px solid var(--border, #e5e7eb); margin-top: 4px !important; font-size: .85rem; color: var(--muted, #6b7280) !important; }
.nav-more-dot { min-width: 8px; height: 8px; padding: 0; border-radius: 50%; }
:root[data-theme="dark"] .nav-more-panel { background: #1f2430; color: #e5e7eb; border-color: #374151; }
:root[data-theme="dark"] .topbar nav .nav-more-panel a { color: #e5e7eb; }
/* Dashboard tiles: the star pins a page to the top bar. */
.admin-tile-wrap { position: relative; display: flex; }
.admin-tile-wrap .admin-tile { flex: 1; }
.tile-pin { position: absolute; top: 6px; right: 6px; background: none; border: 0; cursor: pointer; font-size: 1.05rem; line-height: 1; color: var(--muted, #9ca3af); padding: 4px; border-radius: 6px; opacity: .55; }
.admin-tile-wrap:hover .tile-pin, .tile-pin.on, .tile-pin:focus-visible { opacity: 1; }
.tile-pin.on { color: #f2b705; }
.tile-pin:hover { background: rgba(0,0,0,.06); }

/* ---- Rail-transload pallet placement grid (warehouse-station/unit.ejs) ---- */
.rt-chip { display: inline-flex; align-items: center; justify-content: center; min-width: 20px; height: 20px; padding: 0 5px; border-radius: 999px; color: #fff; font-weight: 700; font-size: 0.72rem; }
.rt-toolbar { display: flex; flex-wrap: wrap; gap: 14px; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.rt-palette { display: flex; flex-wrap: wrap; gap: 6px; }
.rt-load-btn { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border: 2px solid var(--border); border-radius: 999px; background: var(--card-bg, #fff); color: var(--text); font: inherit; font-size: 0.82rem; font-weight: 600; cursor: pointer; }
.rt-load-btn.on { border-color: var(--c, #2563eb); box-shadow: inset 0 0 0 1px var(--c, #2563eb); }
.rt-load-btn.rt-erase { color: var(--danger); }
.rt-tools { display: flex; gap: 14px; }
.rt-tool { display: inline-flex; align-items: center; gap: 6px; font-size: 0.85rem; font-weight: 600; cursor: pointer; }
.rt-truck { display: inline-block; }
.rt-truck-end { text-align: center; font-weight: 800; letter-spacing: 3px; border: 2px solid var(--text); padding: 4px; width: 180px; }
.rt-grid { display: grid; grid-template-columns: 90px 90px; border: 2px solid var(--text); border-top: 0; border-bottom: 0; }
.rt-spot { border: 1px solid var(--border); min-height: 46px; position: relative; display: flex; flex-direction: column; cursor: pointer; }
.rt-spot-n { position: absolute; top: 1px; left: 3px; font-size: 10px; color: var(--muted); z-index: 1; }
.rt-level { display: flex; flex: 1; min-height: 20px; }
.rt-level.rt-upper-lvl { flex: 0 0 16px; border-bottom: 1px dashed var(--muted); }
.rt-fill { flex: 1; display: flex; align-items: center; justify-content: center; color: #fff; font-weight: 700; font-size: 0.8rem; }
.rt-fill.rt-half { border-right: 1px dashed rgba(255,255,255,.6); }
.rt-level.rt-empty .rt-fill { color: transparent; }
:root[data-theme="dark"] .rt-load-btn { background: var(--card-bg, #1f2430); }

/* ---- Rail-transload milestone stepper + log (rail/unit.ejs) ---- */
.rt-steps { list-style: none; display: flex; flex-wrap: wrap; gap: 6px 4px; padding: 0; margin: 0 0 6px; }
.rt-step { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: 999px; background: var(--bg); color: var(--muted); font-size: 0.82rem; font-weight: 600; }
.rt-step-dot { display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; border-radius: 50%; background: var(--border); color: var(--text); font-size: 0.72rem; font-weight: 700; }
.rt-step.done { color: #15803d; } .rt-step.done .rt-step-dot { background: #16a34a; color: #fff; }
.rt-step.cur { color: var(--text); background: var(--accent-soft, #eef3ff); } .rt-step.cur .rt-step-dot { background: var(--blue, #2563eb); color: #fff; }
.rt-step-btns { display: flex; flex-wrap: wrap; gap: 8px; }
.rt-log { list-style: none; padding: 0; margin: 0; }
.rt-log li { padding: 8px 0; border-bottom: 1px solid var(--border); }
.rt-log li:last-child { border-bottom: 0; }

/* ---- Rail-transload sheet + finance (rail/sheet.ejs, rail/unit.ejs) ---- */
.table-scroll { overflow-x: auto; }
.rt-sheet th.num, .rt-sheet td.num { text-align: right; font-variant-numeric: tabular-nums; }
.rt-pos { color: #15803d; font-weight: 700; }
.rt-neg { color: #b91c1c; font-weight: 700; }
.rt-leg-load { border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin-bottom: 8px; }
.rt-leg-head { margin-bottom: 6px; }
.rt-leg-form { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 4px 0; }
.rt-leg-label { min-width: 150px; font-weight: 600; font-size: 0.85rem; }
/* Demurrage / per-diem clocks (migration 166) */
.rt-warn { color: #b45309; font-weight: 700; }
.rt-clocks { display: flex; flex-wrap: wrap; gap: 12px; }
.rt-clock { flex: 1 1 260px; border: 1px solid var(--border); border-left: 4px solid #94a3b8; border-radius: 8px; padding: 10px 12px; }
.rt-clock.over { border-left-color: #b91c1c; background: rgba(185,28,28,0.04); }
.rt-clock-t { font-weight: 700; font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.04em; color: var(--muted, #64748b); margin-bottom: 4px; }
.rt-clock-main { font-size: 1.05rem; margin-bottom: 4px; display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.badge.rt-neg { background: rgba(185,28,28,0.12); color: #b91c1c; }
.badge.rt-warn { background: rgba(180,83,9,0.12); color: #b45309; }
.badge.rt-pos { background: rgba(21,128,61,0.12); color: #15803d; }
.rt-watch.has-over { border-left: 4px solid #b91c1c; }
.rt-row-over td { background: rgba(185,28,28,0.05); }
/* Customer tracking & alerts (migration 167) */
.rt-track-load { border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; margin-bottom: 8px; }
.rt-track-head { margin-bottom: 6px; }
.rt-track-link { display: flex; gap: 6px; align-items: center; margin-bottom: 6px; }
.rt-track-url { flex: 1; min-width: 0; font-family: ui-monospace, monospace; font-size: 0.82rem; padding: 5px 8px; border: 1px solid var(--border); border-radius: 6px; background: #f6f8fb; color: var(--text); }
/* Combined-trip backfill review (migration 168) */
.dash-combo-review { display: flex; align-items: center; gap: 12px; padding: 12px 16px; margin-bottom: 16px; border: 1px solid #f0b659; border-left: 4px solid #d97706; border-radius: 10px; background: #fff8ec; text-decoration: none; color: var(--text); }
.dash-combo-review:hover { background: #fdf0d8; }
.dash-combo-review .dcr-icon { font-size: 1.4rem; line-height: 1; }
.dash-combo-review .dcr-text { flex: 1; }
.dash-combo-review .dcr-text strong { font-size: 1.1rem; }
.dash-combo-review .dcr-go { font-weight: 700; color: #b45309; white-space: nowrap; }
.combo-review-item { border-left: 4px solid #d97706; }
.cri-loads { display: flex; gap: 14px; align-items: stretch; flex-wrap: wrap; margin-bottom: 10px; }
.cri-load { flex: 1 1 240px; border: 1px solid var(--border); border-radius: 8px; padding: 8px 10px; }
.cri-tag { font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--muted, #64748b); font-weight: 700; margin-bottom: 2px; }
.cri-vs { display: flex; flex-direction: column; align-items: center; justify-content: center; font-size: 1.3rem; color: #d97706; flex: 0 0 auto; }
.cri-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.cri-combined { margin-top: 12px; padding-top: 12px; border-top: 1px dashed var(--border); }

/* ---- Games hub + new games (2026-10-05) ---- */
.games-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 14px; margin-top: 10px; }
.game-card { display: flex; flex-direction: column; align-items: center; gap: 4px; text-align: center; padding: 20px 12px; border: 1px solid var(--border); border-radius: 12px; background: var(--card-bg, #fff); color: var(--text); text-decoration: none; }
.game-card:hover { border-color: var(--blue, #2563eb); box-shadow: 0 6px 16px rgba(0,0,0,0.08); }
.game-card .game-emoji { font-size: 2rem; line-height: 1; }
/* 2048 */
.g2048-top { display: flex; align-items: center; gap: 16px; margin: 12px 0; flex-wrap: wrap; }
.g2048-score { display: flex; flex-direction: column; min-width: 80px; }
.g2048-score strong { font-size: 1.3rem; font-variant-numeric: tabular-nums; }
.g2048-wrap { max-width: 440px; }
.g2048-board { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; background: #bbada0; padding: 8px; border-radius: 8px; aspect-ratio: 1; outline: none; }
.g2048-cell { display: flex; align-items: center; justify-content: center; border-radius: 5px; background: rgba(238,228,218,0.35); font-weight: 800; font-size: clamp(1rem, 6vw, 2rem); color: #776e65; }
.g2048-cell.v2 { background: #eee4da; } .g2048-cell.v4 { background: #ede0c8; }
.g2048-cell.v8 { background: #f2b179; color: #f9f6f2; } .g2048-cell.v16 { background: #f59563; color: #f9f6f2; }
.g2048-cell.v32 { background: #f67c5f; color: #f9f6f2; } .g2048-cell.v64 { background: #f65e3b; color: #f9f6f2; }
.g2048-cell.v128 { background: #edcf72; color: #f9f6f2; } .g2048-cell.v256 { background: #edcc61; color: #f9f6f2; }
.g2048-cell.v512 { background: #edc850; color: #f9f6f2; } .g2048-cell.v1024 { background: #edc53f; color: #f9f6f2; font-size: clamp(0.9rem,5vw,1.6rem); }
.g2048-cell.v2048, .g2048-cell.vbig { background: #edc22e; color: #f9f6f2; font-size: clamp(0.9rem,5vw,1.6rem); }
/* Snake */
.snake-canvas { width: 100%; max-width: 420px; border: 1px solid var(--border); border-radius: 8px; touch-action: none; }
/* Connect Four */
.c4-board { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; width: min(420px, 92vw); }
.c4-col { grid-row: 1; height: 24px; border: 0; background: transparent; cursor: default; color: var(--muted); border-radius: 4px; }
.c4-board.my-turn .c4-col { cursor: pointer; background: rgba(37,99,235,0.08); }
.c4-board.my-turn .c4-col:hover { background: rgba(37,99,235,0.2); }
.c4-grid { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; background: #1d4ed8; padding: 6px; border-radius: 10px; }
.c4-cell { aspect-ratio: 1; display: flex; align-items: center; justify-content: center; }
.c4-disc { width: 86%; height: 86%; border-radius: 50%; background: #e5edff; box-shadow: inset 0 -2px 4px rgba(0,0,0,0.15); }
.c4-game-list { list-style: none; padding: 0; margin: 0; }
.c4-game-list li { display: flex; align-items: center; gap: 10px; padding: 8px 0; border-bottom: 1px solid var(--border); }

/* ---- Games batch 2: Memory, Minesweeper, Daily word ---- */
.mem-board { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; max-width: 360px; margin-top: 8px; }
.mem-card { aspect-ratio: 1; border: 1px solid var(--border); border-radius: 8px; background: var(--blue, #2563eb); color: transparent; font-size: clamp(1.4rem, 8vw, 2rem); cursor: pointer; display: flex; align-items: center; justify-content: center; }
.mem-card.flipped { background: var(--card-bg, #fff); color: var(--text); }
.mem-card.done { background: #dcfce7; color: var(--text); cursor: default; }
.ms-board { display: inline-grid; gap: 2px; background: var(--border); padding: 2px; border-radius: 6px; margin-top: 8px; }
.ms-cell { width: 30px; height: 30px; border: 0; border-radius: 3px; background: #cbd5e1; font-weight: 800; cursor: pointer; display: flex; align-items: center; justify-content: center; padding: 0; }
.ms-cell.open { background: var(--card-bg, #f1f5f9); cursor: default; }
.ms-cell.flag { background: #fde68a; }
.ms-cell.mine { background: #fecaca; }
.ms-cell.n1 { color: #2563eb; } .ms-cell.n2 { color: #16a34a; } .ms-cell.n3 { color: #dc2626; } .ms-cell.n4 { color: #7c3aed; }
.ms-cell.n5 { color: #b45309; } .ms-cell.n6 { color: #0891b2; } .ms-cell.n7 { color: #111827; } .ms-cell.n8 { color: #6b7280; }
.word-wrap { max-width: 340px; margin: 10px auto 0; }
.word-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; }
.word-tile { aspect-ratio: 1; border: 2px solid var(--border); border-radius: 6px; display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: clamp(1.2rem, 7vw, 1.8rem); text-transform: uppercase; color: var(--text); }
.word-tile.correct { background: #16a34a; border-color: #16a34a; color: #fff; }
.word-tile.present { background: #eab308; border-color: #eab308; color: #fff; }
.word-tile.absent { background: #94a3b8; border-color: #94a3b8; color: #fff; }

/* Checkers */
.ck-board { display: grid; grid-template-columns: repeat(8, 1fr); width: min(480px, 94vw); aspect-ratio: 1; border: 2px solid var(--border); border-radius: 6px; overflow: hidden; }
.ck-sq { display: flex; align-items: center; justify-content: center; position: relative; }
.ck-sq.light { background: #f0d9b5; }
.ck-sq.dark { background: #b58863; }
.ck-sq.sel { box-shadow: inset 0 0 0 3px #2563eb; }
.ck-sq.dest { cursor: pointer; }
.ck-sq.dest::after { content: ''; position: absolute; width: 30%; height: 30%; border-radius: 50%; background: rgba(37,99,235,0.55); }
.ck-piece { width: 74%; height: 74%; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 1.1rem; box-shadow: 0 2px 3px rgba(0,0,0,0.4); }
.ck-piece.red { background: radial-gradient(circle at 35% 30%, #ef4444, #991b1b); color: #fde68a; }
.ck-piece.black { background: radial-gradient(circle at 35% 30%, #4b5563, #111827); color: #fde68a; }
.ck-piece.king { box-shadow: 0 0 0 2px #fbbf24, 0 2px 3px rgba(0,0,0,0.4); }

/* Geography trivia */
.geo-card { max-width: 560px; margin-top: 12px; padding: 18px; border: 1px solid var(--border); border-radius: 10px; background: var(--card-bg, var(--bg)); }
.geo-question { font-size: 1.15rem; font-weight: 700; margin: 0 0 14px; }
.geo-options { display: grid; gap: 10px; }
.geo-opt { text-align: left; padding: 12px 14px; border: 2px solid var(--border); border-radius: 8px; background: transparent; color: var(--text); font-size: 1rem; cursor: pointer; }
.geo-opt:hover { border-color: #2563eb; }
.geo-opt.right { background: #16a34a; border-color: #16a34a; color: #fff; }
.geo-opt.wrong { background: #dc2626; border-color: #dc2626; color: #fff; }

/* Reversi / Othello */
.rv-score { display: flex; gap: 18px; margin: 8px 0; font-weight: 700; }
.rv-tally { display: inline-flex; align-items: center; gap: 6px; }
.rv-board { display: grid; grid-template-columns: repeat(8, 1fr); width: min(480px, 94vw); aspect-ratio: 1; background: #1f7a3d; border: 3px solid #14532d; border-radius: 6px; gap: 2px; padding: 2px; }
.rv-sq { background: #2e9e52; display: flex; align-items: center; justify-content: center; position: relative; border-radius: 2px; }
.rv-sq.play { cursor: pointer; }
.rv-sq.play::after { content: ''; width: 26%; height: 26%; border-radius: 50%; background: rgba(255,255,255,0.35); }
.rv-disc { width: 78%; height: 78%; border-radius: 50%; display: inline-block; box-shadow: 0 1px 2px rgba(0,0,0,0.5); }
.rv-disc.black { background: radial-gradient(circle at 35% 30%, #4b5563, #0b0f17); }
.rv-disc.white { background: radial-gradient(circle at 35% 30%, #ffffff, #cbd5e1); }
.rv-tally .rv-disc { width: 18px; height: 18px; }

/* Sudoku */
.sd-diff { padding: 4px 6px; border: 1px solid var(--border); border-radius: 6px; background: transparent; color: var(--text); }
.sd-board { display: grid; grid-template-columns: repeat(9, 1fr); width: min(450px, 94vw); aspect-ratio: 1; border: 2px solid var(--text); border-radius: 4px; margin-top: 8px; }
.sd-cell { display: flex; align-items: center; justify-content: center; border: 1px solid var(--border); font-size: clamp(1rem, 5vw, 1.4rem); font-weight: 600; cursor: pointer; color: #2563eb; user-select: none; }
.sd-cell.given { color: var(--text); font-weight: 800; }
.sd-cell.sel { background: rgba(37,99,235,0.18); }
.sd-cell.bad { color: #dc2626; }
.sd-cell.br { border-right: 2px solid var(--text); }
.sd-cell.bb { border-bottom: 2px solid var(--text); }
.sd-pad { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 10px; max-width: 450px; }
.sd-key { flex: 1 1 36px; min-width: 36px; padding: 10px 0; font-size: 1.1rem; font-weight: 700; border: 1px solid var(--border); border-radius: 6px; background: transparent; color: var(--text); cursor: pointer; }
.sd-key:hover { border-color: #2563eb; }

/* Simon */
.si-board { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; width: min(340px, 90vw); aspect-ratio: 1; margin-top: 8px; }
.si-pad { border: none; border-radius: 12px; cursor: pointer; opacity: 0.55; transition: opacity 0.1s; }
.si-pad.lit { opacity: 1; box-shadow: 0 0 20px rgba(255,255,255,0.6); }
.si-g { background: #22c55e; border-top-left-radius: 100%; }
.si-r { background: #ef4444; border-top-right-radius: 100%; }
.si-y { background: #eab308; border-bottom-left-radius: 100%; }
.si-b { background: #3b82f6; border-bottom-right-radius: 100%; }

/* Nonogram */
.ng-wrap { margin-top: 8px; overflow-x: auto; }
.ng-grid { display: inline-grid; gap: 1px; background: var(--border); border: 2px solid var(--text); }
.ng-corner, .ng-cclue, .ng-rclue { background: var(--bg); }
.ng-cclue { display: flex; flex-direction: column; align-items: center; justify-content: flex-end; font-size: 0.7rem; line-height: 1.1; padding: 2px; min-width: 24px; color: var(--text); }
.ng-rclue { display: flex; flex-direction: row; align-items: center; justify-content: flex-end; gap: 4px; font-size: 0.75rem; padding: 0 6px; color: var(--text); }
.ng-cell { width: 26px; height: 26px; background: var(--card-bg, #fff); cursor: pointer; display: flex; align-items: center; justify-content: center; color: #94a3b8; }
.ng-cell.on { background: #1f2937; }
.ng-cell.bl { border-left: 2px solid var(--text); }
.ng-cell.bt { border-top: 2px solid var(--text); }

/* Word search */
.ws-layout { display: flex; flex-wrap: wrap; gap: 16px; margin-top: 8px; align-items: flex-start; }
.ws-grid { display: grid; width: min(480px, 92vw); aspect-ratio: 1; gap: 1px; background: var(--border); border: 2px solid var(--text); user-select: none; }
.ws-cell { background: var(--bg); display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: clamp(0.7rem, 3.2vw, 1rem); cursor: pointer; text-transform: uppercase; color: var(--text); }
.ws-cell.sel { background: #2563eb; color: #fff; }
.ws-cell.done { background: #16a34a; color: #fff; }
.ws-words { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(2, auto); gap: 2px 18px; font-weight: 600; }
.ws-words li.done { text-decoration: line-through; color: #16a34a; }

/* Solitaire - fixed card metrics so the tableau overlap is predictable */
:root { --sol-w: 58px; --sol-h: 82px; --sol-peek: 22px; }
.sol-top { display: flex; gap: 6px; margin-top: 8px; flex-wrap: nowrap; }
.sol-gap { flex: 0 0 20px; }
.sol-slot { width: var(--sol-w); }
.sol-tableau { display: flex; gap: 6px; margin-top: 14px; align-items: flex-start; }
.sol-pile { width: var(--sol-w); min-height: var(--sol-h); position: relative; display: flex; flex-direction: column; }
.sol-card { width: var(--sol-w); height: var(--sol-h); box-sizing: border-box; border: 1px solid #94a3b8; border-radius: 5px; background: #fff; color: #111827; display: flex; flex-direction: column; align-items: center; justify-content: flex-start; padding: 2px 0; font-weight: 700; font-size: 0.95rem; cursor: pointer; box-shadow: 0 1px 1px rgba(0,0,0,0.2); }
.sol-card.red { color: #dc2626; }
.sol-card.down { background: repeating-linear-gradient(45deg, #1d4ed8, #1d4ed8 4px, #3b82f6 4px, #3b82f6 8px); border-color: #1e3a8a; }
.sol-card .sol-s { font-size: 1.15em; line-height: 1; }
.sol-card.sel { outline: 3px solid #f59e0b; outline-offset: -1px; }
.sol-pile .sol-card { margin-top: calc(var(--sol-peek) - var(--sol-h)); }
.sol-pile .sol-card:first-child { margin-top: 0; }
.sol-empty { width: var(--sol-w); height: var(--sol-h); box-sizing: border-box; border: 1px dashed #94a3b8; border-radius: 5px; display: flex; align-items: center; justify-content: center; color: #94a3b8; font-size: 1.3rem; }
.sol-empty.red { color: #f87171; }
.sol-empty.tab { width: 100%; }
@media (max-width: 560px) { :root { --sol-w: 40px; --sol-h: 56px; --sol-peek: 16px; } .sol-card { font-size: 0.72rem; } }

/* Load history download for taxes (partials/_load-history-download.ejs). */
.lh-download { position: relative; display: inline-block; }
.lh-download > summary { list-style: none; cursor: pointer; }
.lh-download > summary::-webkit-details-marker { display: none; }
.lh-panel {
  position: absolute; right: 0; top: calc(100% + 6px); z-index: 950; width: 300px; max-width: calc(100vw - 32px);
  display: flex; flex-direction: column; gap: 6px; padding: 12px 14px;
  background: var(--surface, #fff); color: var(--text); border: 1px solid var(--border); border-radius: 10px;
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.22); text-align: left;
}
.lh-panel .hint { margin: 0 0 4px; font-size: 0.8rem; color: var(--muted); font-weight: 400; }
.lh-panel label { margin: 4px 0 0; font-weight: 600; font-size: 0.85rem; }
.lh-panel select { width: 100%; }
.lh-panel .btn { margin-top: 8px; }

/* Receivables (2026-10-08): Aging, Record payment, Payments received,
   reminders (views/invoices/aging|payment-new|payments|bulk-remind.ejs). */
.aging-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(130px, 1fr)); gap: 10px; margin: 12px 0 16px; }
.aging-card { display: flex; flex-direction: column; gap: 2px; padding: 10px 12px; border-radius: 10px; background: var(--surface, #fff); border: 1px solid var(--border); border-top: 3px solid #94a3b8; font-variant-numeric: tabular-nums; }
.aging-card strong { font-size: 1.15rem; }
.aging-card.aging-current { border-top-color: #16a34a; }
.aging-card.aging-d30 { border-top-color: #eab308; }
.aging-card.aging-d60 { border-top-color: #f97316; }
.aging-card.aging-d90, .aging-card.aging-d90p, .aging-card.aging-card-late { border-top-color: #dc2626; }
.aging-table { font-variant-numeric: tabular-nums; }
.aging-table td.aging-d90p:not(:has(.hint)), .aging-table td.aging-d90:not(:has(.hint)) { color: #b91c1c; font-weight: 600; }
.aging-row-late td:first-child { box-shadow: inset 3px 0 0 #dc2626; }
.aging-actions { white-space: nowrap; }
.aging-actions a + a { margin-left: 10px; }
.aging-noemail { color: #b45309; }
.pay-payer { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 10px 0 14px; max-width: 620px; }
.pay-payer label { font-weight: 600; margin: 0; }
.pay-payer select { flex: 1; min-width: 260px; }
.pay-h { margin-top: 18px; }
.pay-table { font-variant-numeric: tabular-nums; }
.pay-table input.pay-alloc { width: 110px; text-align: right; }
.pay-table tr.pay-row-on { background: color-mix(in srgb, #16a34a 8%, transparent); }
.pay-late { color: #b91c1c; font-weight: 600; }
.pay-summary { margin: 10px 0; font-weight: 600; }
.pay-summary.pay-good { color: #15803d; }
.pay-summary.pay-left { color: #b45309; }
.pay-summary.pay-bad { color: #b91c1c; }
.pay-history { font-variant-numeric: tabular-nums; }
.pay-row-new { background: color-mix(in srgb, #16a34a 10%, transparent); }
.pay-left { color: #b45309; }
.inv-pay-h { margin: 18px 0 6px; font-size: 1rem; }

/* Dashboard: drag tiles to reorder (views/dashboard.ejs, 2026-10-08). */
.admin-tile-wrap[draggable="true"] { cursor: grab; }
.admin-tile-wrap.is-dragging { opacity: 0.35; outline: 2px dashed var(--brand, #b91c1c); outline-offset: 2px; border-radius: 10px; }
.dash-self-pin { color: var(--muted); }
.dash-self-pin.on { color: inherit; }
.dash-order-toast { position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%) translateY(20px); z-index: 1000; padding: 8px 16px; border-radius: 999px; background: #14532d; color: #fff; font-weight: 600; font-size: 0.9rem; opacity: 0; pointer-events: none; transition: opacity .2s, transform .2s; }
.dash-order-toast.show { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) { .dash-order-toast { transition: none; } }
/* Touch: press and hold a tile, then slide it (views/dashboard.ejs). No
   long-press link preview / text selection on tiles; the held tile pops up. */
#dash-grid .admin-tile-wrap { -webkit-touch-callout: none; -webkit-user-select: none; user-select: none; }
#dash-grid .admin-tile-wrap.is-lifted { opacity: 0.9; transform: scale(1.04); box-shadow: 0 12px 28px rgba(15, 23, 42, 0.28); z-index: 2; outline: 2px solid var(--brand, #b91c1c); outline-offset: 2px; border-radius: 10px; transition: transform .12s, box-shadow .12s; }
#dash-grid.is-touch-sorting .admin-tile-wrap:not(.is-lifted) { transition: transform .12s; }
@media (prefers-reduced-motion: reduce) { #dash-grid .admin-tile-wrap.is-lifted { transition: none; transform: none; } }

/* Demo copy only (utils/demoMode.js): a banner on every page + the sample
   logins on the sign-in page. */
.demo-banner { position: sticky; top: 0; z-index: 2000; padding: 4px 12px; background: #fde047; color: #713f12; text-align: center; font-size: 0.8rem; font-weight: 700; letter-spacing: 0.02em; }
.demo-logins { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--border); display: flex; flex-wrap: wrap; gap: 6px; }
.demo-logins p { flex-basis: 100%; margin: 0 0 4px; }
.demo-logins code { font-size: 0.9rem; }
