const { useState, useMemo, useEffect, useRef } = React;
const BrokerSidebar = window.Sidebar;
const BrokerTopbar = window.Topbar;

/* ─── Tweak defaults ─────────────────────────────────────────────────── */
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "confidenceMode": "all-review",
  "showEmptyState": false,
  "showSkeleton": false
}/*EDITMODE-END*/;

/* ─── Data ──────────────────────────────────────────────────────────────────── */
const FREIGHT_DATA = [
{ id: 1, stops: 0, status: 'pickup', bol: 'SHOWCASE-006', origin: 'Rancho Cucamonga, CA', dest: 'Pittsburgh, PA', refs: ['21250176697'], eta: '2026-05-26T14:00:00Z', onTime: true, pct: 22, mabd: '2026-05-27T00:00:00Z', appt: '2026-05-26T10:00:00Z', pallets: 4, cartons: 12, wt: 1840, shipper: 'LogiWest Distribution Center', consignee: 'Rocky Mountain Logistics', carriers: [{ name: 'XPO Logistics', active: true }] },
{ id: 2, stops: 2, status: 'in_transit', bol: 'SHOWCASE-LTL-007', origin: 'Carson, CA', dest: 'Pittsburgh, PA', refs: ['32250000646', 'PO-44821'], eta: '2026-05-26T18:00:00Z', onTime: true, pct: 55, mabd: '2026-05-27T00:00:00Z', appt: '2026-05-27T08:00:00Z', pallets: 2, cartons: 8, wt: 960, shipper: 'ASUS-SBG c/o Prime Freight', consignee: 'Pittsburgh Gateway Hub', carriers: [{ name: 'Old Dominion', active: true }, { name: 'XPO Logistics', active: false }] },
{ id: 3, stops: 1, status: 'order_created', bol: 'NC00000634', origin: 'Carson, CA', dest: 'Columbus, OH', refs: ['21260076426', '21260076427', '21260076428'], eta: null, onTime: null, pct: 0, mabd: '2026-05-29T00:00:00Z', appt: '2026-05-29T09:00:00Z', pallets: 6, cartons: 24, wt: 3200, shipper: 'Carson Fulfillment Co.', consignee: 'STAPLES-US-C-DC895', carriers: [{ name: 'Estes Express', active: true }] },
{ id: 4, stops: 0, status: 'order_created', bol: 'NC00000635', origin: 'Carson, CA', dest: 'Mechanicsburg, PA', refs: ['21260076415'], eta: null, onTime: null, pct: 0, mabd: '2026-05-29T00:00:00Z', appt: '2026-05-29T10:00:00Z', pallets: 3, cartons: 15, wt: 1450, shipper: 'Carson Fulfillment Co.', consignee: 'STAPLES-US-C-DC994', carriers: [{ name: 'R+L Carriers', active: true }], awaitingDriver: true },
{ id: 5, stops: 3, status: 'in_transit', bol: 'NC00000636', origin: 'Carson, CA', dest: 'Fayetteville, NC', refs: ['21260076411', 'SO-77021'], eta: '2026-05-27T14:00:00Z', onTime: true, pct: 62, mabd: '2026-05-28T00:00:00Z', appt: '2026-05-27T14:00:00Z', pallets: 5, cartons: 18, wt: 2100, shipper: 'Carson Fulfillment Co.', consignee: 'STAPLES-US-C-DC799', carriers: [{ name: 'ABF Freight', active: true }, { name: 'Saia LTL', active: false }] },
{ id: 6, stops: 2, status: 'billing', bol: 'NC00000637', origin: 'Carson, CA', dest: 'Killingly, CT', refs: ['21260076416', 'PO-33021', 'SO-77120', 'REF-91044', '21260077000'], eta: null, onTime: null, pct: 100, mabd: '2026-05-20T00:00:00Z', appt: '2026-05-20T08:00:00Z', pallets: 8, cartons: 32, wt: 4800, shipper: 'Carson Fulfillment Co.', consignee: 'STAPLES-US-C-DC580', carriers: [{ name: 'XPO Logistics', active: true }], billingIssues: ['no_pod', 'awaiting_charges'] },
{ id: 7, stops: 1, status: 'invoiced', bol: 'INVLTL-2201', origin: 'Ontario, CA', dest: 'Dallas, TX', refs: ['PO-88821-C'], eta: null, onTime: null, pct: 100, mabd: '2026-05-15T00:00:00Z', appt: '2026-05-15T11:00:00Z', pallets: 10, cartons: 42, wt: 5900, shipper: 'Pacific Coast Distributors', consignee: 'Target DC \u2013 Dallas', carriers: [{ name: 'Saia LTL', active: true }] },
{ id: 8, stops: 0, status: 'out_for_delivery', bol: 'BL-44892', origin: 'Memphis, TN', dest: 'Chicago, IL', refs: ['PO-77612', 'REF-20901'], eta: '2026-05-25T16:00:00Z', onTime: true, pct: 94, mabd: '2026-05-25T00:00:00Z', appt: '2026-05-25T15:00:00Z', pallets: 3, cartons: 9, wt: 870, shipper: 'Mid-South Logistics', consignee: 'Amazon FBA \u2013 ORD4', carriers: [{ name: 'FedEx Freight', active: true }] },
{ id: 9, stops: 0, status: 'pickup', bol: 'LTL-99021', origin: 'Portland, OR', dest: 'Las Vegas, NV', refs: ['SO-12045'], eta: '2026-05-27T09:00:00Z', onTime: true, pct: 18, mabd: '2026-05-28T00:00:00Z', appt: '2026-05-27T08:00:00Z', pallets: 2, cartons: 6, wt: 530, shipper: 'Northwest Freight Partners', consignee: 'Costco \u2013 Las Vegas DC', carriers: [{ name: 'Old Dominion', active: true }], awaitingDriver: true },
{ id: 10, stops: 1, status: 'out_for_delivery', bol: 'RL-20044', origin: 'Atlanta, GA', dest: 'Charlotte, NC', refs: ['REF-45892'], eta: '2026-05-25T11:00:00Z', onTime: true, pct: 97, isEarly: true, mabd: '2026-05-26T00:00:00Z', appt: '2026-05-26T08:00:00Z', pallets: 1, cartons: 4, wt: 320, shipper: 'Southeast Express LLC', consignee: 'Home Depot \u2013 Charlotte', carriers: [{ name: 'R+L Carriers', active: true }] },
{ id: 11, stops: 2, status: 'billing', bol: 'BL-55001', origin: 'Houston, TX', dest: 'Phoenix, AZ', refs: ['PO-90044', 'PO-90045', 'PO-90046', 'SO-11200'], eta: null, onTime: null, pct: 100, mabd: '2026-05-18T00:00:00Z', appt: '2026-05-18T10:00:00Z', pallets: 7, cartons: 28, wt: 3800, shipper: 'Gulf Coast Shipping LLC', consignee: 'Walmart DC \u2013 Phoenix', carriers: [{ name: 'TForce Freight', active: true }, { name: 'XPO Logistics', active: false }], billingIssues: ['no_pod'] },
{ id: 12, stops: 0, status: 'invoiced', bol: 'INV-88001', origin: 'Seattle, WA', dest: 'Salt Lake City, UT', refs: ['REF-31200'], eta: null, onTime: null, pct: 100, mabd: '2026-05-10T00:00:00Z', appt: '2026-05-10T09:00:00Z', pallets: 4, cartons: 16, wt: 2200, shipper: 'Pacific NW Logistics', consignee: "Smith's Food Distribution", carriers: [{ name: 'Estes Express', active: true }] },
{ id: 13, stops: 1, status: 'in_transit', bol: 'LTL-44120', origin: 'Louisville, KY', dest: 'Nashville, TN', refs: ['PO-55612'], eta: '2026-05-25T20:00:00Z', onTime: true, pct: 80, mabd: '2026-05-26T00:00:00Z', appt: '2026-05-25T22:00:00Z', pallets: 5, cartons: 20, wt: 2600, shipper: 'Bluegrass Distribution', consignee: 'Dollar General DC', carriers: [{ name: 'ABF Freight', active: true }] },
{ id: 14, stops: 3, status: 'in_transit', bol: 'NC-88500', origin: 'Denver, CO', dest: 'Kansas City, MO', refs: ['21260099100', 'REF-20021', 'PO-60014', 'SO-44892', '21260099101', '21260099102'], eta: '2026-05-27T15:00:00Z', onTime: false, pct: 40, isDelayed: true, mabd: '2026-05-26T00:00:00Z', appt: '2026-05-26T09:00:00Z', pallets: 9, cartons: 36, wt: 5100, shipper: 'Rocky Mtn. Supply Chain', consignee: 'CVS Distribution', carriers: [{ name: 'Old Dominion', active: true }, { name: 'J.B. Hunt', active: false }] },
{ id: 15, stops: 0, status: 'in_transit', bol: 'FT-22891', origin: 'Phoenix, AZ', dest: 'San Antonio, TX', refs: ['PO-44102', 'SO-88310'], eta: '2026-05-28T12:00:00Z', onTime: false, pct: 28, isDelayed: true, mabd: '2026-05-27T00:00:00Z', appt: '2026-05-27T10:00:00Z', pallets: 6, cartons: 22, wt: 3100, shipper: 'Desert SW Shipping Inc.', consignee: 'H-E-B DC \u2013 San Antonio', carriers: [{ name: 'Werner Enterprises', active: true }] },
{ id: 16, stops: 2, status: 'billing', bol: 'BILL-99401', origin: 'Minneapolis, MN', dest: 'Indianapolis, IN', refs: ['PO-33021'], eta: null, onTime: null, pct: 100, mabd: '2026-05-19T00:00:00Z', appt: '2026-05-19T13:00:00Z', pallets: 4, cartons: 18, wt: 2400, shipper: 'Northstar Freight LLC', consignee: 'Target DC \u2013 Indianapolis', carriers: [{ name: 'Schneider', active: true }], billingIssues: ['awaiting_charges'] },
{ id: 17, stops: 1, status: 'invoiced', bol: 'INV-77002', origin: 'Columbus, OH', dest: 'Richmond, VA', refs: ['REF-10044', 'REF-10045', 'REF-10046'], eta: null, onTime: null, pct: 100, mabd: '2026-05-12T00:00:00Z', appt: '2026-05-12T09:00:00Z', pallets: 3, cartons: 10, wt: 1100, shipper: 'Great Lakes Logistics', consignee: "Lowe's DC \u2013 Richmond", carriers: [{ name: 'XPO Logistics', active: true }] },
{ id: 18, stops: 0, status: 'in_transit', bol: 'SPOT-40012', origin: 'Chicago, IL', dest: 'Miami, FL', refs: ['SO-88203'], eta: '2026-05-28T10:00:00Z', onTime: true, pct: 44, mabd: null, appt: '2026-05-28T09:00:00Z', pallets: 3, cartons: 11, wt: 1320, shipper: 'Midwest Spot Freight Inc.', consignee: 'Port Miami Distribution', carriers: [{ name: 'J.B. Hunt', active: true }] },
{ id: 19, stops: 1, status: 'pickup', bol: 'SPOT-40013', origin: 'Kansas City, MO', dest: 'Tampa, FL', refs: ['SO-88204'], eta: '2026-05-29T08:00:00Z', onTime: true, pct: 12, mabd: null, appt: '2026-05-29T08:00:00Z', pallets: 2, cartons: 7, wt: 690, shipper: 'Heartland Express Co.', consignee: 'Suncoast Wholesale LLC', carriers: [{ name: 'Schneider', active: true }] },
{ id: 20, stops: 3, status: 'order_created', bol: 'NC00000701', origin: 'Los Angeles, CA', dest: 'Boston, MA', refs: ['PO-12241'], eta: null, onTime: null, pct: 0, mabd: null, appt: '2026-06-02T10:00:00Z', pallets: 5, cartons: 21, wt: 2750, shipper: 'Pacific Rim Logistics', consignee: 'New England DC', carriers: [{ name: 'Old Dominion', active: true }, { name: 'XPO Logistics', active: false }, { name: 'Estes Express', active: false }] }];


/* ─── Status map ─────────────────────────────────────────────────────────────── */
const STATUS_MAP = {
  draft: { label: 'Draft', cls: 'st-draft' },
  order_created: { label: 'Order Created', cls: 'st-order_created' },
  pickup: { label: 'Pickup', cls: 'st-pickup' },
  in_transit: { label: 'In Transit', cls: 'st-in_transit' },
  out_for_delivery: { label: 'Out for Delivery', cls: 'st-out_for_delivery' },
  delivered: { label: 'Delivered', cls: 'st-delivered' },
  billing: { label: 'Billing', cls: 'st-billing' },
  invoiced: { label: 'Invoiced', cls: 'st-invoiced' }
};

/* Warehouse view collapses the broker pipeline into 4 operational states.
   getWarehouseStatusKey returns the key for any row; iteration order in the
   map drives both the dropdown order and the status-filter pills. */
const WAREHOUSE_STATUS_MAP = {
  needs_bol:        { label: 'Needs BOL',        cls: 'st-order_created' },
  ready_for_pickup: { label: 'Ready for Pickup', cls: 'st-pickup' },
  picked_up:        { label: 'Picked Up',        cls: 'st-in_transit' },
  exception:        { label: 'Exception',        cls: 'st-exception' }
};

