/* ============================================================
   Pipeline Overview — the three sections.
   FunnelSection · LeadSection · SourcingSection
   Each consumes a shared ctx built in pl_app.jsx. Measure-aware
   (count / € EBITDA / € revenue), period-aware (month/quarter/year),
   compare-aware (ghost vs prior period). Everything drills.
   ============================================================ */

/* small conversion pill */
function Conv({ rate }) {
  const tone = rate >= 0.10 ? ['var(--positive-soft)', 'var(--positive)'] : rate >= 0.045 ? ['var(--warn-soft)', 'var(--warn)'] : ['var(--danger-soft)', 'var(--danger)'];
  return <span className="fit" style={{ background: tone[0], color: tone[1], minWidth: 44 }}>{(rate * 100).toFixed(1)}%</span>;
}
/* build trend rows from ctx periods (+ prior period ghost) */
function trendData(ctx, fn) {
  const f = fn || ((s) => s);
  return ctx.periods.map((p, i) => ({ label: p.label, key: p.key, cur: ctx.val(f(p.set)), prev: ctx.val(f((ctx.prevPeriods[i] || { set: [] }).set)) }));
}

/* ============================================================
   FUNNEL
   ============================================================ */
function FunnelKpis({ ctx }) {
  const { cur, prev, val, fmtVal, periods } = ctx;
  const spark = (fn) => periods.map((p) => fn(p.set).length);
  const card = (label, sel, opts = {}) => {
    const v = val(sel(cur)), pv = val(sel(prev));
    return { label, value: opts.pct ? v : fmtVal(v), delta: opts.noDelta ? null : plPct(v, pv), sub: opts.sub, spark: opts.pct ? null : spark(sel), accent: opts.accent, sel };
  };
  const convCur = cur.length ? plReach(cur, 8).length / cur.length * 100 : 0;
  const convPrev = prev.length ? plReach(prev, 8).length / prev.length * 100 : 0;
  const kpis = [
    card('Leads added', (s) => s, { accent: true, sub: `${ctx.pLbl}: ${fmtVal(val(prev))}` }),
    card('Appointments', (s) => plReach(s, 1), { sub: `${cur.length ? Math.round(plReach(cur, 1).length / cur.length * 100) : 0}% of leads` }),
    card('First meetings', (s) => s.filter((d) => d.firstMeeting), { sub: `${ctx.pLbl}: ${fmtVal(val(prev.filter((d) => d.firstMeeting)))}` }),
    card('Portfolio', (s) => plReach(s, 8), { sub: 'signed' }),
  ];
  return (
    <div style={{ display: 'flex', gap: 11 }}>
      {kpis.map((k) => (
        <button key={k.label} className="card" onClick={() => ctx.openDrawer(k.label, `${plYearLabel(ctx.year)} · ${MEASURE_LABEL[ctx.measure]}`, k.sel(cur))}
          style={{ padding: '12px 13px', display: 'flex', flexDirection: 'column', flex: 1, minWidth: 0, textAlign: 'left', cursor: 'pointer', background: 'var(--surface-card)' }}>
          <div className="micro" style={{ marginBottom: 6, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{k.label}</div>
          <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
            <span className="tabular" style={{ fontSize: 22, fontWeight: 700, lineHeight: 1, color: k.accent ? 'var(--accent)' : 'var(--ink)' }}>{k.value}</span>
            <Delta v={k.delta} />
          </div>
          <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 6, marginTop: 7 }}>
            <div style={{ fontSize: 10.5, color: 'var(--ink-soft)', fontWeight: 500 }}>{k.sub}</div>
            {k.spark && <Sparkline values={k.spark} color={k.accent ? 'var(--accent)' : PC.accent2} />}
          </div>
        </button>
      ))}
      {/* conversion card (always %) */}
      <Card style={{ flex: 1, minWidth: 0 }} pad="12px 13px">
        <div className="micro" style={{ marginBottom: 6 }}>Lead → portfolio</div>
        <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
          <span className="tabular" style={{ fontSize: 22, fontWeight: 700, lineHeight: 1 }}>{convCur.toFixed(1)}%</span>
          <Delta v={convPrev ? Math.round((convCur - convPrev) * 10) / 10 : null} unit="pp" />
        </div>
        <div style={{ fontSize: 10.5, color: 'var(--ink-soft)', fontWeight: 500, marginTop: 7 }}>{ctx.pLbl}: {convPrev.toFixed(1)}%</div>
      </Card>
    </div>
  );
}

