// ───────────────────────────────────────────────────────────
// Live charts driven by Google Sheet data
// All charts adapt to whatever buyers are returned from the Sheet.
// ───────────────────────────────────────────────────────────

const { useState: useStateC, useMemo: useMemoC, useRef: useRefC, useEffect: useEffectC } = React;

// Number / percent formatters (re-declared to avoid scope sharing issues)
const fmtNumLive = (n) => {
  if (n == null || !Number.isFinite(n)) return '—';
  if (Math.abs(n) >= 1_000_000) return (n / 1_000_000).toFixed(2).replace(/\.?0+$/, '') + 'M';
  if (Math.abs(n) >= 1000) return (n / 1000).toFixed(1).replace(/\.0$/, '') + 'k';
  return Math.round(n).toLocaleString();
};
const fmtPctLive = (n, d = 1) => n == null ? '—' : `${n.toFixed(d)}%`;

// Smooth path
const buildPathC = (pts) => {
  if (pts.length < 2) return '';
  let d = `M ${pts[0][0]} ${pts[0][1]}`;
  for (let i = 0; i < pts.length - 1; i++) {
    const p1 = pts[i],p2 = pts[i + 1];
    d += ` L ${p2[0]} ${p2[1]}`;
  }
  return d;
};

// ─── Tooltip ─────────────────────────────────────────────
function ChartTooltipC({ x, y, children, visible, parentWidth }) {
  if (!visible) return null;
  const flip = x > parentWidth - 220;
  return (
    <div
      className="ms-tooltip"
      style={{
        left: flip ? x - 12 : x + 12,
        top: y,
        transform: flip ? 'translate(-100%, -50%)' : 'translateY(-50%)'
      }}>
      
      {children}
    </div>);

}

// ─── Sparkline ───────────────────────────────────────────
function SparklineC({ data, color = '#00BBEA', width = 140, height = 32, fill = true }) {
  if (!data || data.length < 2) return <div style={{ width, height }} />;
  const min = Math.min(...data);
  const max = Math.max(...data);
  const range = max - min || 1;
  const stepX = width / (data.length - 1);
  const pts = data.map((v, i) => [i * stepX, height - (v - min) / range * (height - 4) - 2]);
  const d = buildPathC(pts);
  const area = `${d} L ${width} ${height} L 0 ${height} Z`;
  const id = useMemoC(() => 'spc-' + Math.random().toString(36).slice(2, 8), []);
  return (
    <svg width={width} height={height} style={{ display: 'block', overflow: 'visible' }}>
      <defs>
        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
          <stop offset="0%" stopColor={color} stopOpacity="0.22" />
          <stop offset="100%" stopColor={color} stopOpacity="0" />
        </linearGradient>
      </defs>
      {fill && <path d={area} fill={`url(#${id})`} />}
      <path d={d} fill="none" stroke={color} strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round" />
      <circle cx={pts[pts.length - 1][0]} cy={pts[pts.length - 1][1]} r="2.5" fill={color} />
    </svg>);

}

// ─── Horizontal bar — generic ranking ────────────────────
function RankBars({ rows, valueKey, valueLabel, valueFmt = fmtPctLive, sortDesc = true, highlight = (r) => r.isUs }) {
  const sorted = [...rows].sort((a, b) => sortDesc ? (b[valueKey] || 0) - (a[valueKey] || 0) : (a[valueKey] || 0) - (b[valueKey] || 0));
  const max = Math.max(...sorted.map((r) => Math.abs(r[valueKey] || 0))) || 1;
  return (
    <div className="ms-rankbars">
      {sorted.map((r, i) => {
        const pct = (r[valueKey] || 0) / max * 100;
        const isUs = highlight(r);
        return (
          <div key={r.domain + i} className={`ms-rankbar ${isUs ? 'is-us' : ''}`}>
            <div className="ms-rankbar-rank">{i + 1}</div>
            <div className="ms-rankbar-name">
              <span className="ms-rankbar-dot" style={{ background: r.color }} />
              {r.name || r.domain}
              {isUs && <span className="ms-legend-tag">us</span>}
            </div>
            <div className="ms-rankbar-track">
              <div className="ms-rankbar-fill" style={{ width: `${pct}%`, background: r.color }} />
            </div>
            <div className="ms-rankbar-val">{valueFmt(r[valueKey])}</div>
          </div>);

      })}
    </div>);

}

