/* Design 7 — "Pulse"
   Map as full-screen background; a single floating panel on the left
   with three stacked sections: Spending by country, Spending by sector,
   Recent deals. Click a country to drill into its sectors and deals.
   Light SaaS palette — navy + cyan accent on slate.
*/

const psFmt = (v, d = 1) => v.toLocaleString('en-GB', { minimumFractionDigits: d, maximumFractionDigits: d });
const psInt = (v) => v.toLocaleString('en-GB');

function PSPanelBack({ onBack, label }) {
  return (
    <button className="ps-back" onClick={onBack}>
      <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
        <path d="M9 3L5 7L9 11" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
      </svg>
      {label}
    </button>);

}

// CPV → human-readable label, sourced from the 45-division palette.
const cpvName = (cpv) => {
  const code = String(cpv).slice(0, 2);
  const s = (window.EU_SECTOR_PALETTE || []).find((x) => x.code === code);
  return s ? s.officialName : 'Other';
};

// ISO-3 alpha → ISO-2 alpha lookup (EU-27 only).
const iso2FromIso3 = (iso3) => {
  if (!iso3) return null;
  const c = window.EU_COUNTRIES.find((x) => x.iso === iso3);
  return c ? c.iso2 : null;
};

// Render the buyer flag, with a secondary winner flag offset behind when the
// winner country differs from the buyer country.
function DealFlags({ buyerIso2, winnerIso2 }) {
  const flag = (iso2) => `https://flagcdn.com/${iso2.toLowerCase()}.svg`;
  const showSecondary = winnerIso2 && buyerIso2 && winnerIso2 !== buyerIso2;
  return (
    <div className="ps-deal-cty">
      {showSecondary && (
        <span className="ps-flag secondary" title={`Winner: ${winnerIso2}`}>
          <img src={flag(winnerIso2)} alt={winnerIso2} />
        </span>
      )}
      <span className={'ps-flag ' + (showSecondary ? 'primary' : 'solo')} title={`Buyer: ${buyerIso2}`}>
        <img src={flag(buyerIso2)} alt={buyerIso2} />
      </span>
    </div>
  );
}

function DealDetailModal({ deal, onClose }) {
  if (!deal) return null;
  const isForeignSupplier = deal.winnerCountry && deal.winnerCountry !== deal.country;
  const isDirect = deal.procedure === 'direct';
  const isSingleBidder = deal.bidsReceived === 1 && !isDirect;
  // Estimated vs actual delta
  let estDelta = null;
  if (deal.estimatedValue) {
    const pct = ((deal.value - deal.estimatedValue) / deal.estimatedValue) * 100;
    estDelta = { pct: Math.abs(pct).toFixed(1), under: pct < 0 };
  }

  return (
    <div className="ps-deal-modal" onClick={(e) => e.stopPropagation()}>
      <div className="ps-dm-head">
        <button className="ps-dm-close" onClick={onClose} aria-label="Close">
          <svg width="12" height="12" viewBox="0 0 12 12" fill="none">
            <path d="M3 3L9 9M9 3L3 9" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
          </svg>
        </button>
        <div className="ps-dm-id">
          <span className="flag">
            <img src={`https://flagcdn.com/${(deal.countryIso2 || '').toLowerCase()}.svg`} alt="" />
          </span>
          <span>{deal.id}</span>
          {deal.pubDate && <span style={{ color: '#cbd5e1' }}>·</span>}
          {deal.pubDate && <span>Published {deal.pubDate}</span>}
        </div>
        <div className="ps-dm-title">{deal.title}</div>
        <div className="ps-dm-value-row">
          <div className="ps-dm-value">€{deal.value.toLocaleString('en-GB', { minimumFractionDigits: 1, maximumFractionDigits: 1 })}M</div>
          {estDelta && (
            <div className="ps-dm-vs-est">
              vs est. €{deal.estimatedValue.toFixed(1)}M <span className={'delta ' + (estDelta.under ? 'under' : 'over')}>{estDelta.under ? '↓' : '↑'} {estDelta.pct}%</span>
            </div>
          )}
        </div>
        <div className="ps-dm-badges">
          <span className="ps-dm-badge">{deal.sectorName}</span>
          {isSingleBidder && <span className="ps-dm-badge red">● 1 bidder</span>}
          {isDirect && <span className="ps-dm-badge violet">⚡ Direct award</span>}
          {isForeignSupplier && <span className="ps-dm-badge cyan">Cross-border</span>}
          {deal.winnerSme && <span className="ps-dm-badge green">SME winner</span>}
          {deal.euFundsName && <span className="ps-dm-badge amber">EU-funded</span>}
        </div>
      </div>

      <div className="ps-dm-body">
        {/* Direct-award justification */}
        {deal.directAwardJustification && (
          <div className="ps-dm-block">
            <div className="ps-dm-block-t">Why direct award</div>
            <div className="ps-dm-just">
              <div className="ps-dm-just-r">{deal.directAwardReason}</div>
              {deal.directAwardJustification}
            </div>
          </div>
        )}

        {/* Buyer */}
        <div className="ps-dm-block">
          <div className="ps-dm-block-t">Who bought it</div>
          <dl className="ps-dm-kv">
            <dt>Buyer</dt><dd>{deal.buyer}</dd>
            {deal.buyerCity && <><dt>City</dt><dd>{deal.buyerCity}, {deal.country}</dd></>}
            {deal.buyerLegalType && <><dt>Legal type</dt><dd>{deal.buyerLegalType}</dd></>}
            {deal.authorityActivity && <><dt>Main activity</dt><dd>{deal.authorityActivity}</dd></>}
          </dl>
        </div>

        {/* Winner */}
        <div className="ps-dm-block">
          <div className="ps-dm-block-t">Who got the money</div>
          <dl className="ps-dm-kv">
            <dt>Winner</dt><dd>{deal.winner}{deal.winnerSme ? ' (SME)' : ''}</dd>
            {deal.winnerCountry && <><dt>Country</dt><dd>{deal.winnerCountry}{isForeignSupplier ? ' · foreign' : ''}</dd></>}
            {deal.winnerCity && <><dt>City</dt><dd>{deal.winnerCity}</dd></>}
            {deal.uboName && <><dt>Beneficial owner</dt><dd>{deal.uboName}{deal.uboCountry ? ` (${deal.uboCountry})` : ''}</dd></>}
          </dl>
        </div>

        {/* Procurement */}
        <div className="ps-dm-block">
          <div className="ps-dm-block-t">How it was procured</div>
          <dl className="ps-dm-kv">
            <dt>Procedure</dt><dd style={{ textTransform: 'capitalize' }}>{deal.procedure}</dd>
            {!isDirect && <><dt>Bids received</dt><dd>{deal.bidsReceived}{isSingleBidder ? ' · single bidder' : ''}</dd></>}
            {!isDirect && deal.bidsSme > 0 && <><dt>SME bids</dt><dd>{deal.bidsSme} of {deal.bidsReceived}</dd></>}
            {deal.bidLow && deal.bidHigh && (
              <>
                <dt>Bid range</dt>
                <dd>€{deal.bidLow.toFixed(1)}M — €{deal.bidHigh.toFixed(1)}M</dd>
              </>
            )}
          </dl>
        </div>

        {/* What */}
        <div className="ps-dm-block">
          <div className="ps-dm-block-t">What was bought</div>
          <dl className="ps-dm-kv">
            <dt>CPV code</dt><dd className="mono">{deal.cpv} · {cpvName(deal.cpv)}</dd>
            {deal.placeOfPerformance && <><dt>Place</dt><dd>{deal.placeOfPerformance}</dd></>}
            {deal.nutsRegion && <><dt>NUTS region</dt><dd className="mono">{deal.nutsRegion}</dd></>}
          </dl>
        </div>

        {/* EU funds */}
        {deal.euFundsName && (
          <div className="ps-dm-block">
            <div className="ps-dm-block-t">Funding</div>
            <dl className="ps-dm-kv">
              <dt>EU programme</dt><dd>{deal.euFundsName}</dd>
            </dl>
          </div>
        )}

        {/* Timeline */}
        <div className="ps-dm-block">
          <div className="ps-dm-block-t">Timeline</div>
          <dl className="ps-dm-kv">
            {deal.contractDate && <><dt>Contract signed</dt><dd>{deal.contractDate} 2026</dd></>}
          </dl>
        </div>
      </div>

    </div>
  );
}