function StageFunnelCard({ ctx }) {
  const { cur, prev, ghost, val, fmtVal } = ctx;
  const fr = plFunnel(cur, val), frp = plFunnel(prev, val);
  const fmax = Math.max(1, fr[0].n, ghost ? frp[0].n : 0);
  return (
    <Card>
      <CardHead title="Stage funnel" sub={`${plYearLabel(ctx.year)}${ghost ? ' · dashed = ' + ctx.pLbl : ''} · platform / add-on · ${MEASURE_LABEL[ctx.measure]}`} />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}>
        {fr.map((s, i) => {
          const w = s.n / fmax * 100, wp = frp[i].n / fmax * 100;
          const yoy = plPct(s.n, frp[i].n);
          const plat = val(s.set.filter((d) => d.dealType === 'platform'));
          const platShare = s.n ? plat / s.n * 100 : 0;
          const conv = i > 0 && fr[i - 1].count ? Math.round(s.count / fr[i - 1].count * 100) : 100;
          return (
            <div key={s.key} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
              <div style={{ width: 92, flexShrink: 0, textAlign: 'right' }}>
                <div style={{ fontSize: 11.5, fontWeight: 600 }}>{s.label}</div>
                <div className="tabular" style={{ fontSize: 9.5, color: PC.soft }}>{conv}%</div>
              </div>
              <div style={{ flex: 1, position: 'relative', height: 26, display: 'flex', alignItems: 'center', cursor: 'pointer' }} onClick={() => ctx.openDrawer(s.label, `Reached ${s.label} · ${plYearLabel(ctx.year)}`, s.set)}>
                {ghost && <div style={{ position: 'absolute', left: 0, width: Math.max(wp, 0.6) + '%', height: 26, border: '1.4px dashed ' + PC.ghost, borderRadius: 4 }}></div>}
                <div style={{ position: 'absolute', left: 0, width: Math.max(w, 1) + '%', height: 22, display: 'flex', borderRadius: 4, overflow: 'hidden', boxShadow: '0 1px 2px rgba(0,0,0,.07)' }}>
                  <div style={{ width: platShare + '%', background: DCH.platform }}></div>
                  <div style={{ width: (100 - platShare) + '%', background: DCH.addon }}></div>
                </div>
              </div>
              <div style={{ width: 92, flexShrink: 0, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', gap: 6 }}>
                <span className="tabular" style={{ fontSize: 13.5, fontWeight: 700 }}>{fmtVal(s.n)}</span>
                {ghost && <Delta v={yoy} size={9.5} />}
              </div>
            </div>
          );
        })}
      </div>
      <div style={{ display: 'flex', gap: 14, marginTop: 12, fontSize: 11, color: PC.muted, fontWeight: 600 }}>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: DCH.platform }}></span>Platform</span>
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: DCH.addon }}></span>Add-on</span>
        <span style={{ flex: 1 }}></span>
        <span style={{ color: PC.soft }}>% = stage-to-stage advance · click a bar for companies</span>
      </div>
    </Card>
  );
}

