// ─── Shared icons for all broker pages ─────────────────────────────
window.Ico = {
  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" style={{ height: "18px", width: "16px" }}><path d="M12 5v14M5 12h14" /></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>,
  check: <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"><path d="M20 6 9 17l-5-5" /></svg>,
  alert: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="m10.3 3.86-8.06 13.94a2 2 0 0 0 1.74 3h16.04a2 2 0 0 0 1.74-3L13.7 3.86a2 2 0 0 0-3.4 0z" /><path d="M12 9v4M12 17h.01" /></svg>,
  inbox: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M22 12h-6l-2 3h-4l-2-3H2" /><path d="M5.45 5.11 2 12v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-6l-3.45-6.89A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.11z" /></svg>,
  truck: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "18px", height: "18px" }}><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>,
  network: <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="M2 12h20M12 2a15.3 15.3 0 0 1 4 10 15.3 15.3 0 0 1-4 10 15.3 15.3 0 0 1-4-10 15.3 15.3 0 0 1 4-10z" /></svg>,
  route: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="6" cy="19" r="3" /><circle cx="18" cy="5" r="3" /><path d="M6 16V8a4 4 0 0 1 8 0v8a4 4 0 0 0 4 0" /></svg>,
  layers: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="m12 2 9 5-9 5-9-5 9-5z" /><path d="m3 17 9 5 9-5M3 12l9 5 9-5" /></svg>,
  chart: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "1px", height: "18px" }}><path d="M3 3v18h18M7 14l4-4 4 4 5-5" /></svg>,
  settings: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" /></svg>,
  bell: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "1px", height: "1px" }}><path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" /><path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" /></svg>,
  help: <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="M9.09 9a3 3 0 0 1 5.83 1c0 2-3 3-3 3M12 17h.01" /></svg>,
  chevDown: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>,
  chevRight: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m9 18 6-6-6-6" /></svg>,
  chevLeft: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" style={{ width: "18px", height: "18px" }}><path d="m15 18-6-6 6-6" /></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>,
  send: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ height: "16px", width: "16px" }}><path d="M22 2 11 13" /><path d="M22 2 15 22l-4-9-9-4z" /></svg>,
  dollar: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 2v20M17 5H9.5a3.5 3.5 0 0 0 0 7h5a3.5 3.5 0 0 1 0 7H6" /></svg>,
  pkg: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M16.5 9.4l-9-5.19" /><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" /><path d="M3.27 6.96 12 12.01l8.73-5.05M12 22.08V12" /></svg>,
  scale: <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="M14 8H8" /><path d="M16 12H8" /><path d="M13 16H8" /></svg>,
  calendar: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><rect x="3" y="4" width="18" height="18" rx="2" /><path d="M16 2v4M8 2v4M3 10h18" /></svg>,
  map: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="m1 6 7-3 8 3 7-3v15l-7 3-8-3-7 3z" /><path d="M8 3v15M16 6v15" /></svg>,
  arrow: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7" /></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>,
  upload: <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="M17 8 12 3 7 8" /><path d="M12 3v12" /></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>,
  bolt: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "18px", height: "18px" }}><path d="M13 2 3 14h9l-1 8 10-12h-9l1-8z" /></svg>,
  doc: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "18px", height: "18px" }}><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 2v6h6M16 13H8M16 17H8M10 9H8" /></svg>,
  mail: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "1px", height: "1px" }}><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z" /><path d="m22 6-10 7L2 6" /></svg>,
  phone: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "18px", height: "18px" }}><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z" /></svg>,
  edit: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "16px", height: "16px" }}><path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7" /><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z" /></svg>,
  star: <svg viewBox="0 0 24 24" fill="currentColor" stroke="none" style={{ height: "18px", width: "18px" }}><path d="m12 2 3 7 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1z" /></svg>,
  starOutline: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"><path d="m12 2 3 7 7 1-5 5 1 7-6-3-6 3 1-7-5-5 7-1z" /></svg>,
  shield: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /></svg>,
  refresh: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" style={{ width: "1px", height: "18px" }}><path d="M3 12a9 9 0 0 1 15-6.7L21 8" /><path d="M21 3v5h-5" /><path d="M21 12a9 9 0 0 1-15 6.7L3 16" /><path d="M3 21v-5h5" /></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>,
  copy: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" 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>,
  trash: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M3 6h18M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" /></svg>,
  api: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M5 3v6M5 21v-6M21 3v6M21 21v-6" /><path d="M3 7h4M3 17h4M17 7h4M17 17h4M7 5h10v14H7z" /></svg>,
  pin: <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" /><circle cx="12" cy="10" r="3" /></svg>
};