function useViewport() {
  const [vp, setVp] = React.useState({ w: window.innerWidth, h: window.innerHeight });
  React.useEffect(() => {
    const onResize = () => setVp({ w: window.innerWidth, h: window.innerHeight });
    window.addEventListener('resize', onResize);
    return () => window.removeEventListener('resize', onResize);
  }, []);
  return vp;
}

function PulseDashboard() {
  const { w: vw, h: vh } = useViewport();
  const [selected, setSelected] = React.useState(null); // ISO3 or null for overview
  const [hovered, setHovered] = React.useState(null);
  const [expandedCountries, setExpandedCountries] = React.useState(false);
  const [expandedTenders, setExpandedTenders] = React.useState(false);
  const [expandedSuppliers, setExpandedSuppliers] = React.useState(false);
  const [expandedDeals, setExpandedDeals] = React.useState(false);
  const [activeDeal, setActiveDeal] = React.useState(null);
  const [period, setPeriod] = React.useState('ttm'); // 'ttm' | '2025' | '2026'
  const [view, setView] = React.useState('overview'); // 'overview' | 'tenders' | 'suppliers'
  // dealsScreen takes over the panel when set.
  //   { scope: 'eu' | 'country', sectorCode?: string, sectorName?: string }
  const [dealsScreen, setDealsScreen] = React.useState(null);
  const [dealsSearch, setDealsSearch] = React.useState('');
  const [dealsLimit, setDealsLimit] = React.useState(50);
  // Reset paging + search whenever we enter a new dealsScreen context.
  React.useEffect(() => {
    setDealsSearch('');
    setDealsLimit(50);
  }, [dealsScreen && dealsScreen.scope, dealsScreen && dealsScreen.sectorCode]);

  // Switching view also clears any selected country + deals screen
  const goToView = (next) => {
    setSelected(null);
    setDealsScreen(null);
    setView(next);
  };
  const sorted = React.useMemo(() => [...window.EU_COUNTRIES].sort((a, b) => b.spend - a.spend), []);
  const max = sorted[0].spend;
  const total = window.EU_TOTAL_SPEND;
  const country = selected ? window.EU_COUNTRIES.find((c) => c.iso === selected) : null;
  const countrySectors = country ? window.getCountrySectors(country) : null;
  const countryDeals = country ? window.getCountryDeals(country) : null;
  const recentDeals = React.useMemo(() => window.getEuRecentDeals(200), []);
  const sectorTotals = React.useMemo(() => {
    return window.EU_SECTOR_PALETTE
      .map((s) => ({ ...s, value: window.EU_TOTAL_OF_SECTOR(s.key) }))
      .sort((a, b) => b.value - a.value)
      .map((s, _, arr) => {
        const sum = arr.reduce((t, x) => t + x.value, 0);
        return { ...s, share: (s.value / sum) * 100 };
      });
  }, []);
  const sectorMax = sectorTotals[0].value;

  const fillFor = (c) => {
    if (!c) return '#cbd5e1';
    const t = 0.28 + 0.72 * Math.min(1, Math.pow(c.spend / max, 0.45));
    const lerp = (a, b) => Math.round(a + (b - a) * t);
    // light sky -> deep navy
    return `rgb(${lerp(186, 23)}, ${lerp(220, 45)}, ${lerp(245, 110)})`;
  };

  // Sector colour by CPV group; lightness modulated by share within group.
  // Avoids a 45-hue rainbow (per spec). Three base hues per: supplies/works/services.
  const GROUP_BASE = {
    supplies: [14, 165, 233],   // sky 500
    works:    [30, 58, 138],    // navy 900
    services: [6, 182, 212],    // cyan 500
    other:    [148, 163, 184],  // slate 400
  };
  const sectorColor = (s, refMax) => {
    const base = GROUP_BASE[s.group] || GROUP_BASE.other;
    const t = 0.45 + 0.55 * Math.min(1, Math.pow((s.value || 0) / refMax, 0.5));
    // mix toward white at low t, toward base at high t
    const mix = (a, b) => Math.round(a + (b - a) * t);
    return `rgb(${mix(230, base[0])}, ${mix(238, base[1])}, ${mix(246, base[2])})`;
  };

  return (
    <div className="ps-root">
      <style>{`
        .ps-root {
          width: 100vw; height: 100vh;
          background: #eef3f9;
          color: #0f172a;
          font-family: 'Inter', sans-serif;
          font-size: 13px;
          position: relative;
          overflow: hidden;
        }
        .ps-root, .ps-root * { box-sizing: border-box; }

        /* Map full-bg */
        .ps-map {
          position: absolute; inset: 0;
          z-index: 0;
          background: #f3f6fb;
        }
        .ps-map svg {
          position: relative;
          z-index: 1;
        }
        .ps-sel-label {
          position: absolute;
          background: #0f172a;
          color: #f8fafc;
          padding: 5px 11px;
          border-radius: 999px;
          font-size: 12px; font-weight: 600;
          pointer-events: none;
          white-space: nowrap;
          transform: translate(-50%, -32px);
          box-shadow: 0 8px 18px -8px rgba(15, 23, 42, 0.3);
        }
        .ps-sel-label::after {
          content: ''; position: absolute;
          bottom: -5px; left: 50%;
          width: 8px; height: 8px;
          background: #0f172a;
          transform: translateX(-50%) rotate(45deg);
        }

        /* Top brand */
        .ps-brand {
          position: absolute; top: 22px; right: 28px;
          display: flex; align-items: center; gap: 18px;
          z-index: 30;
        }
        .ps-brand-logo {
          display: flex; align-items: center; gap: 8px;
          font-weight: 800; font-size: 17px; letter-spacing: -0.02em;
        }
        .ps-brand-logo .b {
          display: inline-flex; align-items: center;
        }
        .ps-brand-logo .b img {
          height: 48px; width: auto; display: block;
        }
        .ps-nav {
          display: flex; gap: 22px;
          font-size: 13px; color: #64748b;
        }
        .ps-nav a { color: #64748b; text-decoration: none; }
        .ps-nav a.on { color: #0f172a; font-weight: 600; }
        .ps-pill {
          display: inline-flex; align-items: center; gap: 6px;
          padding: 5px 12px;
          background: rgba(255, 255, 255, 0.7);
          backdrop-filter: blur(6px);
          border: 1px solid rgba(255, 255, 255, 0.8);
          border-radius: 999px;
          font-size: 11px; color: #1e3a8a; font-weight: 600;
        }
        .ps-pill::before {
          content: ''; width: 6px; height: 6px; border-radius: 50%; background: #0ea5e9;
          animation: psPulse 2s ease-in-out infinite;
        }
        @keyframes psPulse {
          0%, 100% { opacity: 1; }
          50% { opacity: 0.3; }
        }
        .ps-avatar {
          width: 32px; height: 32px; border-radius: 50%;
          background: linear-gradient(135deg, #06b6d4, #1e3a8a);
          color: #fff; font-weight: 700; font-size: 12px;
          display: inline-flex; align-items: center; justify-content: center;
        }

        /* Map legend (bottom right) */
        .ps-legend {
          position: absolute; bottom: 22px; right: 28px;
          background: rgba(255, 255, 255, 0.92);
          border: 1px solid rgba(30, 58, 138, 0.08);
          backdrop-filter: blur(6px);
          border-radius: 12px;
          padding: 12px 14px;
          font-size: 11px; color: #475569;
          z-index: 20;
          box-shadow: 0 30px 50px -24px rgba(15, 23, 42, 0.18);
        }
        .ps-legend-title { font-weight: 700; color: #0f172a; margin-bottom: 6px; }
        .ps-legend-bar { display: flex; width: 180px; height: 6px; border-radius: 99px; overflow: hidden; }
        .ps-legend-bar span { flex: 1; }
        .ps-legend-ticks {
          display: flex; justify-content: space-between;
          font-family: 'JetBrains Mono', monospace;
          font-size: 9px; color: #94a3b8;
          margin-top: 4px;
          width: 180px;
        }

        /* Period + search row */
        .ps-toolbar {
          margin-top: 14px;
          display: flex;
          gap: 10px;
          align-items: stretch;
        }

        /* Period selector */
        .ps-period {
          display: inline-flex;
          padding: 3px;
          gap: 2px;
          background: #f1f5f9;
          border-radius: 10px;
          font-size: 12px;
          flex-shrink: 0;
        }
        .ps-period button {
          background: transparent;
          border: 0;
          padding: 6px 12px;
          border-radius: 7px;
          color: #64748b;
          font-family: inherit;
          font-size: 12px;
          font-weight: 500;
          cursor: pointer;
        }
        .ps-period button.on {
          background: #ffffff;
          color: #0f172a;
          font-weight: 700;
          box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
        }

        /* Stats widget top-right */
        .ps-stats-widget {
          position: absolute;
          top: 80px; right: 28px;
          z-index: 20;
          background: #ffffff;
          border-radius: 14px;
          padding: 14px 18px;
          display: flex; gap: 22px;
          align-items: stretch;
          box-shadow: 0 12px 28px -16px rgba(15, 23, 42, 0.22), 0 1px 3px rgba(15, 23, 42, 0.05);
          border: 1px solid rgba(15, 23, 42, 0.04);
        }
        .ps-sw { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
        .ps-sw + .ps-sw { padding-left: 22px; border-left: 1px solid #eef2f7; }
        .ps-sw-v {
          font-size: 22px; font-weight: 800;
          letter-spacing: -0.02em; line-height: 1;
          font-variant-numeric: tabular-nums; color: #0f172a;
        }
        .ps-sw-l { font-size: 11px; color: #64748b; font-weight: 500; margin-top: 4px; }

        /* Tender KPIs */
        .ps-tkpis {
          display: grid;
          grid-template-columns: repeat(3, 1fr);
          gap: 10px;
        }
        .ps-tkpi {
          background: #f8fafc;
          border-radius: 10px;
          padding: 10px 12px;
        }
        .ps-tkpi-l {
          font-size: 10px; color: #94a3b8;
          font-weight: 600; letter-spacing: 0.04em;
          text-transform: uppercase;
        }
        .ps-tkpi-v {
          font-size: 19px; font-weight: 800;
          letter-spacing: -0.01em; margin-top: 2px;
          font-variant-numeric: tabular-nums;
        }
        .ps-tkpi-d { font-size: 10px; color: #15803d; font-weight: 600; margin-top: 2px; }
        .ps-tkpi-d.neg { color: #b91c1c; }

        .ps-tender-days {
          font-size: 10px;
          color: #15803d;
          font-weight: 600;
          margin-top: 2px;
          font-family: 'JetBrains Mono', monospace;
        }
        .ps-tender-days.soon { color: #c2410c; }
        .ps-tender-days.urgent { color: #b91c1c; }

        /* Deal detail modal */
        .ps-deal-modal {
          position: absolute;
          bottom: 22px; right: 28px;
          width: 420px;
          max-height: calc(100% - 44px);
          background: #ffffff;
          border-radius: 18px;
          box-shadow: 0 30px 50px -24px rgba(15, 23, 42, 0.18);
          z-index: 35;
          display: flex; flex-direction: column;
          overflow: hidden;
          animation: psDealIn 220ms cubic-bezier(.2, .8, .2, 1);
        }
        @keyframes psDealIn {
          from { opacity: 0; transform: translate(20px, 20px); }
          to   { opacity: 1; transform: translate(0, 0); }
        }
        .ps-dm-head {
          padding: 18px 20px 14px;
          border-bottom: 1px solid #eef2f7;
          flex-shrink: 0;
          position: relative;
        }
        .ps-dm-close {
          position: absolute;
          top: 14px; right: 14px;
          width: 26px; height: 26px;
          border-radius: 999px;
          background: #f1f5f9;
          border: 0; color: #475569;
          cursor: pointer;
          display: flex; align-items: center; justify-content: center;
        }
        .ps-dm-close:hover { background: #e2e8f0; }
        .ps-dm-id {
          display: flex; align-items: center; gap: 8px;
          font-size: 10px; letter-spacing: 0.08em;
          text-transform: uppercase; color: #94a3b8;
          font-weight: 700;
        }
        .ps-dm-id .flag {
          width: 18px; height: 12px; border-radius: 2px;
          overflow: hidden; box-shadow: 0 0 0 1px rgba(15,23,42,0.08);
        }
        .ps-dm-id .flag img { width: 100%; height: 100%; object-fit: cover; display: block; }
        .ps-dm-title {
          font-size: 16px; font-weight: 700;
          letter-spacing: -0.01em;
          line-height: 1.3;
          margin-top: 8px;
          padding-right: 30px;
        }
        .ps-dm-value-row {
          margin-top: 14px;
          display: flex; align-items: baseline; gap: 12px;
        }
        .ps-dm-value {
          font-size: 30px; font-weight: 800;
          letter-spacing: -0.025em;
          line-height: 1;
          font-variant-numeric: tabular-nums;
        }
        .ps-dm-vs-est {
          font-size: 11px; color: #64748b;
          font-weight: 500;
        }
        .ps-dm-vs-est .delta { font-weight: 700; }
        .ps-dm-vs-est .delta.under { color: #15803d; }
        .ps-dm-vs-est .delta.over  { color: #b91c1c; }
        .ps-dm-badges {
          margin-top: 12px;
          display: flex; gap: 6px; flex-wrap: wrap;
        }
        .ps-dm-badge {
          display: inline-flex; align-items: center;
          padding: 3px 8px;
          font-size: 10px;
          font-weight: 700;
          letter-spacing: 0.04em;
          text-transform: uppercase;
          border-radius: 999px;
          background: #f1f5f9;
          color: #475569;
        }
        .ps-dm-badge.red    { background: #fee2e2; color: #b91c1c; }
        .ps-dm-badge.violet { background: #ede9fe; color: #6d28d9; }
        .ps-dm-badge.cyan   { background: #cffafe; color: #0e7490; }
        .ps-dm-badge.green  { background: #dcfce7; color: #166534; }
        .ps-dm-badge.amber  { background: #fef3c7; color: #92400e; }

        .ps-dm-body {
          overflow-y: auto;
          flex: 1; min-height: 0;
          padding: 8px 20px 18px;
        }
        .ps-dm-body::-webkit-scrollbar { width: 6px; }
        .ps-dm-body::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }

        .ps-dm-block {
          padding: 12px 0;
          border-top: 1px solid #f1f5f9;
        }
        .ps-dm-block:first-child { border-top: 0; }
        .ps-dm-block-t {
          font-size: 10px; letter-spacing: 0.08em;
          text-transform: uppercase;
          color: #94a3b8;
          font-weight: 700;
          margin-bottom: 8px;
        }
        .ps-dm-kv {
          display: grid;
          grid-template-columns: 120px 1fr;
          gap: 6px 12px;
          font-size: 12px;
        }
        .ps-dm-kv dt { color: #64748b; font-weight: 500; }
        .ps-dm-kv dd {
          margin: 0;
          color: #0f172a;
          font-weight: 600;
          font-variant-numeric: tabular-nums;
        }
        .ps-dm-kv dd.mono {
          font-family: 'JetBrains Mono', monospace;
          font-weight: 500;
          font-size: 11px;
        }
        .ps-dm-just {
          background: #fef9c3;
          border-left: 3px solid #ca8a04;
          padding: 9px 12px;
          border-radius: 0 8px 8px 0;
          font-size: 12px;
          color: #713f12;
          line-height: 1.4;
        }
        .ps-dm-just-r {
          font-weight: 700;
          color: #713f12;
          margin-bottom: 3px;
        }
        .ps-dm-foot {
          padding: 12px 20px;
          border-top: 1px solid #eef2f7;
          display: flex; gap: 8px;
          flex-shrink: 0;
        }
        .ps-dm-foot button {
          background: #f1f5f9;
          border: 0;
          padding: 8px 14px;
          border-radius: 8px;
          font-family: inherit;
          font-size: 12px; color: #475569; font-weight: 600;
          cursor: pointer;
          display: inline-flex; align-items: center; gap: 5px;
        }
        .ps-dm-foot button.primary {
          background: #1e3a8a;
          color: #ffffff;
        }
        .ps-dm-foot button:hover { filter: brightness(0.96); }

        /* Two-column row for sector + deals */
        .ps-twoup {
          display: grid;
          grid-template-columns: 1fr 1fr;
          border-top: 1px solid #eef2f7;
        }
        .ps-twoup .ps-section { border-top: 0; padding-top: 18px; }
        .ps-twoup .ps-section + .ps-section { border-left: 1px solid #eef2f7; padding-left: 20px; }
        .ps-twoup .ps-section:first-child { padding-top: 18px; padding-right: 20px; }

        /* Expand toggle */
        .ps-expand {
          margin-top: 10px;
          display: inline-flex; align-items: center; gap: 5px;
          background: transparent; border: 0;
          padding: 6px 0;
          color: #1e3a8a;
          font-size: 11px; font-weight: 700;
          letter-spacing: 0.02em;
          cursor: pointer;
          font-family: inherit;
        }
        .ps-expand svg { transition: transform 180ms; }
        .ps-expand.open svg { transform: rotate(180deg); }

        /* Left panel */
        .ps-panel {
          position: absolute;
          top: 22px; left: 22px; bottom: 22px;
          width: calc(45% - 33px);
          background: #ffffff;
          border-radius: 18px;
          box-shadow: 0 30px 50px -24px rgba(15, 23, 42, 0.18);
          z-index: 20;
          display: flex; flex-direction: column;
          overflow: hidden;
        }
        .ps-head {
          padding: 18px 22px 14px;
          border-bottom: 1px solid #eef2f7;
          flex-shrink: 0;
        }
        .ps-head-row {
          display: flex; justify-content: space-between; align-items: flex-start;
        }
        .ps-eyebrow {
          font-size: 10px; letter-spacing: 0.08em;
          text-transform: uppercase; color: #94a3b8;
          font-weight: 700;
        }
        .ps-title {
          font-size: 19px; font-weight: 800;
          letter-spacing: -0.02em;
          margin-top: 2px;
          line-height: 1.15;
        }
        .ps-search {
          flex: 1;
          min-width: 0;
          min-height: 34px;
          background: #f1f5f9;
          padding: 0 12px 0 36px;
          border-radius: 10px;
          font-size: 12px; color: #94a3b8;
          position: relative;
          display: flex;
          align-items: center;
        }
        .ps-search input {
          flex: 1;
          background: transparent;
          border: 0;
          outline: 0;
          font: inherit;
          color: #0f172a;
          padding: 0;
        }
        .ps-search input::placeholder { color: #94a3b8; }
        .ps-search::before {
          content: ''; position: absolute;
          left: 12px; top: 50%; transform: translateY(-50%);
          width: 14px; height: 14px;
          background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2.5' xmlns='http://www.w3.org/2000/svg'%3E%3Ccircle cx='11' cy='11' r='8'/%3E%3Cpath d='M21 21l-4.3-4.3'/%3E%3C/svg%3E") no-repeat center / contain;
        }
        .ps-body {
          flex: 1; min-height: 0;
          overflow-y: auto;
          padding: 16px 22px 22px;
        }
        .ps-body::-webkit-scrollbar { width: 6px; }
        .ps-body::-webkit-scrollbar-thumb { background: #e2e8f0; border-radius: 99px; }

        .ps-section {
          padding: 16px 0 18px;
          border-top: 1px solid #eef2f7;
        }
        .ps-section:first-child { border-top: 0; padding-top: 4px; }
        .ps-section-h {
          display: flex; justify-content: space-between; align-items: baseline;
          margin-bottom: 12px;
        }
        .ps-section-t {
          font-size: 15px; font-weight: 700;
          letter-spacing: -0.01em;
        }
        .ps-section-meta {
          font-size: 11px; color: #94a3b8;
          font-family: 'JetBrains Mono', monospace;
        }
        .ps-section-link {
          font-size: 11px; color: #1e3a8a; font-weight: 600;
        }

        /* Country list */
        .ps-clist {
          display: flex; flex-direction: column;
        }
        .ps-c {
          display: grid;
          grid-template-columns: 22px 1fr 64px;
          gap: 10px; align-items: center;
          padding: 8px 10px;
          margin: 0 -10px;
          border-radius: 8px;
          cursor: pointer;
          font-size: 12px;
        }
        .ps-c:hover { background: #f8fafc; }
        .ps-c-rank {
          font-size: 10px;
          color: #94a3b8;
          font-family: 'JetBrains Mono', monospace;
        }
        .ps-c-mid { min-width: 0; }
        .ps-c-name { font-weight: 600; font-size: 13px; color: #0f172a; }
        .ps-c-bar {
          height: 5px; background: #f1f5f9; border-radius: 99px;
          margin-top: 5px; overflow: hidden;
        }
        .ps-c-bar > i {
          display: block; height: 100%;
          background: linear-gradient(90deg, #38bdf8, #1e3a8a);
          border-radius: 99px;
        }
        .ps-c-r {
          text-align: right;
        }
        .ps-c-v {
          font-weight: 700;
          font-variant-numeric: tabular-nums;
          font-size: 12px;
        }
        .ps-c-yoy {
          font-size: 10px; color: #15803d; font-weight: 600;
          margin-top: 1px;
        }
        .ps-c-yoy.neg { color: #b91c1c; }

        /* Sector list */
        .ps-slist {
          display: flex; flex-direction: column; gap: 8px;
        }
        .ps-s {
          display: grid;
          grid-template-columns: 12px 1fr 70px;
          gap: 10px; align-items: center;
          font-size: 12px;
          padding: 6px 10px;
          margin: 0 -10px;
          border-radius: 8px;
        }
        .ps-s-click { cursor: pointer; transition: background 120ms; }
        .ps-s-click:hover { background: #f8fafc; }
        .ps-s-dot { width: 10px; height: 10px; border-radius: 50%; }
        .ps-s-name { color: #0f172a; font-weight: 500; }
        .ps-s-bar {
          height: 4px; background: #f1f5f9; border-radius: 99px;
          margin-top: 4px; overflow: hidden;
        }
        .ps-s-bar > i { display: block; height: 100%; border-radius: 99px; }
        .ps-s-r {
          text-align: right;
          font-weight: 700;
          font-variant-numeric: tabular-nums;
        }
        .ps-s-pct {
          font-size: 9px; color: #94a3b8;
          font-family: 'JetBrains Mono', monospace;
          margin-top: 1px;
        }

        /* Deals */
        .ps-deal {
          display: grid;
          grid-template-columns: 48px 1fr 70px;
          gap: 10px; align-items: flex-start;
          padding: 10px 12px;
          margin: 0 -12px;
          border-radius: 8px;
          cursor: pointer;
          transition: background 120ms;
          position: relative;
        }
        .ps-deal + .ps-deal { border-top: 1px solid #f1f5f9; }
        .ps-deal:hover { background: #f8fafc; }
        .ps-deal-cty {
          position: relative;
          width: 48px; height: 36px;
          flex-shrink: 0;
        }
        .ps-deal-cty .ps-flag {
          position: absolute;
          border-radius: 4px;
          overflow: hidden;
        }
        .ps-deal-cty .ps-flag.solo {
          inset: 0;
        }
        .ps-deal-cty .ps-flag.primary {
          top: 0; left: 0;
          width: 42px; height: 30px;
          z-index: 2;
        }
        .ps-deal-cty .ps-flag.secondary {
          bottom: 0; right: 0;
          width: 42px; height: 30px;
          z-index: 1;
        }
        .ps-deal-cty .ps-flag img {
          width: 100%; height: 100%; object-fit: cover; display: block;
        }
        .ps-deal-mid { min-width: 0; }
        .ps-deal-title {
          font-size: 12px; font-weight: 600; color: #0f172a;
          line-height: 1.3;
          white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        }
        .ps-deal-sub {
          font-size: 11px; color: #64748b;
          margin-top: 2px;
          line-height: 1.3;
        }
        .ps-deal-meta {
          font-size: 10px; color: #94a3b8;
          font-family: 'JetBrains Mono', monospace;
          margin-top: 3px;
          display: flex; gap: 8px;
        }
        .ps-deal-r {
          text-align: right;
        }
        .ps-deal-v {
          font-weight: 700;
          font-variant-numeric: tabular-nums;
          font-size: 13px;
        }
        .ps-deal-date {
          font-size: 10px; color: #94a3b8;
          font-family: 'JetBrains Mono', monospace;
          margin-top: 2px;
        }

        /* Country drill mode */
        .ps-back {
          display: inline-flex; align-items: center; gap: 6px;
          background: #f1f5f9; border: 0;
          padding: 5px 10px;
          border-radius: 999px;
          font-family: inherit;
          font-size: 11px; color: #475569;
          font-weight: 600;
          cursor: pointer;
        }
        .ps-back:hover { background: #e2e8f0; }
        .ps-country-head {
          display: flex; align-items: center; gap: 14px;
          margin-top: 14px;
          padding-bottom: 14px;
          border-bottom: 1px solid #eef2f7;
        }
        .ps-country-iso {
          width: 48px; height: 36px;
          border-radius: 6px;
          overflow: hidden;
          background: #f1f5f9;
          box-shadow: 0 0 0 1px rgba(15, 23, 42, 0.06), 0 4px 12px -4px rgba(15, 23, 42, 0.15);
          flex-shrink: 0;
        }
        .ps-country-iso img {
          width: 100%; height: 100%; object-fit: cover; display: block;
        }
        .ps-country-name {
          font-size: 22px; font-weight: 800;
          letter-spacing: -0.02em;
          line-height: 1;
        }
        .ps-country-rank {
          font-size: 11px; color: #64748b;
          margin-top: 4px;
        }
        .ps-country-stats {
          display: grid; grid-template-columns: repeat(3, 1fr);
          gap: 12px;
          margin: 14px 0 4px;
        }
        .ps-stat {
          background: #f8fafc;
          border-radius: 10px;
          padding: 10px 12px;
        }
        .ps-stat-l { font-size: 10px; color: #94a3b8; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; }
        .ps-stat-v { font-size: 18px; font-weight: 800; letter-spacing: -0.01em; margin-top: 2px; font-variant-numeric: tabular-nums; }
        .ps-stat-d { font-size: 10px; color: #15803d; font-weight: 600; margin-top: 2px; }
        .ps-stat-d.neg { color: #b91c1c; }
      `}</style>

      {/* Map full-bg */}
      <div className="ps-map">
        <EuropeMap
          width={vw}
          height={vh}
          extent={[[vw * 0.47, vh * 0.05], [vw * 0.98, vh * 0.98]]}
          otherFill="#e2e8f0"
          otherStroke="#b8c4d6"
          euFill={fillFor}
          euStroke="#ffffff"
          euStrokeWidth={1.8}
          selectedIso={selected}
          onSelect={(iso) => setSelected(iso)}
          onHover={setHovered}
          hoveredIso={hovered}
          interactive>
          {(({ proj, zoom: z }) => {
            if (!proj) return null;
            const renderPill = (iso, fill) => {
              const cap = EU_CAPITALS[iso];
              if (!cap) return null;
              const [cx, cy] = proj([cap[1], cap[0]]);
              const c = window.EU_COUNTRIES.find((x) => x.iso === iso);
              const name = c ? c.name : iso;
              const w = name.length * 7.4 + 28;
              const inv = 1 / z;
              return (
                <g key={iso} style={{ pointerEvents: 'none' }} transform={`translate(${cx},${cy}) scale(${inv})`}>
                  <rect x={-w / 2} y={-30} width={w} height={22} rx={11} fill={fill} />
                  <text x={0} y={-15} textAnchor="middle" fontSize="12" fontWeight="700" fill="#f8fafc" fontFamily="Inter">{name}</text>
                  <circle cx={0} cy={0} r={3} fill={fill} stroke="#f8fafc" strokeWidth={1.5} />
                </g>
              );
            };
            return (
              <>
                {hovered && hovered !== selected && renderPill(hovered, 'rgba(15, 23, 42, 0.92)')}
                {selected && renderPill(selected, '#0f172a')}
              </>
            );
          })}
        </EuropeMap>
      </div>

      {/* Floating brand top-right */}
      <div className="ps-brand">
        <div className="ps-brand-logo">
          <span className="b"><img src="logo2.png" alt="Pulse" /></span>
        </div>
        <nav className="ps-nav">
          <a href="#" className={view === 'overview' ? 'on' : ''} onClick={(e) => { e.preventDefault(); goToView('overview'); }}>Overview</a>
          <a href="#" className={view === 'tenders' ? 'on' : ''} onClick={(e) => { e.preventDefault(); goToView('tenders'); }}>Tenders</a>
          <a href="#" className={view === 'suppliers' ? 'on' : ''} onClick={(e) => { e.preventDefault(); goToView('suppliers'); }}>Suppliers</a>
        </nav>
      </div>

      {/* Stats widget — top-right under the brand */}
      <div className="ps-stats-widget">
        <div className="ps-sw">
          <div className="ps-sw-v">27</div>
          <div className="ps-sw-l">countries</div>
        </div>
        <div className="ps-sw">
          <div className="ps-sw-v">142K</div>
          <div className="ps-sw-l">contracts</div>
        </div>
        <div className="ps-sw">
          <div className="ps-sw-v">€812B</div>
          <div className="ps-sw-l">tracked spend</div>
        </div>
      </div>

      {/* Left panel */}
      <aside className="ps-panel">
        {dealsScreen ? (() => {
          const base = dealsScreen.scope === 'country' && country ? countryDeals : recentDeals;
          const sectorFiltered = dealsScreen.sectorCode
            ? base.filter((d) => d.sectorCode === dealsScreen.sectorCode)
            : base;
          const q = dealsSearch.trim().toLowerCase();
          const matchesQuery = (d) => {
            if (!q) return true;
            return (
              (d.title && d.title.toLowerCase().includes(q)) ||
              (d.winner && d.winner.toLowerCase().includes(q)) ||
              (d.buyer && d.buyer.toLowerCase().includes(q)) ||
              (d.sectorName && d.sectorName.toLowerCase().includes(q)) ||
              (d.cpv && d.cpv.includes(q)) ||
              (d.countryName && d.countryName.toLowerCase().includes(q)) ||
              (d.id && d.id.toLowerCase().includes(q))
            );
          };
          const list = sectorFiltered.filter(matchesQuery);
          const visible = list.slice(0, dealsLimit);
          const hasMore = list.length > visible.length;
          const inCountry = dealsScreen.scope === 'country' && country;
          const title = dealsScreen.sectorName
            ? (inCountry ? `Recent ${country.name} deals · ${dealsScreen.sectorName}` : `Recent deals · ${dealsScreen.sectorName}`)
            : (inCountry ? `All ${country.name} deals` : 'Recent deals — all sectors');
          const eyebrow = inCountry ? `${country.name} · TTM` : 'EU-27 · TTM';
          return (
            <>
              <div className="ps-head">
                <PSPanelBack label={inCountry ? `Back to ${country.name}` : 'Back to overview'} onBack={() => setDealsScreen(null)} />
                <div style={{ marginTop: 12 }}>
                  <div className="ps-eyebrow">{eyebrow}</div>
                  <div className="ps-title">{title}</div>
                </div>
                <div className="ps-toolbar" style={{ marginTop: 12 }}>
                  <div className="ps-search">
                    <input
                      type="text"
                      placeholder={`Search ${dealsScreen.sectorName || 'deals'}…`}
                      value={dealsSearch}
                      onChange={(e) => { setDealsSearch(e.target.value); setDealsLimit(50); }} />
                  </div>
                </div>
              </div>
              <div className="ps-body">
                <div className="ps-section" style={{ borderTop: 0, paddingTop: 4 }}>
                  <div className="ps-section-h">
                    <div className="ps-section-t">{list.length} deal{list.length === 1 ? '' : 's'}</div>
                    <span className="ps-section-meta">{q ? `match "${dealsSearch}"` : 'sorted by value'}</span>
                  </div>
                  {visible.map((d) => (
                    <div
                      className="ps-deal"
                      key={d.id}
                      onClick={() => {
                        const iso2 = d.countryIso2 || (country && country.iso2);
                        const iso = d.country || (country && country.iso);
                        const cname = d.countryName || (country && country.name);
                        setActiveDeal({ ...d, countryIso2: iso2, country: iso, countryName: cname });
                      }}>
                      <DealFlags
                        buyerIso2={d.countryIso2 || (country && country.iso2)}
                        winnerIso2={iso2FromIso3(d.winnerCountry)} />
                      <div className="ps-deal-mid">
                        <div className="ps-deal-title">{d.title}</div>
                        <div className="ps-deal-sub">{d.winner} · {d.buyer}</div>
                        <div className="ps-deal-meta">
                          <span>{d.sectorName}</span>
                        </div>
                      </div>
                      <div className="ps-deal-r">
                        <div className="ps-deal-v">€{psFmt(d.value, 1)}M</div>
                        <div className="ps-deal-date">{d.date}</div>
                      </div>
                    </div>
                  ))}
                  {visible.length === 0 && (
                    <div style={{ padding: '24px 0', color: '#64748b', fontSize: 12 }}>
                      No deals match this filter.
                    </div>
                  )}
                  {hasMore && (
                    <button
                      className="ps-expand"
                      onClick={() => setDealsLimit(dealsLimit + 50)}>
                      Load 50 more ({list.length - visible.length} remaining)
                      <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                        <path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                      </svg>
                    </button>
                  )}
                </div>
              </div>
            </>
          );
        })() : !country ?
        <>
            <div className="ps-head">
              <div className="ps-head-row">
                <div>
                  <div className="ps-eyebrow">
                    {view === 'tenders' ? 'Open tenders · Live now' :
                      view === 'suppliers' ? 'Suppliers · EU-27 · TTM' :
                      'EU-27 · Trailing 12 months'}
                  </div>
                  <div className="ps-title">
                    {view === 'tenders' ? 'Active tenders' :
                      view === 'suppliers' ? 'Top suppliers' :
                      'Public spending overview'}
                  </div>
                </div>
                <div className="ps-period">
                  {[
                { id: 'ttm', label: 'Trailing 12mo' },
                { id: '2025', label: '2025' },
                { id: '2026', label: '2026' }].
                map((p) =>
                <button
                  key={p.id}
                  className={period === p.id ? 'on' : ''}
                  onClick={() => setPeriod(p.id)}>
                      {p.label}
                    </button>
                )}
                </div>
              </div>
            </div>
            <div className="ps-body" data-comment-anchor="781199d019-div-480-13">
              {view === 'overview' && (<>
              {/* Spending by country */}
              <div className="ps-section" data-comment-anchor="1cd3fbedf5-div-482-15">
                <div className="ps-section-h">
                  <div className="ps-section-t">Spending by country</div>
                  <span className="ps-section-meta">{expandedCountries ? sorted.length : 7} of {sorted.length} states</span>
                </div>
                <div className="ps-clist">
                  {sorted.slice(0, expandedCountries ? sorted.length : 7).map((c, i) =>
                <div key={c.iso} className="ps-c" onClick={() => setSelected(c.iso)}>
                      <span className="ps-c-rank">{String(i + 1).padStart(2, '0')}</span>
                      <div className="ps-c-mid">
                        <div className="ps-c-name">{c.name}</div>
                        <div className="ps-c-bar"><i style={{ width: `${c.spend / max * 100}%` }}></i></div>
                      </div>
                      <div className="ps-c-r">
                        <div className="ps-c-v">€{psFmt(c.spend, 1)}B</div>
                      </div>
                    </div>
                )}
                </div>
                <button
                className={'ps-expand ' + (expandedCountries ? 'open' : '')}
                onClick={() => setExpandedCountries(!expandedCountries)}>
                  {expandedCountries ? 'Show less' : `Show all ${sorted.length} countries`}
                  <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                    <path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                  </svg>
                </button>
              </div>

              {/* Sector + Recent deals side-by-side */}
              <div className="ps-twoup">
                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Spending by sector</div>
                    <span className="ps-section-meta">45 CPV divisions</span>
                  </div>
                  <div className="ps-slist">
                    {sectorTotals.map((s) => {
                    const color = sectorColor(s, sectorMax);
                    return (
                      <div
                        className="ps-s ps-s-click"
                        key={s.key}
                        title={s.officialName}
                        onClick={() => setDealsScreen({ scope: 'eu', sectorCode: s.code, sectorName: s.name })}>
                          <span className="ps-s-dot" style={{ background: color }}></span>
                          <div>
                            <div className="ps-s-name">{s.name}</div>
                            <div className="ps-s-bar"><i style={{ width: `${Math.max(2, s.value / sectorMax * 100)}%`, background: color }}></i></div>
                          </div>
                          <div className="ps-c-r">
                            <div className="ps-s-r">€{psFmt(s.value, 0)}B</div>
                            <div className="ps-s-pct">{s.share.toFixed(1)}%</div>
                          </div>
                        </div>);
                  })}
                  </div>
                </div>

                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Recent deals</div>
                    <span className="ps-section-meta">30 of {recentDeals.length}</span>
                  </div>
                  {recentDeals.slice(0, 30).map((d) =>
                <div className="ps-deal" key={d.id} onClick={() => setActiveDeal({ ...d, countryIso2: d.countryIso2 })}>
                      <DealFlags
                        buyerIso2={d.countryIso2}
                        winnerIso2={iso2FromIso3(d.winnerCountry)} />
                      <div className="ps-deal-mid">
                        <div className="ps-deal-title">{d.title}</div>
                        <div className="ps-deal-sub">{d.winner} · {d.buyer}</div>
                        <div className="ps-deal-meta">
                          <span>{d.sectorName}</span>
                        </div>
                      </div>
                      <div className="ps-deal-r">
                        <div className="ps-deal-v">€{psFmt(d.value, 1)}M</div>
                        <div className="ps-deal-date">{d.date}</div>
                      </div>
                    </div>
                )}
                  <button
                    className="ps-expand"
                    onClick={() => setDealsScreen({ scope: 'eu' })}>
                    Show all recent deals
                    <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                      <path d="M3 2L7 5L3 8" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                    </svg>
                  </button>
                </div>
              </div>
              </>)}

              {view === 'tenders' && (<>
                {/* KPIs */}
                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Open tenders right now</div>
                    <span className="ps-section-meta">{window.EU_LIVE_TENDERS.length} active</span>
                  </div>
                  <div className="ps-tkpis">
                    <div className="ps-tkpi">
                      <div className="ps-tkpi-l">Live</div>
                      <div className="ps-tkpi-v">14,820</div>
                      <div className="ps-tkpi-d">▲ 312 today</div>
                    </div>
                    <div className="ps-tkpi">
                      <div className="ps-tkpi-l">Open value</div>
                      <div className="ps-tkpi-v">€38.6B</div>
                      <div className="ps-tkpi-d">across 27 states</div>
                    </div>
                    <div className="ps-tkpi">
                      <div className="ps-tkpi-l">Closing &lt; 7d</div>
                      <div className="ps-tkpi-v">2,164</div>
                      <div className="ps-tkpi-d neg">act soon</div>
                    </div>
                  </div>
                </div>

                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Closing this week</div>
                    <span className="ps-section-meta">sorted by deadline</span>
                  </div>
                  {[...window.EU_LIVE_TENDERS]
                    .sort((a, b) => a.days - b.days)
                    .slice(0, expandedTenders ? window.EU_LIVE_TENDERS.length : 5)
                    .map((t) => (
                      <div className="ps-deal" key={t.id}>
                        <div className="ps-deal-cty">
                          <img src={`https://flagcdn.com/${t.country.toLowerCase().slice(0, 2)}.svg`} alt={t.country} />
                        </div>
                        <div className="ps-deal-mid">
                          <div className="ps-deal-title">{t.title}</div>
                          <div className="ps-deal-sub">{t.buyer}</div>
                          <div className="ps-deal-meta">
                            <span>CPV {t.cpv.slice(0, 2)}</span>
                            <span>·</span>
                            <span>{t.id}</span>
                          </div>
                        </div>
                        <div className="ps-deal-r">
                          <div className="ps-deal-v">€{psFmt(t.value, 1)}M</div>
                          <div className={'ps-tender-days ' + (t.days < 7 ? 'urgent' : t.days < 14 ? 'soon' : '')}>{t.days}d left</div>
                        </div>
                      </div>
                    ))}
                  <button
                    className={'ps-expand ' + (expandedTenders ? 'open' : '')}
                    onClick={() => setExpandedTenders(!expandedTenders)}>
                    {expandedTenders ? 'Show less' : `Show all ${window.EU_LIVE_TENDERS.length} live tenders`}
                    <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                      <path d="M2 3.5L5 6.5L8 3.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                    </svg>
                  </button>
                </div>

                <div className="ps-twoup">
                  <div className="ps-section">
                    <div className="ps-section-h">
                      <div className="ps-section-t">Open value by sector</div>
                      <span className="ps-section-meta">CPV</span>
                    </div>
                    <div className="ps-slist">
                      {[
                        { name: 'Construction', v: 12.4, share: 32.1, color: '#1e3a8a' },
                        { name: 'Health', v: 7.8, share: 20.2, color: '#0ea5e9' },
                        { name: 'Transport', v: 6.1, share: 15.8, color: '#06b6d4' },
                        { name: 'IT services', v: 4.4, share: 11.4, color: '#84cc16' },
                        { name: 'Engineering', v: 3.2, share: 8.3, color: '#f59e0b' },
                        { name: 'Medical', v: 2.6, share: 6.7, color: '#ec4899' },
                        { name: 'Other', v: 2.1, share: 5.5, color: '#94a3b8' },
                      ].map((s) => (
                        <div className="ps-s" key={s.name}>
                          <span className="ps-s-dot" style={{ background: s.color }}></span>
                          <div>
                            <div className="ps-s-name">{s.name}</div>
                            <div className="ps-s-bar"><i style={{ width: `${(s.v / 12.4) * 100}%`, background: s.color }}></i></div>
                          </div>
                          <div className="ps-c-r">
                            <div className="ps-s-r">€{s.v.toFixed(1)}B</div>
                            <div className="ps-s-pct">{s.share.toFixed(1)}%</div>
                          </div>
                        </div>
                      ))}
                    </div>
                  </div>

                  <div className="ps-section">
                    <div className="ps-section-h">
                      <div className="ps-section-t">Top buyers</div>
                      <span className="ps-section-link">VIEW ALL ↗</span>
                    </div>
                    {window.EU_TOP_BUYERS.slice(0, 6).map((b) => (
                      <div className="ps-deal" key={b.name}>
                        <div className="ps-deal-cty">
                          <img src={`https://flagcdn.com/${b.country.toLowerCase().slice(0, 2)}.svg`} alt={b.country} />
                        </div>
                        <div className="ps-deal-mid">
                          <div className="ps-deal-title">{b.name}</div>
                          <div className="ps-deal-sub">{b.sector} · {psInt(b.contracts)} contracts</div>
                        </div>
                        <div className="ps-deal-r">
                          <div className="ps-deal-v">€{psFmt(b.spend, 1)}B</div>
                          <div className="ps-deal-date">awarded</div>
                        </div>
                      </div>
                    ))}
                  </div>
                </div>
              </>)}

              {view === 'suppliers' && (<>
                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Top suppliers by spend</div>
                    <span className="ps-section-meta">{window.EU_TOP_WINNERS.length} suppliers</span>
                  </div>
                  <div className="ps-clist">
                    {window.EU_TOP_WINNERS.slice(0, 10).map((w, i) => {
                      const maxSpend = window.EU_TOP_WINNERS[0].spend;
                      return (
                        <div className="ps-c" key={w.name}>
                          <span className="ps-c-rank">{String(i + 1).padStart(2, '0')}</span>
                          <div className="ps-c-mid">
                            <div className="ps-c-name">{w.name}</div>
                            <div className="ps-c-bar"><i style={{ width: `${(w.spend / maxSpend) * 100}%` }}></i></div>
                          </div>
                          <div className="ps-c-r">
                            <div className="ps-c-v">€{psFmt(w.spend, 1)}B</div>
                            <div className="ps-c-yoy">{w.wins} wins</div>
                          </div>
                        </div>
                      );
                    })}
                  </div>
                </div>

                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Supplier countries</div>
                    <span className="ps-section-meta">27 countries · by € won</span>
                  </div>
                  <div className="ps-clist">
                    {(() => {
                      // Seed supplier-won totals from EU_TOP_WINNERS, fall back to
                      // a fraction of country spend for the remaining states.
                      const byCountry = {};
                      window.EU_TOP_WINNERS.forEach((w) => {
                        byCountry[w.country] = (byCountry[w.country] || 0) + w.spend;
                      });
                      const rows = window.EU_COUNTRIES.map((c) => ({
                        iso: c.iso,
                        iso2: c.iso2,
                        name: c.name,
                        // ~40% of domestic spend as supplier-won proxy when no top-winner data.
                        won: byCountry[c.iso] || c.spend * 0.4,
                      })).sort((a, b) => b.won - a.won);
                      const maxV = rows[0].won;
                      return rows.map((r) => (
                        <div className="ps-c" key={r.iso}>
                          <span className="ps-c-rank" style={{ display: 'inline-flex', alignItems: 'center', justifyContent: 'center' }}>
                            <span style={{ display: 'inline-block', width: 18, height: 12, borderRadius: 2, overflow: 'hidden' }}>
                              <img src={`https://flagcdn.com/${r.iso2.toLowerCase()}.svg`} alt={r.iso2} style={{ width: '100%', height: '100%', objectFit: 'cover' }} />
                            </span>
                          </span>
                          <div className="ps-c-mid">
                            <div className="ps-c-name">{r.name}</div>
                            <div className="ps-c-bar"><i style={{ width: `${(r.won / maxV) * 100}%` }}></i></div>
                          </div>
                          <div className="ps-c-r">
                            <div className="ps-c-v">€{psFmt(r.won, 1)}B</div>
                          </div>
                        </div>
                      ));
                    })()}
                  </div>
                </div>
              </>)}
            </div>
          </> :

        <>
            <div className="ps-head">
              <PSPanelBack label="Back to overview" onBack={() => setSelected(null)} />
              <div className="ps-country-head">
                <div className="ps-country-iso">
                  <img src={`https://flagcdn.com/${country.iso2.toLowerCase()}.svg`} alt={country.iso2} />
                </div>
                <div>
                  <div className="ps-country-name">{country.name}</div>
                  <div className="ps-country-rank">Ranked #{sorted.findIndex((c) => c.iso === country.iso) + 1} of 27 · {(country.spend / total * 100).toFixed(1)}% of EU total</div>
                </div>
              </div>
              <div className="ps-country-stats">
                <div className="ps-stat">
                  <div className="ps-stat-l">Awarded</div>
                  <div className="ps-stat-v">€{psFmt(country.spend, 1)}B</div>
                  <div className={'ps-stat-d ' + (country.yoy < 0 ? 'neg' : '')}>{country.yoy > 0 ? '▲' : '▼'} {psFmt(Math.abs(country.yoy))}% YoY</div>
                </div>
                <div className="ps-stat">
                  <div className="ps-stat-l">Contracts</div>
                  <div className="ps-stat-v">{psInt(country.contracts)}</div>
                  <div className="ps-stat-d" style={{ color: '#64748b' }}>€{psFmt(country.spend * 1000 / country.contracts, 2)}M avg</div>
                </div>
                <div className="ps-stat">
                  <div className="ps-stat-l">1-bidder</div>
                  <div className="ps-stat-v">22.4%</div>
                  <div className="ps-stat-d" style={{ color: '#64748b' }}>EU avg 24.6%</div>
                </div>
              </div>
            </div>

            <div className="ps-body">
              <div className="ps-twoup">
                {/* Sectors for this country */}
                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Spending by sector</div>
                    <span className="ps-section-meta">45 CPV · {country.iso}</span>
                  </div>
                  <div className="ps-slist">
                    {countrySectors.map((s) => {
                    const localMax = countrySectors[0].value;
                    const color = sectorColor(s, localMax);
                    return (
                      <div
                        className="ps-s ps-s-click"
                        key={s.key}
                        title={s.officialName}
                        onClick={() => setDealsScreen({ scope: 'country', sectorCode: s.code, sectorName: s.name })}>
                          <span className="ps-s-dot" style={{ background: color }}></span>
                          <div>
                            <div className="ps-s-name">{s.name}</div>
                            <div className="ps-s-bar"><i style={{ width: `${Math.max(2, s.value / localMax * 100)}%`, background: color }}></i></div>
                          </div>
                          <div className="ps-c-r">
                            <div className="ps-s-r">€{psFmt(s.value, 1)}B</div>
                            <div className="ps-s-pct">{s.share.toFixed(1)}%</div>
                          </div>
                        </div>);
                  })}
                  </div>
                </div>

                {/* Deals for this country */}
                <div className="ps-section">
                  <div className="ps-section-h">
                    <div className="ps-section-t">Recent deals · {country.iso}</div>
                    <span className="ps-section-meta">{Math.min(30, countryDeals.length)} of {countryDeals.length}</span>
                  </div>
                  {countryDeals.slice(0, 30).map((d) =>
                <div className="ps-deal" key={d.id} onClick={() => setActiveDeal({ ...d, countryIso2: country.iso2, country: country.iso, countryName: country.name })}>
                      <DealFlags
                        buyerIso2={country.iso2}
                        winnerIso2={iso2FromIso3(d.winnerCountry)} />
                      <div className="ps-deal-mid">
                        <div className="ps-deal-title">{d.title}</div>
                        <div className="ps-deal-sub">{d.winner} · {d.buyer}</div>
                        <div className="ps-deal-meta">
                          <span>{d.sectorName}</span>
                        </div>
                      </div>
                      <div className="ps-deal-r">
                        <div className="ps-deal-v">€{psFmt(d.value, 1)}M</div>
                        <div className="ps-deal-date">{d.date}</div>
                      </div>
                    </div>
                )}
                  {countryDeals.length > 30 && (
                    <button
                      className="ps-expand"
                      onClick={() => setDealsScreen({ scope: 'country' })}>
                      Show all {country.name} deals
                      <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                        <path d="M3 2L7 5L3 8" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
                      </svg>
                    </button>
                  )}
                </div>
              </div>
            </div>
          </>
        }
      </aside>

      {/* Map legend bottom right */}
      <div className="ps-legend">
        <div className="ps-legend-title">€ awarded · trailing 12mo</div>
        <div className="ps-legend-bar">
          {[0.05, 0.2, 0.4, 0.7, 1].map((t, i) =>
          <span key={i} style={{ background: fillFor({ spend: t * max }) }}></span>
          )}
        </div>
        <div className="ps-legend-ticks">
          <span>0</span><span>40B</span><span>90B</span><span>180B+</span>
        </div>
      </div>

      {/* Deal detail modal — bottom right */}
      {activeDeal && <DealDetailModal deal={activeDeal} onClose={() => setActiveDeal(null)} />}
    </div>);

}

// Capital cities — used to anchor the selected-country label on the map.
const EU_CAPITALS = {
  DEU: [52.520, 13.405], FRA: [48.857,  2.352], ITA: [41.903, 12.496], ESP: [40.417, -3.704],
  POL: [52.230, 21.012], NLD: [52.370,  4.895], SWE: [59.329, 18.069], BEL: [50.850,  4.351],
  DNK: [55.676, 12.568], AUT: [48.208, 16.373], FIN: [60.170, 24.937], ROU: [44.439, 26.097],
  CZE: [50.075, 14.437], PRT: [38.722, -9.139], GRC: [37.984, 23.728], IRL: [53.350, -6.260],
  HUN: [47.498, 19.040], SVK: [48.149, 17.111], BGR: [42.698, 23.319], HRV: [45.815, 15.982],
  SVN: [46.056, 14.508], LTU: [54.687, 25.280], LVA: [56.946, 24.106], EST: [59.437, 24.754],
  LUX: [49.611,  6.130], CYP: [35.185, 33.382], MLT: [35.899, 14.514],
};

window.PulseDashboard = PulseDashboard;