/* global React */
/* Rate Query — search a lane, get spot/contracted/market rates as expandable cards */

window.RateQueryScreen = function RateQueryScreen() {
  const today = new Date();
  const isoToday = today.toISOString().slice(0, 10);
  const default30 = new Date(today.getTime() + 30 * 86400000).toISOString().slice(0, 10);

  const [pol, setPol] = React.useState('SIN');
  const [pod, setPod] = React.useState('RTM');
  const [date, setDate] = React.useState(default30);
  const [incoterms, setIncoterms] = React.useState('FOB');
  const [containerType, setContainerType] = React.useState('40HC');
  const [commodity, setCommodity] = React.useState('General cargo');
  const [weight, setWeight] = React.useState('');
  const [advancedOpen, setAdvancedOpen] = React.useState(false);
  const [filter, setFilter] = React.useState('all');
  const [submitted, setSubmitted] = React.useState({ pol: 'SIN', pod: 'RTM', date: default30 });
  const [expanded, setExpanded] = React.useState(null);
  const [loading, setLoading] = React.useState(false);
  const [swapAnim, setSwapAnim] = React.useState(false);

  const submit = (e) => {
    e?.preventDefault?.();
    if (!pol || !pod || pol === pod) return;
    setLoading(true);
    setExpanded(null);
    setTimeout(() => {
      setSubmitted({ pol, pod, date });
      setLoading(false);
    }, 600);
  };

  const swap = () => {
    setSwapAnim(true);
    setTimeout(() => setSwapAnim(false), 350);
    setPol(pod); setPod(pol);
  };

  const rates = React.useMemo(() => buildRates(submitted.pol, submitted.pod, submitted.date, containerType, incoterms), [submitted, containerType, incoterms]);
  const filtered = rates.filter(r => filter === 'all' || r.source === filter);

  /* Aggregate stats for the results header */
  const airRates = rates.filter(r => r.mode === 'air');
  const seaRates = rates.filter(r => r.mode === 'sea');
  const cheapestAir = airRates.length ? Math.min(...airRates.map(r => r.total)) : 0;
  const cheapestSea = seaRates.length ? Math.min(...seaRates.map(r => r.total)) : 0;
  const cheapest = rates.length ? Math.min(...rates.map(r => r.total)) : 0;
  const fastest = rates.length ? Math.min(...rates.map(r => r.transitDays)) : 0;
  const avgMarket = rates.length ? Math.round(rates.reduce((s, r) => s + r.total, 0) / rates.length) : 0;
  const counts = { spot: 0, contracted: 0, market: 0 };
  rates.forEach(r => counts[r.source]++);

  /* Filter & split by mode for sectioned rendering */
  const filteredAir = filtered.filter(r => r.mode === 'air');
  const filteredSea = filtered.filter(r => r.mode === 'sea');

  const polPort = window.PortByCode[pol];
  const podPort = window.PortByCode[pod];

  return (
    <div style={{ padding: 24, display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 1200 }}>
      {/* Header */}
      <div>
        <div style={{ fontSize: 22, fontWeight: 600, letterSpacing: '-0.02em' }}>Rate Query</div>
        <div style={{ fontSize: 13, color: 'var(--fg-3)', marginTop: 4, display: 'flex', alignItems: 'center', gap: 8 }}>
          <window.Icon name="sparkles" size={12} color="#7C5CFF"/>
          <span>Search a lane to see all available rates. <strong style={{ color: 'var(--fg-1)' }}>Air carriers</strong> are listed first, then sea — contracted, spot, and market benchmarks across both modes.</span>
        </div>
      </div>

      {/* Query form */}
      <form className="card" onSubmit={submit} style={{ padding: 18, display: 'flex', flexDirection: 'column', gap: 14 }}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 36px 1fr 200px auto', gap: 10, alignItems: 'flex-end' }}>
          <PortPicker label="POL · Port of Loading" value={pol} onChange={setPol} otherValue={pod}/>

          <button type="button" className="icon-btn" onClick={swap} title="Swap origin & destination"
            style={{
              width: 36, height: 36, marginBottom: 0, background: 'var(--n-50)', border: '1px solid var(--n-100)',
              transform: swapAnim ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform .3s ease',
              alignSelf: 'flex-end',
            }}>
            <window.Icon name="route" size={15}/>
          </button>

          <PortPicker label="POD · Port of Discharge" value={pod} onChange={setPod} otherValue={pol}/>

          <div>
            <label className="rq-label">Estimated departure</label>
            <input type="date" className="input" min={isoToday} value={date} onChange={e => setDate(e.target.value)} style={{ width: '100%' }}/>
          </div>

          <button type="submit" className="btn btn-primary btn-lg" disabled={!pol || !pod || pol === pod || loading} style={{ minWidth: 130 }}>
            {loading ? <><span className="dots"><span/><span/><span/></span> Fetching…</> : <><window.Icon name="search" size={14}/> Fetch rates</>}
          </button>
        </div>

        {/* Advanced fields toggle */}
        <div>
          <button type="button" className="btn btn-sm btn-ghost" onClick={() => setAdvancedOpen(o => !o)}
            style={{ padding: '0 4px', height: 22, color: 'var(--fg-3)', fontSize: 11.5 }}>
            <window.Icon name={advancedOpen ? 'chev-d' : 'chev-r'} size={11}/>
            {advancedOpen ? 'Hide' : 'Show'} optional fields
            <span style={{ color: 'var(--fg-4)', fontWeight: 500 }}>· Incoterms, container, commodity, weight</span>
          </button>
        </div>

        {advancedOpen && (
          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 10, padding: '12px 14px', background: 'var(--n-25)', border: '1px solid var(--n-100)', borderRadius: 10 }}>
            <div>
              <label className="rq-label">Incoterms</label>
              <select className="input" value={incoterms} onChange={e => setIncoterms(e.target.value)} style={{ width: '100%' }}>
                {['EXW','FCA','FOB','CFR','CIF','CPT','CIP','DAP','DPU','DDP'].map(t => <option key={t}>{t}</option>)}
              </select>
            </div>
            <div>
              <label className="rq-label">Equipment</label>
              <select className="input" value={containerType} onChange={e => setContainerType(e.target.value)} style={{ width: '100%' }}>
                <option value="20GP">20ft Std (20GP)</option>
                <option value="40GP">40ft Std (40GP)</option>
                <option value="40HC">40ft High Cube (40HC)</option>
                <option value="40RF">40ft Reefer (40RF)</option>
                <option value="LCL">LCL · per CBM</option>
              </select>
            </div>
            <div>
              <label className="rq-label">Commodity</label>
              <select className="input" value={commodity} onChange={e => setCommodity(e.target.value)} style={{ width: '100%' }}>
                {['General cargo','Industrial machinery','Electronics','Auto parts','Pharma','Apparel & textiles','Food (non-perishable)','Reefer · food','Chemicals (non-haz)','DG · Class 9'].map(t => <option key={t}>{t}</option>)}
              </select>
            </div>
            <div>
              <label className="rq-label">Gross weight (kg)</label>
              <input className="input" placeholder="e.g. 18,400" value={weight} onChange={e => setWeight(e.target.value)} style={{ width: '100%' }}/>
            </div>
          </div>
        )}
      </form>

      {/* Results header */}
      {pol === pod && (
        <div className="card" style={{ padding: 14, background: 'var(--warning-50)', borderColor: 'var(--warning-100)', color: 'var(--warning-700)', display: 'flex', alignItems: 'center', gap: 8, fontSize: 12.5 }}>
          <window.Icon name="alert" size={14}/> POL and POD cannot be the same port.
        </div>
      )}

      {loading && (
        <div className="card" style={{ padding: 24, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 10, color: 'var(--agent-700)' }}>
          <window.Icon name="sparkles" size={14}/>
          <span>Agent is querying air freighter capacity, contracted rates, spot APIs, and market benchmarks…</span>
          <span className="dots"><span/><span/><span/></span>
        </div>
      )}

      {!loading && rates.length > 0 && (
        <>
          {/* Lane summary */}
          <div className="card" style={{ padding: '14px 18px', display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr 1fr', gap: 16, alignItems: 'center' }}>
            <div>
              <div style={{ fontSize: 10, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Lane</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginTop: 4 }}>
                <window.Flag port={submitted.pol} lg/>
                <span className="mono" style={{ fontSize: 16, fontWeight: 700 }}>{submitted.pol}</span>
                <window.Icon name="arrow-r" size={14} color="#98A2B3"/>
                <span className="mono" style={{ fontSize: 16, fontWeight: 700 }}>{submitted.pod}</span>
                <window.Flag port={submitted.pod} lg/>
              </div>
              <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 4 }}>
                {window.PortByCode[submitted.pol]?.name} → {window.PortByCode[submitted.pod]?.name}
              </div>
            </div>
            <SummaryStat label="Rates found" value={rates.length} sub={`${airRates.length} air · ${seaRates.length} sea`}/>
            <SummaryStat label="Cheapest air" icon="plane" value={`$${cheapestAir.toLocaleString()}`} sub={`per ${airRates[0]?.chargeableKg?.toLocaleString() || '1,000'} kg`} color="var(--brand-700)"/>
            <SummaryStat label="Cheapest sea" icon="ship" value={`$${cheapestSea.toLocaleString()}`} sub={`per ${containerType}`} color="var(--success-700)"/>
            <SummaryStat label="Fastest transit" value={`${fastest}d`} sub="port-to-port"/>
          </div>

          {/* Filter strip */}
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.05em' }}>Show</div>
            {[
              { id: 'all',        label: 'All rates',  icon: 'layers', count: rates.length },
              { id: 'contracted', label: 'Contracted', icon: 'check-circle', count: counts.contracted, color: 'b-blue' },
              { id: 'spot',       label: 'Spot',       icon: 'bolt',  count: counts.spot, color: 'b-warning' },
              { id: 'market',     label: 'Market',     icon: 'globe', count: counts.market, color: 'b-agent' },
            ].map(f => (
              <button key={f.id} className={`chip ${filter === f.id ? 'active' : ''}`} onClick={() => setFilter(f.id)}>
                <window.Icon name={f.icon} size={11}/>
                {f.label}
                <span className="chip-count">{f.count}</span>
              </button>
            ))}
            <div style={{ flex: 1 }}/>
            <span style={{ fontSize: 11, color: 'var(--fg-3)', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
              <window.Icon name="plane" size={11} color="#1659CB"/>
              Air shown first · sorted by lowest total within each mode
            </span>
          </div>

          {/* Rate cards — sectioned by mode (air first) */}
          <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {filteredAir.length > 0 && (
              <>
                <ModeSectionHeader mode="air" count={filteredAir.length} note="Client priority · daily freighter capacity"/>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                  {filteredAir.map((r) => (
                    <RateQueryCard key={r.id} rate={r} isOpen={expanded === r.id} onToggle={() => setExpanded(expanded === r.id ? null : r.id)} containerType={containerType} cheapestInMode={cheapestAir}/>
                  ))}
                </div>
              </>
            )}
            {filteredSea.length > 0 && (
              <>
                <ModeSectionHeader mode="sea" count={filteredSea.length} note="Lower cost, longer transit"/>
                <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
                  {filteredSea.map((r) => (
                    <RateQueryCard key={r.id} rate={r} isOpen={expanded === r.id} onToggle={() => setExpanded(expanded === r.id ? null : r.id)} containerType={containerType} cheapestInMode={cheapestSea}/>
                  ))}
                </div>
              </>
            )}
            {filteredAir.length === 0 && filteredSea.length === 0 && (
              <div className="card" style={{ padding: 24, textAlign: 'center', color: 'var(--fg-3)', fontSize: 12.5 }}>
                No rates match the selected filter.
              </div>
            )}
          </div>
        </>
      )}

      <style>{`
        .rq-label { font-size: 10.5px; font-weight: 600; color: var(--fg-3); text-transform: uppercase; letter-spacing: 0.05em; display: block; margin-bottom: 5px; }
        .rate-card {
          background: var(--bg-surface);
          border: 1px solid var(--n-100);
          border-radius: 12px;
          transition: border-color .14s, box-shadow .14s;
          overflow: hidden;
        }
        .rate-card:hover { border-color: var(--n-200); box-shadow: var(--shadow-sm); }
        .rate-card.open { border-color: var(--brand-300); box-shadow: 0 0 0 3px var(--brand-50), var(--shadow-sm); }
        .source-stripe { width: 4px; align-self: stretch; }
      `}</style>
    </div>
  );
};

