/* Interwil Container Tracker — application styles.
 *
 * Layered ON TOP of Bootstrap 5.3 (loaded via CDN in index.html / login.html).
 * Bootstrap provides the responsive grid, utility classes (d-flex, flex-wrap,
 * container-fluid, ms-auto, gap-*, w-*, d-md-block, etc.) used directly in the
 * HTML. This file only adds Interwil-specific look-and-feel and the few
 * responsive rules Bootstrap's utilities can't express inline.
 *
 * Custom class names below (`.shp-pill`, `.icon-btn`, `.region-tab`,
 * `.carrier .dot`, `.modal-backdrop`, etc.) are referenced by the front-end
 * JS in public/js/. Renaming them will break dashboard.js / state.js / etc. */

:root {
  color-scheme: light;
  --navy: #15295C;
  --green: #1d8348;
  --ink: #1a2332;
  --muted: #5b6b80;
  --muted-2: #8a94a6;
  --line: #e3e7ee;
  --line-soft: #eef1f5;
  --bg: #f7f8fa;
  --row-hover: #fafbfc;

  /* Map Interwil brand to Bootstrap's theme variables so anything we render
   * via Bootstrap utility classes (btn-primary, text-success, alert-primary,
   * focus rings, etc.) picks up the right colour without per-class overrides. */
  --bs-primary: #15295C;
  --bs-primary-rgb: 21, 41, 92;
  --bs-success: #1d8348;
  --bs-success-rgb: 29, 131, 72;
  --bs-link-color: #15295C;
  --bs-link-hover-color: #0d1a3e;
  --bs-body-font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  --bs-body-color: #1a2332;
  --bs-body-bg: #f7f8fa;
  --bs-body-font-size: 14px;
  --bs-body-line-height: 1.4;
}

/* Bootstrap already handles box-sizing, body margin, and button font-family
 * inheritance — no need to repeat those rules. */

/* ===== Brand bar =====
 * Uses Bootstrap's d-flex flex-wrap utilities in the markup. We add the
 * Interwil look (navy bg, green underline) and mobile padding here. */
.brandbar {
  background: var(--navy);
  color: #fff;
  padding: 14px 24px;
  border-bottom: 3px solid var(--green);
}
/* Icon mark: sits left of the wordmark. Inline SVG inherits the brandbar's
 * white `color`, so `stroke="currentColor"` inside the SVG renders white
 * against the navy background. */