// ─── Sidebar nav ───────────────────────────────────────────
window.Sidebar = function Sidebar({ active }) {
  const [shipmentsOpen, setShipmentsOpen] = React.useState(active !== 'quoting' && active !== 'routing' ? true : false);

  const [collapsed, setCollapsed] = React.useState(() => {
    try {return localStorage.getItem('broker-sidebar-collapsed') === '1';} catch {return false;}
  });
  const toggleCollapsed = () => setCollapsed((c) => {
    const next = !c;
    try {localStorage.setItem('broker-sidebar-collapsed', next ? '1' : '0');} catch {}
    return next;
  });

  return (
    <>
    <aside className={`sidebar${collapsed ? ' is-collapsed' : ''}`} style={{ backgroundColor: "rgb(10, 10, 10)" }}>
      <div className="brand">
        <div className="brand-text">
          <svg className="brand-wordmark" viewBox="0 0 457 71" fill="none" xmlns="http://www.w3.org/2000/svg" aria-label="Infomatics" style={{ width: "110px", height: "16px" }}>
            <g clipPath="url(#clip0_infomatics)">
              <path d="M0 1.36011H14.84V69.2601H0V1.36011Z" fill="#fff" />
              <path d="M61.89 39.1899V69.2599H47.05V42.2899C47.05 33.7499 45.01 30.5499 40.26 30.5499C35.22 30.5499 32.11 34.9199 32.11 42.5799V69.2499H17.27V20.7599H30.17L31.04 26.8699C33.85 23.2799 38.31 19.8899 44.52 19.8899C55.97 19.8899 61.88 26.3899 61.88 39.1899H61.89Z" fill="#fff" />
              <path d="M83.7099 17.27V20.76H95.8299V31.43H83.7099V69.26H68.8699V31.43H61.3999V20.76H68.8699V15.91C68.8699 5.72 76.1499 0 86.6199 0C89.5299 0 92.6299 0.48 95.9299 1.36V11.06C93.1199 10.57 90.8899 10.28 89.2399 10.28C84.8699 10.28 83.7099 12.12 83.7099 17.26V17.27Z" fill="#fff" />
              <path d="M92.54 45.01C92.54 29.59 102.34 19.79 117.37 19.79C132.4 19.79 142.2 29.68 142.2 45.01C142.2 60.34 132.5 70.23 117.37 70.23C102.24 70.23 92.54 60.43 92.54 45.01ZM126.68 45.01C126.68 36.09 122.99 30.94 117.37 30.94C111.75 30.94 108.06 36.08 108.06 45.01C108.06 53.94 111.75 59.08 117.37 59.08C122.99 59.08 126.68 53.94 126.68 45.01Z" fill="#fff" />
              <path d="M214.56 39.19V69.26H199.72V42.29C199.72 33.75 197.88 31.43 193.51 31.43C189.14 31.43 186.04 35.02 186.04 42.59V69.26H171.2V42.29C171.2 33.75 169.36 31.43 164.99 31.43C160.62 31.43 157.52 35.02 157.52 42.59V69.26H142.68V20.76H155.58L156.45 26.87C159.17 23.09 163.34 19.79 169.55 19.79C175.37 19.79 179.73 23.09 182.84 27.65C185.94 23.67 190.6 19.79 197.39 19.79C208.54 19.79 214.56 26.68 214.56 39.19Z" fill="#fff" />
              <path d="M263.26 58.59V69.26C261.03 69.75 258.99 70.04 257.25 70.04C251.72 70.04 248.04 67.81 246.19 64.22C243.47 67.71 239.11 70.23 232.03 70.23C220.2 70.23 214.09 65.38 214.09 56.07C214.09 46.76 220.49 42.01 235.14 40.36L243.87 39.29C243.58 32.31 241.74 30.46 237.66 30.46C233.58 30.46 231.55 32.79 230.77 36.67H216.22C216.8 26.48 225.63 19.79 238.14 19.79C251.82 19.79 258.7 27.74 258.7 40.74V54.8C258.7 57.52 259.67 58.87 261.51 58.87C262.09 58.87 262.58 58.77 263.26 58.58V58.59ZM243.86 49.76V48.01L236.49 48.98C232.51 49.47 229.6 51.41 229.6 55.19C229.6 58.97 232.41 60.91 235.23 60.91C240.86 60.91 243.86 57.22 243.86 49.75V49.76Z" fill="#fff" />
              <path d="M283.63 58.4901C284.7 58.4901 286.05 58.3901 287.61 58.3001V69.2601C284.51 69.5501 281.79 69.6501 279.36 69.6501C266.94 69.6501 263.45 65.5801 263.45 54.0301V31.4301H256.95V20.7601H263.45V9.99008L278.29 7.08008V20.7601H287.6V31.4301H278.29V52.3801C278.29 57.1301 279.07 58.4901 283.63 58.4901Z" fill="#fff" />
              <path d="M288.09 1.36011H302.93V14.3601H288.09V1.36011ZM288.09 20.7601H302.93V69.2601H288.09V20.7601Z" fill="#fff" />
              <path d="M303.41 45.01C303.41 29.49 313.01 19.79 328.05 19.79C340.95 19.79 349.29 26.48 350.75 38.03H335.52C334.74 33.18 332.61 30.95 328.05 30.95C322.04 30.95 318.93 35.99 318.93 45.02C318.93 54.05 322.03 59.09 328.05 59.09C332.03 59.09 334.65 55.69 335.52 50.46H350.75C349.2 62.58 340.37 70.25 328.05 70.25C313.01 70.25 303.41 60.55 303.41 45.03V45.01Z" fill="#fff" />
              <path d="M349.29 53.25H364.42C364.42 56.84 367.23 59.55 372.18 59.55C377.13 59.55 379.65 57.51 379.65 54.89C379.65 45.58 350.36 56.35 350.36 35.1C350.36 25.88 358.8 19.77 371.22 19.77C383.64 19.77 392.08 26.56 392.08 35.39H377.34C377.34 31.8 374.62 30.35 370.94 30.35C368.22 30.35 364.93 31.61 364.93 34.13C364.93 42.86 394.22 33.06 394.22 53.92C394.22 63.81 385.59 70.22 372.69 70.22C357.75 70.22 349.31 63.24 349.31 53.25H349.29Z" fill="#fff" />
              <path d="M416.71 39.8701V46.1701H392.75V39.8701H416.71Z" fill="#fff" />
              <path d="M439.21 39.8701V46.1701H415.25V39.8701H439.21Z" fill="#fff" />
            </g>
            <defs>
              <clipPath id="clip0_infomatics">
                <rect width="456.05" height="70.23" fill="#fff" />
              </clipPath>
            </defs>
          </svg>
        </div>
        <button className="brand-collapse" aria-label={collapsed ? 'Expand sidebar' : 'Collapse sidebar'} onClick={toggleCollapsed}>
          {collapsed ?
          <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" width="16" height="16">
              <path d="M14 8H5" />
              <path d="M10 5l3 3-3 3" />
              <path d="M3 3v10" />
            </svg> :
          <svg viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" width="16" height="16">
              <path d="M2 8h9" />
              <path d="M6 5l-3 3 3 3" />
              <path d="M13 3v10" />
            </svg>
          }
        </button>
      </div>

      <div className="nav-section">
        <a className={`ai-ask-pill${active === 'ai' ? ' is-active' : ''}`} href="AI Agent.html" aria-label="Ask anything">
          <span className="ai-ask-pill-l">
            <svg className="ai-ask-sparkles" viewBox="0 0 24 24" fill="none" stroke="url(#ai-agent-grad)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
              <path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/>
              <path d="M20 2v4"/><path d="M22 4h-4"/>
              <circle cx="4" cy="20" r="2"/>
            </svg>
            <span className="ai-ask-pill-text">Ask anything!</span>
          </span>
          <svg className="ai-ask-chev" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m6 4 4 4-4 4"/></svg>
        </a>
        <div className={`nav-group ${shipmentsOpen ? 'is-open' : ''}`}>
          <button className="nav-item nav-group-head" onClick={() => setShipmentsOpen((o) => !o)}>
            {window.Ico.truck}
            <span>All Shipments</span>
            <svg className="nav-chev" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="m6 9 6 6 6-6" /></svg>
          </button>
          {shipmentsOpen &&
          <div className="nav-subgroup">
              <a className={`nav-subitem ${active === 'freight' ? 'is-active' : ''}`} href="Freight Table.html">
                <span>Freight</span>
              </a>
              <a className={`nav-subitem ${active === 'postal' ? 'is-active' : ''}`} href="Postal Table.html">
                <span>Postal</span>
              </a>
            </div>
          }
        </div>

        <a className={`nav-item ${active === 'quoting' ? 'is-active' : ''}`} href="Quoting.html">
          {window.Ico.scale}
          <span>Quoting</span>
          {(() => {
            const qrs = (typeof window !== 'undefined' && window.QUOTE_REQUESTS) || [];
            const n = qrs.filter((q) => q.status === 'received').length;
            return n > 0 ? <span className="badge">{n}</span> : null;
          })()}
        </a>

        <a className={`nav-item ${active === 'network' ? 'is-active' : ''}`} href="Network.html">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="9" cy="7" r="4" /><path d="M3 21v-1a6 6 0 0 1 12 0v1" /><circle cx="17" cy="9" r="3" /><path d="M21 21v-1a4 4 0 0 0-4-4" /></svg>
          <span>Network</span>
        </a>

        <a className={`nav-item ${active === 'trackers' ? 'is-active' : ''}`} href="Trackers.html">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z" /><circle cx="12" cy="10" r="3" /></svg>
          <span>Trackers</span>
        </a>

        <a className={`nav-item ${active === 'settings' ? 'is-active' : ''}`} href="#">
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="3" /><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" /></svg>
          <span>Settings</span>
        </a>
      </div>

      <div className="sidebar-foot">
        <PersonaSwitch />
      </div>
    </aside>
    <CommandCenterDock />
    </>);

};