const getWarehouseStatusKey = (r) => {
  if (r.isDelayed || r.isEarly || r.exception) return 'exception';
  if (r.isDraft || r.status === 'draft' || r.status === 'order_created') return 'needs_bol';
  if (r.status === 'pickup') return 'ready_for_pickup';
  return 'picked_up';
};

/* Synthesized driver + carrier info for the warehouse driver chip. Deterministic
   per row.id so the same row always shows the same driver across renders. */
const WH_DRIVERS = [
  'Mark Allen', 'Sarah Chen', 'Diego Rivera', 'Priya Shah',
  'Tyler Bell', 'Wen Liu', 'Lucia Romero', 'Owen Pak',
  'Jamal King', 'Bea Costa', 'Hugo Reyes', 'Noah Park'
];
const WH_CARRIERS = [
  { name: 'VEI Transport',     short: 'VEI' },
  { name: 'NSF Logistics',     short: 'NSF' },
  { name: 'Klear Freight',     short: 'KLR' },
  { name: 'Trex Hauling',      short: 'TRX' },
  { name: 'Westar Lines',      short: 'WST' },
  { name: 'Cardinal Carriers', short: 'CDN' }
];
const getDriverInfo = (row) => {
  // Hash the row id (string or number) so draft rows like "D-1042" don't all
  // collapse to NaN → 0 and end up showing the same driver.
  const seed = String(row.id == null ? '' : row.id)
    .split('')
    .reduce((a, c) => (a * 31 + c.charCodeAt(0)) >>> 0, 0);
  const driver = WH_DRIVERS[seed % WH_DRIVERS.length];
  const firstName = driver.split(' ')[0];
  const carrier = WH_CARRIERS[seed % WH_CARRIERS.length];
  // Stable but varied 7-digit-ish license / 4-digit truck #.
  const license = 'CA-D' + String(1000000 + (seed * 8431 % 8999999)).padStart(7, '0');
  const truck   = 'T-'   + String(1000    + (seed * 433  % 9000)).padStart(4, '0');
  return { driver, firstName, carrier: carrier.name, carrierShort: carrier.short, license, truck };
};

/* ─── Draft rows (parsed-from-document shipments awaiting review) ─────────────────
   Built from the shared review dataset so the table count and the review queue
   always match. Clicking a draft row opens the full-screen review flow. */
const DRAFT_ROWS = (window.FREIGHT_DRAFTS || []).map((d) => {
  const getF = (k) => {
    for (const s of d.sections || []) {
      const f = (s.fields || []).find((x) => x.key === k);
      if (f) return f.value != null ? f.value : f.current;
    }
    return null;
  };
  return {
    id: d.id, isDraft: true, stops: 0, status: 'draft', bol: d.bol,
    origin: d.origin, dest: d.dest, refs: [d.bol],
    eta: null, onTime: null, pct: 0, mabd: null, appt: null,
    pallets: getF('pallets'), cartons: getF('cartons'),
    wt: parseInt(String(getF('weight')).replace(/,/g, ''), 10) || 0,
    shipper: d.shipper, consignee: d.consignee, carriers: []
  };
});
// Prepend drafts so they surface at the top of the table.
FREIGHT_DATA.unshift(...DRAFT_ROWS);

/* ─── Billing issue map ──────────────────────────────────────────────────────── */
const BILLING_ISSUE_MAP = {
  no_pod: { label: 'No POD', icon: 'M9 12h6m-6 4h6m2 5H7a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5.586a1 1 0 0 1 .707.293l5.414 5.414a1 1 0 0 1 .293.707V19a2 2 0 0 1-2 2z', colorVar: '--bad' },
  awaiting_charges: { label: 'Awaiting Final Charges', icon: 'M12 8v4m0 4h.01M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z', colorVar: '--warn' }
};

/* ─── Persona detection ──────────────────────────────────────────────────────── */
const IS_WAREHOUSE = typeof window !== 'undefined' && /warehouse/i.test(window.location.pathname);

/* ─── Filter categories ──────────────────────────────────────────────────────── */
const FILTER_CATS_BROKER = [
{ key: 'en_route', label: 'En Route', sub: 'Pickup through delivery', statuses: ['pickup', 'in_transit', 'out_for_delivery'], icon: 'truck' },
{ key: 'delayed_early', label: 'Delayed / Early', sub: 'Off-schedule shipments', filter: (r) => r.isDelayed || r.isEarly, icon: 'clock' },
{ key: 'billing', label: 'Billing', sub: 'Awaiting bill resolution', statuses: ['billing'], icon: 'receipt' },
{ key: 'invoiced', label: 'Invoiced', sub: 'Fully processed', statuses: ['invoiced'], icon: 'checkCircle' }];

const FILTER_CATS_WAREHOUSE = [
{ key: 'needs_bol', label: 'Needs BOL', sub: 'Create BOL for shipments', filter: (r) => r.draft || r.status === 'order_created', icon: 'bol' },
{ key: 'awaiting_pickup', label: 'Awaiting Pickup', sub: 'Driver & carrier ETA', statuses: ['pickup'], icon: 'clock' },
{ key: 'departed', label: 'Departed', sub: 'Released to carrier', statuses: ['in_transit', 'out_for_delivery'], icon: 'truck' },
{ key: 'exception', label: 'Exception', sub: 'Something went wrong', filter: (r) => r.isDelayed || r.isEarly || r.exception, icon: 'alert' }];

const FILTER_CATS = IS_WAREHOUSE ? FILTER_CATS_WAREHOUSE : FILTER_CATS_BROKER;
const STATUS_MAP_VIEW = IS_WAREHOUSE ? WAREHOUSE_STATUS_MAP : STATUS_MAP;


/* ─── Helpers ────────────────────────────────────────────────────────────────── */
const fmtDateMed = (iso) => !iso ? '\u2014' : new Date(iso).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });
const fmtDateTimeSh = (iso) => !iso ? '\u2014' : new Date(iso).toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });

/* ─── Icons ──────────────────────────────────────────────────────────────────── */
const Ico = {
  truck: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect x="1" y="6" width="14" height="11" rx="1" /><path d="M15 9h4l3 4v4h-7" /><circle cx="6" cy="19" r="2" /><circle cx="18" cy="19" r="2" /></svg>,
  clock: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /><path d="M12 6v6l4 2" /></svg>,
  receipt: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1z" /><path d="M16 8H8M16 12H8M12 16H8" /></svg>,
  checkCircle: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" /><path d="m9 11 3 3L22 4" /></svg>,
  search: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>,
  plus: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M12 5v14M5 12h14" /></svg>,
  download: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" /><path d="m7 10 5 5 5-5M12 15V3" /></svg>,
  more: <svg viewBox="0 0 24 24" fill="currentColor"><circle cx="5" cy="12" r="1.5" /><circle cx="12" cy="12" r="1.5" /><circle cx="19" cy="12" r="1.5" /></svg>,
  bell: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" /><path d="M13.73 21a2 2 0 0 1-3.46 0" /></svg>,
  close: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg>,
  filter: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18" /><path d="M7 12h10" /><path d="M11 18h6" /></svg>,
  bulkActions: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="5" width="4" height="4" rx="1" /><path d="M10 7h11" /><rect x="3" y="11" width="4" height="4" rx="1" /><path d="M10 13h11" /><rect x="3" y="17" width="4" height="4" rx="1" /><path d="M10 19h11" /></svg>
};

/* Extra icons not in broker shell */
const FreightIco = {
  receipt: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M4 2v20l2-1 2 1 2-1 2 1 2-1 2 1 2-1 2 1V2l-2 1-2-1-2 1-2-1-2 1-2-1-2 1z" /><path d="M16 8H8M16 12H8M12 16H8" /></svg>,
  checkCircle: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 11.08V12a10 10 0 1 1-5.93-9.14" /><path d="m9 11 3 3L22 4" /></svg>
};



/* ─── Filter Cards ───────────────────────────────────────────────────────────── */
function FilterCards({ activeFilter, setActiveFilter, data }) {
  const counts = useMemo(() => {
    const c = {};
    FILTER_CATS.forEach((cat) => {
      c[cat.key] = cat.filter ?
      data.filter(cat.filter).length :
      data.filter((r) => cat.statuses.includes(r.status)).length;
    });
    return c;
  }, [data]);

  const iconMap = {
    truck: Ico.truck,
    clock: Ico.clock,
    receipt: FreightIco.receipt,
    checkCircle: FreightIco.checkCircle,
    bol: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" /><path d="M14 2v6h6" /><path d="M9 13h6M9 17h4" /></svg>,
    alert: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" /><path d="M12 9v4M12 17h.01" /></svg>
  };

  return (
    <div className="filter-cards">
      {FILTER_CATS.map((cat) => {
        const active = activeFilter === cat.key;
        return (
          <div
            key={cat.key}
            className={`fcard${active ? ' is-active' : ''}`}
            onClick={() => setActiveFilter(active ? null : cat.key)}>
            
            <div className="fcard-icon">{iconMap[cat.icon]}</div>
            <div className="fcard-body">
              <div className="fcard-title">{cat.label}</div>
              <div className="fcard-sub">{cat.sub}</div>
            </div>
            <div className="fcard-count">{counts[cat.key]}</div>
          </div>);

      })}
    </div>);

}