function FunnelSection({ ctx }) {
  const { show } = ctx;
  const target = Math.max(2, Math.round(ctx.val(ctx.prev) / Math.max(1, ctx.periods.length) * 1.12));
  const leadTrend = trendData(ctx);
  const roll = plRollingLTM(ctx.base);
  // exits read
  const exit = [['Passed', ctx.cur.filter((d) => d.terminal === 'Passed'), PCH.exit.Passed], ['On hold', ctx.cur.filter((d) => d.terminal === 'On Hold'), PCH.exit['On Hold']], ['Lost', ctx.cur.filter((d) => d.terminal === 'Lost'), PCH.exit.Lost]];
  const exitTot = exit.reduce((s, e) => s + ctx.val(e[1]), 0) || 1;
  // aging
  const agingStages = [0, 1, 2, 3];
  const agingRows = agingStages.map((rk) => {
    const set = ctx.cur.filter((d) => d.active && d.stageRank === rk);
    return { key: rk, label: PL.STAGES[rk].label, cells: PL.AGE_BUCKETS.map((b) => set.filter((d) => d.ageBucket === b).length), total: set.length, set };
  });

  return (
    <SectionBlock id="funnel" eyebrow="Section 01 · the engine" title="The funnel"
      right={<button className="btn" onClick={ctx.openMatrix}><Icon name="table" size={14} /> All seasons</button>}>
      {show.funnel_kpis && <div style={{ marginBottom: 16 }}><FunnelKpis ctx={ctx} /></div>}

      <div style={{ display: 'grid', gridTemplateColumns: '1.12fr 1fr', gap: 16 }}>
        {show.funnel_funnel && <StageFunnelCard ctx={ctx} />}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
          {show.funnel_trend && (
            <Card>
              <CardHead title="Leads added over time" sub={`Bars this season · dashed = prior · ${MEASURE_LABEL[ctx.measure]}`} />
              <ComboBars data={leadTrend} series={[{ key: 'cur', color: DCH.platform, label: 'Added' }]} ghostKey="prev" height={172}
                target={{ value: target, label: 'Pace ' + ctx.fmtVal(target) }} fmtBar={ctx.fmtVal}
                onBar={(d) => ctx.openDrawer('Leads added · ' + d.label, 'Entered the pipeline', ctx.periods.find((p) => p.key === d.key).set)} />
            </Card>
          )}
          {show.funnel_exits && (
            <Card>
              <CardHead title="Where they left" sub={`${plYearLabel(ctx.year)} · exits this season`} />
              <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
                {exit.map(([lab, set, col]) => (
                  <div key={lab} style={{ display: 'flex', alignItems: 'center', gap: 10, cursor: 'pointer' }} onClick={() => ctx.openDrawer(lab + ' deals', plYearLabel(ctx.year), set)}>
                    <div style={{ width: 60, fontSize: 11.5, fontWeight: 600, color: PC.muted }}>{lab}</div>
                    <div style={{ flex: 1, height: 16, background: 'var(--surface-deep)', borderRadius: 4, overflow: 'hidden' }}><div style={{ width: ctx.val(set) / exitTot * 100 + '%', height: '100%', background: col }}></div></div>
                    <span className="tabular" style={{ width: 56, textAlign: 'right', fontSize: 12.5, fontWeight: 700 }}>{ctx.fmtVal(ctx.val(set))}</span>
                  </div>
                ))}
              </div>
            </Card>
          )}
        </div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: '1.3fr 1fr', gap: 16, marginTop: 16 }}>
        {show.funnel_roll && (
          <Card>
            <CardHead title="Leads added · rolling LTM" sub="Trailing-12 sum across five seasons · % = change vs prior month" />
            <RollChart data={roll} />
          </Card>
        )}
        {show.funnel_aging && (
          <Card>
            <CardHead title="Stage aging" sub="Active deals by days untouched: what's sitting stale" />
            <AgingHeatmap rows={agingRows} colLabels={PL.AGE_BUCKETS}
              onCell={(r, c) => ctx.openDrawer(`${r.label} · ${PL.AGE_BUCKETS[c]} days`, 'Active, untouched this long', r.set.filter((d) => d.ageBucket === PL.AGE_BUCKETS[c]))} />
          </Card>
        )}
      </div>
    </SectionBlock>
  );
}