// ─── Command Center dock (bottom-right, all broker pages) ──
window.CommandCenterDock = function CommandCenterDock() {
  React.useEffect(function () {
    if (window.__ccDockInit || document.getElementById('cc-dock-script')) return;
    var s = document.createElement('script');
    s.id = 'cc-dock-script';
    s.src = 'command-center-dock.js';
    document.body.appendChild(s);
  }, []);
  return null;
};

// ─── AI agent floating bar ─────────────────────────────────
window.AIAgentBar = function AIAgentBar() {
  const [value, setValue] = React.useState('');
  const [messages, setMessages] = React.useState([]);
  const [open, setOpen] = React.useState(false);
  const [attachments, setAttachments] = React.useState([]);
  const [recording, setRecording] = React.useState(false);
  const [recSecs, setRecSecs] = React.useState(0);
  const inputRef = React.useRef(null);
  const wrapRef = React.useRef(null);
  const fileInputRef = React.useRef(null);

  const focusInput = () => {
    setOpen(true);
    requestAnimationFrame(() => inputRef.current && inputRef.current.focus());
  };

  // Listen for external open events (sidebar "Ask anything" pill)
  React.useEffect(() => {
    const onOpen = () => focusInput();
    window.addEventListener('ai-agent:open', onOpen);
    return () => window.removeEventListener('ai-agent:open', onOpen);
  }, []);

  // Recording timer
  React.useEffect(() => {
    if (!recording) { setRecSecs(0); return; }
    const id = setInterval(() => setRecSecs((s) => s + 1), 1000);
    return () => clearInterval(id);
  }, [recording]);

  const pickFiles = () => {
    setOpen(true);
    if (fileInputRef.current) fileInputRef.current.click();
  };
  const onFilesChosen = (e) => {
    const files = Array.from(e.target.files || []);
    if (!files.length) return;
    setAttachments((a) => [...a, ...files.map((f) => ({
      name: f.name,
      size: f.size,
      url: /^image\//.test(f.type) ? URL.createObjectURL(f) : null
    }))]);
    e.target.value = '';
  };
  const removeAttachment = (i) => setAttachments((a) => {
    const item = a[i];
    if (item && item.url) { try { URL.revokeObjectURL(item.url); } catch (e) {} }
    return a.filter((_, idx) => idx !== i);
  });

  const toggleRecording = () => {
    setOpen(true);
    setRecording((r) => {
      if (r) {
        // Stopping → inject a transcription placeholder
        setValue((v) => (v ? v + ' ' : '') + '[voice note]');
      }
      return !r;
    });
  };

  const HINT_SUGGESTIONS = [
    { prefix: 'Track', hint: 'a shipment' },
    { prefix: 'Find', hint: 'shipments in transit' },
    { prefix: 'Show', hint: 'delivery status' },
    { prefix: 'Create', hint: 'a new load' },
    { prefix: 'Filter', hint: 'by carrier' },
    { prefix: 'What', hint: 'is delayed today?' },
    { prefix: 'Book', hint: 'a carrier' }
  ];
  const activeHint = React.useMemo(() => {
    const v = value.trim();
    if (!v) return null;
    const lower = v.toLowerCase();
    const match = HINT_SUGGESTIONS.find((s) => s.prefix.toLowerCase().startsWith(lower) || lower.startsWith(s.prefix.toLowerCase()));
    return match ? match.hint : null;
  }, [value]);
  const acceptHint = () => {
    if (!activeHint) return;
    const match = HINT_SUGGESTIONS.find((s) => s.hint === activeHint);
    if (!match) return;
    setValue(`${match.prefix} ${match.hint}`);
  };

  const [thinking, setThinking] = React.useState(false);
  const thinkTimer = React.useRef(null);
  const messagesRef = React.useRef(null);

  React.useEffect(() => {
    if (messagesRef.current) messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
  }, [messages, thinking]);

  const buildReplies = (text) => {
    const lower = text.toLowerCase();
    if (lower.includes('track')) {
      return [{ role: 'ai', text: 'Please enter BOL, Shipment ID, or PO number' }];
    }
    if (/^bol\s*\d+/i.test(text) || /^\d{5,}$/.test(text)) {
      const bol = text.replace(/[^0-9]/g, '') || '892347';
      return [
        { role: 'ai', text: 'Shipment is currently in transit and expected to arrive at 3:00 PM' },
        { role: 'ai-card', card: { bol, driver: 'John Ramirez', location: 'Phoenix, AZ', eta: '4:15 PM', updated: '30 min ago', status: 'In Transit' } },
        { role: 'ai-actions' }
      ];
    }
    return [{ role: 'ai', text: `I'll help with "${text}". Connect the assistant to enable live responses.` }];
  };

  const send = () => {
    const q = value.trim();
    if (!q && attachments.length === 0) return;
    const attachSummary = attachments.length ? ` (with ${attachments.length} file${attachments.length > 1 ? 's' : ''}: ${attachments.map((a) => a.name).join(', ')})` : '';
    const userMsg = { role: 'user', text: q + attachSummary };
    setMessages((m) => [...m, userMsg]);
    setValue('');
    setAttachments([]);
    setThinking(true);
    if (thinkTimer.current) clearTimeout(thinkTimer.current);
    thinkTimer.current = setTimeout(() => {
      setThinking(false);
      setMessages((m) => [...m, ...buildReplies(q)]);
    }, 700);
  };

  const copyText = async (t) => { try { await navigator.clipboard.writeText(t); } catch (e) {} };
  const closeSide = () => { setMessages([]); setThinking(false); setOpen(false); };

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

  const gradientDefs = (
    <svg width="0" height="0" style={{ position: 'absolute' }} aria-hidden="true">
      <defs>
        <linearGradient id="ai-agent-grad" x1="0%" y1="50%" x2="100%" y2="50%">
          <stop offset="0%" stopColor="#5386EF" />
          <stop offset="50%" stopColor="#8FEFFF" />
          <stop offset="100%" stopColor="#D58FFF" />
        </linearGradient>
      </defs>
    </svg>
  );

  // ── Side panel mode: active once the user has sent something ──
  if (messages.length > 0 || thinking) {
    return (
      <>
        {gradientDefs}
        <aside className="ai-side-panel" aria-label="AI Agent">
          <div className="ai-side-head">
            <h2 className="ai-side-title">AI Agent</h2>
            <div className="ai-side-head-actions">
              <button type="button" className="ai-side-icon-btn" onClick={() => {
                try { sessionStorage.setItem('ai-agent:handoff', JSON.stringify(messages)); } catch (e) {}
                window.location.href = 'AI Agent.html';
              }} aria-label="Expand" title="Open full view">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg>
              </button>
              <button type="button" className="ai-side-icon-btn" onClick={closeSide} aria-label="Close">
                <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>
              </button>
            </div>
          </div>
          <div className="ai-side-messages" ref={messagesRef}>
            {messages.map((m, i) => {
              if (m.role === 'user') {
                return (
                  <div key={i} className="ai-side-row ai-side-row-user">
                    <div className="ai-side-bubble ai-side-bubble-user">{m.text}</div>
                    <div className="ai-side-msg-actions">
                      <button onClick={() => copyText(m.text)} aria-label="Copy" title="Copy"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button>
                      <button onClick={() => { setValue(m.text); setMessages(messages.slice(0, i)); }} aria-label="Edit" title="Edit"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M12 20h9M16.5 3.5a2.121 2.121 0 1 1 3 3L7 19l-4 1 1-4z"/></svg></button>
                      <button aria-label="Regenerate" title="Regenerate"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg></button>
                    </div>
                  </div>
                );
              }
              if (m.role === 'ai') {
                return (
                  <div key={i} className="ai-side-row ai-side-row-ai">
                    <div className="ai-side-bubble ai-side-bubble-ai">{m.text}</div>
                    <div className="ai-side-msg-actions">
                      <button onClick={() => copyText(m.text)} aria-label="Copy" title="Copy"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button>
                      <button aria-label="Download" title="Download"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8 12 3 7 8"/><path d="M12 3v12"/></svg></button>
                      <button aria-label="Regenerate" title="Regenerate"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg></button>
                    </div>
                  </div>
                );
              }
              if (m.role === 'ai-card') {
                const c = m.card;
                return (
                  <div key={i} className="ai-side-row ai-side-row-ai">
                    <div className="ai-side-shipcard">
                      <div className="ai-side-shipcard-top">
                        <div className="ai-side-shipcard-icon">
                          <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="#14121D" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 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.73z"/><path d="M3.3 7 12 12l8.7-5M12 22V12"/></svg>
                        </div>
                        <div className="ai-side-shipcard-body">
                          <div className="ai-side-shipcard-head">
                            <div>
                              <div className="ai-side-shipcard-eyebrow">Preview</div>
                              <div className="ai-side-shipcard-title">Shipment BOL {c.bol}</div>
                            </div>
                            <span className="ai-side-badge">{c.status}</span>
                          </div>
                          <div className="ai-side-shipcard-facts">
                            <div className="ai-side-fact"><span className="ai-side-fact-l">Driver:</span><span className="ai-side-fact-v">{c.driver}</span></div>
                            <div className="ai-side-fact"><span className="ai-side-fact-l">Location:</span><span className="ai-side-fact-v">{c.location}</span></div>
                            <div className="ai-side-fact"><span className="ai-side-fact-l">ETA:</span><span className="ai-side-fact-v">{c.eta}</span></div>
                            <div className="ai-side-fact"><span className="ai-side-fact-l">Updated:</span><span className="ai-side-fact-v">{c.updated}</span></div>
                          </div>
                        </div>
                      </div>
                      <a className="ai-side-shipcard-link" href="#">View Shipment <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><path d="M5 12h14M12 5l7 7-7 7"/></svg></a>
                    </div>
                    <div className="ai-side-msg-actions">
                      <button aria-label="Copy" title="Copy"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><rect width="14" height="14" x="8" y="8" rx="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/></svg></button>
                      <button aria-label="Download" title="Download"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8 12 3 7 8"/><path d="M12 3v12"/></svg></button>
                      <button aria-label="Regenerate" title="Regenerate"><svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"/><path d="M21 3v5h-5"/><path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"/><path d="M8 16H3v5"/></svg></button>
                    </div>
                  </div>
                );
              }
              if (m.role === 'ai-actions') {
                return null;
              }
              return null;
            })}
            {thinking &&
              <div className="ai-side-row ai-side-row-ai">
                <div className="ai-side-thinking" aria-label="AI is thinking">
                  <span></span><span></span><span></span>
                </div>
              </div>
            }
          </div>
          <div className="ai-side-composer-wrap">
            {messages.some((m) => m.role === 'ai-actions') &&
              <div className="ai-side-cta-row">
                <button type="button" className="ai-side-cta" onClick={() => setMessages((m) => [...m, { role: 'user', text: 'Report an issue' }, { role: 'ai', text: 'Got it — what happened with this shipment? A short description helps the team respond faster.' }])}>
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="m21.73 18-8-14a2 2 0 0 0-3.46 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3z"/><path d="M12 9v4M12 17h.01"/></svg>Report Issue
                </button>
                <button type="button" className="ai-side-cta" onClick={pickFiles}>
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><path d="M17 8 12 3 7 8"/><path d="M12 3v12"/></svg>Upload POD
                </button>
                <button type="button" className="ai-side-cta is-primary" onClick={() => setMessages((m) => [...m, { role: 'user', text: 'Contact driver' }, { role: 'ai', text: 'Calling John Ramirez… the driver will receive your ping in a few seconds.' }])}>
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="M22 16.92v3a2 2 0 0 1-2.18 2 19.79 19.79 0 0 1-8.63-3.07 19.5 19.5 0 0 1-6-6 19.79 19.79 0 0 1-3.07-8.67A2 2 0 0 1 4.11 2h3a2 2 0 0 1 2 1.72 12.84 12.84 0 0 0 .7 2.81 2 2 0 0 1-.45 2.11L8.09 9.91a16 16 0 0 0 6 6l1.27-1.27a2 2 0 0 1 2.11-.45 12.84 12.84 0 0 0 2.81.7A2 2 0 0 1 22 16.92z"/></svg>Contact Driver
                </button>
              </div>
            }
            <div className="ai-side-composer">
              {attachments.length > 0 &&
                <div className="ai-side-attachments">
                  {attachments.map((a, i) => {
                    const isImage = /\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(a.name);
                    const ext = (a.name.split('.').pop() || '').toUpperCase().slice(0, 5);
                    const kb = Math.max(1, Math.round(a.size / 1024));
                    const sizeLbl = kb >= 1024 ? `${(kb / 1024).toFixed(kb >= 10240 ? 0 : 1)} MB` : `${kb} KB`;
                    return (
                      <div key={i} className={`ai-side-attach-card${isImage && a.url ? ' has-image' : ''}`} style={isImage && a.url ? { backgroundImage: `url(${a.url})` } : undefined} title={a.name}>
                        <button type="button" className="ai-side-attach-x" onClick={() => removeAttachment(i)} aria-label={`Remove ${a.name}`}>
                          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true"><circle cx="12" cy="12" r="10"/><path d="m15 9-6 6M9 9l6 6"/></svg>
                        </button>
                        {!(isImage && a.url) &&
                          <div className="ai-side-attach-body">
                            <span className="ai-side-attach-title">{ext || 'FILE'}</span>
                            <span className="ai-side-attach-meta">{sizeLbl}</span>
                          </div>
                        }
                      </div>
                    );
                  })}
                </div>
              }
              <div className="ai-side-composer-top">
                <svg className="ai-side-sparkles" viewBox="0 0 24 24" fill="none" stroke="url(#ai-agent-grad)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
                  <path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z"/>
                  <path d="M20 2v4M22 4h-4"/><circle cx="4" cy="20" r="2"/>
                </svg>
                <input
                  ref={inputRef}
                  type="text"
                  className="ai-side-composer-input"
                  placeholder="Ask anything!"
                  value={value}
                  onChange={(e) => setValue(e.target.value)}
                  onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); send(); } }}
                />
                <button type="button" className="ai-side-composer-audio" aria-label="Voice input">
                  <svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"><path d="M2 10v3"/><path d="M6 6v11"/><path d="M10 3v18"/><path d="M14 8v7"/><path d="M18 5v13"/><path d="M22 10v3"/></svg>
                </button>
              </div>
              <div className="ai-side-composer-bot">
                <button type="button" className="ai-side-composer-attach" onClick={pickFiles}>
                  <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></svg>
                  Attach
                </button>
                <button type="button" className="ai-side-composer-send" onClick={send} aria-label="Send">
                  <img src="assets/zeroe-logo.svg" alt="zeroe" />
                </button>
              </div>
            </div>
            <input ref={fileInputRef} type="file" multiple style={{ display: 'none' }} onChange={onFilesChosen} />
          </div>
        </aside>
      </>
    );
  }

  return (
    <div className={`ai-agent-wrap${open ? ' is-open' : ''}`} ref={wrapRef}>
      {gradientDefs}

      <div className={`ai-agent-bar${attachments.length > 0 || recording ? ' has-attach' : ''}`} role="search" aria-label="Ask anything" onClick={focusInput}>
        {(attachments.length > 0 || recording) &&
          <div className="ai-agent-attachments" onClick={(e) => e.stopPropagation()}>
            {recording &&
              <div className="ai-agent-attach-card is-recording" aria-label="Recording">
                <button type="button" className="ai-agent-attach-x" onClick={toggleRecording} aria-label="Stop recording">
                  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="m15 9-6 6M9 9l6 6" /></svg>
                </button>
                <div className="ai-agent-attach-body">
                  <span className="ai-agent-attach-rec-dot" />
                  <span className="ai-agent-attach-title">Voice</span>
                  <span className="ai-agent-attach-meta">{String(Math.floor(recSecs / 60)).padStart(2, '0')}:{String(recSecs % 60).padStart(2, '0')}</span>
                </div>
              </div>
            }
            {attachments.map((a, i) => {
              const isImage = /\.(png|jpe?g|gif|webp|bmp|svg)$/i.test(a.name);
              const ext = (a.name.split('.').pop() || '').toUpperCase().slice(0, 5);
              const kb = Math.max(1, Math.round(a.size / 1024));
              const sizeLbl = kb >= 1024 ? `${(kb / 1024).toFixed(kb >= 10240 ? 0 : 1)} MB` : `${kb} KB`;
              return (
                <div key={i} className={`ai-agent-attach-card${isImage && a.url ? ' has-image' : ''}`} style={isImage && a.url ? { backgroundImage: `url(${a.url})` } : undefined} title={a.name}>
                  <button type="button" className="ai-agent-attach-x" onClick={() => removeAttachment(i)} aria-label={`Remove ${a.name}`}>
                    <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" aria-hidden="true"><circle cx="12" cy="12" r="10" /><path d="m15 9-6 6M9 9l6 6" /></svg>
                  </button>
                  {!(isImage && a.url) &&
                    <div className="ai-agent-attach-body">
                      <span className="ai-agent-attach-title">{ext || 'FILE'}</span>
                      <span className="ai-agent-attach-meta">{sizeLbl}</span>
                    </div>
                  }
                </div>);

            })}
          </div>
        }
        <div className="ai-agent-bar-row">
        <div className="ai-agent-bar-l">
          <svg className="ai-agent-sparkles" viewBox="0 0 24 24" fill="none" stroke="url(#ai-agent-grad)" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
            <path d="M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z" />
            <path d="M20 2v4" />
            <path d="M22 4h-4" />
            <circle cx="4" cy="20" r="2" />
          </svg>
          <div className="ai-agent-input-wrap">
            {value && activeHint &&
              <div className="ai-agent-input-ghost" aria-hidden="true">
                <span className="ghost-typed">{value}</span>
                <span className="ghost-sep">|</span>
                <span className="ghost-hint">{activeHint}</span>
              </div>
            }
            <input
              ref={inputRef}
              type="text"
              className={`ai-agent-input${value && activeHint ? ' has-hint' : ''}`}
              placeholder="Ask anything!"
              value={value}
              onChange={(e) => setValue(e.target.value)}
              onFocus={() => setOpen(true)}
              onKeyDown={(e) => {
                if (e.key === 'Enter') { e.preventDefault(); send(); }
                else if ((e.key === 'Tab' || e.key === 'ArrowRight') && activeHint) {
                  if (e.key === 'Tab' || (e.key === 'ArrowRight' && e.target.selectionStart === value.length)) {
                    e.preventDefault(); acceptHint();
                  }
                }
              }} />
          </div>

        </div>
        <div className="ai-agent-bar-r" onClick={(e) => e.stopPropagation()}>
          <input
            ref={fileInputRef}
            type="file"
            multiple
            style={{ display: 'none' }}
            onChange={onFilesChosen} />
          <button type="button" className={`ai-agent-icon-btn${recording ? ' is-recording' : ''}`} aria-label={recording ? 'Stop recording' : 'Voice input'} onClick={toggleRecording} title={recording ? `Recording ${recSecs}s — click to stop` : 'Voice input'}>
            {recording ?
              <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2" /></svg>
              :
              <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="M2 10v3" /><path d="M6 6v11" /><path d="M10 3v18" /><path d="M14 8v7" /><path d="M18 5v13" /><path d="M22 10v3" /></svg>
            }
          </button>
          <button type="button" className="ai-agent-icon-btn" aria-label="Attach file" onClick={pickFiles} title="Attach file">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true"><path d="m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48" /></svg>
          </button>
        </div>
        </div>
      </div>
    </div>);

};