/* ─── Status Multi-Select ────────────────────────────────────────────────────── */
function StatusMultiSelect({ value, onChange }) {
  const [open, setOpen] = useState(false);
  const ref = React.useRef(null);

  React.useEffect(() => {
    if (!open) return;
    const handler = (e) => {if (ref.current && !ref.current.contains(e.target)) setOpen(false);};
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  const statuses = Object.entries(STATUS_MAP_VIEW);
  const allSelected = value.length === 0;

  const toggle = (key) => {
    onChange(value.includes(key) ? value.filter((v) => v !== key) : [...value, key]);
  };

  const label = allSelected ?
  'Status — All' :
  value.length === 1 ?
  STATUS_MAP_VIEW[value[0]].label :
  `Status — ${value.length} selected`;

  return (
    <div className="ms-wrap" ref={ref}>
      <button
        className={`select-ctl ms-trigger${!allSelected ? ' ms-active' : ''}`}
        onClick={() => setOpen((o) => !o)}
        type="button">
        
        {label}
      </button>
      {open &&
      <div className="ms-dropdown">
          <div
          className={`ms-option ms-all-row${allSelected ? ' is-checked' : ''}`}
          onClick={() => {onChange([]);setOpen(false);}}>
          
            <span className="ms-check">{allSelected ? '✓' : ''}</span>
            All Statuses
          </div>
          <div className="ms-sep"></div>
          {statuses.map(([key, s]) => {
          const checked = value.includes(key);
          return (
            <div key={key} className={`ms-option${checked ? ' is-checked' : ''}`} onClick={() => toggle(key)}>
                <span className="ms-check">{checked ? '✓' : ''}</span>
                <span className={`status-badge ${s.cls}`}>{s.label}</span>
              </div>);

        })}
        </div>
      }
    </div>);

}

/* ─── Auto-Archive Settings ──────────────────────────────────────────────────── */
function AutoArchiveSettings() {
  const [open, setOpen] = useState(false);
  const wrapRef = useRef(null);
  const [enabled, setEnabled] = useState(() => {
    try { return JSON.parse(localStorage.getItem('freight_autoArchiveEnabled') || 'true'); }
    catch { return true; }
  });
  const [days, setDays] = useState(() => {
    try { return parseInt(localStorage.getItem('freight_autoArchiveDays') || '90', 10); }
    catch { return 90; }
  });

  useEffect(() => { localStorage.setItem('freight_autoArchiveEnabled', JSON.stringify(enabled)); }, [enabled]);
  useEffect(() => { localStorage.setItem('freight_autoArchiveDays', String(days)); }, [days]);

  useEffect(() => {
    if (!open) return;
    const handler = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', handler);
    return () => document.removeEventListener('mousedown', handler);
  }, [open]);

  const opts = [
    { value: 30, label: '30 days', sub: null },
    { value: 90, label: '90 days', sub: null },
    { value: 180, label: '180 days', sub: null },
    { value: 365, label: '365 days', sub: null }
  ];

  return (
    <div ref={wrapRef} style={{ position: 'relative', display: 'inline-flex' }}>
      <button
        className="btn-ico-sm"
        onClick={() => setOpen((o) => !o)}
        title="Auto-archive settings"
        style={open ? { borderColor: 'var(--ink-2)', color: 'var(--ink)', background: 'var(--line-2)' } : {}}>
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" /><circle cx="12" cy="12" r="3" /></svg>
      </button>
      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 6px)', right: 0,
          background: 'var(--panel)', border: '1px solid var(--line)',
          borderRadius: 12, boxShadow: '0 8px 28px rgba(20,18,29,.14)',
          width: 290, zIndex: 100, overflow: 'hidden'
        }}>
          {/* Header */}
          <div style={{ padding: '13px 16px 11px', borderBottom: '1px solid var(--line-2)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="var(--ink-2)" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                <polyline points="21 8 21 21 3 21 3 8" /><rect x="1" y="3" width="22" height="5" rx="1" /><line x1="10" y1="12" x2="14" y2="12" />
              </svg>
              <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.012em' }}>Auto-archive</span>
            </div>
            <button onClick={() => setOpen(false)} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--muted)', padding: 3, display: 'flex', borderRadius: 5, transition: 'color 100ms' }}
              onMouseEnter={(e) => e.currentTarget.style.color = 'var(--ink)'}
              onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted)'}>
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
            </button>
          </div>

          {/* Toggle row */}
          <div style={{ padding: '12px 16px', display: 'flex', alignItems: 'center', justifyContent: 'space-between', borderBottom: '1px solid var(--line-2)' }}>
            <span style={{ fontSize: 13, color: 'var(--ink)', fontWeight: 500 }}>Auto-archive delivered</span>
            <button className={`toggle${enabled ? ' is-on' : ''}`} onClick={() => setEnabled((e) => !e)} type="button" />
          </div>

          {/* Day options */}
          <div style={{ padding: '10px 8px', opacity: enabled ? 1 : 0.38, pointerEvents: enabled ? 'auto' : 'none', transition: 'opacity 150ms' }}>
            <div style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.065em', padding: '2px 8px 8px' }}>
              Archive after
            </div>
            {opts.map((opt) => {
              const active = days === opt.value;
              return (
                <div key={opt.value} onClick={() => setDays(opt.value)} style={{
                  display: 'flex', alignItems: 'center', gap: 10,
                  padding: '7px 10px', borderRadius: 8, cursor: 'pointer',
                  background: active ? 'var(--tint)' : 'transparent',
                  transition: 'background 100ms'
                }}>
                  <div style={{
                    width: 16, height: 16, borderRadius: '50%', flexShrink: 0,
                    border: `2px solid ${active ? 'var(--ink)' : 'var(--line)'}`,
                    display: 'flex', alignItems: 'center', justifyContent: 'center',
                    transition: 'border-color 120ms'
                  }}>
                    {active && <div style={{ width: 8, height: 8, borderRadius: '50%', background: 'var(--ink)' }} />}
                  </div>
                  <span style={{ fontSize: 13, color: active ? 'var(--ink)' : 'var(--ink-2)', fontWeight: active ? 600 : 400, transition: 'color 120ms' }}>
                    {opt.label}
                  </span>
                  {opt.sub && <span style={{ fontSize: 11, color: 'var(--muted)', fontWeight: 400 }}>{opt.sub}</span>}
                </div>
              );
            })}
          </div>

          {/* Footer */}
          <div style={{ padding: '10px 16px 13px', borderTop: '1px solid var(--line-2)' }}>
            <div style={{ fontSize: 12, color: 'var(--muted)', lineHeight: 1.5 }}>
              {enabled
                ? <>Delivered shipments will move to archive after <strong style={{ color: 'var(--ink-2)', fontWeight: 600 }}>{days} days</strong>.</>
                : 'Enable to automatically archive delivered shipments after a set period.'}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ─── Filter Bar ─────────────────────────────────────────────────────────────── */
function FilterBar({ searchQ, setSearchQ, statusFilter, setStatusFilter, archived, setArchived, selectedCount, onClear, bulkMode, onToggleBulk, onArchive, onRestoreBulk }) {
  return (
    <div className="filter-bar">
      {selectedCount > 0 ?
      <>
          <div className="bulk-label"><span className="bulk-n">{selectedCount}</span> selected</div>
          <button className="clear-sel-btn" onClick={onClear}>Clear</button>
          <div className="fb-spacer" />
          <button className="btn-ghost btn-sm">Export</button>
          <button className="btn-ghost btn-sm">{Ico.download} Download</button>
          {archived ?
        <button className="btn-ghost btn-sm" onClick={onRestoreBulk}>Restore</button> :
        <button className="btn-ghost btn-sm" onClick={onArchive}>Archive</button>
        }

        </> :

      <>
          <div className="search">
            <div className="search-ico">{Ico.search}</div>
            <input
            placeholder="Search BOL, reference, shipper…"
            value={searchQ}
            onChange={(e) => setSearchQ(e.target.value)} />
          
          </div>
          <StatusMultiSelect value={statusFilter} onChange={setStatusFilter} />
          <button
          className={`btn-ghost btn-ico-sm${bulkMode ? ' btn-bulk-active' : ''}`}
          onClick={onToggleBulk}
          aria-label="Bulk actions"
          title="Bulk actions">
          
            {Ico.bulkActions}
          </button>

          <div className="fb-spacer" />
          <label className="toggle-wrap">
            <button
            className={`toggle${archived ? ' is-on' : ''}`}
            onClick={() => setArchived((a) => !a)}
            type="button" />
          
            Archived shipments
          </label>
          <AutoArchiveSettings />
          <button className="btn-primary btn-sm btn-add-shipment">
            <span className="btn-ico-lg">{Ico.plus}</span>
            <span className="btn-label-nowrap">Add Shipment</span>
          </button>
        </>
      }
    </div>);

}

/* ─── Status Badge ───────────────────────────────────────────────────────────── */
function StatusBadge({ status, row }) {
  // Warehouse view: derive the operational status from the row, not the raw
  // shipment.status field, so the column label matches the filter chips above.
  if (IS_WAREHOUSE && row) {
    const key = getWarehouseStatusKey(row);
    const s = WAREHOUSE_STATUS_MAP[key];
    return <span className={`status-badge ${s.cls}`}>{s.label}</span>;
  }
  const s = STATUS_MAP[status] || { label: status, cls: '' };
  return <span className={`status-badge ${s.cls}`}>{s.label}</span>;
}

/* ─── Driver Chip (warehouse) ─────────────────────────────────────────────────
   Replaces the stops/carrier line on warehouse rows. Click opens a small
   popover with the driver's license, full name, carrier, and truck number.
   When row.awaitingDriver is true, renders an "Assign driver" pending chip
   with a small Assign action inside the popover. */
function DriverChip({ row }) {
  const [open, setOpen] = useState(false);
  const wrapRef = React.useRef(null);
  const info = React.useMemo(() => getDriverInfo(row), [row.id]);
  const awaiting = !!row.awaitingDriver;

  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false); };
    const onKey = (e) => { if (e.key === 'Escape') setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    document.addEventListener('keydown', onKey);
    return () => {
      document.removeEventListener('mousedown', onDoc);
      document.removeEventListener('keydown', onKey);
    };
  }, [open]);

  if (awaiting) {
    return (
      <span className="driver-chip-wrap" ref={wrapRef}>
        <button
          type="button"
          className={`driver-chip is-awaiting${open ? ' is-open' : ''}`}
          title="Awaiting driver assignment"
          onClick={(e) => { e.stopPropagation(); setOpen((o) => !o); }}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" width="11" height="11" aria-hidden="true">
            <circle cx="12" cy="12" r="9" />
            <path d="M12 7v5l3 2" />
          </svg>
          <span>Awaiting driver</span>
        </button>
        {open &&
        <div className="driver-pop" role="dialog" onClick={(e) => e.stopPropagation()}>
          <div className="driver-pop-head">
            <div className="driver-pop-name">Awaiting driver assignment</div>
            <div className="driver-pop-carrier">No driver assigned yet</div>
          </div>
          <div className="driver-pop-rows">
            <div className="driver-pop-row">
              <span className="driver-pop-lbl">Carrier</span>
              <span className="driver-pop-val" style={{ fontFamily: 'inherit' }}>
                {row.carriers && row.carriers[0] ? row.carriers[0].name : '\u2014'}
              </span>
            </div>
            <div className="driver-pop-row">
              <span className="driver-pop-lbl">Pickup</span>
              <span className="driver-pop-val">{fmtDateTimeSh(row.appt)}</span>
            </div>
          </div>
          <button
            type="button"
            className="driver-pop-assign"
            onClick={(e) => { e.stopPropagation(); setOpen(false); }}>
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.9" strokeLinecap="round" strokeLinejoin="round" width="12" height="12" aria-hidden="true">
              <path d="M12 5v14M5 12h14" />
            </svg>
            Assign driver
          </button>
        </div>
        }
      </span>);
  }

  return (
    <span className="driver-chip-wrap" ref={wrapRef}>
      <button
        type="button"
        className={`driver-chip${open ? ' is-open' : ''}`}
        title={`${info.driver} · ${info.carrier}`}
        onClick={(e) => { e.stopPropagation(); setOpen((o) => !o); }}>
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round" width="11" height="11" aria-hidden="true">
          <circle cx="12" cy="8" r="3.2" />
          <path d="M5 20c1.5-3.5 4-5 7-5s5.5 1.5 7 5" />
        </svg>
        <span>{info.firstName} &middot; {info.carrierShort}</span>
      </button>
      {open &&
      <div className="driver-pop" role="dialog" onClick={(e) => e.stopPropagation()}>
        <div className="driver-pop-head">
          <div className="driver-pop-name">{info.driver}</div>
          <div className="driver-pop-carrier">{info.carrier}</div>
        </div>
        <div className="driver-pop-rows">
          <div className="driver-pop-row">
            <span className="driver-pop-lbl">License</span>
            <span className="driver-pop-val">{info.license}</span>
          </div>
          <div className="driver-pop-row">
            <span className="driver-pop-lbl">Truck #</span>
            <span className="driver-pop-val">{info.truck}</span>
          </div>
        </div>
      </div>
      }
    </span>);
}

/* ─── Billing Pipeline ───────────────────────────────────────────────────────── */
function BillingPipeline({ row }) {
  const issues = row.billingIssues || [];
  const isInvoiced = row.status === 'invoiced';

  const podDone = isInvoiced || !issues.includes('no_pod');
  const chargesDone = isInvoiced || !issues.includes('awaiting_charges');
  const completedCount = (podDone ? 1 : 0) + (chargesDone ? 1 : 0);

  const headerLabel = isInvoiced ? 'Invoiced' :
  !podDone && !chargesDone ? 'Awaiting POD & Charges' :
  !podDone ? 'Awaiting POD' :
  !chargesDone ? 'Awaiting Charges' :
  'Ready to Invoice';

  const tasks = [
  { key: 'pod', label: 'POD', done: podDone },
  { key: 'charges', label: 'Charges', done: chargesDone }];


  const segColor = (t) => t.done ?
  'var(--good)' :
  t.key === 'pod' ? 'var(--bad)' : 'var(--warn)';

  const labelColor = (t) => t.done ?
  'var(--ink-2)' :
  t.key === 'pod' ? 'var(--bad)' : 'var(--warn)';

  if (isInvoiced) {
    return (
      <div style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
        <div style={{
          width: 18, height: 18, borderRadius: '50%',
          background: 'var(--good)', display: 'flex',
          alignItems: 'center', justifyContent: 'center', flexShrink: 0
        }}>
          <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
            <path d="m20 6-11 11-5-5" />
          </svg>
        </div>
        <span style={{ fontSize: 12, color: 'var(--good)', fontWeight: 500, letterSpacing: '-0.01em' }}>Completed</span>
      </div>);
  }

  return (
    <div style={{ minWidth: 190 }}>
      {/* Header row */}
      <div style={{ marginBottom: 5 }}>
        <span style={{ fontSize: 12, color: 'var(--ink)', letterSpacing: '-0.01em', whiteSpace: 'nowrap', fontWeight: "400" }}>
          {headerLabel}
        </span>
      </div>

      {/* Segmented bar */}
      <div style={{ display: 'flex', gap: 2 }}>
        {tasks.map((t) =>
        <div key={t.key} style={{
          flex: 1, height: 4, borderRadius: 99,
          background: segColor(t),
          transition: 'background 200ms'
        }} />
        )}
      </div>

      {/* Labels */}
      <div style={{ display: 'flex', marginTop: 4 }}>
        {tasks.map((t) =>
        <div key={t.key} style={{
          flex: 1,
          fontSize: 9.5,
          color: labelColor(t),
          letterSpacing: '0.055em', textTransform: 'uppercase',
          lineHeight: 1, fontWeight: "500"
        }}>
            {t.label}
          </div>
        )}
      </div>
    </div>);

}