/* ============================================================
   LEAD ANALYSIS
   ============================================================ */
function LeadSection({ ctx }) {
  const { cur, prev, val, fmtVal, show } = ctx;
  const [dist, setDist] = useState('ebitda');
  // sector mix
  const secRows = PL.SECTORS.map((sec) => ({ label: sec, value: val(cur.filter((d) => d.sector === sec)), prev: val(prev.filter((d) => d.sector === sec)), set: cur.filter((d) => d.sector === sec) }))
    .filter((r) => r.set.length).sort((a, b) => b.value - a.value);
  // reasons
  const reasonRows = (terminal, reasons) => reasons.map((r) => { const set = cur.filter((d) => d.terminal === terminal && d.terminalReason === r); return { label: r, value: val(set), set }; }).filter((r) => r.set.length).sort((a, b) => b.value - a.value);
  const passRows = reasonRows('Passed', PL.PASS_REASONS);
  const lostRows = reasonRows('Lost', PL.LOST_REASONS);
  const passN = cur.filter((d) => d.terminal === 'Passed').length, lostN = cur.filter((d) => d.terminal === 'Lost').length;
  // distribution
  const field = dist; // 'ebitda' | 'revenue'
  const edges = dist === 'ebitda' ? [0, 0.5, 1, 1.5, 2.5, 4, 99] : [0, 2, 5, 10, 20, 40, 999];
  const labels = dist === 'ebitda' ? ['<0.5', '0.5–1', '1–1.5', '1.5–2.5', '2.5–4', '4m+'] : ['<2', '2–5', '5–10', '10–20', '20–40', '40m+'];
  const vals = cur.map((d) => d[field]).filter((x) => x != null).sort((a, b) => a - b);
  const median = vals.length ? vals[vals.length >> 1] : 0;
  const buckets = labels.map((lab, i) => { const lo = edges[i], hi = edges[i + 1]; const set = cur.filter((d) => d[field] >= lo && d[field] < hi); return { label: lab, n: set.length, set, hi: median >= lo && median < hi }; });

  return (
    <SectionBlock id="lead" eyebrow="Section 02 · why & where" title="Lead analysis"
      right={<span className="badge" style={{ background: 'var(--surface-deep)' }}>{plYearLabel(ctx.year)} · {MEASURE_LABEL[ctx.measure]}</span>}>
      <div style={{ display: 'grid', gridTemplateColumns: '1.25fr 1fr 1fr', gap: 16 }}>
        {show.lead_sector && (
          <Card>
            <CardHead title="Deals by sector" sub={`This season · dashed = ${ctx.pLbl}`} />
            <RankedBars rows={secRows} color={DCH.platform} prior fmt={fmtVal} height={300}
              onRow={(r) => ctx.openDrawer(r.label, 'Deals sourced from this sector', r.set)} />
          </Card>
        )}
        {show.lead_pass && (
          <Card>
            <CardHead title="Pass reasons" sub={`${passN} passed · ${MEASURE_LABEL[ctx.measure]}`} />
            <RankedBars rows={passRows} color={PCH.exit['On Hold']} fmt={fmtVal} height={300}
              onRow={(r) => ctx.openDrawer('Passed · ' + r.label, 'Passed for this reason', r.set)} />
          </Card>
        )}
        {show.lead_lost && (
          <Card>
            <CardHead title="Lost reasons" sub={`${lostN} lost · the ones that got away`} />
            <RankedBars rows={lostRows} color={PCH.exit.Lost} fmt={fmtVal} height={140}
              onRow={(r) => ctx.openDrawer('Lost · ' + r.label, 'Lost for this reason', r.set)} />
            <div style={{ marginTop: 14, paddingTop: 12, borderTop: '1px solid var(--line-soft)' }}>
              <div className="micro" style={{ marginBottom: 8 }}>Pass vs lost vs on-hold</div>
              {[['Passed', passN, PCH.exit.Passed], ['Lost', lostN, PCH.exit.Lost], ['On hold', cur.filter((d) => d.terminal === 'On Hold').length, PCH.exit['On Hold']]].map(([l, n, c]) => {
                const tot = passN + lostN + cur.filter((d) => d.terminal === 'On Hold').length || 1;
                return <div key={l} style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}><span style={{ width: 54, fontSize: 11, color: PC.muted, fontWeight: 600 }}>{l}</span><div style={{ flex: 1, height: 8, background: 'var(--surface-deep)', borderRadius: 3, overflow: 'hidden' }}><div style={{ width: n / tot * 100 + '%', height: '100%', background: c }}></div></div><span className="tabular" style={{ fontSize: 11, fontWeight: 700, width: 26, textAlign: 'right' }}>{n}</span></div>;
              })}
            </div>
          </Card>
        )}
      </div>

      {show.lead_dist && (
        <div style={{ marginTop: 16 }}>
          <Card>
            <CardHead title="Size of the deals we chase" sub={`Distribution of ${plReach(cur, 0).length} leads · highlighted = median (€${(Math.round(median * 10) / 10)}m)`}
              right={<Segmented value={dist} onChange={setDist} options={[{ value: 'ebitda', label: '€ EBITDA' }, { value: 'revenue', label: '€ Revenue' }]} />} />
            <BucketBars buckets={buckets} color={DCH.platform} onBar={(b) => ctx.openDrawer(`${dist === 'ebitda' ? 'EBITDA' : 'Revenue'} ${b.label}m`, 'Deals in this band', b.set)} />
          </Card>
        </div>
      )}
    </SectionBlock>
  );
}