.brandbar .brand-icon {
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  display: block;
}
.brandbar .wordmark { display: flex; flex-direction: column; line-height: 1; }
.brandbar .wordmark .top { font-size: 22px; font-weight: 800; letter-spacing: 0.06em; }
.brandbar .wordmark .bot { font-size: 11px; font-weight: 600; letter-spacing: 0.22em; margin-top: 5px; color: #c4c4c4; }
.brandbar .tagline {
  font-size: 11px;
  color: #9aa3ad;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: right;
}
.brandbar .tagline b { color: #fff; font-weight: 700; }

/* Brandbar centre status: LIVE pill + countdown. Replaces the old tagline. */
.brand-status {
  /* The .d-none d-sm-flex utility on the element handles show/hide; this
   * rule just controls the centred sitting position via auto-margin so it
   * stays in the middle of the brandbar between the wordmark and authbar. */
  margin-left: auto;
  margin-right: auto;
  color: #c4cad6;
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
}
/* LIVE pill: pulsing green dot + white text. Glows softly via the same
 * @keyframes pulse animation used by the row-level live dots, so the
 * "data is current" cue feels consistent app-wide. */
.live-pill {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 700;
  color: #fff;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.live-pill-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #2ecc71;            /* fresh green — pops on the navy bar */
  box-shadow: 0 0 0 0 rgba(46, 204, 113, 0.6);
  animation: pulse 2s infinite;
}
.refresh-countdown {
  color: #c4cad6;
  font-size: 12px;
  font-variant-numeric: tabular-nums;  /* keep HH:MM digits from shifting */
  white-space: nowrap;
}

@media (max-width: 575.98px) {
  .brandbar { padding: 12px 14px; gap: 8px !important; }
  .brandbar .brand-icon { width: 30px; height: 30px; }
  .brandbar .wordmark .top { font-size: 18px; }
  .brandbar .tagline { font-size: 10px; text-align: left; }
}

/* ===== Region tabs =====
 * Horizontal scroll on small screens so the 3 region tabs + view toggle stay
 * on one row without squashing. `flex-nowrap` is set inline; we just need to
 * make the row scrollable when it overflows. */
.regionbar {
  background: #fff;
  border-bottom: 1px solid var(--line);
  padding: 0 24px;
  box-shadow: 0 1px 3px rgba(20, 30, 60, 0.04);
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: thin;
}
.region-tab {
  padding: 14px 26px;
  font-size: 14px;
  font-weight: 700;
  color: #6b7a8f;
  cursor: pointer;
  border: none;
  background: transparent;
  border-bottom: 3px solid transparent;
  transition: color .12s, border-color .12s, background .12s;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  flex-shrink: 0;
}
.region-tab:hover { color: var(--navy); background: #f6f8fc; }
.region-tab.active { color: var(--navy); border-bottom-color: var(--green); }
.region-tab .region-name { color: #6b7a8f; font-weight: 600; margin-left: 6px; text-transform: none; letter-spacing: 0; font-size: 12px; }
.region-tab.active .region-name { color: var(--ink); }
.region-tab .count {
  display: inline-block;
  margin-left: 9px;
  background: #eef1f6;
  color: #5b6b80;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  vertical-align: 1px;
  letter-spacing: 0;
}
.region-tab.active .count { background: var(--green); color: #fff; }

@media (max-width: 575.98px) {
  .regionbar { padding: 0 12px; }
  .region-tab { padding: 12px 14px; font-size: 13px; }
}

/* ===== Layout ===== */
/* .wrap uses Bootstrap's container-fluid in the markup; we just cap max-width
 * (Bootstrap's container-fluid is 100% wide by default — too wide for tables
 * on huge monitors) and tighten padding on mobile. */
.wrap { padding: 20px; max-width: 1500px; margin: 0 auto; }
header h1, h1 { margin: 0 0 4px; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }
.sub { color: var(--muted); font-size: 13px; }
.muted { color: var(--muted-2); }
.updated { font-size: 12px; color: var(--muted); text-align: right; }
.updated b { color: var(--ink); font-weight: 600; }
header { margin-bottom: 20px; }

@media (max-width: 575.98px) {
  .wrap { padding: 14px 12px; }
  .updated { text-align: left; }
  h1 { font-size: 18px; }
}

/* ===== Stats ===== */
/* CSS Grid auto-fit handles responsiveness — tiles flow into N columns based on
 * available width (minmax 140px). Slightly tighter on mobile. */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}
/* KPI tile — now a <button> so each tile is clickable to filter the table.
 * Hover lifts slightly; .active fills the left border with the tile's accent
 * colour so the user sees which filter is on. */
.stat {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 16px;
  border-left: 4px solid #cfd6e0;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  transition: transform 0.12s, box-shadow 0.12s, border-color 0.12s;
}
.stat:hover {
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
}
.stat:focus-visible {
  outline: 2px solid var(--navy);
  outline-offset: 2px;
}
.stat.active {
  border-left-width: 6px;
  box-shadow: 0 0 0 1px var(--navy), 0 4px 12px rgba(15, 23, 42, 0.08);
}
.stat .num { font-size: 28px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.1; }
.stat .lbl { font-size: 11px; color: var(--muted); text-transform: uppercase; letter-spacing: 0.06em; margin-bottom: 6px; font-weight: 600; }
.stat .stat-hint {
  font-size: 11px;
  color: var(--muted-2);
  margin-top: 4px;
  font-weight: 400;
}
.stat.green   { border-left-color: var(--green); }
.stat.green   .num { color: var(--green); }
.stat.transit { border-left-color: #1f5fa8; }
.stat.transit .num { color: #1f5fa8; }
.stat.berthed { border-left-color: #0f9c8e; }
.stat.berthed .num { color: #0f9c8e; }
.stat.blue    { border-left-color: #4a90e2; }
.stat.blue    .num { color: #4a90e2; }
.stat.amber   { border-left-color: #d68a1f; }
.stat.amber   .num { color: #b8761f; }
.stat.orange  { border-left-color: #e67e22; }
.stat.orange  .num { color: #c2611c; }
.stat.red     { border-left-color: #b53626; }
.stat.red     .num { color: #b53626; }
.stat.unknown { border-left-color: #94a3b8; }
.stat.unknown .num { color: #64748b; }

@media (max-width: 575.98px) {
  .stats { grid-template-columns: repeat(2, 1fr); gap: 8px; }
  .stat { padding: 10px 12px; }
  .stat .num { font-size: 22px; }
  .stat .stat-hint { display: none; }   /* hide hint copy on phones to keep tiles compact */
}

/* ===== Smart Insights panel =====
 * Aggregated patterns surfaced as actionable cards above the Attention
 * Required banner. Each card has a severity colour (critical/warning/info),
 * a dismiss X, and an optional action button that applies a saved filter.
 * Dismissals persist across reloads via localStorage. */
.insights-panel {
  margin-bottom: 16px;
}
.insights-panel[hidden] { display: none; }
.insights-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.insights-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.insights-reset {
  background: transparent;
  border: 0;
  font-size: 12px;
  color: var(--navy);
  cursor: pointer;
  font-family: inherit;
  font-weight: 500;
  padding: 4px 8px;
  border-radius: 6px;
}
.insights-reset:hover { background: #e0e7f3; }
.insights-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 10px;
}
.insight-card {
  position: relative;
  background: #fff;
  border: 1px solid var(--line);
  border-left: 4px solid #94a3b8;
  border-radius: 8px;
  padding: 12px 36px 12px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.insight-card.critical { border-left-color: #c0392b; background: #fef5f3; }
.insight-card.warning  { border-left-color: #d68a1f; background: #fffbf2; }
.insight-card.info     { border-left-color: #1f5fa8; background: #f5f9ff; }
.insight-title {
  margin: 0;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
  line-height: 1.3;
}
.insight-detail {
  margin: 0;
  font-size: 12px;
  color: var(--muted);
  line-height: 1.4;
}
.insight-action {
  align-self: flex-start;
  background: transparent;
  border: 0;
  color: var(--navy);
  font-weight: 600;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
  padding: 4px 0 0;
  text-decoration: none;
}
.insight-action:hover { text-decoration: underline; }
.insight-dismiss {
  position: absolute;
  top: 8px;
  right: 8px;
  background: transparent;
  border: 0;
  color: var(--muted-2);
  cursor: pointer;
  font-size: 13px;
  padding: 2px 6px;
  border-radius: 4px;
  line-height: 1;
}
.insight-dismiss:hover { background: rgba(0,0,0,0.06); color: var(--ink); }

@media (max-width: 575.98px) {
  .insights-grid { grid-template-columns: 1fr; }
}

/* ===== Attention Required banner =====
 * Sits between the KPI tiles and the table on the Active view. Shows up to
 * 5 at-risk / watch shipments so the operator's eye lands on the most
 * urgent rows first — before they start scanning the full table. */
.attention-banner {
  background: #fff;
  border: 1px solid #f0c7bf;
  border-left: 4px solid #c0392b;
  border-radius: 8px;
  margin-bottom: 18px;
  overflow: hidden;
}
.attention-banner[hidden] { display: none; }
/* Attention header is a full-width button so the whole bar is clickable,
 * not just the chevron. Resets the default <button> styling so it visually
 * matches the original div + adds the cursor / focus affordances. */
.attention-header {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
  width: 100%;
  padding: 10px 16px;
  background: #fef5f3;
  border: 0;
  border-bottom: 1px solid #f0c7bf;
  cursor: pointer;
  font-family: inherit;
  text-align: left;
  transition: background 0.12s;
}
.attention-header:hover { background: #fce6df; }
.attention-header:focus-visible {
  outline: 2px solid #c0392b;
  outline-offset: -2px;
}
/* When collapsed, drop the divider since there's no list below it. */
.attention-banner.collapsed .attention-header { border-bottom-color: transparent; }
.attention-banner.collapsed .attention-list { display: none; }

.attention-title {
  font-weight: 700;
  font-size: 13px;
  color: #8a2818;
  letter-spacing: 0.02em;
}
.attention-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 22px;
  height: 22px;
  padding: 0 8px;
  background: #c0392b;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  border-radius: 11px;
}
/* Chevron rotates between expanded (▾ pointing down) and collapsed (▸-ish,
 * rotated −90° so it points right). Pushed to the far right via margin-left
 * auto so the count stays close to the title and the chevron anchors the
 * end of the bar. */
.attention-chevron {
  margin-left: auto;
  color: #8a2818;
  font-size: 11px;
  transition: transform 0.18s ease;
  display: inline-block;
}
.attention-banner.collapsed .attention-chevron { transform: rotate(-90deg); }
.attention-list { display: flex; flex-direction: column; }
.attention-row {
  display: grid;
  grid-template-columns: 80px 150px 1fr 1fr 140px 80px 1fr 16px;
  gap: 12px;
  align-items: center;
  padding: 10px 16px;
  border-top: 1px solid #fbe6e0;
  background: #fff;
  border: 0;
  width: 100%;
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  font-size: 12px;
  color: var(--ink);
  transition: background 0.1s;
}
.attention-row:first-child { border-top: 0; }
.attention-row:hover { background: #fef5f3; }
.attention-shp { font-weight: 700; font-family: ui-monospace, "SF Mono", monospace; }
.attention-bol { font-family: ui-monospace, "SF Mono", monospace; font-size: 11px; }
.attention-vessel, .attention-supplier { color: var(--muted); font-size: 12px; }
.attention-eta { color: #c0392b; font-weight: 600; }
.attention-reason { color: var(--muted); font-size: 12px; }
.attention-chevron { color: var(--muted-2); font-size: 18px; font-weight: 700; }
.attention-more {
  padding: 8px 16px;
  text-align: center;
  font-size: 12px;
  background: #fafbfc;
}

/* On narrow screens the attention rows collapse to a vertical stack so the
 * grid columns don't overflow the card. */
@media (max-width: 767.98px) {
  .attention-row {
    grid-template-columns: 1fr auto;
    grid-template-areas:
      "shp eta"
      "bol bol"
      "vessel vessel"
      "supplier supplier"
      "reason health"
      "chevron chevron";
    gap: 4px 12px;
  }
  .attention-shp { grid-area: shp; }
  .attention-bol { grid-area: bol; }
  .attention-vessel { grid-area: vessel; }
  .attention-supplier { grid-area: supplier; }
  .attention-eta { grid-area: eta; text-align: right; }
  .attention-reason { grid-area: reason; }
  .attention-chevron { display: none; }
}

/* ===== Advanced filters row =====
 * Three dropdowns (Supplier · Shipping line · ETA range) above the quick-
 * filter chips. AND-combined with the chip filter and search box. Clear-all
 * button only appears when at least one dropdown is set to a non-default. */
.advanced-filters {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 12px;
  margin-bottom: 10px;
}
.adv-filter {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.adv-filter-label { font-weight: 600; }
.adv-filter select {
  background: #fff;
  color: var(--ink);
  border: 1px solid #ced4da;
  border-radius: 6px;
  padding: 7px 10px;
  font-size: 13px;
  font-family: inherit;
  font-weight: 400;
  text-transform: none;
  letter-spacing: normal;
  min-width: 180px;
  cursor: pointer;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.adv-filter select:hover { border-color: #a8b8d0; }
.adv-filter select:focus {
  outline: 0;
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(21, 41, 92, 0.18);
}
.adv-filter-clear {
  background: #fff;
  color: var(--muted);
  border: 1px solid #d4dae3;
  border-radius: 6px;
  padding: 7px 12px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
  align-self: flex-end;
}
.adv-filter-clear:hover {
  background: #fde0db;
  border-color: #e29388;
  color: #8a2818;
}

/* "More filters" popover — secondary filter dimensions (Watching, Tracking
 * mode, BOL status) tucked behind a single trigger button so the primary
 * filter row stays readable. Badge on the trigger surfaces the count of
 * non-default filters inside so hidden state is never invisible. */
.more-filters-wrap {
  position: relative;
  align-self: flex-end;
}
.more-filters-trigger {
  background: #fff;
  color: var(--navy);
  border: 1px solid #b8c8e0;
  padding: 7px 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background 0.12s, border-color 0.12s;
}
.more-filters-trigger:hover { background: #e0e7f3; border-color: var(--navy); }
.more-filters-trigger.open { background: #e0e7f3; border-color: var(--navy); }
.more-filters-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 6px;
  background: var(--navy);
  color: #fff;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
}
.more-filters-badge[hidden] { display: none; }

.more-filters-panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  min-width: 280px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);
  z-index: 50;
  padding: 12px;
  font-size: 13px;
}
.more-filters-panel[hidden] { display: none; }
.mf-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  font-size: 13px;
  text-transform: none;
  letter-spacing: normal;
}
.mf-row:last-child { margin-bottom: 0; }
.mf-toggle {
  cursor: pointer;
  user-select: none;
  color: var(--ink);
  font-weight: 500;
}
.mf-toggle input { width: 16px; height: 16px; accent-color: var(--navy); cursor: pointer; }
.mf-label {
  flex: 1;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
}
.mf-row select {
  background: #fff;
  color: var(--ink);
  border: 1px solid #ced4da;
  border-radius: 6px;
  padding: 5px 8px;
  font-size: 12px;
  font-family: inherit;
  cursor: pointer;
  min-width: 130px;
}
.mf-row select:focus {
  outline: 0;
  border-color: var(--navy);
  box-shadow: 0 0 0 2px rgba(21, 41, 92, 0.18);
}
.mf-divider {
  height: 1px;
  background: var(--line);
  margin: 8px 0 10px;
}

@media (max-width: 767.98px) {
  .more-filters-wrap { flex: 0 0 auto; }
  .more-filters-panel { left: auto; right: 0; min-width: 260px; }
}

/* Saved-views dropdown — trigger button + absolutely-positioned panel.
 * Sits at the end of the advanced-filters row. The panel is anchored
 * via `.views-wrap { position: relative }` and floats over neighbouring
 * content via z-index. */
.views-wrap {
  position: relative;
  align-self: flex-end;
  margin-left: auto;
}
.views-trigger {
  background: #fff;
  color: var(--navy);
  border: 1px solid #b8c8e0;
  padding: 7px 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background 0.12s, border-color 0.12s;
}
.views-trigger:hover { background: #e0e7f3; border-color: var(--navy); }
.views-trigger.open { background: #e0e7f3; border-color: var(--navy); }
.views-chevron {
  font-size: 10px;
  transition: transform 0.15s;
  display: inline-block;
}
.views-trigger.open .views-chevron { transform: rotate(180deg); }

.views-panel {
  position: absolute;
  top: calc(100% + 4px);
  right: 0;
  min-width: 260px;
  max-width: 360px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);
  z-index: 50;
  font-size: 13px;
}
.views-panel[hidden] { display: none; }
.views-panel-inner { padding: 6px; }

.views-empty {
  padding: 14px 12px;
  color: var(--muted);
  font-size: 12px;
  text-align: center;
  font-style: italic;
}

.views-list {
  list-style: none;
  margin: 0;
  padding: 0;
  max-height: 240px;
  overflow-y: auto;
}
.views-item {
  display: flex;
  align-items: stretch;
  border-radius: 6px;
  margin: 1px 0;
}
.views-item:hover { background: #f0f3f8; }
.views-item-label {
  flex: 1;
  background: transparent;
  border: 0;
  text-align: left;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  color: var(--ink);
  cursor: pointer;
  border-radius: 6px 0 0 6px;
  text-transform: none;
  letter-spacing: normal;
  font-weight: 400;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.views-item-delete {
  background: transparent;
  border: 0;
  color: var(--muted-2);
  cursor: pointer;
  padding: 0 10px;
  font-size: 12px;
  font-family: inherit;
  border-radius: 0 6px 6px 0;
  opacity: 0;
  transition: opacity 0.1s, color 0.1s, background 0.1s;
}
.views-item:hover .views-item-delete { opacity: 1; }
.views-item-delete:hover { color: #c0392b; background: #fde0db; }

.views-divider {
  height: 1px;
  background: var(--line);
  margin: 4px 6px;
}
.views-save-btn {
  display: block;
  width: 100%;
  background: transparent;
  border: 0;
  border-radius: 6px;
  padding: 8px 10px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--navy);
  text-align: left;
  cursor: pointer;
}
.views-save-btn:hover { background: #e0e7f3; }

@media (max-width: 767.98px) {
  .views-wrap { margin-left: 0; flex: 1 1 100%; }
  .views-trigger { width: 100%; justify-content: center; }
  .views-panel { right: auto; left: 0; min-width: 100%; max-width: 100%; }
}
@media (max-width: 575.98px) {
  .adv-filter select { min-width: 0; width: 100%; }
  .adv-filter { flex: 1 1 100%; }
}

/* ===== Quick filter chips =====
 * Mirror the KPI tiles below the controls row. The bulk-actions strip lives
 * inside the same flex container — it appears when there are selected rows. */
.filter-chips {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  margin-bottom: 12px;
}
.filter-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  background: #fff;
  color: var(--ink);
  border: 1px solid #d4dae3;
  padding: 6px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.filter-chip:hover { background: #f0f3f8; border-color: #b8c8e0; }
.filter-chip.active {
  background: var(--navy);
  color: #fff;
  border-color: var(--navy);
}
.filter-chip .chip-count {
  background: rgba(0,0,0,0.08);
  color: inherit;
  padding: 1px 8px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.filter-chip.active .chip-count {
  background: rgba(255,255,255,0.25);
}

/* Bulk actions appear when at least one row is checked. Sits at the end of
 * the filter-chips row (right-aligned via margin-left: auto). */
.bulk-actions {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-left: auto;
  padding: 4px 10px 4px 12px;
  background: #f0f7ff;
  border: 1px solid #b8d4f0;
  border-radius: 8px;
}
.bulk-actions[hidden] { display: none; }
.bulk-summary { font-size: 12px; font-weight: 600; color: var(--navy); }
.bulk-action-btn {
  background: #fff;
  color: var(--navy);
  border: 1px solid #b8c8e0;
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.1s, border-color 0.1s;
}
.bulk-action-btn:hover { background: #e0e7f3; border-color: var(--navy); }
.bulk-action-btn.danger { color: #b53626; border-color: #e29388; }
.bulk-action-btn.danger:hover { background: #fde0db; border-color: #b53626; }
.bulk-action-btn.cancel { color: var(--muted); }

/* ===== Checkbox column =====
 * Sticky-narrow column at the left of the table for multi-select. Uses
 * accent-color so the checkmark picks up brand navy. */
th.th-check, td.td-check { width: 32px; padding-left: 12px; padding-right: 4px; }
th.th-check input, td.td-check input { width: 16px; height: 16px; accent-color: var(--navy); cursor: pointer; }

/* ===== Row health-state highlighting =====
 * Subtle left-border tint on rows flagged as at-risk or watch — gives the
 * operator a peripheral-vision cue while scanning the table. */
tr.row-at-risk td:first-child { box-shadow: inset 3px 0 0 #c0392b; }
tr.row-watch td:first-child { box-shadow: inset 3px 0 0 #e67e22; }
tr.row-selected td { background: #f5f9ff !important; }

/* ===== Health pill =====
 * Tier badge in the Health column. Pill shape with tinted background +
 * matching dark text so it reads even on a busy row. */
.health-pill {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}
.health-pill.healthy { background: #d4f0e2; color: #155f34; }
.health-pill.watch   { background: #fef0d8; color: #8a5a14; }
.health-pill.at-risk { background: #fde0db; color: #8a2818; }

/* ===== Row action buttons v2 (replaces the icon stack) =====
 * "View" primary button + "⋮ More" dropdown trigger. Cleaner scan than
 * the previous 5-icon grid. */
.row-actions-v2 {
  display: inline-flex;
  align-items: center;
  gap: 4px;
}
.view-btn-row {
  background: #fff;
  color: var(--navy);
  border: 1px solid #b8c8e0;
  padding: 5px 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.view-btn-row:hover { background: #e0e7f3; border-color: var(--navy); }
.more-btn {
  background: #fff;
  color: var(--muted);
  border: 1px solid #d4dae3;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  font-size: 18px;
  line-height: 1;
  font-weight: 700;
  cursor: pointer;
  font-family: inherit;
  padding: 0;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.more-btn:hover { background: #e2e8f1; border-color: #b3bdcc; color: var(--ink); }

/* ===== Action menu portal =====
 * Single shared dropdown menu element, positioned via JS next to whichever
 * ⋮ button was clicked. Fixed-positioned so it escapes table-wrap overflow. */
.action-menu {
  position: fixed;
  z-index: 5000;
  min-width: 220px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);
  padding: 4px;
  font-family: inherit;
}
.action-menu[hidden] { display: none; }
.action-menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  background: transparent;
  border: 0;
  border-radius: 6px;
  font-size: 13px;
  color: var(--ink);
  text-align: left;
  cursor: pointer;
  font-family: inherit;
  text-decoration: none;
}
.action-menu-item:hover { background: #f0f3f8; }
.action-menu-item.danger { color: #b53626; }
.action-menu-item.danger:hover { background: #fde0db; }
.action-menu-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  font-size: 14px;
}
.action-menu-label { flex: 1; }
.action-menu-sep {
  height: 1px;
  background: var(--line);
  margin: 4px 6px;
}

/* ===== Excel dropzone ===== */
.dropzone {
  background: #fff;
  border: 2px dashed #cfd6e0;
  border-radius: 8px;
  padding: 18px 22px;
  margin-bottom: 14px;
  cursor: pointer;
  transition: border-color .12s, background .12s;
}
.dropzone:hover { border-color: var(--navy); background: #f6f8fc; }
.dropzone.dragging { border-color: var(--navy); background: #eaf0fa; border-style: solid; }
.dropzone.success  { border-color: var(--green); background: #f0f9f4; }
.dropzone.error    { border-color: #b53626; background: #fdf0ed; }
.dz-inner { display: flex; align-items: center; justify-content: center; gap: 16px; flex-wrap: wrap; }
.dz-icon  { font-size: 30px; line-height: 1; flex-shrink: 0; }
.dz-text  { text-align: left; }
.dz-text b { display: block; font-size: 14px; color: var(--ink); margin-bottom: 2px; }
.dz-sub   { font-size: 12px; color: var(--muted); }
.dz-status { display: none; margin: 8px auto 0; max-width: 700px; text-align: center; font-size: 12px; padding: 6px 10px; border-radius: 5px; background: #e6f4ec; color: #1d6e3d; }
.dz-status.show { display: block; }
.dz-status.error { background: #fde0db; color: #8a2818; }

/* "Recent imports" link — small chip in the dropzone top-right that opens
 * the imports history modal. Pinned with absolute positioning so it doesn't
 * shift around when the dropzone changes size. */
.dropzone { position: relative; }
.recent-imports-link {
  position: absolute;
  top: 8px;
  right: 8px;
  background: transparent;
  color: var(--muted);
  border: 1px solid #d4dae3;
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 11px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.recent-imports-link:hover {
  background: #fff;
  color: var(--navy);
  border-color: var(--navy);
}

/* ===== Undo banner — slides in after a successful bulk import =====
 * Pinned below the brandbar, full-width on phones, centred with a
 * max-width on desktop. Auto-dismisses after 30s; or the operator can
 * click Reverse / Dismiss inline. */
.undo-banner {
  position: fixed;
  top: 60px;
  left: 50%;
  transform: translate(-50%, -20px);
  z-index: 1200;
  min-width: 320px;
  max-width: calc(100vw - 32px);
  background: #fff;
  border: 1px solid #c5e1cc;
  border-left: 4px solid var(--green);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(15, 23, 42, 0.16);
  opacity: 0;
  transition: opacity 0.18s, transform 0.18s;
  pointer-events: none;
}
.undo-banner[hidden] { display: none; }
.undo-banner.show {
  opacity: 1;
  transform: translate(-50%, 0);
  pointer-events: auto;
}
.undo-banner-inner {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px 10px 14px;
  font-size: 13px;
}
.undo-banner-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  background: var(--green);
  color: #fff;
  border-radius: 50%;
  font-weight: 700;
  flex-shrink: 0;
}
.undo-banner-msg {
  color: var(--ink);
  line-height: 1.4;
  flex: 1;
}
.undo-banner-action {
  background: #fff;
  color: #c0392b;
  border: 1px solid #e29388;
  border-radius: 6px;
  padding: 6px 12px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  white-space: nowrap;
}
.undo-banner-action:hover { background: #fde0db; border-color: #c0392b; }
.undo-banner-dismiss {
  background: transparent;
  border: 0;
  color: var(--muted-2);
  font-size: 16px;
  cursor: pointer;
  font-family: inherit;
  padding: 4px 6px;
  line-height: 1;
}
.undo-banner-dismiss:hover { color: var(--ink); }

@media (max-width: 575.98px) {
  .undo-banner { left: 12px; right: 12px; transform: translateY(-20px); max-width: none; }
  .undo-banner.show { transform: translateY(0); }
  .undo-banner-inner { padding: 10px 8px 10px 12px; gap: 8px; }
  .undo-banner-msg { font-size: 12px; }
}

/* Recent imports table inside the modal. */
.recent-imports-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 13px;
}
.recent-imports-table th,
.recent-imports-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid var(--line-soft);
}
.recent-imports-table th {
  background: #fafbfc;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  font-weight: 600;
}
.recent-imports-table td.num {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  text-align: right;
  font-family: ui-monospace, "SF Mono", monospace;
}
.batch-status { font-size: 12px; }
.batch-status.active   { color: var(--ink); }
.batch-status.reversed { color: var(--muted); font-style: italic; }
.batch-status.muted    { color: var(--muted-2); }

@media (max-width: 575.98px) {
  .dropzone { padding: 14px 12px; }
  .dz-inner { gap: 10px; justify-content: flex-start; }
  .dz-text b { font-size: 13px; }
  .dz-sub { font-size: 11px; }
}

/* ===== Controls ===== */
.controls {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  align-items: center;
}
.controls input[type="search"] {
  padding: 7px 10px;
  border: 1px solid #d4dae3;
  border-radius: 6px;
  font-size: 13px;
  background: #fff;
  color: var(--ink);
  font-family: inherit;
  min-width: 200px;
  flex: 1 1 200px;
}
.controls input[type="search"]:focus { outline: 2px solid #4a90e2; outline-offset: -1px; border-color: transparent; }
.controls .count { margin-left: auto; color: var(--muted); font-size: 13px; }

/* Mobile: search takes full row (Bootstrap's flex-wrap puts buttons on the
 * next line); count drops below the buttons with a small top margin so it
 * doesn't collide with them when wrapped. */
@media (max-width: 575.98px) {
  .controls input[type="search"] { flex: 1 1 100%; min-width: 0; }
  .controls .count { margin-left: 0; flex: 1 1 100%; }
  .refresh-btn, .add-btn { font-size: 13px; padding: 8px 14px; }
}

.refresh-btn, .primary-btn, .add-btn, .export-btn {
  background: var(--navy);
  color: #fff;
  border: none;
  padding: 7px 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-family: inherit;
}
.refresh-btn:hover, .primary-btn:hover, .add-btn:hover, .export-btn:hover { background: #1f3a82; }
.refresh-btn:disabled, .primary-btn:disabled, .export-btn:disabled { opacity: 0.6; cursor: wait; }
.add-btn { background: var(--green); }
.add-btn:hover { background: #16693a; }
/* Export button: white-on-navy outlined variant — visually distinct from the
 * green "add" (creates data) and the navy "refresh" (re-scrapes data) so the
 * operator can spot the "take data out" action at a glance. */
.export-btn {
  background: #fff;
  color: var(--navy);
  border: 1px solid var(--navy);
}
.export-btn:hover { background: #e8edf7; color: var(--navy); }

/* View-mode toggle (list / grid icons) — matches the mockup pattern. Pill
 * container with two segmented buttons; .active fills the selected mode. */
.view-mode-toggle {
  display: inline-flex;
  align-items: center;
  background: #f0f3f8;
  border: 1px solid #d4dae3;
  border-radius: 6px;
  padding: 2px;
  gap: 2px;
}
.view-mode-btn {
  background: transparent;
  border: 0;
  padding: 5px 10px;
  border-radius: 4px;
  color: var(--muted);
  cursor: pointer;
  font-family: inherit;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.12s, color 0.12s;
}
.view-mode-btn:hover { color: var(--ink); background: #e2e8f1; }
.view-mode-btn.active {
  background: #fff;
  color: var(--navy);
  box-shadow: 0 1px 2px rgba(15, 23, 42, 0.06);
}
.view-mode-btn svg { display: block; }

/* ===== Shipment cards (grid view) =====
 * Alternative to the dense table. Responsive grid — auto-fit cards at
 * ~320px min. Each card carries the same actions as a table row (View +
 * ⋮ More + docs), via the same data-action attributes. Sub-pieces reuse
 * existing classes (shp-pill, health-pill, carrier, docs-btn) so the
 * card view stays in sync with the rest of the design without duplicating
 * styles. */
.shipments-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}
.shipments-cards[hidden] { display: none; }
.empty-cards {
  grid-column: 1 / -1;
  padding: 60px 20px;
  text-align: center;
  color: var(--muted);
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
}

.shipment-card {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 0;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: box-shadow 0.12s, border-color 0.12s;
}
.shipment-card:hover {
  box-shadow: 0 4px 12px rgba(15, 23, 42, 0.08);
  border-color: #b3bdcc;
}
.shipment-card.card-at-risk { border-left: 3px solid #c0392b; }
.shipment-card.card-watch   { border-left: 3px solid #e67e22; }
.shipment-card.card-selected { background: #f5f9ff; border-color: var(--navy); }

.card-header {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  border-bottom: 1px solid var(--line-soft);
  background: #fafbfc;
}
.card-check input[type="checkbox"] {
  width: 16px;
  height: 16px;
  accent-color: var(--navy);
  cursor: pointer;
  display: block;
}
.card-shp {
  font-family: ui-monospace, "SF Mono", Menlo, monospace;
  font-size: 14px;
  font-weight: 700;
  color: var(--ink);
}
.card-spacer { flex: 1; }

.card-body {
  padding: 10px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex: 1;
}
.card-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
  font-size: 11px;
}
.card-po {
  color: var(--muted);
  font-family: ui-monospace, "SF Mono", monospace;
}
.card-bol {
  color: var(--muted);
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 11px;
}
.card-vessel {
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  margin-top: 2px;
}
.card-supplier {
  font-size: 12px;
  color: var(--muted);
}
.card-containers {
  display: flex;
  flex-wrap: wrap;
  gap: 4px;
  font-family: ui-monospace, "SF Mono", monospace;
  font-size: 11px;
}
.card-containers .cont {
  background: #f0f3f8;
  padding: 1px 6px;
  border-radius: 3px;
  color: #3d4a5c;
}

.card-eta-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-top: 4px;
  padding-top: 8px;
  border-top: 1px solid var(--line-soft);
}
.card-eta { display: flex; flex-direction: column; }
.card-eta-date {
  font-size: 13px;
  font-weight: 700;
  color: var(--ink);
}
.card-eta-label {
  font-size: 10px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}

.card-live-status {
  font-size: 11px;
  color: var(--ink);
  margin-top: 4px;
  line-height: 1.3;
  word-break: break-word;
}

.card-footer {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 8px 12px;
  border-top: 1px solid var(--line-soft);
  background: #fafbfc;
}
.card-footer .view-btn-row { padding: 5px 16px; }
.card-footer .docs-btn { padding: 3px 8px; }

.reset-btn {
  background: #fff;
  color: var(--muted);
  border: 1px solid #d4dae3;
  padding: 6px 12px;
  border-radius: 6px;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
}
.reset-btn:hover { background: #f0f3f7; color: var(--ink); }

/* ===== Table ===== */
.table-wrap { background: #fff; border: 1px solid var(--line); border-radius: 8px; overflow-x: auto; overflow-y: visible; margin-bottom: 16px; }

/* Pager — sits under the table on the Complete view when there are more
 * than 30 rows. Hidden on Active / Recycle Bin via `hidden` attribute set
 * by renderPager() in dashboard.js. */
.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  margin: -8px 0 16px;
  padding: 12px 16px;
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
}
.pager[hidden] { display: none; }
.pager-btn {
  background: #fff;
  color: var(--navy);
  border: 1px solid #d4dae3;
  padding: 6px 14px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
}
.pager-btn:hover:not(:disabled) {
  background: #f0f3f8;
  border-color: var(--navy);
}
.pager-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.pager-info {
  color: var(--muted);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.pager-info b { color: var(--ink); font-weight: 700; }
table { width: 100%; border-collapse: collapse; }
th {
  text-align: left;
  padding: 10px 12px;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
  background: #fafbfc;
  user-select: none;
  white-space: nowrap;
  font-weight: 600;
}
th[data-sort] { cursor: pointer; }
th[data-sort]:hover { background: #f0f3f7; }
th .arrow::after { content: ""; display: inline-block; width: 0.7em; }
th.sorted .arrow::after { content: "▲"; color: var(--ink); }
th.sorted.desc .arrow::after { content: "▼"; }

td { padding: 11px 12px; border-bottom: 1px solid var(--line-soft); vertical-align: top; }
tr:last-child td { border-bottom: none; }

/* Zebra striping: alternate rows get a subtle grey wash so the eye can
 * track horizontally across a wide row without losing the line.
 * Pattern: odd rows white (the table's default), even rows light grey.
 * Convention is to NOT stripe the header row — `tbody tr:nth-child(even)`
 * limits this to data rows only. */
tbody tr:nth-child(even) td { background: #f7f8fa; }

/* Hover wins over zebra (both have specificity 0,0,1,2 but :hover comes
 * later in source order). Slightly bolder than the zebra tint so a hovered
 * row still pops on an even (already-tinted) row. */
tbody tr:hover td,
tbody tr:nth-child(even):hover td { background: #eaeef5; }

td.bol { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-weight: 600; font-size: 13px; line-height: 1.5; }
td.bol .cont { font-weight: 500; color: #3d4a5c; font-size: 11px; display: block; }
td.eta { white-space: nowrap; }
td.eta .label { font-size: 11px; color: var(--muted); display: block; margin-top: 2px; }
td.eta .label.live { color: var(--green); font-weight: 700; }
td.eta .label.was { color: #a0aab8; text-decoration: line-through; }
td.eta .live-eta { font-weight: 700; color: var(--green); }
td.action { white-space: nowrap; text-align: right; }

.empty-row td { text-align: center; padding: 50px 20px; color: var(--muted); }
.empty-row h3 { color: var(--ink); margin: 0 0 8px; font-weight: 600; }

/* ===== Pills + dots ===== */
.shp-pill {
  display: inline-block;
  padding: 4px 10px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 700;
  font-family: ui-monospace, "SF Mono", monospace;
  letter-spacing: 0.02em;
  min-width: 48px;
  text-align: center;
}
.shp-pill.delayed   { background: #fde0db; color: #8a2818; border: 1px solid #f5b8ad; }
.shp-pill.soon      { background: #fce8cd; color: #8a5a14; border: 1px solid #f5d49a; }
.shp-pill.upcoming  { background: #e0eaf3; color: #2d5a87; border: 1px solid #b8cfe5; }
.shp-pill.transit   { background: #d6e4f5; color: #1f4f88; border: 1px solid #a8c4e6; }
.shp-pill.berthed   { background: #d4f0eb; color: #0a5b53; border: 1px solid #97d9cf; }
.shp-pill.unknown   { background: #ececf0; color: #4a5568; border: 1px solid #d4d8df; }

.live-dot {
  display: inline-block;
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--green);
  margin-right: 4px;
  box-shadow: 0 0 0 0 rgba(29,131,72,0.5);
  animation: pulse 2s infinite;
  vertical-align: middle;
}
@keyframes pulse {
  0%   { box-shadow: 0 0 0 0 rgba(29,131,72,0.5); }
  70%  { box-shadow: 0 0 0 6px rgba(29,131,72,0); }
  100% { box-shadow: 0 0 0 0 rgba(29,131,72,0); }
}
.live-status {
  font-size: 11px;
  color: var(--ink);
  margin-top: 4px;
  max-width: 320px;
  line-height: 1.3;
  word-break: break-word;
}

.ais-badge {
  display: inline-block;
  background: #4a90e2;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  letter-spacing: 0.06em;
  margin-left: 4px;
  vertical-align: middle;
}

.manual-badge {
  display: inline-block;
  background: #8e44ad;
  color: #fff;
  font-size: 9px;
  font-weight: 700;
  padding: 1px 6px;
  border-radius: 4px;
  letter-spacing: 0.06em;
  margin-left: 4px;
  vertical-align: middle;
}

.mode-chip {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 4px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.02em;
  vertical-align: middle;
}
.mode-chip.manual {
  background: #f1e8fa;
  color: #6b2d96;
  border: 1px solid #d4baf0;
}

.manual-live {
  margin-top: 16px;
  padding: 12px 14px;
  border: 1px dashed #d4baf0;
  border-radius: 6px;
  background: #faf6fe;
}
.manual-live legend {
  font-weight: 600;
  color: #6b2d96;
  padding: 0 6px;
}
.manual-live .sub { margin-bottom: 8px; }

.req-mark { color: #c0392b; font-weight: 700; margin-left: 2px; }

/* Active / Complete / Recycle view toggle */
.view-toggle {
  display: inline-flex;
  gap: 4px;
  padding: 4px;
  background: rgba(21, 41, 92, 0.08);
  border-radius: 6px;
  flex-shrink: 0;
}
.view-btn {
  background: transparent;
  border: 0;
  color: #15295C;
  padding: 6px 14px;
  border-radius: 4px;
  font-weight: 600;
  font-size: 13px;
  cursor: pointer;
  transition: background 0.12s;
  white-space: nowrap;
}
.view-btn:hover { background: rgba(21, 41, 92, 0.08); }
.view-btn.active {
  background: #15295C;
  color: #fff;
}

@media (max-width: 575.98px) {
  .view-btn { padding: 5px 10px; font-size: 12px; }
}

/* Row-action button colour tiers — three categories conveying click consequence:
 *   .quick   — neutral grey at rest, navy on hover. Reversible / low-risk
 *              actions: refresh, edit, carrier-link.
 *   .toggle  — coloured ON (amber for watch), dim OFF. Shows row state at a
 *              glance without hovering.
 *   action-specific (.archive-forward / .archive-back / .restore / .soft-delete
 *              / .hard-delete) — coloured by direction + risk:
 *                forward / positive  → green tint
 *                backwards / undo    → muted grey
 *                destructive          → red tint
 *
 * Tooltips still spell out the action; colour just lets the eye pre-classify
 * before clicking. */

/* Quick actions fallback colour. Per-action overrides below give each of the
 * three quick buttons (refresh, edit, carrier-link) its own distinctive hue
 * so the five-button cluster reads as five different intents at a glance,
 * not three identical grey blobs. */
.icon-btn.quick { color: #6b7280; }
.icon-btn.quick:hover { background: #e0e7f3; color: var(--navy); border-color: #b8c8e0; }

/* Refresh — blue. The universal "sync / get fresh data" colour. */
.icon-btn.refresh { color: #2563eb; border-color: #c7d2fe; background: #f5f7ff; }
.icon-btn.refresh:hover { color: #1d4ed8; background: #dbeafe; border-color: #93a8f7; }

/* Edit — Interwil navy. Brand-primary "modify this row" colour. */
.icon-btn.edit { color: var(--navy); border-color: #c8d0e3; background: #f5f7fb; }
.icon-btn.edit:hover { color: #0d1a3e; background: #e0e7f3; border-color: #a8b8d0; }

/* Carrier link — teal. "External outbound link" cue, distinct from refresh blue. */
.icon-btn.carrier-link { color: #0891b2; border-color: #a5e3ee; background: #f0fbfd; }
.icon-btn.carrier-link:hover { color: #0e7490; background: #cffafe; border-color: #67d4e3; }

/* Forward / positive state changes: archive→, restore. Light green tint at
 * rest so it sits in the same "I've been coloured" visual category as the
 * other action buttons (vs. defaulting to the white-ish rest background). */
.icon-btn.archive-forward,
.icon-btn.restore { color: #1d8348; border-color: #c5e1cc; background: #f0faf3; }
.icon-btn.archive-forward:hover,
.icon-btn.restore:hover { background: #d4f4dd; border-color: #8fcfa1; color: #155f34; }

/* Undo / backwards: archive-back. Stays subtle (undo isn't a "loud" action). */
.icon-btn.archive-back { color: #6b7280; background: #f5f6f9; }
.icon-btn.archive-back:hover { background: #e8edf7; color: var(--navy); border-color: #b8c8e0; }

/* Destructive: soft-delete (warning red — recoverable from bin),
 * hard-delete (solid red — irreversible, strongest visual). */
.icon-btn.soft-delete { color: #b53626; border-color: #f0c7bf; background: #fef5f3; }
.icon-btn.soft-delete:hover { background: #fde0db; color: #8a2818; border-color: #e29388; }
.icon-btn.hard-delete { color: #fff; background: #c0392b; border-color: #a82e22; }
.icon-btn.hard-delete:hover { background: #a82e22; border-color: #8a2818; }

body.view-deleted .dropzone,
body.view-deleted #btn-add,
body.view-deleted #btn-refresh-all { display: none; }

.admin-only[hidden] { display: none !important; }

/* ETD date colour-coding (see etdColourClass in dashboard.js) */
.etd-date {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 12px;
  font-weight: 700;
  color: #fff;
  font-size: 12px;
  line-height: 1.4;
}
.etd-date.etd-red    { background: #c0392b; }
.etd-date.etd-orange { background: #e67e22; }
.etd-date.etd-green  { background: #1d8348; }

/* Toggle buttons: show state at a glance via colour.
 *   .toggle (off)      — muted grey
 *   .toggle.on         — coloured (amber for watch — same warm "subscribed"
 *                        cue Slack / GitHub / Notion use for active notifications)
 * Watch bell uses the bell-fill icon when on, bell outline when off (set by JS). */
.icon-btn.toggle {
  color: #94a3b8;
}
.icon-btn.toggle:hover { background: #e0e7f3; color: var(--navy); border-color: #b8c8e0; }
.icon-btn.toggle.watch.on {
  color: #d97706;          /* amber */
  background: #fef3c7;
  border-color: #fde68a;
}
.icon-btn.toggle.watch.on:hover { background: #fde68a; border-color: #fcd34d; color: #b45309; }

/* Inline checkbox row inside the edit modal */
.checkbox-row {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: 8px;
  padding-top: 4px;
}
.checkbox-row input[type="checkbox"] {
  margin: 0;
  width: 18px;
  height: 18px;
}

/* Info icon (ⓘ) — replaces the old 💬 emoji for per-shipment comments. */
.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  margin-left: 6px;
  color: #1565c0;
  opacity: 0.85;
  cursor: help;
  vertical-align: middle;
  outline: none;
  border-radius: 50%;
  transition: opacity 0.12s, background 0.12s;
}
.info-icon:hover,
.info-icon:focus { opacity: 1; background: rgba(21, 101, 192, 0.12); }
.info-icon:focus-visible { outline: 2px solid #1565c0; outline-offset: 1px; }
.info-icon svg { display: block; pointer-events: none; }

/* Body-level tooltip portal — repositioned per icon by dashboard.js. */
.info-tooltip-portal {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9999;
  min-width: 80px;
  max-width: 320px;
  padding: 6px 10px;
  background: rgba(0, 0, 0, 0.9);
  color: #fff;
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
  text-align: center;
  white-space: pre-wrap;
  word-wrap: break-word;
  border-radius: 4px;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  pointer-events: none;
}
.info-tooltip-portal[hidden] { display: none; }
.info-tooltip-portal::after {
  content: '';
  position: absolute;
  top: 100%;
  left: var(--arrow-left, 50%);
  transform: translateX(-50%);
  border: 5px solid transparent;
  border-top-color: rgba(0, 0, 0, 0.9);
}
.info-tooltip-portal.below::after {
  top: auto;
  bottom: 100%;
  border-top-color: transparent;
  border-bottom-color: rgba(0, 0, 0, 0.9);
}

/* ETD cell */
td.etd { white-space: nowrap; font-size: 12px; }
td.etd .label {
  display: block;
  font-size: 9px;
  color: var(--muted);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  margin-top: 2px;
}

/* ─────────────────────────────────────────────────────────────────────
   Auth — login page, top-bar widget, capability gates, Users modal.
   ───────────────────────────────────────────────────────────────────── */

body.login-page {
  background: #f3f4f6;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100vh;
  margin: 0;
}
.login-wrap {
  width: 100%;
  max-width: 460px;        /* wider than before (was 400px) — more comfortable */
  padding: 24px;
}
.login-card {
  background: #fff;
  padding: 40px 40px 32px;
  border-radius: 12px;
  /* Layered shadow — close ambient + softer fall-off — feels less "Bootstrap default" */
  box-shadow:
    0 1px 3px rgba(15, 23, 42, 0.04),
    0 8px 24px rgba(15, 23, 42, 0.08);
}
.login-card h1 {
  margin: 20px 0 4px;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.login-card .sub {
  margin: 0 0 28px;
  color: #6b7280;
  font-size: 14px;
}
.login-logo {
  width: 56px;
  height: 56px;
  display: block;
}
/* Full Interwil Wood Products logo lockup (icon + wordmark) at the top of
 * the login card. Wider aspect ratio (~3.2:1) so we set width and let height
 * follow. Subtle rounded corners + soft drop-shadow so the navy rectangle
 * sits cleanly on the white card. */
.login-brand-logo {
  display: block;
  margin: 0 auto 16px;
  width: 280px;
  max-width: 100%;        /* shrink on narrow phones to fit the card */
  height: auto;
  border-radius: 8px;
  box-shadow: 0 2px 8px rgba(21, 41, 92, 0.18);
}
.login-card label {
  display: block;
  margin-bottom: 18px;
  font-weight: 600;
  font-size: 13px;
  color: #374151;
}
.login-card label input {
  display: block;
  width: 100%;
  margin-top: 6px;
  padding: 11px 14px;
  border: 1px solid #ced4da;          /* Bootstrap form-control border colour */
  border-radius: 8px;
  font-size: 14px;
  font-family: inherit;
  color: var(--ink);
  background: #fff;
  box-sizing: border-box;
  transition: border-color 0.12s ease-in-out, box-shadow 0.12s ease-in-out;
}
/* Soft navy glow focus ring — same look as the modal form-control fields,
 * so the visual language stays consistent app-wide. */
.login-card label input:focus {
  outline: 0;
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(21, 41, 92, 0.18);
}
.login-card label input::placeholder { color: #9aa3b1; }
.login-card .primary-btn {
  margin-top: 12px;
  justify-content: center;
  /* Bigger primary CTA than the in-app primary buttons — login is the one-shot
   * action on this page, so the button should be unmistakeable. Bumped from
   * 12px/7px-14px to 15px/12px-20px, plus heavier weight and tighter tracking. */
  font-size: 15px;
  padding: 12px 20px;
  font-weight: 700;
  letter-spacing: 0.02em;
  border-radius: 8px;
  min-height: 48px;
}
.login-error {
  background: #fee2e2;
  border: 1px solid #fca5a5;
  color: #991b1b;
  padding: 10px 12px;
  border-radius: 6px;
  margin-bottom: 12px;
  font-size: 13px;
}
.login-help {
  margin: 24px 0 0;
  padding-top: 20px;
  border-top: 1px solid #eef1f5;       /* subtle separator between button and help text */
  color: #6b7280;
  font-size: 13px;
  text-align: center;
  line-height: 1.5;
}

@media (max-width: 575.98px) {
  .login-wrap { padding: 12px; }
  .login-card { padding: 22px 18px; }
}

/* Top-bar auth widget. Buttons are bordered pills with subtle translucent
 * fill — same visual language as the reference design. Icon + text pairs sit
 * inside via inline-flex, with a small gap. Bigger touch targets than before
 * (was 4px padding; now 6px/12px for proper button feel). */
.authbar {
  display: flex;
  align-items: center;
  gap: 8px;
  color: #fff;
  font-size: 13px;
  flex-wrap: wrap;
}
.authbar-name {
  font-weight: 500;
  margin-right: 4px;
}
.authbar-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  background: rgba(255,255,255,0.06);
  color: #fff;
  border: 1px solid rgba(255,255,255,0.22);
  padding: 6px 12px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  transition: background 0.12s, border-color 0.12s;
  line-height: 1;
}
.authbar-btn:hover {
  background: rgba(255,255,255,0.15);
  border-color: rgba(255,255,255,0.4);
}
.authbar-btn.icon-only {
  /* Square-ish for the icon-only key button — width matches its height */
  padding: 6px;
  width: 32px;
}
.authbar-btn svg {
  display: block;
  flex-shrink: 0;
}

/* Admin pill — sits inline next to the user's name. Subtle translucent
 * white-on-navy treatment so it reads as a small badge rather than a loud
 * tag. (The old amber gold was eye-catching but didn't match the brand bar.) */
.admin-badge {
  display: inline-flex;
  align-items: center;
  background: rgba(255,255,255,0.14);
  color: #fff;
  padding: 2px 8px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.06em;
  margin-left: 6px;
  vertical-align: middle;
  border: 1px solid rgba(255,255,255,0.18);
}

/* Capability gates: hide UI elements when the current user lacks the cap. */
body:not(.cap-delete) .row-action-delete { display: none !important; }
body:not(.cap-import) #excel-dropzone { display: none !important; }

/* Users modal table */
#users-table { width: 100%; border-collapse: collapse; font-size: 13px; }
#users-table th, #users-table td {
  padding: 8px 10px;
  text-align: left;
  border-bottom: 1px solid #e5e7eb;
}
#users-table tr.disabled td { opacity: 0.5; }
.add-user-header { margin: 24px 0 12px 0; font-size: 16px; color: #15295C; }
.link-btn {
  background: none;
  border: none;
  color: #15295C;
  text-decoration: underline;
  cursor: pointer;
  font-size: 13px;
  padding: 2px 6px;
}
.link-btn.danger { color: #b91c1c; }
.link-btn:hover { text-decoration: none; background: #f3f4f6; }
label.caps { display: flex; flex-direction: column; gap: 4px; }
label.caps > span { font-weight: 500; margin-bottom: 4px; }
label.cb { font-weight: 400; font-size: 13px; display: flex; align-items: center; gap: 6px; }
label.cb input { margin: 0; }

/* Inline-checkbox labels need higher-specificity overrides to defeat the
 * `.modal form label` block above (which sets flex-direction: column,
 * text-transform: uppercase, font-weight: 600 on every modal-form label).
 * Without this, the .cb checkboxes inside the Users modal Permissions list
 * stack ABOVE the label text instead of sitting beside it. Same trap for
 * the shipment modal's "Email me updates" .checkbox-row.
 *
 * Selector specificity: `.modal form label.cb` = (0,0,2,2), beats both
 * `.modal form label` (0,0,1,2) and bare `label.cb` (0,0,1,1). */
.modal form label.cb,
.modal form label.checkbox-row {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 8px;
  font-weight: 400;
  font-size: 13px;
  text-transform: none;
  letter-spacing: normal;
  color: var(--ink);
}
/* Checkbox inputs inside these labels: stop the `input { width: 100% }`
 * form-control rule (which excludes [type="checkbox"], but defensively
 * pin width: auto here in case a future selector catches them). Slight
 * upsize matches the .checkbox-row pattern already in use elsewhere. */
.modal form label.cb input[type="checkbox"],
.modal form label.checkbox-row input[type="checkbox"] {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin: 0;
}

.po-num {
  font-family: ui-monospace, "SFMono-Regular", Menlo, Monaco, Consolas, monospace;
  font-size: 12px;
  color: #2c3e50;
}

/* .icon-btn.carrier-link styling now comes from .icon-btn.quick (added in the
 * row-action colour-tier block above). The dedicated rules previously here
 * predated the tier system. */

.bol-pending {
  display: inline-block;
  font-style: italic;
  color: #8e44ad;
  background: #f1e8fa;
  border: 1px dashed #d4baf0;
  border-radius: 4px;
  padding: 1px 6px;
  font-size: 11px;
}

.carrier { display: inline-flex; align-items: center; gap: 6px; font-weight: 500; }
.carrier .dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.carrier.msc    .dot { background: #f7a81b; }
.carrier.maersk .dot { background: #42b0d5; }
.carrier.one    .dot { background: #d4006a; }
.carrier.pil    .dot { background: #1a3d7c; }
.carrier.kn     .dot { background: #005ca9; }
.carrier.hl     .dot { background: #ec9a17; }   /* Hapag-Lloyd orange */

/* ===== Action buttons in row =====
 * 3-column grid on desktop fits all five action buttons (refresh, watch,
 * carrier-link, edit, archive) in 2 rows. On phones the action <td> is the
 * rightmost visible cell — drop to 2 columns there so the grid stays narrow
 * and doesn't squeeze the Status column. */
.row-actions {
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: 3px;
  width: max-content;
}
@media (max-width: 575.98px) {
  .row-actions { grid-template-columns: repeat(2, auto); }
}
/* Base row-action button. Sized to fit a 16×16 SVG comfortably with enough
 * tap target (28×28 minimum on mobile per Apple HIG / Material). Specific
 * colour tiers below override the resting colour. */
.icon-btn {
  background: #f7f8fa;
  color: var(--ink);
  border: 1px solid #d4dae3;
  border-radius: 6px;
  padding: 5px;
  width: 30px;
  height: 28px;
  font-size: 12px;
  cursor: pointer;
  font-family: inherit;
  line-height: 1;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
  transition: background 0.12s, border-color 0.12s, color 0.12s;
}
.icon-btn svg { display: block; }
.icon-btn:hover { background: #e2e8f1; border-color: #b3bdcc; }
.icon-btn:focus-visible { outline: 2px solid var(--navy); outline-offset: 1px; }
.icon-btn:disabled { opacity: 0.5; cursor: wait; }

.docs-btn {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: #f0f3f8;
  color: var(--ink);
  border: 1px solid #d4dae3;
  padding: 4px 9px;
  border-radius: 5px;
  font-size: 12px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}
.docs-btn:hover { background: #e2e8f1; }
.docs-btn.has { background: #eaf3eb; border-color: #b3d2bb; color: #1d5e2a; }
.docs-btn .n {
  display: inline-block;
  background: var(--green);
  color: #fff;
  border-radius: 999px;
  padding: 1px 6px;
  font-size: 10px;
  font-weight: 700;
}

/* ===== Activity log ===== */
.activity-log {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  margin-bottom: 16px;
}
.activity-log summary {
  padding: 12px 16px;
  cursor: pointer;
  font-weight: 600;
  font-size: 13px;
  user-select: none;
  list-style: none;
}
.activity-log summary::-webkit-details-marker { display: none; }
.activity-log summary::before { content: "▶"; display: inline-block; margin-right: 8px; transition: transform .15s; color: var(--muted); }
.activity-log[open] summary::before { transform: rotate(90deg); }
.activity-log summary:hover { background: var(--row-hover); }
.activity-log[open] summary { border-bottom: 1px solid var(--line); }
.activity-log .body { padding: 4px 0; }
.activity-log .hint { color: var(--muted); font-weight: 400; }
.run-row {
  display: grid;
  grid-template-columns: 160px 80px 1fr 80px;
  gap: 12px;
  padding: 8px 16px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 12px;
  align-items: center;
}
.run-row:last-child { border-bottom: none; }
.run-row .when { color: var(--muted); font-variant-numeric: tabular-nums; }
.run-row .trigger { font-weight: 600; }
.run-row .trigger.cron { color: var(--green); }
.run-row .trigger.manual { color: var(--navy); }
.run-row .summary { color: var(--ink); }
.run-row .blocked { color: #8a2818; font-size: 11px; }
.run-row .ok { color: var(--green); font-weight: 600; text-align: right; }

@media (max-width: 575.98px) {
  .run-row { grid-template-columns: 1fr; gap: 2px; padding: 10px 14px; }
  .run-row .ok { text-align: left; }
}

/* ===== Modals ===== */
/* IMPORTANT: Bootstrap 5.3 also defines `.modal-backdrop` and `.modal` with
 * very different semantics — its `.modal` is a fixed-position full-screen
 * overlay containing a `.modal-dialog` child. Our markup re-uses both class
 * names but with a flat structure: `.modal-backdrop` is the centering flex
 * container, `.modal` is the centered dialog card. The selectors below have
 * to defeat Bootstrap's positioning explicitly — Bootstrap's `position: fixed;
 * top: 0; left: 0; width: 100%; height: 100%; display: none` would otherwise
 * win for any property we don't set.
 *
 * Bumping specificity via `.modal-backdrop > .modal` ensures we win regardless
 * of stylesheet source order. */
.modal-backdrop {
  position: fixed; inset: 0;
  background: rgba(15, 25, 45, 0.42);
  display: flex; align-items: center; justify-content: center;
  z-index: 1000; padding: 16px;
  /* Override Bootstrap's `width: 100vw; height: 100vh` (which can cause a
   * 1-2px horizontal scrollbar on Windows when a vertical scrollbar is
   * present, since 100vw includes the scrollbar width). */
  width: auto; height: auto;
}
.modal-backdrop[hidden] { display: none; }

/* Lock the underlying page when any modal-backdrop is visible. Using :has()
 * so it works regardless of which entry point opened the modal (the openModal
 * helper, a [data-modal-close] click, the Esc key, or any future caller) —
 * no JS bookkeeping required.
 *
 * `position: fixed; width: 100%` (rather than just `overflow: hidden`) is the
 * iOS-safe pattern: on iOS Safari, plain `overflow: hidden` still allows
 * rubber-band scrolling. Pinning the body with `position: fixed` stops that.
 *
 * Browser support for :has() is Chrome/Edge 105+, Safari 15.4+, Firefox 121+
 * — all current as of late 2024, which covers every browser our users run.
 * The pre-:has() fallback (toggling a body class from JS) isn't worth the
 * complexity for an internal tool. */
html:has(.modal-backdrop:not([hidden])),
body:has(.modal-backdrop:not([hidden])) {
  overflow: hidden;
}
.modal-backdrop > .modal,
.modal {
  /* Reset Bootstrap's full-screen positioning so the modal becomes a flex
   * item inside the centered backdrop. */
  position: relative;
  top: auto; left: auto;
  background: #fff;
  border-radius: 10px;
  box-shadow: 0 16px 48px rgba(0,0,0,0.18);
  width: 560px; max-width: 100%;
  height: auto;
  max-height: calc(100vh - 32px);
  overflow: hidden;
  display: flex; flex-direction: column;
  pointer-events: auto;
}
.modal.wide { width: 1100px; max-width: calc(100vw - 32px); }
.modal header {
  padding: 16px 24px;
  background: var(--navy);
  color: #fff;
  display: flex; align-items: center; justify-content: space-between;
  margin: 0;
}
.modal h2 { margin: 0; font-size: 16px; font-weight: 600; letter-spacing: 0.01em; }
.modal .close {
  background: transparent; border: none; color: #fff;
  font-size: 22px; line-height: 1; cursor: pointer;
  padding: 0 4px;
}
.modal .close:hover { color: #c4c4c4; }
/* Generous body padding (Bootstrap-equivalent default is 1rem ≈ 16px; we go
 * a bit more breathable at 24px top/bottom × 28px sides). Footer gets
 * matching horizontal padding so the action buttons line up with the form
 * fields above them. */
.modal-body { padding: 24px 28px; overflow-y: auto; }
.modal-footer { padding: 16px 28px; border-top: 1px solid var(--line); display: flex; gap: 8px; justify-content: flex-end; background: #fafbfc; flex-wrap: wrap; }

.modal > header { flex: 0 0 auto; }
.modal > .modal-body { flex: 1 1 auto; min-height: 0; }
.modal > .modal-footer { flex: 0 0 auto; }

/* Shipment modal nests modal-body/footer inside <form> */
.modal form {
  display: flex;
  flex-direction: column;
  min-height: 0;
  flex: 1 1 auto;
  padding: 0;
}
.modal form > .modal-body { flex: 1 1 auto; min-height: 0; padding: 24px 28px; }
.modal form > .modal-footer { flex: 0 0 auto; }

/* Defensive padding: if a modal-form forgets the `.modal-body` wrapper, the
 * direct `.grid-2` / `.form-errors` children would otherwise touch the modal
 * edges (see https://… the change-password modal bug). This catches that case
 * by padding any non-footer flex child of the form directly.
 *
 * Skipped when modal-body IS present — we use :not() to avoid double-padding. */
.modal form > .grid-2:first-child,
.modal form > .form-errors:first-child {
  padding: 24px 28px;
}
@media (max-width: 767.98px) {
  .modal form > .grid-2:first-child,
  .modal form > .form-errors:first-child { padding: 18px 18px; }
}

.modal form .grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.modal form label.full { grid-column: 1 / -1; }
.modal form label { display: flex; flex-direction: column; gap: 4px; font-size: 12px; color: var(--muted); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; }

/* Bootstrap-style form-control styling for ALL editable inputs/selects inside
 * a modal form. The original selector listed `[type="text"]`, `[type="date"]`,
 * and untyped inputs explicitly — but missed `[type="password"]`, `[type="email"]`,
 * `[type="number"]`, `[type="search"]` and `<select>`, which fell back to the
 * browser default (just an underline). Using a negation list catches every
 * editable type without needing to enumerate them. */
.modal form input:not([type="checkbox"]):not([type="radio"]):not([type="hidden"]):not([type="file"]),
.modal form select,
.modal form textarea {
  display: block;
  width: 100%;
  border: 1px solid #ced4da;       /* Bootstrap form-control border colour */
  border-radius: 6px;
  padding: 7px 10px;
  font-size: 13px;
  line-height: 1.5;
  font-family: inherit;
  text-transform: none;
  font-weight: 400;
  letter-spacing: normal;
  color: var(--ink);
  background-color: #fff;
  background-clip: padding-box;
  transition: border-color 0.12s ease-in-out, box-shadow 0.12s ease-in-out;
  box-sizing: border-box;
}
.modal form textarea { resize: vertical; min-height: 60px; font-family: ui-monospace, "SF Mono", monospace; font-size: 12px; }
/* Focus state matches Bootstrap's form-control focus — soft glow ring in
 * Interwil navy (not the default electric blue). */
.modal form input:focus,
.modal form select:focus,
.modal form textarea:focus {
  outline: 0;
  border-color: var(--navy);
  box-shadow: 0 0 0 3px rgba(21, 41, 92, 0.18);
}
.modal form input::placeholder,
.modal form textarea::placeholder { color: #9aa3b1; opacity: 1; }
.modal form input:disabled,
.modal form select:disabled,
.modal form textarea:disabled { background: #f1f3f6; opacity: 1; cursor: not-allowed; }

/* On phones, the two-column form grid collapses to one column so labels and
 * inputs are wide enough to read/tap. */
@media (max-width: 767.98px) {
  .modal form .grid-2 { grid-template-columns: 1fr; }
  /* Slightly tighter than desktop but still breathable on phones. */
  .modal-body { padding: 18px 18px; }
  .modal form > .modal-body { padding: 18px 18px; }
  .modal-footer { padding: 14px 18px; }
  .modal header { padding: 14px 18px; }
}

.form-errors {
  margin-top: 12px;
  padding: 10px 12px;
  background: #fde0db;
  border: 1px solid #f5b8ad;
  border-radius: 6px;
  color: #8a2818;
  font-size: 12px;
}
.form-errors ul { margin: 4px 0 0 18px; padding: 0; }

/* Import preview specifically */
#import-preview-table tr.invalid td { background: #fdf0ed; }
#import-preview-table tr.invalid td:first-child { color: #8a2818; font-weight: 700; }
#import-preview-table .errors { color: #8a2818; font-size: 11px; }

/* Document drawer */
.docs-list { list-style: none; padding: 0; margin: 0; max-height: 320px; overflow-y: auto; }
.docs-list li {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 4px;
  border-bottom: 1px solid var(--line-soft);
  font-size: 13px;
}
.docs-list li:last-child { border-bottom: none; }
.docs-list .fname { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink); font-weight: 500; }
.docs-list .fmeta { color: var(--muted-2); font-size: 11px; flex-shrink: 0; }
.docs-list .fdl, .docs-list .fdel {
  background: none; border: none; cursor: pointer; padding: 4px 8px; border-radius: 4px;
  font-size: 14px; color: var(--muted); line-height: 1;
}
.docs-list .fdl:hover { background: #eaf0fa; color: var(--navy); }
.docs-list .fdel:hover { background: #fde0db; color: #8a2818; }
.docs-empty { color: var(--muted-2); font-size: 12px; text-align: center; padding: 20px 0; }
.docs-upload { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--line); display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }

/* ===== Side drawer =====
 * Right-side panel that opens when the user clicks "View" on a row.
 * Read-only quick info + three tabs (Details / Documents / Notes). The
 * existing edit modal stays as the deeper "Edit" affordance, reached via
 * the drawer's footer Edit button.
 *
 * Slide-in animation: the `.open` class slides the panel from off-screen
 * right into view (transform-only — GPU-accelerated, no layout reflow). */
.side-drawer {
  position: fixed;
  inset: 0;
  z-index: 1100;       /* above modals (1000) so it can stack on top */
  pointer-events: none;
}
.side-drawer[hidden] { display: none; }
.drawer-overlay {
  position: absolute;
  inset: 0;
  background: rgba(15, 25, 45, 0.32);
  opacity: 0;
  transition: opacity 0.2s ease-out;
  pointer-events: auto;
}
.side-drawer.open .drawer-overlay { opacity: 1; }
.drawer-panel {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  width: 480px;
  max-width: 100%;
  background: #fff;
  box-shadow: -8px 0 32px rgba(15, 23, 42, 0.18);
  display: flex;
  flex-direction: column;
  transform: translateX(100%);
  transition: transform 0.22s cubic-bezier(0.32, 0.72, 0, 1);
  pointer-events: auto;
}
.side-drawer.open .drawer-panel { transform: translateX(0); }

/* Header — sticky, full-width brand colour. */
.drawer-header {
  padding: 18px 22px 14px;
  background: var(--navy);
  color: #fff;
  flex-shrink: 0;
}
.drawer-title-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 4px;
}
.drawer-title-text {
  display: flex;
  align-items: center;
  gap: 10px;
  flex: 1;
  min-width: 0;
}
.drawer-header h2 {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.drawer-close {
  background: transparent;
  color: #fff;
  border: 0;
  font-size: 28px;
  line-height: 1;
  cursor: pointer;
  padding: 0 4px;
  flex-shrink: 0;
  opacity: 0.85;
}
.drawer-close:hover { opacity: 1; }
.drawer-subtitle {
  font-size: 12px;
  color: rgba(255,255,255,0.72);
  font-family: ui-monospace, "SF Mono", monospace;
}
.drawer-subtitle .muted { color: rgba(255,255,255,0.5); font-style: italic; font-family: inherit; }

/* Body — scrollable middle region. */
.drawer-body {
  flex: 1 1 auto;
  overflow-y: auto;
  background: #fafbfc;
}

/* Quick info — compact label/value pairs at the top of the body. */
.drawer-quick-info { padding: 18px 22px 8px; }
.qi-grid { display: grid; gap: 8px; }
.qi-row {
  display: grid;
  grid-template-columns: 100px 1fr;
  gap: 12px;
  align-items: baseline;
  font-size: 13px;
}
.qi-label {
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 600;
}
.qi-value { font-weight: 600; color: var(--ink); }
.qi-strike { color: var(--muted-2); text-decoration: line-through; font-size: 12px; margin-left: 4px; }

/* Tab navigation — sticky under the quick-info block. */
.drawer-tabs {
  display: flex;
  gap: 2px;
  padding: 0 22px;
  background: #fafbfc;
  border-bottom: 1px solid var(--line);
  position: sticky;
  top: 0;
  z-index: 1;
}
.drawer-tab {
  background: transparent;
  color: var(--muted);
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 600;
  font-family: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: color 0.12s, border-color 0.12s;
}
.drawer-tab:hover { color: var(--ink); }
.drawer-tab.active {
  color: var(--navy);
  border-bottom-color: var(--navy);
}
.drawer-tab-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  padding: 0 6px;
  height: 16px;
  background: var(--line);
  color: var(--muted);
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
}
.drawer-tab.active .drawer-tab-count { background: var(--navy); color: #fff; }

/* Tab content panel. */
.drawer-tab-content { padding: 16px 22px 32px; }
.drawer-detail-list {
  display: grid;
  grid-template-columns: 130px 1fr;
  gap: 10px 14px;
  margin: 0;
  font-size: 13px;
}
.drawer-detail-list dt {
  font-weight: 600;
  color: var(--muted);
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  align-self: center;
}
.drawer-detail-list dd {
  margin: 0;
  color: var(--ink);
  word-break: break-word;
}

.drawer-empty {
  text-align: center;
  padding: 32px 16px;
  color: var(--muted);
}
.drawer-empty p { margin: 0 0 14px; font-size: 13px; }

.drawer-note {
  background: #fff;
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 14px 16px;
  margin-bottom: 12px;
}
.drawer-note h4 {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 600;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.drawer-note p {
  margin: 0;
  font-size: 13px;
  color: var(--ink);
  white-space: pre-wrap;
  line-height: 1.5;
}

/* Footer — sticky, holds the action buttons. */
.drawer-footer {
  flex-shrink: 0;
  padding: 12px 22px;
  background: #fff;
  border-top: 1px solid var(--line);
  display: flex;
  gap: 8px;
  justify-content: flex-end;
}
.drawer-footer .primary-btn { padding: 8px 18px; font-size: 13px; }
.drawer-footer .reset-btn { padding: 8px 14px; font-size: 13px; }

@media (max-width: 575.98px) {
  .drawer-panel { width: 100%; }
  .drawer-header { padding: 14px 16px 10px; }
  .drawer-quick-info { padding: 14px 16px 6px; }
  .drawer-tabs { padding: 0 16px; }
  .drawer-tab-content { padding: 14px 16px 28px; }
  .drawer-footer { padding: 10px 16px; }
  .qi-row { grid-template-columns: 90px 1fr; }
  .drawer-detail-list { grid-template-columns: 110px 1fr; }
}

/* ===== Toast ===== */
.toast {
  position: fixed; bottom: 20px; right: 20px;
  background: var(--ink); color: #fff;
  padding: 12px 18px; border-radius: 6px;
  font-size: 13px;
  box-shadow: 0 4px 12px rgba(0,0,0,0.18);
  opacity: 0; transform: translateY(8px);
  transition: opacity .2s, transform .2s;
  pointer-events: none; z-index: 1100;
  max-width: 360px;
}
.toast.show { opacity: 1; transform: translateY(0); }
.toast.success { background: var(--green); }
.toast.error { background: #b53626; }

@media (max-width: 575.98px) {
  .toast { left: 12px; right: 12px; bottom: 12px; max-width: none; }
}

.footer { margin-top: 16px; font-size: 12px; color: var(--muted-2); text-align: center; }
.footer a { color: inherit; }

/* Spinner used by row refresh button */
.spinner {
  display: inline-block;
  width: 11px; height: 11px;
  border: 2px solid #cfd6e0;
  border-top-color: var(--navy);
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
  vertical-align: -2px;
}
@keyframes spin { to { transform: rotate(360deg); } }