// ─── Persona Switcher ──────────────────────────────────────
window.PersonaSwitch = function PersonaSwitch() {
  const [open, setOpen] = React.useState(false);
  const wrapRef = React.useRef(null);

  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]);

  const personas = [
  { id: 'shipper', initials: 'MT', name: 'Marcus Tan', role: 'Shipper · ASUS', href: 'Shipper Routing.html' },
  { id: 'carrier', initials: 'JR', name: 'Jamie Reyes', role: 'Carrier · Reliant Transport', href: 'All Loads.html' },
  { id: 'broker', initials: 'DV', name: 'Diana Vega', role: 'Broker · Alfred Logistics', href: 'Broker Routing.html', current: true }];

  const me = personas.find((p) => p.current);

  return (
    <div className="persona-wrap" ref={wrapRef}>
      {open &&
      <div className="persona-pop" role="menu" aria-label="Switch persona">
          <div className="persona-pop-head">Switch persona</div>
          {personas.map((p) =>
        p.current ?
        <div key={p.id} className="persona-opt is-current" role="menuitem" aria-current="true">
                <div className="av">{p.initials}</div>
                <div className="who"><b>{p.name}</b><span>{p.role}</span></div>
                <span className="check">{window.Ico.check}</span>
              </div> :

        <a key={p.id} className="persona-opt" href={p.href} role="menuitem">
                <div className="av">{p.initials}</div>
                <div className="who"><b>{p.name}</b><span>{p.role}</span></div>
              </a>

        )}
        </div>
      }
      <button
        type="button"
        className={`persona-switch ${open ? 'is-open' : ''}`}
        title="Switch persona"
        aria-haspopup="menu"
        aria-expanded={open}
        onClick={() => setOpen((o) => !o)}>

        <div className="av">{me.initials}</div>
        <div className="who">
          <b>{me.name}</b>
          <span>{me.role}</span>
        </div>
        <span className="chev">{window.Ico.chevDown}</span>
      </button>
    </div>);

};