/* ============================================================
   SOURCING
   ============================================================ */
function SourcingSection({ ctx }) {
  const { cur, val, fmtVal, show } = ctx;
  const median = (a) => { if (!a.length) return 0; const s = [...a].sort((x, y) => x - y); const m = s.length >> 1; return s.length % 2 ? s[m] : (s[m - 1] + s[m]) / 2; };
  // channel mix over time
  const chanTrend = ctx.periods.map((p, i) => { const o = { label: p.label, key: p.key }; PL.CHANNELS.forEach((ch) => o[ch] = p.set.filter((d) => d.channel === ch).length); return o; });
  const unattr = cur.filter((d) => !d.channel);
  const unattrShare = cur.length ? Math.round(unattr.length / cur.length * 100) : 0;
  // advisor quadrant + league
  const advMap = {};
  cur.forEach((d) => { if (!d.advisorOrg) return; const a = advMap[d.advisorOrg] || (advMap[d.advisorOrg] = { set: [], deals: 0, nbo: 0, appt: 0, port: 0, eb: 0, rev: 0 }); a.set.push(d); a.deals++; if (d.stageRank >= 4) a.nbo++; if (d.stageRank >= 1) a.appt++; if (d.stageRank >= 8) a.port++; a.eb += d.ebitda; a.rev += d.revenue; });
  const advPoints = Object.entries(advMap).map(([name, a]) => ({ label: name, x: a.deals, y: a.deals ? Math.round(a.nbo / a.deals * 100) : 0, r: a.eb, set: a.set }));
  const advRows = Object.entries(advMap).map(([name, a]) => ({ name, ...a })).sort((x, y) => y.deals - x.deals).slice(0, 10);
  const advMax = Math.max(1, ...advRows.map((r) => r.deals));
  const xMed = median(advPoints.map((p) => p.x)), yMed = median(advPoints.map((p) => p.y));
  // owners
  const ownRows = PL.OWNERS.map((o) => { const set = cur.filter((d) => d.owner === o.id); return { name: o.name, set, deals: set.length, appt: plReach(set, 1).length, port: plReach(set, 8).length, eb: set.reduce((s, d) => s + d.ebitda, 0) }; }).filter((r) => r.deals).sort((a, b) => b.deals - a.deals);
  const ownMax = Math.max(1, ...ownRows.map((r) => r.deals));
  // funnel by channel (small multiples) — 5 compressed stages
  const COMP = [0, 1, 2, 4, 8];
  const chanFunnels = ['Advisor', 'Network', 'Cold call', 'Dealsuite'].map((ch) => {
    const set = cur.filter((d) => d.channel === ch);
    return { ch, set, stages: COMP.map((rk) => plReach(set, rk).length) };
  });

  return (
    <SectionBlock id="sourcing" eyebrow="Section 03 · where deals come from" title="Sourcing analysis"
      right={<button className="badge warn" onClick={() => ctx.openDrawer('Unattributed deals', 'No sourcing channel set: a CRM-hygiene worklist', unattr)} style={{ border: 'none', cursor: 'pointer', height: 22 }}><Icon name="alert" size={12} /> {unattrShare}% unattributed</button>}>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16 }}>
        {show.src_channel && (
          <Card>
            <CardHead title="Channel mix over time" sub="Share of attributed sourcing: watch a channel rise or fade" />
            <StackedTimeBars data={chanTrend} mode="mix" series={PL.CHANNELS.map((ch, i) => ({ key: ch, color: PCH.cat[i], label: ch }))}
              onSeg={(d, s) => ctx.openDrawer(`${s.label} · ${d.label}`, 'Sourced via this channel', ctx.periods.find((p) => p.key === d.key).set.filter((x) => x.channel === s.key))} />
            <ChartLegend items={PL.CHANNELS.map((ch, i) => ({ label: ch, color: PCH.cat[i] }))} />
          </Card>
        )}
        {show.src_advisor && (
          <Card>
            <CardHead title="Advisor quality" sub="Deals sent vs → NBO rate · bubble = € EBITDA introduced" />
            <Quadrant points={advPoints} xLabel="Deals sent" yLabel="→ NBO rate" xMed={xMed} yMed={yMed}
              onPoint={(p) => ctx.openDrawer(p.label, 'Deals introduced by this advisor', p.set)} />
          </Card>
        )}
      </div>

      {show.src_funnels && (
        <div style={{ marginTop: 16 }}>
          <Card>
            <CardHead title="Funnel shape by channel" sub="Lead → Appt → Qualified → NBO → Portfolio · which sources mature, not just send" />
            <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14 }}>
              {chanFunnels.map(({ ch, set, stages }) => {
                const mx = Math.max(1, stages[0]);
                return (
                  <button key={ch} onClick={() => ctx.openDrawer(ch + ' · funnel', 'All deals sourced via ' + ch, set)} style={{ border: '1px solid var(--line)', borderRadius: 8, padding: '12px 13px', background: 'var(--surface-card)', textAlign: 'left', cursor: 'pointer' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 9 }}>
                      <span style={{ fontSize: 12.5, fontWeight: 700 }}>{ch}</span>
                      <span className="tabular" style={{ fontSize: 11, color: PC.soft }}>{set.length} deals</span>
                    </div>
                    <div style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
                      {['Lead', 'Appt', 'Qual', 'NBO', 'Port'].map((lab, i) => (
                        <div key={lab} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                          <span style={{ width: 30, fontSize: 9.5, color: PC.muted, fontWeight: 600 }}>{lab}</span>
                          <div style={{ flex: 1, height: 11, background: 'var(--surface-deep)', borderRadius: 2, overflow: 'hidden' }}><div style={{ width: Math.max(stages[i] / mx * 100, 1.5) + '%', height: '100%', background: `color-mix(in srgb, ${DCH.platform} ${100 - i * 12}%, #c9d4db)` }}></div></div>
                          <span className="tabular" style={{ width: 22, textAlign: 'right', fontSize: 10, fontWeight: 700 }}>{stages[i]}</span>
                        </div>
                      ))}
                    </div>
                  </button>
                );
              })}
            </div>
          </Card>
        </div>
      )}

      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 16, marginTop: 16 }}>
        {show.src_advtable && (
          <Card pad="0">
            <div style={{ padding: '14px 16px 11px' }}><CardHead title="Top advisors" sub="Volume → appointment → NBO, with average ticket" /></div>
            <table className="tbl">
              <thead><tr><th>Advisor</th><th style={{ width: 116 }}>Deals</th><th className="num" style={{ width: 66 }}>→Appt</th><th className="num" style={{ width: 64 }}>→NBO</th><th className="num" style={{ width: 78 }}>Avg €EB</th></tr></thead>
              <tbody>
                {advRows.map((r) => (
                  <tr key={r.name} className="clickable" onClick={() => ctx.openDrawer(r.name, 'Deals introduced by this advisor', r.set)}>
                    <td style={{ fontWeight: 600, fontSize: 12 }}>{r.name}</td>
                    <td><div style={{ display: 'flex', alignItems: 'center', gap: 8 }}><div style={{ flex: 1, height: 7, background: 'var(--surface-deep)', borderRadius: 3, overflow: 'hidden', maxWidth: 70 }}><div style={{ width: r.deals / advMax * 100 + '%', height: '100%', background: DCH.platform, borderRadius: 3 }}></div></div><span className="tabular" style={{ fontSize: 12, fontWeight: 700 }}>{r.deals}</span></div></td>
                    <td className="num"><Conv rate={r.deals ? r.appt / r.deals : 0} /></td>
                    <td className="num"><Conv rate={r.deals ? r.nbo / r.deals : 0} /></td>
                    <td className="num tabular" style={{ color: PC.muted }}>€{(Math.round(r.eb / r.deals * 10) / 10) || 0}m</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </Card>
        )}
        {show.src_owners && (
          <Card pad="0">
            <div style={{ padding: '14px 16px 11px' }}><CardHead title="By team member" sub="Who sources volume, and who converts it" /></div>
            <table className="tbl">
              <thead><tr><th>Owner</th><th style={{ width: 116 }}>Deals</th><th className="num" style={{ width: 66 }}>→Appt</th><th className="num" style={{ width: 72 }}>Portfolio</th><th className="num" style={{ width: 78 }}>Avg €EB</th></tr></thead>
              <tbody>
                {ownRows.map((r) => (
                  <tr key={r.name} className="clickable" onClick={() => ctx.openDrawer(r.name, 'Deals owned by ' + r.name, r.set)}>
                    <td style={{ fontWeight: 600, fontSize: 12 }}>{r.name}</td>
                    <td><div style={{ display: 'flex', alignItems: 'center', gap: 8 }}><div style={{ flex: 1, height: 7, background: 'var(--surface-deep)', borderRadius: 3, overflow: 'hidden', maxWidth: 70 }}><div style={{ width: r.deals / ownMax * 100 + '%', height: '100%', background: DCH.addon, borderRadius: 3 }}></div></div><span className="tabular" style={{ fontSize: 12, fontWeight: 700 }}>{r.deals}</span></div></td>
                    <td className="num"><Conv rate={r.deals ? r.appt / r.deals : 0} /></td>
                    <td className="num tabular" style={{ fontWeight: 700 }}>{r.port}</td>
                    <td className="num tabular" style={{ color: PC.muted }}>€{(Math.round(r.eb / r.deals * 10) / 10) || 0}m</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </Card>
        )}
      </div>
    </SectionBlock>
  );
}

/* tiny legend (local — df_shared not loaded) */
function ChartLegend({ items }) {
  return (
    <div style={{ display: 'flex', flexWrap: 'wrap', gap: 12, marginTop: 10 }}>
      {items.map((it) => <span key={it.label} style={{ display: 'inline-flex', alignItems: 'center', gap: 5, fontSize: 11, color: PC.muted, fontWeight: 600 }}><span style={{ width: 9, height: 9, borderRadius: 2, background: it.color }}></span>{it.label}</span>)}
    </div>
  );
}

Object.assign(window, { FunnelSection, LeadSection, SourcingSection, ChartLegend });