/* ─── ETA Cell ───────────────────────────────────────────────────────────────── */
function EtaCell({ row }) {
  const isBillingStage = ['billing', 'invoiced'].includes(row.status);
  const isDelivered = row.status === 'delivered';
  const isOrdered = row.status === 'order_created';
  const isDelayed = !!row.isDelayed;
  const isEarly = !!row.isEarly;
  const isEarlyWarn = isEarly && !!(row.mabd || row.appt);

  // Warehouse: once the shipment has been released to the carrier, the
  // warehouse's job is done. Show a finished progress bar with a "Picked up"
  // timestamp instead of an in-transit ETA / billing pipeline.
  if (IS_WAREHOUSE && getWarehouseStatusKey(row) === 'picked_up') {
    const pickupBase = new Date('2026-05-27T07:00:00Z').getTime();
    const seed = String(row.id == null ? '' : row.id)
      .split('')
      .reduce((a, c) => (a * 31 + c.charCodeAt(0)) >>> 0, 0);
    const pickupISO = new Date(pickupBase + (seed * 7 % 72) * 3600 * 1000).toISOString();
    return (
      <div className="eta-cell">
        <div className="eta-line is-good" style={{ fontWeight: 500 }}>
          <span>Picked up {fmtDateTimeSh(pickupISO)}</span>
        </div>
        <div className="progress-track is-done" style={{ marginTop: 6 }}>
          <div className="progress-fill" style={{ width: '100%' }}></div>
          <span className="progress-end-check" aria-hidden="true">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round" width="10" height="10"><path d="m20 6-11 11-5-5" /></svg>
          </span>
        </div>
      </div>);
  }

  if (row.status === 'draft') {
    return (
      <div className="eta-cell">
        <div className="eta-line is-warn" style={{ fontWeight: 500 }}>
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z" /><path d="M4 22v-7" /></svg>
          Needs review
        </div>
        <div className="eta-sub">Parsed from document</div>
      </div>);
  }

  if (isOrdered) {
    return (
      <div className="eta-cell">
        <div className="eta-line muted-txt">ETA Pending</div>
        <div className="progress-track"><div className="progress-fill" style={{ width: '0%' }}></div></div>
      </div>);

  }

  if (isBillingStage) {
    return (
      <div className="eta-cell">
        <BillingPipeline row={row} />
      </div>);

  }

  if (isDelivered) {
    return (
      <div className="eta-cell">
        <div className="eta-line is-good">
          <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="m20 6-11 11-5-5" /></svg>
          Delivered
        </div>
      </div>);

  }

  return (
    <div className="eta-cell">
      <div className={`eta-line${isDelayed ? ' is-bad' : isEarlyWarn ? ' is-warn' : isEarly ? ' is-good' : ''}`}>
        <span>ETA {fmtDateTimeSh(row.eta)}</span>
        {isDelayed && <span className="eta-late-tag">late</span>}
        {isEarly && <span className={`eta-early-tag${isEarlyWarn ? ' is-warn' : ''}`}>early</span>}
      </div>
      {!IS_WAREHOUSE && <div className="eta-sub">{row.pct}% complete</div>}
      <div className="progress-track" style={IS_WAREHOUSE ? { marginTop: 6 } : undefined}>
        <div className={`progress-fill${isDelayed ? ' is-bad' : isEarlyWarn ? ' is-warn' : ''}`} style={{ width: `${row.pct}%` }}></div>
      </div>
    </div>);

}

/* ─── Column defs ────────────────────────────────────────────────────────────── */
const COLS = [
{ key: 'status', label: 'Status', sortable: true, filterType: 'set' },
{ key: 'bol', label: 'BOL #', sortable: true, filterType: 'text' },
{ key: 'route', label: 'Route', sortable: true, filterType: 'text' },
{ key: 'ref', label: 'Reference #', sortable: true, filterType: 'text' },
{ key: 'eta', label: 'ETA / Progress', sortable: true, filterType: null },
{ key: 'mabd', label: 'MABD & Appt', sortable: true, filterType: 'date' },
{ key: 'info', label: 'Info', sortable: false, filterType: null },
{ key: 'shipper', label: 'Shipper', sortable: true, filterType: 'set' },
{ key: 'consignee', label: 'Consignee', sortable: true, filterType: 'set' }];


/* ─── Set filter option lists ────────────────────────────────────────────────── */
const SET_OPTIONS = {
  status: Object.keys(STATUS_MAP_VIEW).map((k) => ({ value: k, label: STATUS_MAP_VIEW[k].label })),
  shipper: [...new Set(FREIGHT_DATA.map((r) => r.shipper))].sort().map((v) => ({ value: v, label: v })),
  consignee: [...new Set(FREIGHT_DATA.map((r) => r.consignee))].sort().map((v) => ({ value: v, label: v }))
};

function isColFilterActive(f, filterType) {
  if (!f) return false;
  if (filterType === 'text') return !!(f.value && f.value.trim());
  if (filterType === 'date') return !!f.date1;
  if (filterType === 'set') return !!(f.selected && f.selected.length > 0);
  return false;
}

/* ─── Copy Cell ──────────────────────────────────────────────────────────────── */
function CopyCell({ value, className }) {
  const [copied, setCopied] = useState(false);
  const [cellHover, setCellHover] = useState(false);
  const [btnHover, setBtnHover] = useState(false);
  const timerRef = useRef(null);

  const handleCopy = (e) => {
    e.stopPropagation();
    // Flip to confirmed state immediately (don't wait on promise)
    setCopied(true);
    clearTimeout(timerRef.current);
    timerRef.current = setTimeout(() => setCopied(false), 1800);
    // Best-effort clipboard write with execCommand fallback
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(value).catch(() => {});
    } else {
      try {
        const ta = document.createElement('textarea');
        ta.value = value;ta.style.cssText = 'position:fixed;opacity:0';
        document.body.appendChild(ta);ta.select();
        document.execCommand('copy');
        document.body.removeChild(ta);
      } catch (_) {}
    }
  };

  const btnColor = copied ? 'var(--good)' : btnHover ? 'var(--ink)' : 'var(--muted)';
  const btnBorderColor = copied ? 'var(--good)' : btnHover ? 'var(--ink-2)' : 'var(--line)';
  const btnBg = copied ? 'color-mix(in oklab, var(--good) 12%, var(--panel))' : 'var(--panel)';

  return (
    <span
      style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}
      onMouseEnter={() => setCellHover(true)}
      onMouseLeave={() => {setCellHover(false);setBtnHover(false);}}>
      
      <span className={className}>{value}</span>
      <button
        onClick={handleCopy}
        title={copied ? 'Copied!' : 'Copy'}
        onMouseEnter={() => setBtnHover(true)}
        onMouseLeave={() => setBtnHover(false)}
        style={{
          display: 'inline-flex',
          alignItems: 'center',
          justifyContent: 'center',
          width: 22,
          height: 22,
          padding: 0,
          border: '1px solid',
          borderColor: btnBorderColor,
          borderRadius: 5,
          background: btnBg,
          color: btnColor,
          cursor: 'pointer',
          flexShrink: 0,
          transition: 'opacity 120ms, color 150ms, border-color 150ms, background 150ms',
          opacity: cellHover || copied ? 1 : 0,
          pointerEvents: cellHover || copied ? 'auto' : 'none'
        }}>
        
        {copied ?
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round"><path d="m20 6-11 11-5-5" /></svg> :
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>
        }
      </button>
    </span>);

}

/* ─── Ref Cell ───────────────────────────────────────────────────────────────── */
function RefCell({ refs }) {
  const [expanded, setExpanded] = useState(false);
  const [copiedAll, setCopiedAll] = useState(false);
  const copyAllTimer = useRef(null);
  const CUTOFF = 2;
  const visible = !expanded && refs.length > CUTOFF ? refs.slice(0, CUTOFF) : refs;
  const hiddenCount = refs.length - CUTOFF;
  const toggleStyle = {
    background: 'none', border: 'none', padding: '1px 0',
    fontFamily: 'var(--mono)', fontSize: 11, color: 'var(--muted)',
    cursor: 'pointer', textAlign: 'left', letterSpacing: '-0.01em',
    lineHeight: 1.4
  };

  const handleCopyAll = (e) => {
    e.stopPropagation();
    const text = refs.join('\n');
    setCopiedAll(true);
    clearTimeout(copyAllTimer.current);
    copyAllTimer.current = setTimeout(() => setCopiedAll(false), 1800);
    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).catch(() => {});
    } else {
      try {
        const ta = document.createElement('textarea');
        ta.value = text;ta.style.cssText = 'position:fixed;opacity:0';
        document.body.appendChild(ta);ta.select();
        document.execCommand('copy');
        document.body.removeChild(ta);
      } catch (_) {}
    }
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
      {visible.map((ref, i) =>
      <CopyCell key={i} value={ref} className="ref-cell" />
      )}
      {!expanded && hiddenCount > 0 &&
      <button onClick={(e) => {e.stopPropagation();setExpanded(true);}} style={toggleStyle}>
          +{hiddenCount} more
        </button>
      }
      {expanded && refs.length > CUTOFF &&
      <button onClick={(e) => {e.stopPropagation();setExpanded(false);}} style={toggleStyle}>
          show less
        </button>
      }
      {refs.length > 1 && expanded &&
      <button onClick={handleCopyAll} style={{
        ...toggleStyle,
        color: copiedAll ? 'var(--good)' : 'var(--muted)',
        display: 'inline-flex', alignItems: 'center', gap: 4,
        transition: 'color 150ms'
      }}>
        {copiedAll ?
        <><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.6" strokeLinecap="round" strokeLinejoin="round"><path d="m20 6-11 11-5-5" /></svg>Copied</> :
        <><svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" /><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1" /></svg>Copy all</>
        }
      </button>
      }
    </div>);

}

/* ─── Billing Issue Flags ────────────────────────────────────────────────────── */
function BillingIssueFlags({ issues }) {
  if (!issues || issues.length === 0) return null;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 4, marginTop: 6 }}>
      {issues.map((key) => {
        const def = BILLING_ISSUE_MAP[key];
        if (!def) return null;
        return (
          <span key={key} style={{
            display: 'inline-flex', alignItems: 'center', gap: 5,
            padding: '2px 7px 2px 5px',
            borderRadius: 5,
            background: `color-mix(in oklab, var(${def.colorVar}) 12%, transparent)`,
            border: `1px solid color-mix(in oklab, var(${def.colorVar}) 30%, transparent)`,
            color: `var(${def.colorVar})`,
            fontSize: 11, fontWeight: 600, letterSpacing: '0.01em',
            whiteSpace: 'nowrap', width: 'fit-content'
          }}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
              <path d={def.icon} />
            </svg>
            {def.label}
          </span>);

      })}
    </div>);

}

/* ─── Freight Row ────────────────────────────────────────────────────────────── */
function FreightRow({ row, checked, onCheck, isArchived, onRestore }) {
  const isDelayed = !!row.isDelayed;
  const mabdPast = !!row.isDelayed;

  return (
    <tr
      className={`${checked ? 'is-checked' : ''} ${isDelayed ? 'is-exception' : ''} ${row.billingIssues && row.billingIssues.length > 0 ? 'is-billing-issue' : ''} ${row.isDraft ? 'is-draft' : ''}`}
      style={{ cursor: 'default' }}>
      <td className="col-check" onClick={(e) => e.stopPropagation()}>
        <input type="checkbox" checked={checked} onChange={() => onCheck(row.id)} />
      </td>

      {/* 1 Status */}
      <td style={{ width: 140 }}>
        <StatusBadge status={row.status} row={row} />
      </td>

      {/* 2 BOL# */}
      <td>
        {IS_WAREHOUSE && getWarehouseStatusKey(row) === 'needs_bol' ? (
          <button
            type="button"
            className="btn-create-bol"
            onClick={(e) => {
              e.stopPropagation();
              window.location.href = row.status === 'draft'
                ? `Freight Review.html?id=${encodeURIComponent(row.id)}`
                : `Freight detail page (Warehouse).html?bol=${encodeURIComponent(row.bol)}`;
            }}>
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" width="12" height="12" aria-hidden="true"><path d="M12 5v14M5 12h14" /></svg>
            Create BOL
          </button>
        ) : (
          <CopyCell value={row.bol} className="bol-no" />
        )}
      </td>

      {/* 3 Route */}
      <td className="route-cell">
        <div className="route-top">
          <span className="route-place">{row.origin}</span>
          <span className="route-arrow">&rarr;</span>
          <span className="route-place">{row.dest}</span>
        </div>
        <div className="route-stops">
          {IS_WAREHOUSE ? (
            <DriverChip row={row} />
          ) : (
            <>
              <span>
                {row.stops === 0 ?
                'No stops' :
                row.stops === 1 ?
                '1 stop' :
                `${row.stops} stops`}
              </span>
              {row.carriers && row.carriers.length > 0 && (() => {
                const active = row.carriers.find((c) => c.active) || row.carriers[0];
                const extra = row.carriers.filter((c) => c !== active);
                return (
                  <>
                    <span className="route-stops-sep">·</span>
                    <span className="route-carrier-name">{active.name}</span>
                    {extra.length > 0 &&
                    <span className="route-carrier-more" title={extra.map((c) => c.name).join(', ')}>
                        +{extra.length}
                      </span>
                    }
                  </>);

              })()}
            </>
          )}
        </div>
      </td>

      {/* 4 Reference# */}
      <td><RefCell refs={row.refs} /></td>

      {/* 5 ETA / Progress */}
      <td>
        <EtaCell row={row} />
      </td>

      {/* 6 MABD & Appt */}
      <td className="date-cell">
        {(!IS_WAREHOUSE || row.mabd) && (
          <div className="date-block">
            <span className="date-lbl">MABD</span>
            {row.mabd ?
            <span className={`date-val${mabdPast ? ' date-bad' : ''}`}>{fmtDateMed(row.mabd)}</span> :
            <span className="date-val" style={{ color: 'var(--muted)', fontStyle: 'normal' }}>-</span>
            }
          </div>
        )}
        <div className="date-block" style={{ marginTop: IS_WAREHOUSE && !row.mabd ? 0 : 5 }}>
          <span className="date-lbl">Appt</span>
          <span className="date-val">{fmtDateTimeSh(row.appt)}</span>
        </div>
      </td>

      {/* 7 Info */}
      <td className="info-cell">
        <div className="info-row"><span className="num">{row.pallets}</span>&nbsp;pallets</div>
        <div className="info-row"><span className="num">{row.cartons}</span>&nbsp;cartons</div>
        <div className="info-row"><span className="num">{row.wt.toLocaleString()}</span>&nbsp;lbs</div>
      </td>

      {/* 8 Shipper */}
      <td className="company-cell"><div className="cname">{row.shipper}</div></td>

      {/* 9 Consignee */}
      <td className="company-cell"><div className="cname">{row.consignee}</div></td>

      {/* Actions */}
      <td style={{ width: isArchived ? 80 : 34, textAlign: 'center' }}>
        {isArchived &&
        <button
          onClick={(e) => {e.stopPropagation();onRestore(row.id);}}
          style={{
            padding: '4px 10px', borderRadius: 7,
            border: '1px solid var(--line)', background: 'transparent',
            fontFamily: 'var(--font)', fontSize: 12, fontWeight: 500,
            color: 'var(--ink-2)', cursor: 'pointer',
            display: 'inline-flex', alignItems: 'center', gap: 5,
            transition: 'all 120ms', whiteSpace: 'nowrap'
          }}
          onMouseEnter={(e) => {e.currentTarget.style.background = 'var(--line-2)';e.currentTarget.style.borderColor = 'var(--ink-2)';e.currentTarget.style.color = 'var(--ink)';}}
          onMouseLeave={(e) => {e.currentTarget.style.background = 'transparent';e.currentTarget.style.borderColor = 'var(--line)';e.currentTarget.style.color = 'var(--ink-2)';}}>
            <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
              <path d="M3 3v5h5" />
            </svg>
            Restore
          </button>
        }
      </td>
    </tr>);

}