/* ============== Port Picker ============== */
function PortPicker({ label, value, onChange, otherValue }) {
  const [open, setOpen] = React.useState(false);
  const [q, setQ] = React.useState('');
  const ref = React.useRef(null);
  React.useEffect(() => {
    const close = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', close);
    return () => document.removeEventListener('mousedown', close);
  }, []);

  const selected = window.PortByCode[value];
  const list = window.PORTS.filter(p => p.code !== otherValue && (!q ||
    p.name.toLowerCase().includes(q.toLowerCase()) ||
    p.code.toLowerCase().includes(q.toLowerCase()) ||
    p.country.toLowerCase().includes(q.toLowerCase())
  ));

  return (
    <div ref={ref} style={{ position: 'relative' }}>
      <label className="rq-label">{label}</label>
      <button type="button" onClick={() => { setOpen(o => !o); setQ(''); }}
        className="input"
        style={{
          width: '100%', display: 'flex', alignItems: 'center', gap: 8, padding: '0 10px',
          background: open ? 'white' : 'var(--bg-surface)',
          borderColor: open ? 'var(--brand-500)' : 'var(--n-150)',
          boxShadow: open ? '0 0 0 3px var(--brand-50)' : 'none',
          cursor: 'pointer', textAlign: 'left',
        }}>
        {selected ? (
          <>
            <window.Flag port={selected.code} lg/>
            <span className="mono" style={{ fontWeight: 700 }}>{selected.code}</span>
            <span style={{ color: 'var(--fg-2)', fontSize: 12.5, flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{selected.name}</span>
          </>
        ) : (
          <span style={{ color: 'var(--fg-4)', flex: 1 }}>Select port…</span>
        )}
        <window.Icon name="chev-d" size={13} color="#98A2B3"/>
      </button>

      {open && (
        <div style={{
          position: 'absolute', top: 'calc(100% + 4px)', left: 0, right: 0,
          background: 'white', border: '1px solid var(--n-100)', borderRadius: 8,
          boxShadow: 'var(--shadow-md)', zIndex: 20,
          maxHeight: 320, display: 'flex', flexDirection: 'column',
        }}>
          <div style={{ padding: 8, borderBottom: '1px solid var(--n-100)', display: 'flex', alignItems: 'center', gap: 6 }}>
            <window.Icon name="search" size={13} color="#98A2B3"/>
            <input autoFocus value={q} onChange={e => setQ(e.target.value)} placeholder="Search by name, code, country…"
              style={{ border: 0, outline: 0, flex: 1, fontSize: 12.5, background: 'transparent', color: 'var(--fg-1)' }}/>
          </div>
          <div style={{ overflow: 'auto', flex: 1 }}>
            {list.map(p => (
              <button key={p.code} type="button" onClick={() => { onChange(p.code); setOpen(false); }}
                style={{
                  display: 'flex', alignItems: 'center', gap: 10, width: '100%',
                  padding: '8px 12px', border: 0, background: 'transparent',
                  textAlign: 'left', cursor: 'pointer', fontSize: 12.5,
                  borderBottom: '1px solid var(--n-50)',
                }}
                onMouseEnter={e => e.currentTarget.style.background = 'var(--n-50)'}
                onMouseLeave={e => e.currentTarget.style.background = 'transparent'}
              >
                <window.Flag port={p.code} lg/>
                <span className="mono" style={{ fontWeight: 700, width: 38 }}>{p.code}</span>
                <span style={{ flex: 1, color: 'var(--fg-1)' }}>{p.name}</span>
                <span style={{ color: 'var(--fg-3)', fontSize: 11 }}>{p.country}</span>
              </button>
            ))}
            {list.length === 0 && (
              <div style={{ padding: 16, textAlign: 'center', color: 'var(--fg-4)', fontSize: 12 }}>No matches</div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

/* ============== Summary stat tile ============== */
function SummaryStat({ label, value, sub, color, icon }) {
  return (
    <div>
      <div style={{ fontSize: 10, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em', display: 'flex', alignItems: 'center', gap: 4 }}>
        {icon && <window.Icon name={icon} size={10} color={color || '#667085'}/>}
        {label}
      </div>
      <div className="mono tnum" style={{ fontSize: 22, fontWeight: 700, marginTop: 3, color: color || 'var(--fg-1)', letterSpacing: '-0.01em' }}>{value}</div>
      <div style={{ fontSize: 10.5, color: 'var(--fg-3)', marginTop: 1 }}>{sub}</div>
    </div>
  );
}

/* ============== Mode section header ============== */
function ModeSectionHeader({ mode, count, note }) {
  const isAir = mode === 'air';
  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 10,
      padding: '6px 2px',
    }}>
      <div style={{
        width: 28, height: 28, borderRadius: 8,
        background: isAir ? 'var(--brand-50)' : 'var(--n-50)',
        color: isAir ? 'var(--brand-700)' : 'var(--fg-2)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        border: isAir ? '1px solid var(--brand-200)' : '1px solid var(--n-100)',
      }}>
        <window.Icon name={isAir ? 'plane' : 'ship'} size={14}/>
      </div>
      <div style={{ display: 'flex', alignItems: 'baseline', gap: 8 }}>
        <span style={{ fontSize: 14, fontWeight: 700, color: 'var(--fg-1)', letterSpacing: '-0.01em' }}>
          {isAir ? 'Air freight' : 'Sea freight'}
        </span>
        <span style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>
          {count} option{count === 1 ? '' : 's'}
        </span>
      </div>
      <div style={{ flex: 1, height: 1, background: 'var(--n-100)', marginLeft: 4 }}/>
      {note && (
        <span style={{ fontSize: 11, color: isAir ? 'var(--brand-700)' : 'var(--fg-3)', fontWeight: isAir ? 600 : 400 }}>
          {note}
        </span>
      )}
    </div>
  );
}

/* ============== Carrier / airline logo ============== */
const CARRIER_CODES = {
  'Emirates SkyCargo':        { code: 'EK',  label: 'Emirates' },
  'Qatar Airways Cargo':      { code: 'QR',  label: 'Qatar' },
  'Cathay Cargo':             { code: 'CX',  label: 'Cathay' },
  'Lufthansa Cargo':          { code: 'LH',  label: 'Lufthansa' },
  'Singapore Airlines Cargo': { code: 'SQ',  label: 'SIA' },
  'Turkish Cargo':            { code: 'TK',  label: 'Turkish' },
  'Etihad Cargo':             { code: 'EY',  label: 'Etihad' },
  'AF-KLM Cargo':             { code: 'AF',  label: 'AF·KL' },
  'Korean Air Cargo':         { code: 'KE',  label: 'Korean' },
  'Maersk':                   { code: 'MSK', label: 'Maersk' },
  'MSC':                      { code: 'MSC', label: 'MSC' },
  'CMA CGM':                  { code: 'CMA', label: 'CMA CGM' },
  'Hapag-Lloyd':              { code: 'HL',  label: 'Hapag' },
  'ONE':                      { code: 'ONE', label: 'ONE' },
  'Evergreen':                { code: 'EMC', label: 'Evergreen' },
  'Yang Ming':                { code: 'YM',  label: 'Yang Ming' },
  'Own Network':              { code: 'OWN', label: 'Own' },
  'TAC Index (Air)':          { code: 'TAC', label: 'Air idx' },
  'Freightos FBX Index':      { code: 'FBX', label: 'Sea idx' },
};

/* Real carrier logo URLs — airlines via pics.avs.io, sea via Google favicons */
const CARRIER_LOGOS = {
  'Emirates SkyCargo':        'https://pics.avs.io/80/80/EK.png',
  'Qatar Airways Cargo':      'https://pics.avs.io/80/80/QR.png',
  'Cathay Cargo':             'https://pics.avs.io/80/80/CX.png',
  'Lufthansa Cargo':          'https://pics.avs.io/80/80/LH.png',
  'Singapore Airlines Cargo': 'https://pics.avs.io/80/80/SQ.png',
  'Turkish Cargo':            'https://pics.avs.io/80/80/TK.png',
  'Etihad Cargo':             'https://pics.avs.io/80/80/EY.png',
  'AF-KLM Cargo':             'https://pics.avs.io/80/80/AF.png',
  'Korean Air Cargo':         'https://pics.avs.io/80/80/KE.png',
  'Maersk':                   'https://www.google.com/s2/favicons?domain=maersk.com&sz=128',
  'MSC':                      'https://www.google.com/s2/favicons?domain=msc.com&sz=128',
  'CMA CGM':                  'https://www.google.com/s2/favicons?domain=cma-cgm.com&sz=128',
  'Hapag-Lloyd':              'https://www.google.com/s2/favicons?domain=www.hapag-lloyd.com&sz=128',
  'ONE':                      'https://www.google.com/s2/favicons?domain=one-line.com&sz=128',
  'Evergreen':                'https://www.google.com/s2/favicons?domain=www.evergreen-line.com&sz=128',
  'Yang Ming':                'https://www.google.com/s2/favicons?domain=www.yangming.com&sz=128',
};

function CarrierLogo({ name, color, mode, source }) {
  const meta = CARRIER_CODES[name] || { code: name.slice(0, 3).toUpperCase(), label: name };
  const isIndex = source === 'market' || name.includes('Index');
  const logoUrl = CARRIER_LOGOS[name];
  const [imgFailed, setImgFailed] = React.useState(false);
  const showLogo = logoUrl && !isIndex && !imgFailed;

  const bg = isIndex ? '#F5F4F2' : showLogo ? '#FFFFFF' : (color || '#0F1E37');
  const fg = isIndex ? '#0F1E37' : 'white';
  return (
    <div style={{
      display: 'flex', flexDirection: 'column', alignItems: 'center',
      gap: 4, flexShrink: 0, width: 56,
    }}>
      <div style={{
        width: 52, height: 38, borderRadius: 7,
        background: bg, color: fg,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        fontFamily: 'JetBrains Mono, monospace',
        fontWeight: 800, fontSize: 14, letterSpacing: '0.04em',
        boxShadow: isIndex
          ? 'inset 0 0 0 1px var(--n-150)'
          : showLogo
            ? '0 1px 2px rgba(15,30,55,0.12), inset 0 0 0 1px rgba(15,30,55,0.08)'
            : '0 1px 2px rgba(15,30,55,0.15), inset 0 1px 0 rgba(255,255,255,0.18)',
        position: 'relative', overflow: 'hidden',
      }}>
        {showLogo ? (
          <img
            src={logoUrl}
            alt={meta.label}
            onError={() => setImgFailed(true)}
            style={{
              width: 44, height: 30,
              objectFit: 'contain',
              position: 'relative',
            }}
          />
        ) : (
          <>
            {/* subtle gloss accent */}
            {!isIndex && (
              <span style={{
                position: 'absolute', inset: 0, background: 'linear-gradient(135deg, rgba(255,255,255,0.18) 0%, rgba(255,255,255,0) 55%)',
                pointerEvents: 'none',
              }}/>
            )}
            <span style={{ position: 'relative' }}>{meta.code}</span>
          </>
        )}
      </div>
      <div style={{ fontSize: 9.5, color: 'var(--fg-3)', fontWeight: 600, letterSpacing: '0.02em', whiteSpace: 'nowrap', maxWidth: 56, overflow: 'hidden', textOverflow: 'ellipsis', textAlign: 'center' }}>
        {meta.label}
      </div>
    </div>
  );
}

/* ============== Rate Query Card (collapsed + expanded) ============== */
function RateQueryCard({ rate, isOpen, onToggle, containerType, cheapestInMode }) {
  const sourceMeta = {
    contracted: { label: 'Contracted', icon: 'check-circle', color: 'var(--brand-700)', bg: 'var(--brand-50)', stripe: 'var(--brand-500)', badge: 'b-blue' },
    spot:       { label: 'Spot',       icon: 'bolt',         color: 'var(--warning-700)', bg: 'var(--warning-50)', stripe: 'var(--warning-500)', badge: 'b-warning' },
    market:     { label: 'Market',     icon: 'globe',        color: 'var(--agent-700)', bg: 'var(--agent-50)', stripe: 'var(--agent-500)', badge: 'b-agent' },
  }[rate.source];

  const isCheapest = rate.total === cheapestInMode;
  const carrierColor = window.CARRIERS.find(c => c.name === rate.carrier)?.color || '#98A2B3';
  const isAir = rate.mode === 'air';
  const unitLabel = isAir ? `per ${rate.chargeableKg ? rate.chargeableKg.toLocaleString() + ' kg' : 'shipment'}` : `per ${containerType}`;
  const allInLabel = isAir ? `All-in / ${rate.chargeableKg ? rate.chargeableKg.toLocaleString() + ' kg' : 'shipment'}` : `All-in / ${containerType}`;

  return (
    <div className={`rate-card ${isOpen ? 'open' : ''}`}>
      <div style={{ display: 'flex' }}>
        <div className="source-stripe" style={{ background: sourceMeta.stripe }}/>
        <div style={{ flex: 1, padding: '14px 18px', cursor: 'pointer', display: 'grid', gridTemplateColumns: '1.4fr 1fr 0.9fr 1.1fr auto', gap: 16, alignItems: 'center' }}
          onClick={onToggle}>
          {/* Carrier + source */}
          <div style={{ display: 'flex', gap: 12, alignItems: 'center' }}>
            <CarrierLogo name={rate.carrier} color={carrierColor} mode={rate.mode} source={rate.source}/>
            <div style={{ minWidth: 0, flex: 1 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 3, flexWrap: 'wrap' }}>
                {isCheapest && <span className="badge b-success" style={{ fontSize: 10 }}>Best {isAir ? 'air' : 'sea'} price</span>}
                <span className={`badge ${isAir ? 'b-blue' : 'b-neutral'}`} style={{ fontSize: 10 }}>
                  <window.Icon name={isAir ? 'plane' : 'ship'} size={9}/>
                  {isAir ? 'Air' : 'Sea'}
                </span>
                <span className={`badge ${sourceMeta.badge}`} style={{ fontSize: 10 }}>
                  <window.Icon name={sourceMeta.icon} size={9}/>
                  {sourceMeta.label}
                </span>
              </div>
              <div style={{ fontSize: 12, color: 'var(--fg-2)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{rate.service}</div>
            </div>
          </div>

          {/* Hero rate */}
          <div>
            <div style={{ fontSize: 10, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>{allInLabel}</div>
            <div className="mono tnum" style={{ fontSize: 24, fontWeight: 700, color: 'var(--fg-1)', letterSpacing: '-0.02em', lineHeight: 1.1, marginTop: 2 }}>
              ${rate.total.toLocaleString()}
            </div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 2 }}>
              {isAir
                ? <><span className="mono">${rate.perKg?.toFixed(2)}</span>/kg base + <span className="mono">${(rate.total - rate.base).toLocaleString()}</span> surcharges</>
                : <><span className="mono">${rate.base.toLocaleString()}</span> base + <span className="mono">${(rate.total - rate.base).toLocaleString()}</span> surcharges</>}
            </div>
          </div>

          {/* Transit */}
          <div>
            <div style={{ fontSize: 10, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Transit</div>
            <div className="mono tnum" style={{ fontSize: 17, fontWeight: 700, marginTop: 2 }}>{rate.transitDays}d</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)', marginTop: 1 }}>{rate.freeDays} free days</div>
          </div>

          {/* Validity */}
          <div>
            <div style={{ fontSize: 10, color: 'var(--fg-3)', fontWeight: 600, textTransform: 'uppercase', letterSpacing: '0.06em' }}>Validity</div>
            <div style={{ fontSize: 12.5, fontWeight: 600, marginTop: 3 }}>{rate.validity}</div>
            <div style={{ fontSize: 11, color: rate.daysLeft <= 14 ? 'var(--warning-700)' : 'var(--fg-3)', marginTop: 1 }}>
              {rate.daysLeft} day{rate.daysLeft === 1 ? '' : 's'} left
            </div>
          </div>

          {/* Toggle */}
          <button className="btn btn-sm btn-secondary" onClick={(e) => { e.stopPropagation(); onToggle(); }}>
            {isOpen ? 'Hide' : 'Breakdown'}
            <window.Icon name={isOpen ? 'chev-u' : 'chev-d'} size={11}/>
          </button>
        </div>
      </div>

      {isOpen && <RateQueryBreakdown rate={rate} sourceMeta={sourceMeta} containerType={containerType}/>}
    </div>
  );
}

/* ============== Expanded breakdown ============== */
function RateQueryBreakdown({ rate, sourceMeta, containerType }) {
  const isAir = rate.mode === 'air';
  const equipmentLabel = isAir
    ? `${rate.chargeableKg?.toLocaleString() || '1,000'} kg chargeable`
    : containerType;
  /* Group line items */
  const groups = {};
  rate.lineItems.forEach(li => {
    if (!groups[li.group]) groups[li.group] = [];
    groups[li.group].push(li);
  });
  const groupOrder = ['Air freight','Ocean freight','Origin charges','Destination charges','Insurance & customs'].filter(g => groups[g]);

  return (
    <div style={{ borderTop: '1px solid var(--n-100)', background: 'var(--n-25)', padding: 18, display: 'flex', flexDirection: 'column', gap: 16 }}>

      {/* Notes / context */}
      {rate.notes && (
        <div style={{ background: sourceMeta.bg, border: `1px solid ${sourceMeta.color}22`, borderRadius: 8, padding: '10px 12px', display: 'flex', gap: 8, alignItems: 'flex-start' }}>
          <window.Icon name="info" size={13} color={sourceMeta.color}/>
          <div style={{ fontSize: 12, color: sourceMeta.color, lineHeight: 1.5 }}>{rate.notes}</div>
        </div>
      )}

      {/* Two-column: line items + summary panel */}
      <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr', gap: 16 }}>
        {/* Line items */}
        <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
          <div style={{ padding: '10px 14px', borderBottom: '1px solid var(--n-100)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.05em' }}>Rate breakdown</div>
            <div style={{ fontSize: 11, color: 'var(--fg-3)' }}>{rate.lineItems.length} line items · USD</div>
          </div>
          <table className="table" style={{ fontSize: 12 }}>
            <thead>
              <tr>
                <th style={{ width: 60 }}>Code</th>
                <th>Charge</th>
                <th style={{ width: 110 }}>Basis</th>
                <th style={{ width: 90, textAlign: 'right' }}>Amount</th>
              </tr>
            </thead>
            <tbody>
              {groupOrder.map(g => (
                <React.Fragment key={g}>
                  <tr>
                    <td colSpan={4} style={{ padding: '8px 12px', background: 'var(--n-50)', fontSize: 10.5, fontWeight: 700, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>
                      {g}
                    </td>
                  </tr>
                  {groups[g].map((li, i) => (
                    <tr key={`${g}-${i}`}>
                      <td><span className="mono" style={{ fontSize: 10.5, padding: '2px 6px', background: 'var(--n-75)', borderRadius: 4, color: 'var(--fg-3)' }}>{li.code}</span></td>
                      <td style={{ color: 'var(--fg-1)' }}>{li.label}</td>
                      <td style={{ color: 'var(--fg-3)', fontSize: 11.5 }}>{li.basis}</td>
                      <td className="mono tnum" style={{ textAlign: 'right', fontWeight: 600 }}>${li.amount.toLocaleString()}</td>
                    </tr>
                  ))}
                </React.Fragment>
              ))}
              <tr style={{ borderTop: '2px solid var(--n-100)', background: 'var(--n-50)' }}>
                <td colSpan={3} style={{ padding: '10px 12px', fontSize: 12, fontWeight: 700, color: 'var(--fg-1)' }}>Total all-in / {equipmentLabel}</td>
                <td className="mono tnum" style={{ textAlign: 'right', fontSize: 14, fontWeight: 700, color: 'var(--fg-1)', padding: '10px 12px' }}>${rate.total.toLocaleString()}</td>
              </tr>
            </tbody>
          </table>
        </div>

        {/* Side: schedule + actions */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <div className="card" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Schedule & service</div>
            <KV k="Service / string" v={rate.serviceName}/>
            <KV k="Vessel / flight" v={rate.vessel}/>
            <KV k="Frequency" v={rate.frequency}/>
            <KV k="ETD" v={rate.etd}/>
            <KV k="ETA" v={rate.eta}/>
            <KV k="Routing" v={rate.routing}/>
          </div>

          <div className="card" style={{ padding: 14 }}>
            <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.05em', marginBottom: 8 }}>Terms</div>
            <KV k="Free days · origin" v={`${rate.freeDays - 2}d`}/>
            <KV k="Free days · destination" v={`${rate.freeDays}d`}/>
            <KV k="Detention/demurrage" v={rate.dnd}/>
            <KV k="Validity" v={rate.validity}/>
            <KV k="Incoterms" v={rate.incoterms}/>
            <KV k={isAir ? 'Chargeable basis' : 'Equipment'} v={equipmentLabel}/>
          </div>

          <div style={{ display: 'flex', gap: 6 }}>
            <button className="btn btn-primary" style={{ flex: 1 }}>
              <window.Icon name="check-circle" size={13}/> Use this rate
            </button>
            <button className="btn btn-secondary" title="Save to quote">
              <window.Icon name="paperclip" size={13}/>
            </button>
            <button className="btn btn-secondary" title="Share">
              <window.Icon name="send" size={13}/>
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

function KV({ k, v }) {
  return (
    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', padding: '4px 0', borderBottom: '1px dashed var(--n-75)', fontSize: 12 }}>
      <span style={{ color: 'var(--fg-3)' }}>{k}</span>
      <span style={{ color: 'var(--fg-1)', fontWeight: 600, textAlign: 'right' }}>{v}</span>
    </div>
  );
}

/* ============== Synthetic rate builder ==============
   Generates realistic-looking spot/contracted/market rates for any POL→POD using
   the lane-health and rate-breakdown seed data as a base.
   Returns both AIR and SEA options — air pinned at top per client preference.
*/
function buildRates(pol, pod, dateStr, containerType, incoterms) {
  /* ----- SEA BASE ----- */
  const O = window.MATRIX_ORIGINS.indexOf(pol);
  const D = window.MATRIX_DESTS.indexOf(pod);
  let seaBaseRate = 3850;
  let topSeaCarrier = 'Maersk';
  if (O !== -1 && D !== -1 && window.LANE_HEALTH[O] && window.LANE_HEALTH[O][D]) {
    seaBaseRate = window.LANE_HEALTH[O][D].rate;
    topSeaCarrier = window.LANE_HEALTH[O][D].topCarrier;
  } else {
    const h = (pol + pod).split('').reduce((s, c) => s + c.charCodeAt(0), 0);
    seaBaseRate = 2200 + (h % 4500);
  }

  /* ----- AIR BASE (per kg) ----- */
  const aO = window.AIR_MATRIX_ORIGINS.indexOf(pol);
  const aD = window.AIR_MATRIX_DESTS.indexOf(pod);
  let airBaseRate = null; // $/kg
  let topAirCarrier = 'Emirates SkyCargo';
  if (aO !== -1 && aD !== -1 && window.MATRIX_BY_MODE.air.health[aO] && window.MATRIX_BY_MODE.air.health[aO][aD]) {
    airBaseRate = window.MATRIX_BY_MODE.air.health[aO][aD].rate;
    topAirCarrier = window.MATRIX_BY_MODE.air.health[aO][aD].topCarrier;
  } else {
    /* Synthesize air rate even when not in matrix — pricing depends on lane region */
    const h = (pol + pod).split('').reduce((s, c) => s + c.charCodeAt(0), 0);
    airBaseRate = +(2.4 + (h % 35) / 10).toFixed(2); // $2.40 - $5.90/kg
  }

  /* Equipment multiplier */
  const eqMult = { '20GP': 0.68, '40GP': 0.95, '40HC': 1.0, '40RF': 1.55, 'LCL': 0.18 }[containerType] || 1;
  const baseRate = Math.round(seaBaseRate * eqMult);

  /* For air, assume 1000kg chargeable weight as default if no weight given */
  const chargeableKg = 1000;
  const airTotalBase = Math.round(airBaseRate * chargeableKg);

  /* Date offset → "days until departure" influences spot pricing */
  const today = new Date();
  const etd = new Date(dateStr);
  const daysOut = Math.max(1, Math.round((etd - today) / 86400000));
  const urgency = daysOut < 14 ? 1.08 : daysOut < 28 ? 1.02 : 0.98;

  const seaCarriers = ['Maersk','MSC','CMA CGM','Hapag-Lloyd','ONE','Evergreen','Yang Ming'];
  const seaCarrierOrder = [topSeaCarrier, ...seaCarriers.filter(c => c !== topSeaCarrier)].slice(0, 5);

  const airCarriers = ['Emirates SkyCargo','Qatar Airways Cargo','Cathay Cargo','Lufthansa Cargo','Singapore Airlines Cargo','Turkish Cargo','Etihad Cargo','AF-KLM Cargo'];
  const airCarrierOrder = [topAirCarrier, ...airCarriers.filter(c => c !== topAirCarrier)].slice(0, 5);

  const services = {
    'Maersk':      { name: 'AE7 · Asia–Europe',    vessel: 'Maersk Halifax 524W',     frequency: 'Weekly', routing: 'Direct · 0 transhipment' },
    'MSC':         { name: 'Swan Service',          vessel: 'MSC Beryl 521W',          frequency: 'Weekly', routing: 'Via Suez · 1 call' },
    'CMA CGM':     { name: 'FAL3 · French Asia',    vessel: 'CMA CGM Marco Polo 528E', frequency: 'Weekly', routing: 'Direct' },
    'Hapag-Lloyd': { name: 'FE3 · Far East Loop',   vessel: 'Hong Kong Express 510W',  frequency: 'Weekly', routing: 'Direct' },
    'ONE':         { name: 'FP1 · East-bound',      vessel: 'ONE Stork 522W',          frequency: 'Weekly', routing: 'Via Colombo' },
    'Evergreen':   { name: 'CES · China-Euro',      vessel: 'Ever Ace 519W',           frequency: 'Weekly', routing: 'Direct' },
    'Yang Ming':   { name: 'AE2 · Asia-Europe 2',   vessel: 'YM Wisdom 514W',          frequency: 'Bi-weekly', routing: 'Direct' },
  };

  const airServices = {
    'Emirates SkyCargo':        { name: 'EK · Daily widebody',           vessel: 'EK 351 / 777F',   frequency: 'Daily', routing: 'Via Dubai · 1 hub' },
    'Qatar Airways Cargo':      { name: 'QR · Daily freighter',          vessel: 'QR 8121 / 777F',  frequency: 'Daily', routing: 'Via Doha · 1 hub' },
    'Cathay Cargo':             { name: 'CX · Asia trunk',               vessel: 'CX 95 / 747-8F',  frequency: '6× weekly', routing: 'Via HKG · 1 hub' },
    'Lufthansa Cargo':          { name: 'LH · MD-11F Europe',            vessel: 'LH 8262 / 777F',  frequency: 'Daily', routing: 'Via Frankfurt · 1 hub' },
    'Singapore Airlines Cargo': { name: 'SQ · Daily 747F',               vessel: 'SQ 7975 / 747-400F', frequency: 'Daily', routing: 'Via Singapore' },
    'Turkish Cargo':            { name: 'TK · Daily widebody',           vessel: 'TK 6485 / 777F',  frequency: 'Daily', routing: 'Via Istanbul' },
    'Etihad Cargo':             { name: 'EY · Daily freighter',          vessel: 'EY 9853 / 777F',  frequency: 'Daily', routing: 'Via Abu Dhabi' },
    'AF-KLM Cargo':             { name: 'AF/KL · Combi · daily',         vessel: 'AF 6743 / 777F',  frequency: 'Daily', routing: 'Via Paris / Amsterdam' },
  };

  /* Build rate cards */
  const out = [];
  const fmtDate = (d) => d.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' });
  const addDays = (d, n) => new Date(d.getTime() + n * 86400000);

  /* ---------------- AIR LINE ITEMS ---------------- */
  const makeAirLineItems = (perKg, src) => {
    const dest = window.PortByCode[pod];
    const orig = window.PortByCode[pol];
    const base = Math.round(perKg * chargeableKg);
    const items = [
      { group: 'Air freight',       label: `Air Freight · ${chargeableKg.toLocaleString()} kg chargeable`,  code: 'AWB',  basis: `${chargeableKg} × $${perKg.toFixed(2)}/kg`, amount: base },
      { group: 'Air freight',       label: 'Fuel Surcharge',                              code: 'MYC',  basis: '$0.42/kg',         amount: Math.round(0.42 * chargeableKg) },
      { group: 'Air freight',       label: 'Security Surcharge',                          code: 'SCC',  basis: '$0.15/kg',         amount: Math.round(0.15 * chargeableKg) },
    ];
    if (src === 'spot' && daysOut < 21) {
      items.push({ group: 'Air freight', label: 'Peak Capacity Surcharge', code: 'PSS', basis: 'short-fuse', amount: 220 });
    }
    items.push(
      { group: 'Origin charges',      label: `Airport Handling · ${orig?.name || pol}`,     code: 'AHC',  basis: 'per shipment', amount: 165 + Math.round(Math.random() * 30) },
      { group: 'Origin charges',      label: 'AWB Documentation Fee',                       code: 'DOC',  basis: 'per AWB',       amount: 60 },
      { group: 'Origin charges',      label: 'X-Ray Screening',                              code: 'XRY',  basis: 'per shipment',  amount: 75 },
      { group: 'Destination charges', label: `Airport Handling · ${dest?.name || pod}`,     code: 'AHC',  basis: 'per shipment', amount: 195 + Math.round(Math.random() * 40) },
      { group: 'Destination charges', label: 'Trucking · airport ⇢ door',                    code: 'INL',  basis: 'door',          amount: 320 },
      { group: 'Insurance & customs', label: incoterms === 'CIF' || incoterms === 'CIP' ? 'Air Cargo Insurance · All Risk' : 'Air Cargo Insurance · optional', code: 'INS', basis: '0.22% of CIF', amount: 195 },
      { group: 'Insurance & customs', label: 'Customs Clearance · Origin',                  code: 'CCO',  basis: 'per shipment',  amount: 85 },
      { group: 'Insurance & customs', label: 'Customs Clearance · Destination',             code: 'CCD',  basis: 'per shipment',  amount: 110 },
    );
    return items;
  };

  /* Air contracted (2) */
  airCarrierOrder.slice(0, 2).forEach((carrier, i) => {
    const perKg = +(airBaseRate * (0.96 - i * 0.04) * urgency * 0.95).toFixed(2);
    const li = makeAirLineItems(perKg, 'contracted');
    const total = li.reduce((s, it) => s + it.amount, 0);
    const validUntil = addDays(today, 60 + i * 15);
    out.push({
      id: `ac-${i}`,
      mode: 'air',
      source: 'contracted',
      carrier,
      service: airServices[carrier]?.name || 'Daily freighter',
      serviceName: airServices[carrier]?.name || 'Daily freighter',
      vessel: airServices[carrier]?.vessel || `${carrier} freighter`,
      frequency: airServices[carrier]?.frequency || 'Daily',
      routing: airServices[carrier]?.routing || 'Via hub',
      transitDays: 2 + i,
      freeDays: 4,
      validity: fmtDate(validUntil),
      daysLeft: 60 + i * 15,
      etd: fmtDate(etd),
      eta: fmtDate(addDays(etd, 2 + i)),
      dnd: '$45/day after free time',
      incoterms,
      perKg,
      chargeableKg,
      base: Math.round(perKg * chargeableKg),
      total,
      lineItems: li,
      notes: i === 0 ? `Contracted block-space agreement with ${carrier} on daily widebody freighter. Allotment confirmed up to 2 tons/day; expanded capacity available with 48h notice.` : null,
    });
  });

  /* Air spot (3) */
  airCarrierOrder.slice(0, 3).forEach((carrier, i) => {
    const perKg = +(airBaseRate * (1.05 + i * 0.06) * urgency).toFixed(2);
    const li = makeAirLineItems(perKg, 'spot');
    const total = li.reduce((s, it) => s + it.amount, 0);
    const daysLeft = [5, 10, 14][i];
    out.push({
      id: `as-${i}`,
      mode: 'air',
      source: 'spot',
      carrier,
      service: airServices[carrier]?.name || 'Spot allocation',
      serviceName: airServices[carrier]?.name || 'Spot allocation',
      vessel: airServices[carrier]?.vessel || `${carrier} freighter`,
      frequency: airServices[carrier]?.frequency || 'Daily',
      routing: airServices[carrier]?.routing || 'Via hub',
      transitDays: 2 + i,
      freeDays: 3 + i,
      validity: fmtDate(addDays(today, daysLeft)),
      daysLeft,
      etd: fmtDate(etd),
      eta: fmtDate(addDays(etd, 2 + i)),
      dnd: '$60/day after free time',
      incoterms,
      perKg,
      chargeableKg,
      base: Math.round(perKg * chargeableKg),
      total,
      lineItems: li,
      notes: i === 0 ? `Spot allotment fetched from ${carrier} Cargo Portal — valid ${daysLeft} days. Confirms capacity on next ${i === 0 ? '3' : '5'} departures.` : null,
    });
  });

  /* ---------------- SEA LINE ITEMS ---------------- */
  const makeLineItems = (base, src) => {
    const dest = window.PortByCode[pod];
    const orig = window.PortByCode[pol];
    const isEU = ['NL','DE','FR','GB','BE','ES','IT'].includes(dest?.country);
    const items = [
      { group: 'Ocean freight',     label: `Ocean Freight · ${containerType}`,           code: 'OFR',  basis: `1 × $${base.toLocaleString()}`, amount: base },
      { group: 'Ocean freight',     label: 'Bunker Adjustment Factor',                    code: 'BAF',  basis: 'fuel index',     amount: Math.round(base * 0.13) },
      { group: 'Ocean freight',     label: 'Currency Adjustment Factor',                  code: 'CAF',  basis: '2.5%',           amount: Math.round(base * 0.025) },
    ];
    if (src === 'spot' && daysOut < 28) {
      items.push({ group: 'Ocean freight', label: 'Peak Season Surcharge', code: 'PSS', basis: 'short-fuse', amount: 180 });
    }
    items.push(
      { group: 'Origin charges',      label: `Terminal Handling · ${orig?.name || pol}`, code: 'THC',  basis: 'per container', amount: 220 + Math.round(Math.random() * 30) },
      { group: 'Origin charges',      label: 'ISPS Security · Origin',                    code: 'ISPS', basis: 'per container', amount: 25 },
      { group: 'Origin charges',      label: 'B/L Documentation Fee',                     code: 'DOC',  basis: 'per B/L',       amount: 80 },
      { group: 'Destination charges', label: `Terminal Handling · ${dest?.name || pod}`,  code: 'THC',  basis: 'per container', amount: 290 + Math.round(Math.random() * 40) },
    );
    if (isEU) {
      items.push({ group: 'Destination charges', label: 'ENS Filing (EU advance manifest)', code: 'ENS', basis: 'per shipment', amount: 35 });
    }
    items.push(
      { group: 'Destination charges', label: 'Inland Haulage · door delivery',           code: 'INL',  basis: 'door',          amount: 420 },
      { group: 'Insurance & customs', label: incoterms === 'CIF' || incoterms === 'CIP' ? 'Marine Insurance · All Risk' : 'Marine Insurance · optional', code: 'INS', basis: '0.18% of CIF', amount: 295 },
      { group: 'Insurance & customs', label: 'Customs Clearance · Origin',               code: 'CCO',  basis: 'per shipment',  amount: 95 },
      { group: 'Insurance & customs', label: 'Customs Clearance · Destination',          code: 'CCD',  basis: 'per shipment',  amount: 110 },
    );
    return items;
  };

  /* Sea Contracted (2) */
  seaCarrierOrder.slice(0, 2).forEach((carrier, i) => {
    const base = Math.round(baseRate * (0.96 - i * 0.025) * urgency * 0.94);
    const li = makeLineItems(base, 'contracted');
    const total = li.reduce((s, it) => s + it.amount, 0);
    const validUntil = addDays(today, 60 + i * 15);
    out.push({
      id: `c-${i}`,
      mode: 'sea',
      source: 'contracted',
      carrier,
      service: services[carrier]?.name || 'Weekly service',
      serviceName: services[carrier]?.name || 'Weekly service',
      vessel: services[carrier]?.vessel || `${carrier} vessel`,
      frequency: services[carrier]?.frequency || 'Weekly',
      routing: services[carrier]?.routing || 'Direct',
      transitDays: 23 + i * 2,
      freeDays: 14,
      validity: fmtDate(validUntil),
      daysLeft: 60 + i * 15,
      etd: fmtDate(etd),
      eta: fmtDate(addDays(etd, 23 + i * 2)),
      dnd: '$95/day after free time',
      incoterms,
      base,
      total,
      lineItems: li,
      notes: i === 0 ? `Contracted lane via signed RFP — locked through ${fmtDate(validUntil)}. ${carrier} has been the primary carrier on this lane for 8+ months.` : null,
    });
  });

  /* Sea Spot (2) */
  seaCarrierOrder.slice(0, 2).forEach((carrier, i) => {
    const base = Math.round(baseRate * (1.04 + i * 0.04) * urgency);
    const li = makeLineItems(base, 'spot');
    const total = li.reduce((s, it) => s + it.amount, 0);
    const daysLeft = [7, 14][i];
    out.push({
      id: `s-${i}`,
      mode: 'sea',
      source: 'spot',
      carrier,
      service: services[carrier]?.name || 'Spot allocation',
      serviceName: services[carrier]?.name || 'Spot allocation',
      vessel: services[carrier]?.vessel || `${carrier} vessel`,
      frequency: services[carrier]?.frequency || 'Weekly',
      routing: services[carrier]?.routing || 'Direct',
      transitDays: 24 + i * 2,
      freeDays: 7 + i,
      validity: fmtDate(addDays(today, daysLeft)),
      daysLeft,
      etd: fmtDate(etd),
      eta: fmtDate(addDays(etd, 24 + i * 2)),
      dnd: '$120/day after free time',
      incoterms,
      base,
      total,
      lineItems: li,
      notes: i === 0 ? `Spot rate fetched live from ${carrier} API — valid ${daysLeft} days. Capacity confirmed for departures up to ${fmtDate(addDays(today, daysLeft))}.` : null,
    });
  });

  /* Market (1 air + 1 sea) */
  const airMarketLi = makeAirLineItems(+(airBaseRate * 1.02).toFixed(2), 'market');
  const airMarketTotal = airMarketLi.reduce((s, it) => s + it.amount, 0);
  out.push({
    id: 'm-air',
    mode: 'air',
    source: 'market',
    carrier: 'TAC Index (Air)',
    service: 'Air market benchmark · 30-day MA',
    serviceName: 'TAC Index',
    vessel: '—',
    frequency: '—',
    routing: 'Reference rate · not bookable',
    transitDays: 3,
    freeDays: 4,
    validity: 'Live index',
    daysLeft: 30,
    etd: fmtDate(etd),
    eta: fmtDate(addDays(etd, 3)),
    dnd: 'Varies by carrier',
    incoterms,
    perKg: +(airBaseRate * 1.02).toFixed(2),
    chargeableKg,
    base: Math.round(airBaseRate * 1.02 * chargeableKg),
    total: airMarketTotal,
    lineItems: airMarketLi,
    notes: 'Composite air market rate from TAC Index. Use as a benchmark when negotiating — not a bookable rate. 30-day moving average across major freighters on this lane.',
  });

  const seaMarketLi = makeLineItems(Math.round(baseRate * 1.0), 'market');
  const seaMarketTotal = seaMarketLi.reduce((s, it) => s + it.amount, 0);
  out.push({
    id: 'm-sea',
    mode: 'sea',
    source: 'market',
    carrier: 'Freightos FBX Index',
    service: 'Sea market index · 30-day MA',
    serviceName: 'Freightos FBX Index',
    vessel: '—',
    frequency: '—',
    routing: 'Reference rate · not bookable',
    transitDays: 26,
    freeDays: 10,
    validity: 'Live index',
    daysLeft: 30,
    etd: fmtDate(etd),
    eta: fmtDate(addDays(etd, 26)),
    dnd: 'Varies by carrier',
    incoterms,
    base: Math.round(baseRate * 1.0),
    total: seaMarketTotal,
    lineItems: seaMarketLi,
    notes: 'Composite sea market rate from Freightos FBX Index. Use as a benchmark when negotiating — not a bookable rate. 30-day moving average across all carriers on this lane.',
  });

  /* Sort: AIR first (then by total), then SEA (then by total) */
  return out.sort((a, b) => {
    if (a.mode !== b.mode) return a.mode === 'air' ? -1 : 1;
    return a.total - b.total;
  });
}

/* Add a 'layers' and 'bolt' icon if not already in the icon set — fallback via 'globe' */