// ─── Topbar ────────────────────────────────────────────────
window.Topbar = function Topbar({ crumbs, title, children }) {
  return (
    <div className="topbar">
      {crumbs.length > 0 && <div className="breadcrumb">
        {crumbs.map((c, i) =>
        <React.Fragment key={i}>
            {i > 0 && <span className="sep">/</span>}
            {c.href ? <a href={c.href}>{c.label}</a> : <span style={{ display: 'flex', flexDirection: 'column', gap: 1 }}><b style={{ fontSize: "22px" }}>{c.label}</b>{c.sub && <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--ink)', letterSpacing: '0.01em', lineHeight: 1.2 }}>{c.sub}</span>}</span>}
          </React.Fragment>
        )}
      </div>}
      {title &&
      <>
          {crumbs.length > 0 && <span style={{ width: 1, height: 18, background: 'var(--line)', flexShrink: 0 }} />}
          <span className="topbar-title" style={{ fontSize: "22px" }}>{title}</span>
        </>
      }
      {children}
      <div className="topbar-spacer" />
      <button className="topbar-icon-btn topbar-bell" data-tip="3 unread notifications" onClick={() => { window.location.href = 'Notifications.html'; }}>
        <svg width="20" height="20" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round">
          <path d="M6 8a6 6 0 0 1 12 0c0 7 3 9 3 9H3s3-2 3-9" />
          <path d="M10.3 21a1.94 1.94 0 0 0 3.4 0" />
        </svg>
      </button>
    </div>);

};

// ─── Date helpers ──────────────────────────────────────────
window.NOW = new Date('2026-05-14T14:30:00Z');
window.fmtDateTime = (iso) => iso ? new Date(iso).toLocaleString(undefined, { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' }) : '—';
window.fmtDate = (iso) => iso ? new Date(iso).toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' }) : '—';
window.fmtTime = (iso) => iso ? new Date(iso).toLocaleString(undefined, { weekday: 'short', hour: 'numeric', minute: '2-digit' }) : '—';
window.minsAgo = (iso) => {
  if (!iso) return null;
  const m = Math.round((window.NOW - new Date(iso)) / 60000);
  if (m < 1) return 'just now';
  if (m < 60) return `${m}m ago`;
  const h = Math.floor(m / 60);
  if (h < 24) return `${h}h ${m % 60}m ago`;
  return `${Math.floor(h / 24)}d ago`;
};
window.fmtCurrency = (n) => '$' + n.toLocaleString(undefined, { minimumFractionDigits: 0, maximumFractionDigits: 0 });
window.fmtMoney = (n) => '$' + n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
window.hoursUntil = (iso) => iso ? (new Date(iso) - window.NOW) / 3600000 : null;
window.daysUntil = (iso) => iso ? Math.round((new Date(iso) - window.NOW) / 86400000) : null;
window.fmtCountdown = (hrs) => {
  if (hrs == null) return '—';
  if (hrs < 0) return 'Expired';
  if (hrs < 1) return `${Math.round(hrs * 60)}m`;
  if (hrs < 48) return `${Math.round(hrs)}h ${Math.round(hrs % 1 * 60)}m`;
  return `${Math.round(hrs / 24)}d`;
};
window.countdownState = (hrs) => {
  if (hrs == null) return null;
  if (hrs < 0) return 'expired';
  if (hrs < 4) return 'cold';
  if (hrs < 12) return 'warn';
  return 'fresh';
};

window.initials = (name) => name.split(' ').map((s) => s[0]).slice(0, 2).join('').toUpperCase();

// ─── Status label map ──────────────────────────────────────
window.QUOTE_STATUS = {
  draft: { label: 'Draft', cls: 'qst-draft' },
  received: { label: 'To Quote', cls: 'qst-received' },
  rfq_sent: { label: 'Awaiting Quotes', cls: 'qst-rfq-sent' },
  submitted: { label: 'Submitted to Shipper', cls: 'qst-submitted' },
  accepted: { label: 'Accepted', cls: 'qst-order' },
  rejected: { label: 'Rejected', cls: 'qst-rejected' },
  expired: { label: 'Expired', cls: 'qst-expired' }
};

window.StatusPill = function StatusPill({ status }) {
  const s = window.QUOTE_STATUS[status] || window.QUOTE_STATUS.draft;
  return <span className={`pill ${s.cls}`}>{s.label}</span>;
};

window.Countdown = function Countdown({ until, label }) {
  const hrs = window.hoursUntil(until);
  const st = window.countdownState(hrs);
  if (!st) return null;
  return (
    <span className={`countdown is-${st}`} title={`Validity: ${window.fmtDateTime(until)}`}>
      {window.Ico.clock}{st === 'expired' ? 'Expired' : (label ? `${label} ` : '') + window.fmtCountdown(hrs)}
    </span>);

};

window.Toast = function Toast({ msg, onDismiss, tone }) {
  React.useEffect(() => {
    const t = setTimeout(onDismiss, 3200);
    return () => clearTimeout(t);
  }, [onDismiss]);
  const color = tone === 'good' ? 'var(--good)' : tone === 'warn' ? 'var(--warn)' : tone === 'bad' ? 'var(--bad)' : 'var(--accent)';
  return <div className="toast"><span style={{ color }}>{window.Ico.check}</span>{msg}</div>;
};