/* ─── Archived Empty State ───────────────────────────────────────────────────── */
function ArchivedEmptyState({ onBack, hasFilters, onClearFilters, archivedCount }) {
  // Show filter-specific state whenever filters are active, regardless of archived count
  const isFiltered = hasFilters;
  const hasArchived = archivedCount > 0;

  const heading = isFiltered ? 'No archived shipments found' : 'No archived shipments';

  const subtext = isFiltered ?
  hasArchived ?
  `${archivedCount} archived shipment${archivedCount !== 1 ? 's' : ''} exist${archivedCount === 1 ? 's' : ''}, but none match your current filters.` :
  'No archived shipments match your current filters.' :
  'Shipments you archive will appear here. None have been archived yet.';

  return (
    <tr>
      <td colSpan={12} style={{ padding: 0, border: 0 }}>
        <div style={{
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          padding: '72px 24px 80px', gap: 0
        }}>
          {/* Icon */}
          <div style={{
            width: 60, height: 60, borderRadius: 18,
            background: isFiltered ? 'color-mix(in oklab, var(--accent) 18%, var(--line-2))' : 'var(--line-2)',
            display: 'grid', placeItems: 'center',
            color: isFiltered ? 'var(--ink-2)' : 'var(--muted)', marginBottom: 22,
            transition: 'background 200ms'
          }}>
            {isFiltered ?
            <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.45" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M22 3H2l8 9.46V19l4 2v-8.54L22 3z" />
                  <line x1="18" y1="18" x2="22" y2="22" strokeWidth="1.8" />
                  <circle cx="18" cy="18" r="4" strokeWidth="1.6" />
                </svg> :
            <svg width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.45" strokeLinecap="round" strokeLinejoin="round">
                  <polyline points="21 8 21 21 3 21 3 8" />
                  <rect x="1" y="3" width="22" height="5" rx="1" />
                  <line x1="10" y1="12" x2="14" y2="12" />
                </svg>
            }
          </div>

          {/* Heading */}
          <div style={{ fontSize: 16, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.022em', marginBottom: 7 }}>
            {heading}
          </div>

          {/* Sub */}
          <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: 24, textAlign: 'center', maxWidth: 340, lineHeight: 1.6 }}>
            {subtext}
          </div>

          {/* CTAs */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            {isFiltered &&
            <button
              onClick={onClearFilters}
              style={{
                display: 'inline-flex', alignItems: 'center', gap: 7,
                padding: '8px 18px', borderRadius: 9,
                background: 'var(--ink)', color: 'var(--panel)',
                border: 'none', fontFamily: 'var(--font)', fontSize: 13,
                fontWeight: 600, cursor: 'pointer', letterSpacing: '-0.01em',
                transition: 'background 120ms'
              }}
              onMouseEnter={(e) => e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 82%, transparent)'}
              onMouseLeave={(e) => e.currentTarget.style.background = 'var(--ink)'}>
                <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M18 6 6 18M6 6l12 12" />
                </svg>
                Clear all filters
              </button>
            }
            <button
              onClick={onBack}
              style={{
                display: 'inline-flex', alignItems: 'center', gap: 7,
                padding: '8px 18px', borderRadius: 9,
                background: isFiltered ? 'transparent' : 'var(--ink)',
                color: isFiltered ? 'var(--ink-2)' : 'var(--panel)',
                border: isFiltered ? '1px solid var(--line)' : 'none',
                fontFamily: 'var(--font)', fontSize: 13,
                fontWeight: isFiltered ? 500 : 600,
                cursor: 'pointer', letterSpacing: '-0.01em',
                transition: 'all 120ms'
              }}
              onMouseEnter={(e) => {
                if (isFiltered) {e.currentTarget.style.background = 'var(--line-2)';e.currentTarget.style.borderColor = 'var(--ink-2)';e.currentTarget.style.color = 'var(--ink)';} else
                e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 82%, transparent)';
              }}
              onMouseLeave={(e) => {
                if (isFiltered) {e.currentTarget.style.background = 'transparent';e.currentTarget.style.borderColor = 'var(--line)';e.currentTarget.style.color = 'var(--ink-2)';} else
                e.currentTarget.style.background = 'var(--ink)';
              }}>
              <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
                <path d="M19 12H5M12 5l-7 7 7 7" />
              </svg>
              View active shipments
            </button>
          </div>
        </div>
      </td>
    </tr>);

}