// ─── Stacked horizontal bar (channel mix per domain) ───────
function ChannelStack({ rows, channels }) {
  // rows: [{ domain, name, color, isUs, organic, paid, direct, referral, social, total }]
  // Normalize per-row: if total absent, sum the channels.
  const normalized = rows.map((r) => {
    const ch = channels.map((c) => ({ ...c, value: r[c.id] || 0 }));
    const sum = ch.reduce((a, b) => a + b.value, 0) || 1;
    return { ...r, ch, sum };
  });
  const [hover, setHover] = useStateC(null);
  return (
    <div className="ms-chstack">
      <div className="ms-chstack-legend">
        {channels.map((c) =>
        <div key={c.id} className="ms-chstack-leg">
            <span className="ms-chstack-dot" style={{ background: c.color }} />
            {c.label}
          </div>
        )}
      </div>
      <div className="ms-chstack-rows">
        {normalized.map((r) =>
        <div key={r.domain} className={`ms-chstack-row ${r.isUs ? 'is-us' : ''}`}>
            <div className="ms-chstack-name">
              <span className="ms-rankbar-dot" style={{ background: r.color }} />
              {r.name || r.domain}
              {r.isUs && <span className="ms-legend-tag">us</span>}
            </div>
            <div className="ms-chstack-bar">
              {r.ch.map((c) => {
              const widthPct = c.value / r.sum * 100;
              if (widthPct < 0.1) return null;
              return (
                <div
                  key={c.id}
                  className="ms-chstack-seg"
                  style={{ width: `${widthPct}%`, background: c.color }}
                  onMouseEnter={() => setHover({ domain: r.domain, ch: c.label, val: c.value })}
                  onMouseLeave={() => setHover(null)}
                  title={`${c.label}: ${c.value.toFixed(1)}%`}>
                  
                    {widthPct > 8 && <span className="ms-chstack-seg-label">{c.value.toFixed(0)}%</span>}
                  </div>);

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

}

// ─── Branded vs Non-Branded — absolute visits (grouped horizontal bars) ──
function BrandedAbsolute({ rows }) {
  const allVals = rows.flatMap((r) => [r.brandedVisits || 0, r.nonBrandedVisits || 0]);
  const max = Math.max(...allVals) || 1;

  return (
    <div className="ms-babs">
      <div className="ms-babs-legend">
        <div className="ms-babs-legend-item">
          <span className="ms-babs-swatch ms-babs-swatch--branded" />
          <span>Branded visits</span>
          <InfoTip text="Estimated monthly visits coming from queries that include the brand's own name (e.g. 'carbrain', 'sell to carbrain')." />
        </div>
        <div className="ms-babs-legend-item">
          <span className="ms-babs-swatch ms-babs-swatch--nonbranded" />
          <span>Non-branded visits</span>
          <InfoTip text="Visits from generic, intent-led queries (e.g. 'sell my junk car', 'buyer for damaged car') — the contestable demand." />
        </div>
      </div>

      <div className="ms-babs-grid">
        {rows.map((r) => {
          const branded = r.brandedVisits || 0;
          const nonBranded = r.nonBrandedVisits || 0;
          const total = branded + nonBranded;
          const brandedPct = total ? branded / total * 100 : 0;
          return (
            <div key={r.domain} className={`ms-babs-row ${r.isUs ? 'is-us' : ''}`}>
              <div className="ms-babs-name">
                <span className="ms-rankbar-dot" style={{ background: r.color }} />
                <div>
                  <div className="ms-babs-name-text">{r.name || r.domain}</div>
                  <div className="ms-babs-name-meta">
                    {fmtPctLive(brandedPct, 0)} branded · {fmtNumLive(total)} total
                  </div>
                </div>
                {r.isUs && <span className="ms-legend-tag">us</span>}
              </div>

              <div className="ms-babs-bars">
                <div className="ms-babs-bar-row">
                  <div className="ms-babs-bar-track">
                    <div
                      className="ms-babs-bar-fill ms-babs-bar-fill--branded"
                      style={{ width: `${branded / max * 100}%`, background: r.color }}>
                      
                      {branded / max * 100 > 14 &&
                      <span className="ms-babs-bar-val-inside">{fmtNumLive(branded)}</span>
                      }
                    </div>
                    {branded / max * 100 <= 14 &&
                    <span className="ms-babs-bar-val-outside">{fmtNumLive(branded)}</span>
                    }
                  </div>
                </div>
                <div className="ms-babs-bar-row">
                  <div className="ms-babs-bar-track">
                    <div
                      className="ms-babs-bar-fill ms-babs-bar-fill--nonbranded"
                      style={{
                        width: `${nonBranded / max * 100}%`,
                        background: r.color,
                        opacity: 0.42
                      }}>
                      
                      {nonBranded / max * 100 > 8 &&
                      <span className="ms-babs-bar-val-inside ms-babs-bar-val-inside--dark" style={{ opacity: "1", color: "rgb(219, 219, 219)" }}>
                          {fmtNumLive(nonBranded)}
                        </span>
                      }
                    </div>
                    {nonBranded / max * 100 <= 8 &&
                    <span className="ms-babs-bar-val-outside">{fmtNumLive(nonBranded)}</span>
                    }
                  </div>
                </div>
              </div>
            </div>);

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

}

// ─── Branded vs Non-Branded comparison ─────────────────────
function BrandedSplit({ rows }) {
  // each row: { domain, name, color, isUs, brandedShareOwn, nonBrandedShare, brandedVisits, nonBrandedVisits }
  return (
    <div className="ms-branded">
      {rows.map((r) => {
        const branded = r.brandedShareOwn || 0;
        const nonBranded = r.nonBrandedShare || 100 - branded;
        return (
          <div key={r.domain} className={`ms-branded-row ${r.isUs ? 'is-us' : ''}`}>
            <div className="ms-branded-head">
              <span className="ms-rankbar-dot" style={{ background: r.color }} />
              <span className="ms-branded-name">{r.name || r.domain}</span>
              {r.isUs && <span className="ms-legend-tag">us</span>}
              <span className="ms-branded-meta">
                {fmtNumLive(r.brandedVisits)} branded · {fmtNumLive(r.nonBrandedVisits)} non-branded
              </span>
            </div>
            <div className="ms-branded-bar">
              <div className="ms-branded-seg ms-branded-seg--brand" style={{ width: `${branded}%`, background: r.color }}>
                <span className="ms-branded-seg-val">{branded.toFixed(0)}%</span>
                <span className="ms-branded-seg-tag">Branded</span>
              </div>
              <div className="ms-branded-seg ms-branded-seg--nb" style={{ width: `${nonBranded}%` }}>
                <span className="ms-branded-seg-val">{nonBranded.toFixed(0)}%</span>
                <span className="ms-branded-seg-tag">Non-branded</span>
              </div>
            </div>
          </div>);

      })}
    </div>);

}

// ─── SEMrush table with built-in sparklines/bars ──────────
function OrganicTable({ rows }) {
  const cols = [
  { key: 'avgPosition', label: 'Avg. position', info: 'Average ranking across all keywords. Lower is better — position 1 is the top of Google.', fmt: (v) => v == null ? '—' : v.toFixed(1), invert: true },
  { key: 'kwsTop3', label: 'KWs top-3', info: 'Number of keywords for which this site ranks in positions 1, 2 or 3 — the "above-the-fold" SEO real estate.', fmt: fmtNumLive },
  { key: 'kwsTop10', label: 'KWs top-10', info: 'Keywords ranking on page 1 of Google (positions 1–10). Bigger pool of meaningful organic visibility.', fmt: fmtNumLive },
  { key: 'winRate', label: 'Win rate', info: 'Of head-to-head keyword overlaps, how often this site ranks above the competition.', fmt: (v) => fmtPctLive(v, 1) },
  { key: 'top3Share', label: 'Top-3 share', info: 'This site\'s share of all top-3 organic positions across the tracked keyword universe.', fmt: (v) => fmtPctLive(v, 1) },
  { key: 'uniqueKws', label: 'Unique KWs', info: 'Keywords this site ranks for that no other competitor in the set does — a moat indicator.', fmt: fmtNumLive }];

  return (
    <div className="ms-table ms-table--7col">
      <div className="ms-table-head">
        <div className="ms-table-cell ms-table-cell--name">Domain</div>
        {cols.map((c) =>
        <div key={c.key} className="ms-table-cell ms-table-cell--num">
            {c.label}
            <InfoTip text={c.info} />
          </div>
        )}
      </div>
      {rows.map((r) =>
      <div key={r.domain} className={`ms-table-row ${r.isUs ? 'is-us' : ''}`}>
          <div className="ms-table-cell ms-table-cell--name">
            <span className="ms-rankbar-dot" style={{ background: r.color }} />
            <span>{r.name || r.domain}</span>
            {r.isUs && <span className="ms-legend-tag">us</span>}
          </div>
          {cols.map((c) => {
          const all = rows.map((x) => x[c.key]).filter((v) => v != null);
          const max = Math.max(...all) || 1;
          const min = Math.min(...all) || 0;
          const v = r[c.key];
          const t = v == null ? 0 : c.invert ? 1 - (v - min) / (max - min || 1) : (v - min) / (max - min || 1);
          return (
            <div key={c.key} className="ms-table-cell ms-table-cell--num">
                <div className="ms-table-bar">
                  <div className="ms-table-bar-fill" style={{ width: `${Math.max(4, t * 100)}%`, background: r.color, opacity: 0.18 }} />
                </div>
                <span className="ms-table-val">{c.fmt(v)}</span>
              </div>);

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

}

// ─── Info Tip — small (i) with hover tooltip ──────────────
function InfoTip({ text }) {
  const [open, setOpen] = useStateC(false);
  return (
    <span
      className="ms-info"
      onMouseEnter={() => setOpen(true)}
      onMouseLeave={() => setOpen(false)}
      onClick={(e) => {e.stopPropagation();setOpen((o) => !o);}}>
      
      <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
        <circle cx="12" cy="12" r="9" />
        <path d="M12 11v6M12 7.5v.5" strokeLinecap="round" />
      </svg>
      {open && <span className="ms-info-tip">{text}</span>}
    </span>);

}

// ─── Section B2 — Absolute channel visits (grouped bar chart) ──
function ChannelAbsolute({ rows, channels }) {
  // rows: [{domain, name, color, isUs, organic, paid, direct, referral, social, total}]
  const [activeChannel, setActiveChannel] = useStateC('all');
  const visibleChannels = activeChannel === 'all' ? channels : channels.filter((c) => c.id === activeChannel);

  // Find global max for scale
  const allVals = rows.flatMap((r) => visibleChannels.map((c) => r[c.id] || 0));
  const max = Math.max(...allVals) || 1;

  return (
    <div className="ms-b2">
      <div className="ms-b2-tabs">
        <button
          className={`ms-b2-tab ${activeChannel === 'all' ? 'is-active' : ''}`}
          onClick={() => setActiveChannel('all')}>
          All channels</button>
        {channels.map((c) =>
        <button
          key={c.id}
          className={`ms-b2-tab ${activeChannel === c.id ? 'is-active' : ''}`}
          onClick={() => setActiveChannel(c.id)}
          style={activeChannel === c.id ? { background: c.color, color: 'white', borderColor: c.color } : {}}>
          
            <span className="ms-b2-tab-dot" style={{ background: c.color }} />
            {c.label}
          </button>
        )}
      </div>

      <div className="ms-b2-grid">
        {rows.map((r) =>
        <div key={r.domain} className={`ms-b2-row ${r.isUs ? 'is-us' : ''}`}>
            <div className="ms-b2-name">
              <span className="ms-rankbar-dot" style={{ background: r.color }} />
              <div>
                <div className="ms-b2-name-text">{r.name || r.domain}</div>
                <div className="ms-b2-name-total">Total: {fmtNumLive(r.total)}</div>
              </div>
              {r.isUs && <span className="ms-legend-tag">us</span>}
            </div>
            <div className="ms-b2-bars">
              {visibleChannels.map((c) => {
              const v = r[c.id] || 0;
              const widthPct = v / max * 100;
              return (
                <div key={c.id} className="ms-b2-bar-row">
                    <div className="ms-b2-bar-label">{c.label}</div>
                    <div className="ms-b2-bar-track">
                      <div
                      className="ms-b2-bar-fill"
                      style={{ width: `${widthPct}%`, background: c.color }}>
                      
                        {widthPct > 14 && <span className="ms-b2-bar-val-inside">{fmtNumLive(v)}</span>}
                      </div>
                      {widthPct <= 14 && <span className="ms-b2-bar-val-outside">{fmtNumLive(v)}</span>}
                    </div>
                  </div>);

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

}


// ─── Paid SOV grid ───────────────────────────────────────
function PaidGrid({ rows }) {
  const metrics = [
  { key: 'impShare', label: 'Impression share', hint: 'Share of total possible impressions' },
  { key: 'topOfPageRate', label: 'Top of page rate', hint: 'Ads shown at top of SERP' },
  { key: 'outrankingShare', label: 'Outranking share', hint: 'Times ranked above the rest' },
  { key: 'overlapRate', label: 'Overlap rate', hint: 'Auctions seen alongside us' },
  { key: 'brandOverlapRate', label: 'Brand bidding', hint: 'Their imp share when searches are for CarBrain branded KWs — how aggressively they bid against our brand' }];

  return (
    <div className="ms-paidgrid">
      {rows.map((r) =>
      <div key={r.domain} className={`ms-paidcard ${r.isUs ? 'is-us' : ''}`}>
          <div className="ms-paidcard-head">
            <span className="ms-rankbar-dot" style={{ background: r.color, width: 10, height: 10 }} />
            <span className="ms-paidcard-name">{r.name || r.domain}</span>
            {r.isUs && <span className="ms-legend-tag">us</span>}
          </div>
          <div className="ms-paidcard-metrics">
            {metrics.map((m) => {
            const v = r[m.key];
            // For "us" row, outranking/overlap/brand are N/A (we don't compete with ourselves)
            const isNA = r.isUs && ['outrankingShare', 'overlapRate', 'brandOverlapRate'].includes(m.key);
            return (
              <div key={m.key} className="ms-paidcard-metric" title={m.hint}>
                  <div className="ms-paidcard-metric-label">{m.label}</div>
                  <div className="ms-paidcard-metric-value">{isNA ? '—' : fmtPctLive(v, 1)}</div>
                  <div className="ms-paidcard-metric-bar">
                    <div className="ms-paidcard-metric-fill" style={{ width: isNA ? '0%' : `${Math.min(100, v || 0)}%`, background: r.color }} />
                  </div>
                </div>);

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

}

// ─── Brand attack — tornado/back-to-back bars ─────────────────────
// LEFT side  = "Auction overlap" — % of CarBrain's non-branded paid auctions
//              where this competitor also appears (Section E col F).
// RIGHT side = "Brand defense gap" — competitor's impression share when the
//              search query is a CarBrain-branded keyword (Section E col G).
//              Note: this is share *within* the CarBrain-branded campaign only,
//              which is itself a slice of total paid activity.
function BrandAttackChord({ rows = [], paidRows = [] }) {
  const us = rows.find(r => r.isUs);
  const competitorsBase = rows.filter(r => !r.isUs);
  if (!us || competitorsBase.length === 0) return null;

  const findPaid = (domain) => {
    if (!domain || !paidRows.length) return null;
    const target = String(domain).toLowerCase().trim();
    let hit = paidRows.find(p => String(p.domain).toLowerCase().trim() === target);
    if (hit) return hit;
    const targetRoot = target.replace(/^www\./, '').split('.')[0];
    return paidRows.find(p => {
      const pRoot = String(p.domain).toLowerCase().trim().replace(/^www\./, '').split('.')[0];
      return pRoot === targetRoot;
    }) || null;
  };

  const competitors = competitorsBase.map(c => {
    const p = findPaid(c.domain);
    return {
      ...c,
      overlapRate: p?.overlapRate ?? 0,
      brandOverlapRate: p?.brandOverlapRate ?? 0,
    };
  });

  // Sort: rows with the largest combined paid-pressure on top
  const sorted = [...competitors].sort((a, b) =>
    ((b.overlapRate + b.brandOverlapRate) - (a.overlapRate + a.brandOverlapRate))
  );

  // Use a shared scale so left/right bars are visually comparable.
  const maxAll = Math.max(
    60,
    ...sorted.flatMap(c => [c.overlapRate, c.brandOverlapRate])
  );
  const widthFor = (v) => Math.max(0, (v / maxAll) * 100);

  return (
    <div className="ms-tornado">
      {/* Header — two side titles + center axis label */}
      <div className="ms-tornado-head">
        <div className="ms-tornado-head-side ms-tornado-head-side--left">
          <div className="ms-tornado-head-eyebrow">Left</div>
          <div className="ms-tornado-head-title">Auction overlap</div>
          <div className="ms-tornado-head-sub">% of {us.name}&apos;s non-branded paid auctions where this competitor also bid</div>
        </div>
        <div className="ms-tornado-head-axis">
          <div className="ms-tornado-axis-marker" />
          <div className="ms-tornado-axis-label">{us.name}</div>
        </div>
        <div className="ms-tornado-head-side ms-tornado-head-side--right">
          <div className="ms-tornado-head-eyebrow">Right</div>
          <div className="ms-tornado-head-title">Brand defense gap</div>
          <div className="ms-tornado-head-sub">Competitor&apos;s imp share within {us.name}&apos;s <strong>branded campaign</strong> (slice of total paid)</div>
        </div>
      </div>

      {/* Rows */}
      <div className="ms-tornado-body">
        {sorted.map((c) => {
          const lW = widthFor(c.overlapRate);
          const rW = widthFor(c.brandOverlapRate);
          const isHighBrand = c.brandOverlapRate >= 25;
          const isHighOverlap = c.overlapRate >= 25;
          return (
            <div key={c.domain} className="ms-tornado-row">
              {/* Left bar */}
              <div className="ms-tornado-cell ms-tornado-cell--left">
                <div className="ms-tornado-val ms-tornado-val--left">
                  {c.overlapRate.toFixed(0)}%
                </div>
                <div className="ms-tornado-track ms-tornado-track--left">
                  <div
                    className={`ms-tornado-bar ms-tornado-bar--left ${isHighOverlap ? 'is-high' : ''}`}
                    style={{ width: `${lW}%`, background: c.color }}
                    title={`${c.name || c.domain} — Auction overlap: ${c.overlapRate.toFixed(1)}%`}
                  />
                </div>
              </div>

              {/* Center label */}
              <div className="ms-tornado-name">
                <span className="ms-rankbar-dot" style={{ background: c.color, width: 10, height: 10 }} />
                <span>{c.name || c.domain}</span>
              </div>

              {/* Right bar */}
              <div className="ms-tornado-cell ms-tornado-cell--right">
                <div className="ms-tornado-track ms-tornado-track--right">
                  <div
                    className={`ms-tornado-bar ms-tornado-bar--right ${isHighBrand ? 'is-high' : ''}`}
                    style={{ width: `${rW}%`, background: c.color }}
                    title={`${c.name || c.domain} — Brand defense gap: ${c.brandOverlapRate.toFixed(1)}%`}
                  />
                </div>
                <div className={`ms-tornado-val ms-tornado-val--right ${isHighBrand ? 'is-high' : ''}`}>
                  {c.brandOverlapRate.toFixed(0)}%
                </div>
              </div>
            </div>
          );
        })}
      </div>

      {/* Footer — what to look for */}
      <div className="ms-tornado-foot">
        <strong>How to read:</strong> bars on both sides = competitor pressures {us.name} both in the open market AND on branded queries (dual-front threat).
        Big right bar only = predatory brand bidding (intercepting users who searched for {us.name} by name).
        Big left bar only = market overlap without direct brand attack.
      </div>
    </div>
  );
}

// ─── Section F — Lead share (estimated leads + purchased units) ────
function LeadShare({ rows, paidRows = [], brandedRows = [] }) {
  const maxLeads = Math.max(...rows.map(r => r.estLeads || 0)) || 1;

  const us = rows.find(r => r.isUs);
  const competitors = rows.filter(r => !r.isUs);

  // Helper: find related row by exact domain match (case-insensitive, trimmed).
  const findByDomain = (list, domain) => {
    if (!list || list.length === 0 || !domain) return null;
    const target = String(domain).toLowerCase().trim();
    let hit = list.find(p => String(p.domain).toLowerCase().trim() === target);
    if (hit) return hit;
    const targetRoot = target.replace(/^www\./, '').split('.')[0];
    hit = list.find(p => {
      const pRoot = String(p.domain).toLowerCase().trim().replace(/^www\./, '').split('.')[0];
      return pRoot === targetRoot;
    });
    return hit || null;
  };

  const nonBrandedShareFor = (domain) => {
    const m = findByDomain(brandedRows, domain);
    return m && m.nonBrandedShare != null ? m.nonBrandedShare : 50;
  };

  // Paid auction overlap (Section E) — only signal we have for our own pool
  const paidOverlapFor = (domain) => {
    const m = findByDomain(paidRows, domain);
    return m && m.overlapRate != null ? m.overlapRate : null;
  };

  // ── Pool composition: of OUR non-branded leads, how much overlaps with each competitor in paid auctions
  const usNonBrandedShare = us ? nonBrandedShareFor(us.domain) : 50;
  const usTotalLeads = us?.estLeads || 0;
  const usNonBrandedLeads = usTotalLeads * (usNonBrandedShare / 100);
  const usBrandedLeads = usTotalLeads - usNonBrandedLeads;

  const overlapBreakdown = competitors.map(c => {
    const overlapPct = paidOverlapFor(c.domain);
    const overlapLeads = overlapPct != null ? usNonBrandedLeads * (overlapPct / 100) : null;
    return { ...c, overlapPct, overlapLeads };
  });

  // Sum of overlaps may exceed 100% — overlaps aren't mutually exclusive.
  const rawOverlapSum = overlapBreakdown.reduce((s, c) => s + (c.overlapLeads || 0), 0);
  let scaledOverlap;
  let exclusiveToUs;
  if (rawOverlapSum > usNonBrandedLeads) {
    const factor = usNonBrandedLeads / rawOverlapSum;
    scaledOverlap = overlapBreakdown.map(c => ({
      ...c,
      overlapLeadsRendered: c.overlapLeads != null ? c.overlapLeads * factor : null,
    }));
    exclusiveToUs = 0;
  } else {
    scaledOverlap = overlapBreakdown.map(c => ({ ...c, overlapLeadsRendered: c.overlapLeads }));
    exclusiveToUs = usNonBrandedLeads - rawOverlapSum;
  }
  const compositionTotal = usNonBrandedLeads;

  // Compute units share % from raw estPurchased
  const totalUnits = rows.reduce((s, r) => s + (r.estPurchased || 0), 0) || 1;
  const rowsWithUnitsShare = rows.map(r => ({
    ...r,
    unitsShare: ((r.estPurchased || 0) / totalUnits) * 100,
  }));

  return (
    <div className="ms-leadshare">
      {/* Top: single donut — units share */}
      <div className="ms-leadshare-twin">
        <div className="ms-leadshare-twin-card ms-leadshare-twin-card--primary" style={{ gridColumn: '1 / -1' }}>
          <div className="ms-leadshare-twin-head">
            <div className="ms-section-eyebrow">Outcome signal</div>
            <h4 className="ms-leadshare-twin-title">
              Estimated units share
              <InfoTip text="Share of category purchases (vehicles bought) each competitor captures. Modeled as leads × purchase rate (PR), normalized. The decisive metric: even if a seller submits to multiple buyers, only one wins the deal." />
            </h4>
          </div>
          <div className="ms-leadshare-twin-body" style={{ gridTemplateColumns: '180px 1fr', gap: 32 }}>
            <DonutShare rows={rowsWithUnitsShare} valueKey="unitsShare" size={180} thickness={26} />
            <div className="ms-leadshare-twin-rank">
              {[...rowsWithUnitsShare].sort((a, b) => (b.unitsShare || 0) - (a.unitsShare || 0)).map((r, i) => (
                <div key={r.domain} className={`ms-leadshare-rank-row ${r.isUs ? 'is-us' : ''}`}>
                  <span className="ms-leadshare-rank-num">{i + 1}</span>
                  <span className="ms-rankbar-dot" style={{ background: r.color }} />
                  <span className="ms-leadshare-rank-name">{r.name || r.domain}</span>
                  {r.isUs && <span className="ms-legend-tag">us</span>}
                  <span className="ms-leadshare-rank-pct">{fmtPctLive(r.unitsShare, 1)}</span>
                </div>
              ))}
            </div>
          </div>
        </div>
      </div>

      {/* Brand attack chord — auction overlap + brand bidding side-by-side */}
      {us && (
        <div className="ms-leadshare-overlap">
          <div className="ms-leadshare-overlap-head">
            <div className="ms-section-eyebrow">Paid search · Two ways competitors contest {us.name}</div>
            <h4 className="ms-leadshare-twin-title" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              How competitors show up against us in paid search
              <InfoTip text={`Two distinct signals from Section E. Auction overlap = % of OUR non-branded auctions where this competitor also appears (they're chasing the same intent). Brand bidding = competitor's impression share when the search query contains "carbrain" — they're paying to intercept users searching for us by name. High brand bidding signals predatory targeting.`} />
            </h4>
            <p className="ms-leadshare-overlap-caption">
              Two stacked metrics from Section E — both show paid-search pressure on {us.name}, but from different angles.
              <strong> Left bars</strong> measure overlap in the open market; <strong>right bars</strong> measure who&apos;s
              intercepting users that already searched for {us.name} by name.
            </p>

            <div className="ms-tornado-scopenote">
              <strong>Scope note · right side:</strong> the &quot;Brand defense gap&quot; is competitor impression share <em>within {us.name}&apos;s branded campaign only</em>
              — i.e. when the search query contains &quot;{us.name.toLowerCase()}&quot;. The branded campaign is itself a slice of total paid activity,
              so a 57% gap doesn&apos;t mean &quot;57% of all paid impressions,&quot; it means &quot;57% of impressions on {us.name}-branded queries.&quot;
            </div>
          </div>

          <BrandAttackChord rows={rows} paidRows={paidRows} />

          <div className="ms-pool-caveat">
            <strong>Read this chart:</strong> a long bar on the <em>right</em> = predatory brand bidding. ClunkerJunker captures{' '}
            {(paidRows.find(c => /clunker/i.test(c.domain))?.brandOverlapRate || 0).toFixed(0)}% of impressions when users search for {us.name} by name —
            and they also overlap heavily on the left ({(paidRows.find(c => /clunker/i.test(c.domain))?.overlapRate || 0).toFixed(0)}% of our non-branded auctions),
            which makes them a dual-front threat. Wheelzy{' '}
            ({(paidRows.find(c => /wheelzy/i.test(c.domain))?.brandOverlapRate || 0).toFixed(0)}% brand) does the same at lower volume.
            Peddle is absent from branded auctions ({(paidRows.find(c => /peddle/i.test(c.domain))?.brandOverlapRate || 0).toFixed(0)}%) but pressures us on the left side — different strategy, possibly heavier on SEO and non-branded paid.
          </div>
        </div>
      )}

      {/* Bottom: per-competitor breakdown table */}
      <div className="ms-leadshare-table">
        <div className="ms-leadshare-thead">
          <div>Domain</div>
          <div className="ms-num">Traffic <InfoTip text="Total monthly visits — same source as Section A." /></div>
          <div className="ms-num">CVR <InfoTip text="Conversion rate applied to estimate leads from traffic. Based on CarBrain benchmarks per competitor." /></div>
          <div className="ms-num">Est. leads/mo <InfoTip text="Modeled monthly lead count = traffic × CVR." /></div>
          <div className="ms-num">Est. PR <InfoTip text="Estimated purchase rate — % of leads that turn into a purchased vehicle." /></div>
          <div className="ms-num">Est. units <InfoTip text="Estimated monthly purchased units = leads × PR." /></div>
        </div>
        {rows.map(r => {
          const leadsW = (r.estLeads || 0) / maxLeads * 100;
          return (
            <div key={r.domain} className={`ms-leadshare-trow ${r.isUs ? 'is-us' : ''}`}>
              <div className="ms-leadshare-tname">
                <span className="ms-rankbar-dot" style={{ background: r.color }} />
                <span>{r.name || r.domain}</span>
                {r.isUs && <span className="ms-legend-tag">us</span>}
              </div>
              <div className="ms-num">{fmtNumLive(r.traffic)}</div>
              <div className="ms-num">{fmtPctLive(r.cvr, 2)}</div>
              <div className="ms-num ms-leadshare-leads">
                <div className="ms-leadshare-leads-bar">
                  <div className="ms-leadshare-leads-fill" style={{ width: `${leadsW}%`, background: r.color, opacity: 0.18 }} />
                </div>
                <span style={{ position: 'relative', zIndex: 1 }}>{fmtNumLive(r.estLeads)}</span>
              </div>
              <div className="ms-num">{fmtPctLive(r.estPR, 1)}</div>
              <div className="ms-num ms-leadshare-units">{fmtNumLive(r.estPurchased)}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Donut for market share (Section A) ─────────────────
function DonutShare({ rows, valueKey = 'marketPct', size = 220, thickness = 32 }) {
  const total = rows.reduce((a, r) => a + (r[valueKey] || 0), 0) || 100;
  const r = size / 2;
  const inner = r - thickness;
  let acc = 0;
  const arcs = rows.map((row) => {
    const start = acc / total * Math.PI * 2 - Math.PI / 2;
    acc += row[valueKey] || 0;
    const end = acc / total * Math.PI * 2 - Math.PI / 2;
    const large = end - start > Math.PI ? 1 : 0;
    const x1 = r + r * Math.cos(start);
    const y1 = r + r * Math.sin(start);
    const x2 = r + r * Math.cos(end);
    const y2 = r + r * Math.sin(end);
    const x3 = r + inner * Math.cos(end);
    const y3 = r + inner * Math.sin(end);
    const x4 = r + inner * Math.cos(start);
    const y4 = r + inner * Math.sin(start);
    return {
      ...row,
      d: `M ${x1} ${y1} A ${r} ${r} 0 ${large} 1 ${x2} ${y2} L ${x3} ${y3} A ${inner} ${inner} 0 ${large} 0 ${x4} ${y4} Z`
    };
  });
  const [hover, setHover] = useStateC(null);
  const us = rows.find((x) => x.isUs);
  return (
    <div className="ms-donut-wrap">
      <svg width={size} height={size}>
        {arcs.map((a, i) =>
        <path
          key={i}
          d={a.d}
          fill={a.color}
          opacity={hover != null && hover !== i ? 0.32 : 1}
          onMouseEnter={() => setHover(i)}
          onMouseLeave={() => setHover(null)}
          style={{ cursor: 'pointer', transition: 'opacity 150ms' }} />

        )}
        <text x={r} y={r - 8} textAnchor="middle" fontSize="11" fill="var(--ms-fg-3)" style={{ textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 700 }}>
          {hover != null ? rows[hover].name || rows[hover].domain : us ? us.name : 'Total'}
        </text>
        <text x={r} y={r + 16} textAnchor="middle" fontSize="26" fill="var(--ms-fg-1)" style={{ fontFamily: 'var(--cb-font-display)' }}>
          {hover != null ? `${(rows[hover][valueKey] || 0).toFixed(1)}%` : us ? `${(us[valueKey] || 0).toFixed(1)}%` : '100%'}
        </text>
      </svg>
      <div className="ms-donut-legend">
        {rows.map((d, i) =>
        <div
          key={i}
          className="ms-donut-legend-row"
          onMouseEnter={() => setHover(i)}
          onMouseLeave={() => setHover(null)}
          style={{ opacity: hover != null && hover !== i ? 0.45 : 1 }}>
          
            <span className="ms-donut-dot" style={{ background: d.color }} />
            <span className="ms-donut-name">
              {d.name || d.domain}
              {d.isUs && <span className="ms-legend-tag" style={{ marginLeft: 6 }}>us</span>}
            </span>
            <span className="ms-donut-val">{(d[valueKey] || 0).toFixed(1)}%</span>
          </div>
        )}
      </div>
    </div>);

}

Object.assign(window, {
  SparklineC, RankBars, ChannelStack, BrandedSplit, BrandedAbsolute, OrganicTable, PaidGrid, DonutShare, LeadShare,
  ChannelAbsolute, InfoTip,
  fmtNumLive, fmtPctLive
});