/* ─── Archive Modal ──────────────────────────────────────────────────────────── */
function ArchiveModal({ count, onConfirm, onCancel }) {
  // Close on Escape
  useEffect(() => {
    const handler = (e) => {if (e.key === 'Escape') onCancel();};
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [onCancel]);

  return ReactDOM.createPortal(
    <div
      onClick={onCancel}
      style={{
        position: 'fixed', inset: 0, zIndex: 10000,
        background: 'rgba(20,18,29,.42)',
        backdropFilter: 'blur(3px)', WebkitBackdropFilter: 'blur(3px)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: 24
      }}>
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: 'var(--panel)', border: '1px solid var(--line)',
          borderRadius: 16, boxShadow: '0 20px 60px rgba(20,18,29,.22)',
          width: 400, maxWidth: '100%', padding: '28px 28px 24px',
          display: 'flex', flexDirection: 'column', gap: 0
        }}>
        {/* Icon */}
        <div style={{
          width: 48, height: 48, borderRadius: 14,
          background: 'var(--line-2)', display: 'grid', placeItems: 'center',
          color: 'var(--ink-2)', marginBottom: 18, flexShrink: 0
        }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
            <polyline points="21 8 21 21 3 21 3 8" />
            <rect x="1" y="3" width="22" height="5" rx="1" />
            <line x1="10" y1="12" x2="14" y2="12" />
          </svg>
        </div>
        {/* Heading */}
        <div style={{ fontSize: 17, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.022em', marginBottom: 8 }}>
          Archive {count} shipment{count !== 1 ? 's' : ''}?
        </div>
        {/* Body */}
        <div style={{ fontSize: 13.5, color: 'var(--muted)', lineHeight: 1.6, marginBottom: 24 }}>
          {count === 1 ? 'This shipment' : `These ${count} shipments`} will be moved to your archive. You can view and restore {count === 1 ? 'it' : 'them'} at any time by toggling <strong style={{ color: 'var(--ink-2)', fontWeight: 600 }}>Archived shipments</strong> in the filter bar.
        </div>
        {/* Actions */}
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button
            onClick={onCancel}
            style={{
              padding: '9px 18px', borderRadius: 9, border: '1px solid var(--line)',
              background: 'transparent', fontFamily: 'var(--font)', fontSize: 13,
              fontWeight: 500, color: 'var(--ink)', cursor: 'pointer',
              transition: 'background 120ms, border-color 120ms'
            }}
            onMouseEnter={(e) => {e.currentTarget.style.background = 'var(--line-2)';e.currentTarget.style.borderColor = 'var(--ink-2)';}}
            onMouseLeave={(e) => {e.currentTarget.style.background = 'transparent';e.currentTarget.style.borderColor = 'var(--line)';}}>
            Cancel
          </button>
          <button
            onClick={onConfirm}
            style={{
              padding: '9px 18px', borderRadius: 9, border: 'none',
              background: 'var(--ink)', fontFamily: 'var(--font)', fontSize: 13,
              fontWeight: 600, color: 'var(--panel)', cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 7,
              transition: 'background 120ms'
            }}
            onMouseEnter={(e) => {e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 82%, transparent)';}}
            onMouseLeave={(e) => {e.currentTarget.style.background = 'var(--ink)';}}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <polyline points="21 8 21 21 3 21 3 8" />
              <rect x="1" y="3" width="22" height="5" rx="1" />
              <line x1="10" y1="12" x2="14" y2="12" />
            </svg>
            Archive
          </button>
        </div>
      </div>
    </div>,
    document.body
  );
}

/* ─── Restore Modal ─────────────────────────────────────────────────────────── */
function RestoreModal({ count, onConfirm, onCancel }) {
  useEffect(() => {
    const handler = (e) => {if (e.key === 'Escape') onCancel();};
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [onCancel]);

  return ReactDOM.createPortal(
    <div
      onClick={onCancel}
      style={{
        position: 'fixed', inset: 0, zIndex: 10000,
        background: 'rgba(20,18,29,.42)',
        backdropFilter: 'blur(3px)', WebkitBackdropFilter: 'blur(3px)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        padding: 24
      }}>
      <div
        onClick={(e) => e.stopPropagation()}
        style={{
          background: 'var(--panel)', border: '1px solid var(--line)',
          borderRadius: 16, boxShadow: '0 20px 60px rgba(20,18,29,.22)',
          width: 400, maxWidth: '100%', padding: '28px 28px 24px',
          display: 'flex', flexDirection: 'column', gap: 0
        }}>
        <div style={{
          width: 48, height: 48, borderRadius: 14,
          background: 'var(--line-2)', display: 'grid', placeItems: 'center',
          color: 'var(--ink-2)', marginBottom: 18, flexShrink: 0
        }}>
          <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
            <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
            <path d="M3 3v5h5" />
          </svg>
        </div>
        <div style={{ fontSize: 17, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.022em', marginBottom: 8 }}>
          Restore {count} shipment{count !== 1 ? 's' : ''}?
        </div>
        <div style={{ fontSize: 13.5, color: 'var(--muted)', lineHeight: 1.6, marginBottom: 24 }}>
          {count === 1 ? 'This shipment' : `These ${count} shipments`} will be moved back to your active shipments list.
        </div>
        <div style={{ display: 'flex', gap: 8, justifyContent: 'flex-end' }}>
          <button
            onClick={onCancel}
            style={{
              padding: '9px 18px', borderRadius: 9, border: '1px solid var(--line)',
              background: 'transparent', fontFamily: 'var(--font)', fontSize: 13,
              fontWeight: 500, color: 'var(--ink)', cursor: 'pointer',
              transition: 'background 120ms, border-color 120ms'
            }}
            onMouseEnter={(e) => {e.currentTarget.style.background = 'var(--line-2)';e.currentTarget.style.borderColor = 'var(--ink-2)';}}
            onMouseLeave={(e) => {e.currentTarget.style.background = 'transparent';e.currentTarget.style.borderColor = 'var(--line)';}}>
            Cancel
          </button>
          <button
            onClick={onConfirm}
            style={{
              padding: '9px 18px', borderRadius: 9, border: 'none',
              background: 'var(--ink)', fontFamily: 'var(--font)', fontSize: 13,
              fontWeight: 600, color: 'var(--panel)', cursor: 'pointer',
              display: 'inline-flex', alignItems: 'center', gap: 7,
              transition: 'background 120ms'
            }}
            onMouseEnter={(e) => {e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 82%, transparent)';}}
            onMouseLeave={(e) => {e.currentTarget.style.background = 'var(--ink)';}}>
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
              <path d="M3 3v5h5" />
            </svg>
            Restore
          </button>
        </div>
      </div>
    </div>,
    document.body
  );
}

/* ─── Empty State ────────────────────────────────────────────────────────────── */
function EmptyState({ activeFilter, statusFilter, searchQ, onClear }) {
  const pills = [];
  if (activeFilter) {
    const cat = FILTER_CATS.find((c) => c.key === activeFilter);
    if (cat) pills.push({ label: cat.label, type: 'card' });
  }
  if (statusFilter.length > 0) {
    statusFilter.forEach((s) => pills.push({ label: STATUS_MAP_VIEW[s]?.label || s, type: 'status' }));
  }
  if (searchQ.trim()) {
    pills.push({ label: `"${searchQ.trim()}"`, type: 'search' });
  }

  return (
    <tr>
      <td colSpan={12} style={{ padding: 0, border: 0 }}>
        <div style={{
          display: 'flex', flexDirection: 'column', alignItems: 'center',
          padding: '64px 24px 72px', gap: 0
        }}>
          {/* Icon */}
          <div style={{
            width: 56, height: 56, borderRadius: 16,
            background: 'var(--line-2)', display: 'grid', placeItems: 'center',
            color: 'var(--muted)', marginBottom: 20
          }}>
            <svg width="26" height="26" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
              <path d="M22 3H2l8 9.46V19l4 2v-8.54L22 3z" />
              <line x1="18" y1="18" x2="22" y2="22" strokeWidth="1.8" />
              <circle cx="18" cy="18" r="4" strokeWidth="1.6" />
            </svg>
          </div>

          {/* Heading */}
          <div style={{ fontSize: 16, fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.02em', marginBottom: 6 }}>
            No shipments found
          </div>

          {/* Sub */}
          <div style={{ fontSize: 13, color: 'var(--muted)', marginBottom: pills.length ? 18 : 24, textAlign: 'center', maxWidth: 340, lineHeight: 1.55 }}>
            No results match your current filters. Try adjusting or clearing them to see shipments.
          </div>

          {/* Active filter pills */}
          {pills.length > 0 &&
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, justifyContent: 'center', marginBottom: 22 }}>
              {pills.map((p, i) =>
            <span key={i} style={{
              display: 'inline-flex', alignItems: 'center', gap: 5,
              padding: '4px 10px', borderRadius: 99,
              background: 'var(--tint)', border: '1px solid color-mix(in oklab, var(--accent) 45%, var(--line))',
              fontSize: 12, fontWeight: 500, color: 'var(--ink-2)',
              fontFamily: p.type === 'search' ? 'var(--mono)' : 'inherit'
            }}>
                  {p.type === 'card' && <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><rect x="1" y="6" width="14" height="11" rx="1" /><path d="M15 9h4l3 4v4h-7" /></svg>}
                  {p.type === 'status' && <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="10" /></svg>}
                  {p.type === 'search' && <svg width="11" height="11" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><circle cx="11" cy="11" r="8" /><path d="m21 21-4.3-4.3" /></svg>}
                  {p.label}
                </span>
            )}
            </div>
          }

          {/* CTA */}
          <button
            onClick={onClear}
            style={{
              display: 'inline-flex', alignItems: 'center', gap: 7,
              padding: '8px 18px', borderRadius: 9,
              background: 'var(--ink)', color: 'var(--panel)',
              border: 'none', fontFamily: 'var(--font)', fontSize: 13,
              fontWeight: 600, cursor: 'pointer', letterSpacing: '-0.01em',
              transition: 'background 120ms'
            }}
            onMouseEnter={(e) => e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 82%, transparent)'}
            onMouseLeave={(e) => e.currentTarget.style.background = 'var(--ink)'}>
            
            <svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
              <path d="M18 6 6 18M6 6l12 12" />
            </svg>
            Clear filters
          </button>
        </div>
      </td>
    </tr>);

}

/* ─── Back To Top ────────────────────────────────────────────────────────────── */
function BackToTop({ scrollRef }) {
  const [visible, setVisible] = useState(false);

  useEffect(() => {
    const el = scrollRef.current;
    if (!el) return;
    const onScroll = () => {
      const nearBottom = el.scrollTop + el.clientHeight >= el.scrollHeight - 120;
      setVisible(nearBottom);
    };
    el.addEventListener('scroll', onScroll, { passive: true });
    return () => el.removeEventListener('scroll', onScroll);
  }, [scrollRef]);

  const scrollToTop = () => {
    scrollRef.current && scrollRef.current.scrollTo({ top: 0, behavior: 'smooth' });
  };

  return (
    <button
      onClick={scrollToTop}
      aria-label="Back to top"
      style={{
        position: 'fixed',
        bottom: 32,
        right: 36,
        zIndex: 999,
        display: 'flex',
        alignItems: 'center',
        gap: 7,
        padding: '9px 16px 9px 13px',
        background: 'var(--ink)',
        color: 'var(--panel)',
        border: 'none',
        borderRadius: 99,
        fontSize: 13,
        fontWeight: 600,
        fontFamily: 'var(--font)',
        cursor: 'pointer',
        boxShadow: '0 4px 20px rgba(20,18,29,.22)',
        letterSpacing: '-0.01em',
        opacity: visible ? 1 : 0,
        transform: visible ? 'translateY(0)' : 'translateY(10px)',
        pointerEvents: visible ? 'auto' : 'none',
        transition: 'opacity 200ms, transform 200ms, background 120ms'
      }}
      onMouseEnter={(e) => e.currentTarget.style.background = 'color-mix(in oklab, var(--ink) 80%, transparent)'}
      onMouseLeave={(e) => e.currentTarget.style.background = 'var(--ink)'}>
      
      <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M12 19V5M5 12l7-7 7 7" />
      </svg>
      Back to top
    </button>);

}

/* ─── Column Filter Popup ────────────────────────────────────────────────────── */
function ColFilterPopup({ colKey, filterType, filter, onChange, onClose, anchorEl }) {
  const popupRef = useRef(null);
  const [local, setLocal] = useState(() => {
    if (filter) return filter;
    if (filterType === 'text') return { mode: 'contains', value: '' };
    if (filterType === 'date') return { mode: 'between', date1: '', date2: '' };
    if (filterType === 'set') return { selected: [] };
    return {};
  });
  const [setSearch, setSetSearch] = useState('');
  const [pos, setPos] = useState({ top: 0, left: 0, width: 230 });

  useEffect(() => {
    if (!anchorEl) return;
    const r = anchorEl.getBoundingClientRect();
    const w = filterType === 'set' ? 220 : 230;
    let left = r.left;
    if (left + w > window.innerWidth - 8) left = window.innerWidth - w - 8;
    setPos({ top: r.bottom + 5, left: Math.max(8, left), width: w });
  }, [anchorEl, filterType]);

  useEffect(() => {
    const handler = (e) => {
      if (!popupRef.current) return;
      if (popupRef.current.contains(e.target)) return;
      if (anchorEl && anchorEl.contains(e.target)) return;
      onClose();
    };
    const t = setTimeout(() => document.addEventListener('mousedown', handler), 0);
    return () => {clearTimeout(t);document.removeEventListener('mousedown', handler);};
  }, [onClose, anchorEl]);

  const apply = () => {
    const empty = filterType === 'text' ? !local.value?.trim() :
    filterType === 'date' ? !local.date1 :
    filterType === 'set' ? local.selected.length === 0 :
    true;
    onChange(empty ? null : local);
    onClose();
  };
  const clear = () => {onChange(null);onClose();};

  const inputSt = {
    width: '100%', padding: '6px 10px', height: 32, boxSizing: 'border-box',
    background: 'var(--bg)', border: '1px solid var(--line)', borderRadius: 7,
    fontFamily: 'var(--font)', fontSize: 12.5, color: 'var(--ink)', outline: 'none'
  };
  const btnSt = (primary) => ({
    flex: 1, padding: '7px 0', fontFamily: 'var(--font)', fontSize: 12.5, fontWeight: 600,
    cursor: 'pointer', borderRadius: 7, border: primary ? 'none' : '1px solid var(--line)',
    background: primary ? 'var(--ink)' : 'transparent',
    color: primary ? 'var(--panel)' : 'var(--ink)',
    transition: 'background 100ms'
  });

  const opts = SET_OPTIONS[colKey] || [];
  const visibleOpts = setSearch ? opts.filter((o) => o.label.toLowerCase().includes(setSearch.toLowerCase())) : opts;

  const toggleVal = (v) => setLocal((f) => ({
    ...f, selected: f.selected.includes(v) ? f.selected.filter((x) => x !== v) : [...f.selected, v]
  }));

  const Chk = ({ checked }) =>
  <div style={{
    width: 14, height: 14, borderRadius: 4, flexShrink: 0,
    border: `1.5px solid ${checked ? '#D4A800' : 'var(--line)'}`,
    background: checked ? '#F5C200' : 'var(--bg)',
    display: 'flex', alignItems: 'center', justifyContent: 'center'
  }}>
      {checked &&
    <svg width="8" height="8" viewBox="0 0 24 24" fill="none" stroke="#3a2e00" strokeWidth="3.5" strokeLinecap="round" strokeLinejoin="round">
          <path d="m20 6-11 11-5-5" />
        </svg>
    }
    </div>;


  const content =
  <div ref={popupRef} style={{
    position: 'fixed', top: pos.top, left: pos.left, width: pos.width,
    background: 'var(--panel)', border: '1px solid var(--line)',
    borderRadius: 10, boxShadow: '0 8px 28px rgba(0,0,0,.16)',
    zIndex: 9999, overflow: 'hidden'
  }}>
      {/* Header */}
      <div style={{ padding: '9px 12px 8px', borderBottom: '1px solid var(--line-2)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <span style={{ fontSize: 10.5, fontWeight: 700, color: 'var(--muted)', textTransform: 'uppercase', letterSpacing: '0.07em' }}>
          {filterType === 'text' ? 'Text Filter' : filterType === 'date' ? 'Date Filter' : 'Set Filter'}
        </span>
        <button onClick={onClose} style={{ background: 'none', border: 'none', cursor: 'pointer', color: 'var(--muted)', padding: 2, display: 'flex', borderRadius: 4 }}>
          <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.3" strokeLinecap="round" strokeLinejoin="round"><path d="M18 6 6 18M6 6l12 12" /></svg>
        </button>
      </div>

      {/* Body */}
      <div style={{ padding: '10px 12px 12px', display: 'flex', flexDirection: 'column', gap: 7 }}>

        {/* ── Text filter ── */}
        {filterType === 'text' &&
      <>
            <select className="select-ctl" style={{ width: '100%', boxSizing: 'border-box', fontSize: 12.5, height: 32 }}
        value={local.mode} onChange={(e) => setLocal((f) => ({ ...f, mode: e.target.value }))}>
              <option value="contains">Contains</option>
              <option value="equals">Equals</option>
              <option value="startsWith">Starts with</option>
              <option value="endsWith">Ends with</option>
            </select>
            <input style={inputSt} placeholder="Filter value…" value={local.value}
        onChange={(e) => setLocal((f) => ({ ...f, value: e.target.value }))}
        onKeyDown={(e) => e.key === 'Enter' && apply()}
        autoFocus />
          </>
      }

        {/* ── Date filter ── */}
        {filterType === 'date' &&
      <>
            <select className="select-ctl" style={{ width: '100%', boxSizing: 'border-box', fontSize: 12.5, height: 32 }}
        value={local.mode} onChange={(e) => setLocal((f) => ({ ...f, mode: e.target.value, date2: '' }))}>
              <option value="after">After</option>
              <option value="before">Before</option>
              <option value="on">On</option>
              <option value="between">Between</option>
            </select>
            <input type="text" style={inputSt} value={local.date1} placeholder="mm/dd/yyyy" maxLength={10}
        onChange={(e) => {
          const v = e.target.value.replace(/[^\d/]/g, '');
          const auto = v.replace(/^(\d{2})(\d)/, '$1/$2').replace(/^(\d{2}\/\d{2})(\d)/, '$1/$2');
          setLocal((f) => ({ ...f, date1: auto }));
        }} />
            {local.mode === 'between' &&
        <>
                <div style={{ textAlign: 'center', fontSize: 11, color: 'var(--muted)' }}>and</div>
                <input type="text" style={inputSt} value={local.date2 || ''} placeholder="mm/dd/yyyy" maxLength={10}
          onChange={(e) => {
            const v = e.target.value.replace(/[^\d/]/g, '');
            const auto = v.replace(/^(\d{2})(\d)/, '$1/$2').replace(/^(\d{2}\/\d{2})(\d)/, '$1/$2');
            setLocal((f) => ({ ...f, date2: auto }));
          }} />
              </>
        }
          </>
      }

        {/* ── Set filter ── */}
        {filterType === 'set' &&
      <>
            <input style={inputSt} placeholder="Search…" value={setSearch}
        onChange={(e) => setSetSearch(e.target.value)} autoFocus />
            <div style={{ border: '1px solid var(--line-2)', borderRadius: 7, overflow: 'hidden' }}>
              {/* All row */}
              <div style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '5px 10px', cursor: 'pointer', borderBottom: '1px solid var(--line-2)', background: local.selected.length === 0 ? 'var(--tint)' : 'transparent' }}
          onClick={() => setLocal((f) => ({ ...f, selected: [] }))}>
                <Chk checked={local.selected.length === 0} />
                <span style={{ fontSize: 12, color: 'var(--ink-2)', fontWeight: 500 }}>All</span>
              </div>
              {/* Option rows */}
              <div style={{ maxHeight: 152, overflowY: 'auto' }}>
                {visibleOpts.map((opt) => {
              const chk = local.selected.includes(opt.value);
              return (
                <div key={opt.value} onClick={() => toggleVal(opt.value)}
                style={{ display: 'flex', alignItems: 'center', gap: 7, padding: '5px 10px', cursor: 'pointer', background: chk ? 'color-mix(in oklab, var(--accent) 8%, var(--panel))' : 'transparent' }}>
                      <Chk checked={chk} />
                      {colKey === 'status' ?
                  <span className={`status-badge ${STATUS_MAP_VIEW[opt.value]?.cls || ''}`} style={{ fontSize: 10.5 }}>{opt.label}</span> :
                  <span style={{ fontSize: 11.5, color: 'var(--ink)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis', maxWidth: 160 }}>{opt.label}</span>
                  }
                    </div>);

            })}
              </div>
            </div>
          </>
      }

        {/* Actions */}
        <div style={{ display: 'flex', gap: 6, marginTop: 2 }}>
          <button style={btnSt(false)} onClick={clear}>Clear</button>
          <button style={btnSt(true)} onClick={apply}>Apply</button>
        </div>
      </div>
    </div>;


  return ReactDOM.createPortal(content, document.body);
}

/* ─── View Switcher ──────────────────────────────────────────────────────────── */
function ViewSwitcher() {
  const [active, setActive] = useState('table');
  const views = [
  { key: 'map',   label: 'Map View',   href: 'Freight Map.html' },
  { key: 'table', label: 'Table View', href: 'Freight Table.html' }];

  return (
    <div style={{
      position: 'fixed', bottom: 28, left: 'calc(50% + 32px)', transform: 'translateX(-50%)',
      zIndex: 1000,
      background: 'color-mix(in oklab, var(--panel) 92%, transparent)',
      border: '1px solid var(--line)',
      borderRadius: 99,
      padding: 4,
      display: 'flex', alignItems: 'center', gap: 2,
      boxShadow: '0 4px 20px rgba(20,18,29,.12), 0 1px 4px rgba(20,18,29,.07)',
      backdropFilter: 'blur(12px)',
      WebkitBackdropFilter: 'blur(12px)'
    }}>
      {views.map((v) => {
        const isActive = active === v.key;
        const baseStyle = {
          padding: '7px 18px',
          borderRadius: 99,
          border: 'none',
          fontFamily: 'var(--font)',
          fontSize: 13,
          fontWeight: isActive ? 600 : 450,
          cursor: 'pointer',
          letterSpacing: '-0.01em',
          textDecoration: 'none',
          display: 'inline-block',
          transition: 'background 150ms, color 150ms, box-shadow 150ms',
          background: isActive ? 'var(--ink)' : 'transparent',
          color: isActive ? 'var(--panel)' : 'var(--ink-2)',
          boxShadow: isActive ? '0 1px 4px rgba(20,18,29,.18)' : 'none'
        };
        if (v.href && !isActive) {
          return <a key={v.key} href={v.href} style={baseStyle}>{v.label}</a>;
        }
        return (
          <button
            key={v.key}
            onClick={() => setActive(v.key)}
            style={baseStyle}>
            {v.label}
          </button>);

      })}
    </div>);

}

/* ─── Skeleton loading state ──────────────────────────────────────────── */
function SkeletonRow({ bulkMode }) {
  return (
    <tr className="is-skel">
      {bulkMode && <td className="col-check"><span className="sk" style={{ width: 14, height: 14, borderRadius: 3, display: 'block' }} /></td>}
      {/* Status */}
      <td><span className="sk sk-pill" style={{ width: 78 }} /></td>
      {/* BOL */}
      <td><span className="sk sk-line" style={{ width: 86 }} /></td>
      {/* Route */}
      <td style={{ minWidth: 280 }}>
        <div className="sk-stack">
          <span className="sk sk-line" style={{ width: '70%' }} />
          <span className="sk sk-line" style={{ width: '40%', height: 9 }} />
        </div>
      </td>
      {/* Ref */}
      <td><span className="sk sk-line" style={{ width: 96 }} /></td>
      {/* ETA / Progress */}
      <td style={{ minWidth: 180 }}>
        <div className="sk-stack">
          <span className="sk sk-line" style={{ width: '60%' }} />
          <span className="sk sk-bar" style={{ marginTop: 2 }} />
        </div>
      </td>
      {/* MABD & Appt */}
      <td style={{ minWidth: 140 }}>
        <div className="sk-stack">
          <span className="sk sk-line" style={{ width: 70, height: 8 }} />
          <span className="sk sk-line" style={{ width: 88 }} />
        </div>
      </td>
      {/* Info */}
      <td style={{ minWidth: 120 }}>
        <div className="sk-stack">
          <span className="sk sk-line" style={{ width: 58 }} />
          <span className="sk sk-line" style={{ width: 44 }} />
        </div>
      </td>
      {/* Shipper */}
      <td><span className="sk sk-line" style={{ width: 130 }} /></td>
      {/* Consignee */}
      <td><span className="sk sk-line" style={{ width: 130 }} /></td>
      {/* Actions */}
      <td><span className="sk" style={{ width: 16, height: 16, borderRadius: 4, display: 'block' }} /></td>
    </tr>
  );
}

function SkeletonFilterCards() {
  return (
    <div className="filter-cards">
      {[0, 1, 2, 3].map((i) => (
        <div key={i} className="fcard" style={{ cursor: 'default' }}>
          <span className="sk" style={{ width: 44, height: 44, borderRadius: 12, display: 'block' }} />
          <div className="fcard-body sk-stack">
            <span className="sk sk-line" style={{ width: '70%' }} />
            <span className="sk sk-line" style={{ width: '40%', height: 9 }} />
          </div>
          <span className="sk sk-num" />
        </div>
      ))}
    </div>
  );
}

/* ─── App ────────────────────────────────────────────────────────────────────── */
function App() {
  const { useTweaks, TweaksPanel, TweakSection, TweakToggle, TweakRadio } = window;
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const confidenceMode = tweaks.confidenceMode || 'all-review';
  const showEmptyState = !!tweaks.showEmptyState;
  const showSkeleton = !!tweaks.showSkeleton;
  const allHighConfidence = confidenceMode === 'all-high';
  const mixedConfidence = confidenceMode === 'mixed';
  const HIGH_CONFIDENCE_COUNT = 3;

  const scrollRef = useRef(null);
  const [activeFilter, setActiveFilter] = useState(null);
  const [searchQ, setSearchQ] = useState('');
  const [statusFilter, setStatusFilter] = useState([]);
  const [archived, setArchived] = useState(false);
  const [selected, setSelected] = useState(new Set());
  const [sortKey, setSortKey] = useState(null);
  const [sortDir, setSortDir] = useState('asc');
  const [bulkMode, setBulkMode] = useState(false);
  const [colFilters, setColFilters] = useState({});
  const [activeFilterColKey, setActiveFilterColKey] = useState(null);
  const filterIconRefs = useRef({});
  const selectAllRef = useRef(null);
  const [archivedIds, setArchivedIds] = useState(() => {
    try {return new Set(JSON.parse(localStorage.getItem('freight_archivedIds') || '[]'));}
    catch {return new Set();}
  });
  const [archiveModal, setArchiveModal] = useState(false);
  const [restoreModal, setRestoreModal] = useState(false);

  useEffect(() => {
    localStorage.setItem('freight_archivedIds', JSON.stringify([...archivedIds]));
  }, [archivedIds]);

  const filtered = useMemo(() => {
    // Start with archived or active slice
    let data = archived ?
    FREIGHT_DATA.filter((r) => archivedIds.has(r.id)) :
    FREIGHT_DATA.filter((r) => !archivedIds.has(r.id));

    if (activeFilter) {
      const cat = FILTER_CATS.find((c) => c.key === activeFilter);
      if (cat) data = cat.filter ? data.filter(cat.filter) : data.filter((r) => cat.statuses.includes(r.status));
    }

    if (statusFilter.length > 0) {
      data = IS_WAREHOUSE
        ? data.filter((r) => statusFilter.includes(getWarehouseStatusKey(r)))
        : data.filter((r) => statusFilter.includes(r.status));
    }

    if (searchQ.trim()) {
      const q = searchQ.trim().toLowerCase();
      data = data.filter((r) =>
      r.bol.toLowerCase().includes(q) ||
      r.refs.some((ref) => ref.toLowerCase().includes(q)) ||
      r.shipper.toLowerCase().includes(q) ||
      r.consignee.toLowerCase().includes(q) ||
      r.origin.toLowerCase().includes(q) ||
      r.dest.toLowerCase().includes(q)
      );
    }

    // Column-level filters
    Object.entries(colFilters).forEach(([key, f]) => {
      if (!f) return;
      const col = COLS.find((c) => c.key === key);
      if (!col || !col.filterType) return;

      if (col.filterType === 'text') {
        const val = (f.value || '').toLowerCase().trim();
        if (!val) return;
        data = data.filter((r) => {
          let cell = '';
          if (key === 'bol') cell = r.bol;else
          if (key === 'route') cell = `${r.origin} ${r.dest}`;else
          if (key === 'ref') cell = r.refs.join(' ');else
          if (key === 'shipper') cell = r.shipper;else
          if (key === 'consignee') cell = r.consignee;else
          cell = String(r[key] || '');
          cell = cell.toLowerCase();
          if (f.mode === 'contains') return cell.includes(val);
          if (f.mode === 'equals') return cell === val;
          if (f.mode === 'startsWith') return cell.startsWith(val);
          if (f.mode === 'endsWith') return cell.endsWith(val);
          return true;
        });
      }

      if (col.filterType === 'date') {
        if (!f.date1) return;
        const parseMDY = (s) => {const [m, d, y] = (s || '').split('/');return m && d && y ? new Date(+y, +m - 1, +d) : null;};
        const d1 = parseMDY(f.date1);
        if (!d1 || isNaN(d1)) return;
        const d2raw = parseMDY(f.date2);
        const d2 = d2raw && !isNaN(d2raw) ? new Date(d2raw.getFullYear(), d2raw.getMonth(), d2raw.getDate(), 23, 59, 59) : null;
        data = data.filter((r) => {
          const raw = key === 'eta' ? r.eta : key === 'mabd' ? r.mabd : null;
          if (!raw) return false;
          const d = new Date(raw);
          if (f.mode === 'after') return d > d1;
          if (f.mode === 'before') return d < d1;
          if (f.mode === 'on') return d.toDateString() === d1.toDateString();
          if (f.mode === 'between') return d2 ? d >= d1 && d <= d2 : d >= d1;
          return true;
        });
      }

      if (col.filterType === 'set') {
        if (!f.selected || f.selected.length === 0) return;
        data = data.filter((r) => {
          if (key === 'status') return f.selected.includes(IS_WAREHOUSE ? getWarehouseStatusKey(r) : r.status);
          if (key === 'shipper') return f.selected.includes(r.shipper);
          if (key === 'consignee') return f.selected.includes(r.consignee);
          return true;
        });
      }
    });

    const issuePriority = (r) => r.status === 'draft' ? 3 : r.isDelayed ? 2 : r.billingIssues && r.billingIssues.length > 0 ? 1 : 0;

    const sortable = [...data];
    sortable.sort((a, b) => {
      // Default (no column chosen): issues first
      if (!sortKey) return issuePriority(b) - issuePriority(a);

      // Issues always bubble above non-issues as a tiebreaker
      const issueCmp = issuePriority(b) - issuePriority(a);

      let av, bv;
      if (sortKey === 'route') {av = a.origin;bv = b.origin;} else
      if (sortKey === 'eta') {av = a.eta || '';bv = b.eta || '';} else
      if (sortKey === 'mabd') {av = a.mabd || '';bv = b.mabd || '';} else
      if (sortKey === 'ref') {av = a.refs[0] ?? '';bv = b.refs[0] ?? '';} else
      {av = a[sortKey] ?? '';bv = b[sortKey] ?? '';}
      const cmp = String(av).localeCompare(String(bv), undefined, { numeric: true });
      return sortDir === 'asc' ? cmp : -cmp;
    });
    return sortable;
  }, [activeFilter, searchQ, statusFilter, sortKey, sortDir, colFilters, archived, archivedIds]);

  const toggleSort = (key) => {
    if (sortKey === key) setSortDir((d) => d === 'asc' ? 'desc' : 'asc');else
    {setSortKey(key);setSortDir('asc');}
  };

  const toggleRow = (id) => setSelected((s) => {const n = new Set(s);n.has(id) ? n.delete(id) : n.add(id);return n;});
  const toggleAll = () => setSelected((s) => s.size === filtered.length ? new Set() : new Set(filtered.map((r) => r.id)));

  const handleArchiveConfirm = () => {
    setArchivedIds((prev) => new Set([...prev, ...selected]));
    setSelected(new Set());
    setBulkMode(false);
    setArchiveModal(false);
  };
  const handleRestore = (id) => {
    setArchivedIds((prev) => {const n = new Set(prev);n.delete(id);return n;});
  };
  const handleRestoreConfirm = () => {
    setArchivedIds((prev) => {const n = new Set(prev);selected.forEach((id) => n.delete(id));return n;});
    setSelected(new Set());
    setBulkMode(false);
    setRestoreModal(false);
  };

  useEffect(() => {
    if (!selectAllRef.current) return;
    const noneSelected = selected.size === 0;
    const allSelected = filtered.length > 0 && selected.size === filtered.length;
    selectAllRef.current.indeterminate = !noneSelected && !allSelected;
  }, [selected, filtered]);
  const onToggleBulk = () => {setBulkMode((m) => !m);setSelected(new Set());};

  const hasActiveFilters = activeFilter || statusFilter.length > 0 || searchQ.trim() || Object.values(colFilters).some((f) => !!f);
  const clearAllFilters = () => {setActiveFilter(null);setStatusFilter([]);setSearchQ('');setColFilters({});};

  const [reviewedToast, setReviewedToast] = useState(() => new URLSearchParams(location.search).get('reviewed') === 'all');

  return (
    <>
    <div className="app">
      <BrokerSidebar active="freight" />
      <div ref={scrollRef} style={{ display: 'flex', flexDirection: 'column', minWidth: 0, overflowY: 'auto', height: '100vh' }}>
        <BrokerTopbar crumbs={[]} title="Freight" />
        <style>{`.topbar:has(~ .ft-tabstrip) { border-bottom: 0; }`}</style>
        <div className="ft-tabstrip" style={{ background: 'var(--panel)', borderBottom: '1px solid var(--line)', padding: '0 28px', display: 'flex', gap: 0 }}>
          <span style={{
                padding: '8px 18px',
                fontFamily: 'var(--font)', fontSize: 13.5,
                fontWeight: 600, color: 'var(--ink)', letterSpacing: '-0.01em',
                borderBottom: '2px solid var(--ink)', marginBottom: -1
              }}>
            General Cargo
          </span>
          <a href="Container.html" style={{
                padding: '8px 18px', textDecoration: 'none',
                fontFamily: 'var(--font)', fontSize: 13.5,
                fontWeight: 400, color: 'var(--muted)', cursor: 'pointer',
                letterSpacing: '-0.01em',
                borderBottom: '2px solid transparent', marginBottom: -1,
                transition: 'color 120ms'
              }} onMouseEnter={(e) => e.currentTarget.style.color = 'var(--ink-2)'}
              onMouseLeave={(e) => e.currentTarget.style.color = 'var(--muted)'}>
            Container
          </a>
        </div>
        <div className="canvas">

        {showSkeleton ? (
          /* ── Skeleton loading state ───────────────── */
          <>
          <SkeletonFilterCards />

          <FilterBar
              searchQ={searchQ} setSearchQ={setSearchQ}
              statusFilter={statusFilter} setStatusFilter={setStatusFilter}
              archived={archived} setArchived={setArchived}
              selectedCount={selected.size}
              onClear={() => {setSelected(new Set());setBulkMode(false);}}
              bulkMode={bulkMode}
              onToggleBulk={onToggleBulk}
              onArchive={() => selected.size > 0 && setArchiveModal(true)}
              onRestoreBulk={() => selected.size > 0 && setRestoreModal(true)} />

          <div className="table-pane">
            <div className="table-pane-head">
              <span className="count"><span className="sk sk-line" style={{ width: 90, height: 10 }} /></span>
              <div className="spacer" />
            </div>
            <div className="table-pane-body">
              <table className={`freight${bulkMode ? ' bulk-mode' : ''}`}>
                <thead>
                  <tr>
                    <th className="col-check"></th>
                    {COLS.map((col) => (
                      <th key={col.key} className="no-sort">
                        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, whiteSpace: 'nowrap' }}>{col.label}</span>
                      </th>
                    ))}
                    <th style={{ width: 34 }}></th>
                  </tr>
                </thead>
                <tbody>
                  {Array.from({ length: 9 }).map((_, i) => (
                    <SkeletonRow key={i} bulkMode={bulkMode} />
                  ))}
                </tbody>
              </table>
            </div>
            <div className="table-footer">
              <span className="sk sk-line" style={{ width: 110, height: 10 }} />
            </div>
          </div>
          </>
        ) : showEmptyState ? (
          /* ── Empty state: no shipments yet ─────────────────── */
          <div style={{
            background: 'transparent', border: 'none',
            borderRadius: 'var(--radius)', boxShadow: 'none',
            display: 'flex', flexDirection: 'column', alignItems: 'center',
            justifyContent: 'center', padding: '120px 24px 140px',
            minHeight: 520
          }}>
            {/* Icon cluster */}
            <div style={{ position: 'relative', width: 48, height: 48, marginBottom: 20 }}>
              {/* Box / package */}
              <svg width="36" height="36" viewBox="0 0 24 24" fill="none" stroke="var(--line)" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round" style={{ position: 'absolute', left: 0, top: 6 }}>
                <path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
                <polyline points="3.27 6.96 12 12.01 20.73 6.96" />
                <line x1="12" y1="22.08" x2="12" y2="12" />
              </svg>
              {/* Small X circle */}
              <div style={{
                position: 'absolute', right: 0, top: 0,
                width: 20, height: 20, borderRadius: '50%',
                background: 'var(--line)', display: 'flex',
                alignItems: 'center', justifyContent: 'center',
                border: '2px solid var(--panel)'
              }}>
                <svg width="9" height="9" viewBox="0 0 24 24" fill="none" stroke="var(--muted)" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round">
                  <path d="M18 6 6 18M6 6l12 12" />
                </svg>
              </div>
            </div>
            <div style={{ fontSize: 15, fontWeight: 600, color: 'var(--muted)', letterSpacing: '-0.01em', marginBottom: 6 }}>
              No Shipments yet
            </div>
            <div style={{ fontSize: 13.5, color: 'color-mix(in oklab, var(--muted) 80%, transparent)', marginBottom: 24 }}>
              Add shipment to track it here.
            </div>
            <button style={{
              display: 'inline-flex', alignItems: 'center', gap: 8,
              padding: '10px 22px', borderRadius: 9,
              background: 'var(--panel)', color: 'var(--ink)',
              border: '1px solid var(--line)', fontFamily: 'var(--font)',
              fontSize: 14, fontWeight: 500, cursor: 'pointer',
              letterSpacing: '-0.005em', transition: 'all 120ms'
            }}
            onMouseEnter={(e) => { e.currentTarget.style.borderColor = 'var(--ink-2)'; e.currentTarget.style.background = 'var(--line-2)'; }}
            onMouseLeave={(e) => { e.currentTarget.style.borderColor = 'var(--line)'; e.currentTarget.style.background = 'var(--panel)'; }}>
              Add Shipment
              <svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
                <path d="M12 5v14M5 12h14" />
              </svg>
            </button>
          </div>
        ) : <>

        <FilterCards activeFilter={activeFilter} setActiveFilter={setActiveFilter} data={archived ? FREIGHT_DATA.filter((r) => archivedIds.has(r.id)) : FREIGHT_DATA.filter((r) => !archivedIds.has(r.id))} />

        <FilterBar
              searchQ={searchQ} setSearchQ={setSearchQ}
              statusFilter={statusFilter} setStatusFilter={setStatusFilter}
              archived={archived} setArchived={setArchived}
              selectedCount={selected.size}
              onClear={() => {setSelected(new Set());setBulkMode(false);}}
              bulkMode={bulkMode}
              onToggleBulk={onToggleBulk}
              onArchive={() => selected.size > 0 && setArchiveModal(true)}
              onRestoreBulk={() => selected.size > 0 && setRestoreModal(true)} />
            

        <div className="table-pane">
          <div className="table-pane-head">
            <span className="count">
              {archived ?
                  <span style={{ display: 'inline-flex', alignItems: 'center', gap: 6 }}>
                    <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><polyline points="21 8 21 21 3 21 3 8" /><rect x="1" y="3" width="22" height="5" rx="1" /><line x1="10" y1="12" x2="14" y2="12" /></svg>
                    Archived
                  </span> :
                  <>
                    {filtered.length} shipment{filtered.length !== 1 ? 's' : ''}
                    {activeFilter ? <span style={{ marginLeft: 6, color: 'var(--muted)' }}>&middot; filtered</span> : null}
                  </>
                  }
            </span>
            <div className="spacer" />
            {Object.values(colFilters).some((f) => !!f) && (() => {
                  const activeCount = Object.values(colFilters).filter((f) => !!f).length;
                  return (
                    <button
                      onClick={() => setColFilters({})}
                      style={{
                        display: 'inline-flex', alignItems: 'center', gap: 5,
                        padding: '4px 10px', borderRadius: 7,
                        background: 'color-mix(in oklab, var(--accent) 18%, var(--panel))',
                        border: '1px solid color-mix(in oklab, var(--accent) 55%, var(--line))',
                        color: 'var(--ink)', fontSize: 12, fontWeight: 600,
                        fontFamily: 'var(--font)', cursor: 'pointer',
                        transition: 'all 120ms'
                      }}
                      onMouseEnter={(e) => {e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 32%, var(--panel))';e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--accent) 80%, var(--line))';}}
                      onMouseLeave={(e) => {e.currentTarget.style.background = 'color-mix(in oklab, var(--accent) 18%, var(--panel))';e.currentTarget.style.borderColor = 'color-mix(in oklab, var(--accent) 55%, var(--line))';}}>
                      
                  <svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round">
                    <path d="M18 6 6 18M6 6l12 12" />
                  </svg>
                  Clear {activeCount} column filter{activeCount !== 1 ? 's' : ''}
                </button>);

                })()}
          </div>

          <div className="table-pane-body">
            <table className={`freight${bulkMode ? ' bulk-mode' : ''}`}>
              <thead>
                <tr>
                  <th className="col-check">
                    <input
                          ref={selectAllRef}
                          type="checkbox"
                          checked={filtered.length > 0 && selected.size === filtered.length}
                          onChange={toggleAll} />
                        
                  </th>
                  {COLS.map((col) => {
                        const filterActive = isColFilterActive(colFilters[col.key], col.filterType);
                        return (
                          <th
                            key={col.key}
                            className={[
                            col.sortable ? 'sortable' : 'no-sort',
                            sortKey === col.key ? 'is-sorted' : ''].
                            filter(Boolean).join(' ')}
                            onClick={() => col.sortable && toggleSort(col.key)}>
                            
                        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 3, whiteSpace: 'nowrap' }}>
                          {col.label}
                          {col.sortable &&
                              <span className="sort-ind">
                              {sortKey === col.key ? sortDir === 'asc' ? ' \u2191' : ' \u2193' : ' \u2195'}
                            </span>
                              }
                          {col.filterType &&
                              <button
                                ref={(el) => {filterIconRefs.current[col.key] = el;}}
                                className={`col-filter-btn${filterActive ? ' is-active' : ''}`}
                                onClick={(e) => {e.stopPropagation();setActiveFilterColKey((k) => k === col.key ? null : col.key);}}
                                title="Filter column">
                                
                              <svg width="12" height="12" viewBox="0 0 24 24"
                                fill="none"
                                stroke="currentColor" strokeWidth="2.2"
                                strokeLinecap="round" strokeLinejoin="round">
                                <path d="M3 6h18" />
                                <path d="M7 12h10" />
                                <path d="M11 18h6" />
                                {filterActive && <circle cx="21" cy="3" r="3.5" fill="#ef4444" stroke="none" />}
                              </svg>
                            </button>
                              }
                        </span>
                        {activeFilterColKey === col.key && col.filterType &&
                            <ColFilterPopup
                              colKey={col.key}
                              filterType={col.filterType}
                              filter={colFilters[col.key] || null}
                              onChange={(f) => setColFilters((cf) => {
                                const next = { ...cf };
                                if (f) next[col.key] = f;else delete next[col.key];
                                return next;
                              })}
                              onClose={() => setActiveFilterColKey(null)}
                              anchorEl={filterIconRefs.current[col.key]} />

                            }
                      </th>);

                      })}
                  <th style={{ width: 34 }}></th>
                </tr>
              </thead>
              <tbody>
                {filtered.length === 0 ?
                    archived ?
                    <ArchivedEmptyState
                      onBack={() => setArchived(false)}
                      hasFilters={hasActiveFilters}
                      onClearFilters={clearAllFilters}
                      archivedCount={archivedIds.size} /> :

                    <EmptyState
                      activeFilter={activeFilter}
                      statusFilter={statusFilter}
                      searchQ={searchQ}
                      onClear={clearAllFilters} /> :

                    filtered.map((row) =>
                    <FreightRow
                      key={row.id}
                      row={row}
                      checked={selected.has(row.id)}
                      onCheck={toggleRow}
                      isArchived={archived}
                      onRestore={handleRestore} />

                    )}
              </tbody>
            </table>
          </div>

          <div className="table-footer">
            Total rows:&nbsp;<strong style={{ color: 'var(--ink)' }}>{filtered.length}</strong>
          </div>
        </div>

      </>}
      </div>
      </div>
    </div>
    <BackToTop scrollRef={scrollRef} />
    <ViewSwitcher />
    {archiveModal && <ArchiveModal count={selected.size} onConfirm={handleArchiveConfirm} onCancel={() => setArchiveModal(false)} />}
    {restoreModal && <RestoreModal count={selected.size} onConfirm={handleRestoreConfirm} onCancel={() => setRestoreModal(false)} />}
    {reviewedToast && <window.Toast msg="All drafts reviewed and submitted" onDismiss={() => setReviewedToast(false)} />}
    <TweaksPanel title="Tweaks">
      <TweakSection label="Draft confidence" />
      <TweakRadio
        label="Banner state"
        value={confidenceMode}
        options={[
          { value: 'all-review', label: 'All need review' },
          { value: 'mixed', label: '3 ready + flagged' },
          { value: 'all-high', label: 'All ready to approve' },
        ]}
        onChange={(v) => setTweak('confidenceMode', v)} />
      <TweakSection label="Table state" />
      <TweakToggle
        label="Show empty state"
        value={showEmptyState}
        onChange={(v) => setTweak('showEmptyState', v)} />
      <TweakToggle
        label="Show skeleton loading"
        value={showSkeleton}
        onChange={(v) => setTweak('showSkeleton', v)} />
    </TweaksPanel>
    </>);

}

ReactDOM.createRoot(document.getElementById('root')).render(<App />);