/* Overview Screen — Cohort Insights Dashboard (real data) */
const { useState, useMemo } = React;

/* ── Pie chart (inline SVG, two slices + optional unknown) ── */
function PieChart({ segments, size }) {
  size = size || 180;
  var r = size / 2 - 2;
  var cx = size / 2, cy = size / 2;
  var total = segments.reduce(function (s, x) { return s + x.value; }, 0);
  if (total <= 0) return null;
  var start = -Math.PI / 2; /* start at 12 o'clock */
  return (
    <svg width={size} height={size} viewBox={'0 0 ' + size + ' ' + size}>
      {segments.map(function (s, i) {
        if (s.value <= 0) return null;
        var frac = s.value / total;
        var end = start + frac * 2 * Math.PI;
        var x1 = cx + r * Math.cos(start), y1 = cy + r * Math.sin(start);
        var x2 = cx + r * Math.cos(end),   y2 = cy + r * Math.sin(end);
        var large = frac > 0.5 ? 1 : 0;
        var d = 'M ' + cx + ' ' + cy + ' L ' + x1 + ' ' + y1 +
                ' A ' + r + ' ' + r + ' 0 ' + large + ' 1 ' + x2 + ' ' + y2 + ' Z';
        var key = s.label + '-' + i;
        start = end;
        return <path key={key} d={d} fill={s.color} stroke="var(--bg-card)" strokeWidth="1.5"><title>{s.label + ': ' + s.value + ' (' + Math.round(frac * 100) + '%)'}</title></path>;
      })}
    </svg>
  );
}

/* NoteCard lived here when Editor's Notes was inline on Overview; now lives
   inside editor-notes.jsx where the dedicated screen renders them. */

/* ── Stat Card ── */
function StatCard({ label, value, accent, sub, onClick, large }) {
  const [hov, setHov] = useState(false);
  const clickable = !!onClick;
  return (
    <div onClick={onClick} onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}
      className={clickable ? 'stat-clickable' : undefined}
      style={{
        background: hov ? 'var(--bg-elevated)' : 'var(--bg-card)',
        border: '1px solid ' + (clickable ? 'transparent' : 'var(--border-subtle)'),
        borderRadius: 12, padding: large ? '24px 28px' : '20px 24px', flex: 1, minWidth: 130,
        cursor: clickable ? 'pointer' : 'default', transition: 'background .15s',
      }}>
      <div style={{ fontSize: large ? 40 : 30, fontWeight: 600, fontFamily: "var(--mono)", color: accent || 'var(--text-primary)', lineHeight: 1.1, fontFeatureSettings: "'tnum' 1" }}>
        <AnimatedNumber value={value} />
      </div>
      <div style={{ fontSize: 13, color: 'var(--text-secondary)', marginTop: 6, display: 'flex', alignItems: 'center', gap: 6 }}>
        {label}
        {clickable && <span style={{ fontSize: 11, color: 'var(--accent)', fontFamily: 'var(--mono)' }}>↗</span>}
      </div>
      {sub && <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 3 }}>{sub}</div>}
    </div>
  );
}

/* ── Horizontal Bar ── */
function HBar({ label, value, max, count, total, color }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', marginBottom: 8, gap: 8 }}>
      <div style={{ fontSize: 12, color: 'var(--text-tertiary)', width: 80, textAlign: 'right', fontFamily: 'var(--mono)', flexShrink: 0 }}>{label}</div>
      <div style={{ flex: 1, height: 24, background: 'var(--bg-elevated)', borderRadius: 4, overflow: 'hidden', position: 'relative' }}>
        <div style={{ height: '100%', width: Math.max(1, (value / Math.max(max, 1)) * 100) + '%', background: color || 'rgba(255,255,255,0.55)', borderRadius: 4, transition: 'width .4s ease' }}></div>
      </div>
      <div style={{ fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--text-secondary)', width: 40, textAlign: 'right', fontFeatureSettings: "'tnum' 1" }}>{count}</div>
      <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', width: 40, textAlign: 'right', fontFeatureSettings: "'tnum' 1" }}>{Math.round(count / total * 100)}%</div>
    </div>
  );
}

/* ── Segment Bar (stacked horizontal) ── */
function SegmentBar({ segments, total }) {
  return (
    <div>
      <div style={{ display: 'flex', height: 28, borderRadius: 6, overflow: 'hidden', gap: 2, marginBottom: 12 }}>
        {segments.map(function (s) {
          var pct = (s.count / Math.max(total, 1)) * 100;
          return pct > 0 ? (
            <div key={s.label} style={{ width: pct + '%', background: s.color, borderRadius: 3, minWidth: pct > 2 ? 2 : 0, transition: 'width .3s' }} title={s.label + ': ' + s.count}></div>
          ) : null;
        })}
      </div>
      <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
        {segments.map(function (s) {
          return (
            <div key={s.label} style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
              <div style={{ width: 8, height: 8, borderRadius: 2, background: s.color, flexShrink: 0 }}></div>
              <span style={{ fontSize: 12, color: 'var(--text-secondary)' }}>{s.label}</span>
              <span style={{ fontSize: 12, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', fontFeatureSettings: "'tnum' 1" }}>{s.count}</span>
              <span style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-disabled)', fontFeatureSettings: "'tnum' 1" }}>{Math.round(s.count / Math.max(total, 1) * 100)}%</span>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ── Section Header ── */
function SectionHead({ title, sub }) {
  return (
    <div style={{ marginBottom: 14 }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-tertiary)', textTransform: 'uppercase', letterSpacing: '0.06em' }}>{title}</div>
      {sub && <div style={{ fontSize: 12, color: 'var(--text-disabled)', marginTop: 2 }}>{sub}</div>}
    </div>
  );
}

/* ── Card Wrapper ── */
function Card({ children, style }) {
  return (
    <div style={Object.assign({ background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: '20px 24px' }, style || {})}>
      {children}
    </div>
  );
}

/* ── Mention Tag ── */
function MentionTag({ mention, count, maxCount }) {
  var intensity = 0.35 + (count / Math.max(maxCount, 1)) * 0.65;
  var fontSize = 12 + Math.round((count / Math.max(maxCount, 1)) * 6);
  var [hov, setHov] = useState(false);
  return (
    <span onMouseEnter={() => setHov(true)} onMouseLeave={() => setHov(false)}
      style={{
        display: 'inline-flex', alignItems: 'baseline', gap: 4,
        padding: '5px 12px', borderRadius: 6,
        background: hov ? 'rgba(255,255,255,' + (intensity * 0.12) + ')' : 'rgba(255,255,255,' + (intensity * 0.06) + ')',
        color: 'rgba(255,255,255,' + (0.4 + intensity * 0.5) + ')',
        fontSize: fontSize, fontFamily: 'var(--mono)', fontWeight: 500,
        cursor: 'default', transition: 'background .15s',
      }}>
      @{mention} <span style={{ opacity: 0.55, fontSize: 11, fontFeatureSettings: "'tnum' 1" }}>{count}</span>
    </span>
  );
}

/* ── Information Diet — Selectivity Quadrant (Followers × Following) ──
   The 2D upgrade of the 1D Following histogram above. Both axes log (both
   distributions are heavily right-skewed). Thresholds are ABSOLUTE, not
   cohort medians, so the cluster %s carry a narrative ("~half are Silent
   Consumers") instead of a forced 25/25/25/25 split. Tweak the two T_*
   constants to reshape the buckets. */
function SelectivityMap({ personal, total }) {
  var [hover, setHover] = useState(null);
  var [selected, setSelected] = useState(null);

  var FOLLOWING_T = 100;   /* ≥ this = follows "many" → low information selectivity */
  var FOLLOWERS_T = 1000;  /* ≥ this = meaningful reach */

  var CLUSTERS = {
    silent:      { label: 'Silent Consumer',     color: 'rgba(255,255,255,0.30)', desc: 'follows <100 · <1K followers' },
    gatherer:    { label: 'Information Gatherer', color: 'var(--accent)',          desc: 'follows ≥100 · <1K followers' },
    broadcaster: { label: 'Broadcaster',          color: '#3B82F6',                desc: 'follows <100 · ≥1K followers' },
    operator:    { label: 'Public Operator',      color: 'rgba(255,255,255,0.80)', desc: 'follows ≥100 · ≥1K followers' },
  };
  function clusterKey(m) {
    var lowDiet = m.following < FOLLOWING_T, lowReach = m.followers < FOLLOWERS_T;
    if (lowDiet && lowReach) return 'silent';
    if (lowDiet && !lowReach) return 'broadcaster';
    if (!lowDiet && lowReach) return 'gatherer';
    return 'operator';
  }

  var counts = useMemo(function () {
    var c = { silent: 0, gatherer: 0, broadcaster: 0, operator: 0 };
    personal.forEach(function (m) { c[clusterKey(m)]++; });
    return c;
  }, [personal]);
  var maxFollowing = useMemo(function () { return Math.max.apply(null, personal.map(function (m) { return m.following || 0; })); }, [personal]);
  var maxFollowers = useMemo(function () { return Math.max.apply(null, personal.map(function (m) { return m.followers || 0; })); }, [personal]);

  var W = 1000, H = 470;
  var PAD = { top: 22, right: 22, bottom: 46, left: 58 };
  var plotW = W - PAD.left - PAD.right, plotH = H - PAD.top - PAD.bottom;
  function sx(v) { return PAD.left + (Math.log10(Math.max(0, v) + 1) / Math.log10(maxFollowing + 2)) * plotW; }
  function sy(v) { return PAD.top + plotH - (Math.log10(Math.max(0, v) + 1) / Math.log10(maxFollowers + 2)) * plotH; }
  function fmtN(n) { return n >= 1000 ? (n / 1000).toFixed(n >= 10000 ? 0 : 1) + 'K' : String(n); }
  function pct(n) { return Math.round(n / Math.max(total, 1) * 100); }

  var xTicks = [0, 10, 100, 1000, 5000].filter(function (t) { return t <= maxFollowing * 1.1; });
  var yTicks = [0, 100, 1000, 10000].filter(function (t) { return t <= maxFollowers * 1.1; });
  var divX = sx(FOLLOWING_T), divY = sy(FOLLOWERS_T);
  var qLabels = [
    { k: 'silent',      x: PAD.left + 6,         y: PAD.top + plotH - 8, anchor: 'start' },
    { k: 'gatherer',    x: PAD.left + plotW - 6, y: PAD.top + plotH - 8, anchor: 'end' },
    { k: 'broadcaster', x: PAD.left + 6,         y: PAD.top + 14,        anchor: 'start' },
    { k: 'operator',    x: PAD.left + plotW - 6, y: PAD.top + 14,        anchor: 'end' },
  ];
  function bioSummary(m) {
    var b = (m.bio || '').replace(/\s+/g, ' ').trim();
    if (!b) return '—';
    return b.length > 90 ? b.slice(0, 90) + '…' : b;
  }
  var hm = hover;
  var selPerson = selected ? personal.find(function (m) { return m.handle === selected; }) : null;

  return (
    <Card style={{ marginBottom: 28 }}>
      <SectionHead
        title="Selectivity Map — Followers × Following"
        sub={counts.silent + ' of ' + total + ' (' + pct(counts.silent) + '%) are Silent Consumers · only ' + pct(counts.broadcaster) + '% are pure Broadcasters'} />

      <div style={{ position: 'relative' }}>
        <svg viewBox={'0 0 ' + W + ' ' + H} preserveAspectRatio="xMidYMid meet" style={{ width: '100%', height: 'auto', display: 'block' }}>
          <rect x={PAD.left} y={PAD.top} width={plotW} height={plotH} fill="var(--bg-elevated)" rx="4" />

          {yTicks.map(function (t) { var y = sy(t); return (
            <React.Fragment key={'y' + t}>
              <line x1={PAD.left} y1={y} x2={PAD.left + plotW} y2={y} stroke="var(--border-subtle)" strokeWidth="0.5" />
              <text x={PAD.left - 8} y={y + 4} fill="var(--text-disabled)" fontSize="11" fontFamily="var(--mono)" textAnchor="end">{fmtN(t)}</text>
            </React.Fragment>); })}
          {xTicks.map(function (t) { var x = sx(t); return (
            <React.Fragment key={'x' + t}>
              <line x1={x} y1={PAD.top} x2={x} y2={PAD.top + plotH} stroke="var(--border-subtle)" strokeWidth="0.5" />
              <text x={x} y={PAD.top + plotH + 18} fill="var(--text-disabled)" fontSize="11" fontFamily="var(--mono)" textAnchor="middle">{fmtN(t)}</text>
            </React.Fragment>); })}

          {/* quadrant dividers at the absolute thresholds */}
          <line x1={divX} y1={PAD.top} x2={divX} y2={PAD.top + plotH} stroke="var(--border-strong)" strokeWidth="1" strokeDasharray="4,4" />
          <line x1={PAD.left} y1={divY} x2={PAD.left + plotW} y2={divY} stroke="var(--border-strong)" strokeWidth="1" strokeDasharray="4,4" />

          {qLabels.map(function (q) { return (
            <text key={q.k} x={q.x} y={q.y} fill="var(--text-tertiary)" fontSize="11" fontFamily="var(--sans)" fontWeight="600" textAnchor={q.anchor}>
              {CLUSTERS[q.k].label} · {counts[q.k]}
            </text>); })}

          <text x={PAD.left + plotW / 2} y={H - 5} fill="var(--text-tertiary)" fontSize="12" fontFamily="var(--sans)" textAnchor="middle" fontWeight="500">Following (curation / information diet) →</text>
          <text x={15} y={PAD.top + plotH / 2} fill="var(--text-tertiary)" fontSize="12" fontFamily="var(--sans)" textAnchor="middle" fontWeight="500" transform={'rotate(-90,15,' + (PAD.top + plotH / 2) + ')'}>Followers (reach) →</text>

          {personal.map(function (m) {
            var cx = sx(m.following), cy = sy(m.followers);
            var isHov = hm && hm.m.handle === m.handle;
            var r = m.followers > 5000 ? 4.5 : 3.2;
            return <circle key={m.handle} cx={cx} cy={cy} r={isHov ? r + 2 : r}
              fill={CLUSTERS[clusterKey(m)].color}
              stroke={isHov ? '#fff' : 'none'} strokeWidth={isHov ? 1 : 0}
              opacity={hm && !isHov ? 0.18 : 0.85}
              style={{ cursor: 'pointer', transition: 'opacity .15s' }}
              onMouseEnter={function () { setHover({ m: m, cx: cx, cy: cy }); }}
              onMouseLeave={function () { setHover(null); }}
              onClick={function () { setSelected(m.handle); }} />;
          })}
        </svg>

        {/* hover tooltip — HTML overlay positioned by viewBox %, so it tracks the
            dot regardless of the SVG's rendered (responsive) width. */}
        {hm && (function () {
          var leftPct = (hm.cx / W) * 100, topPct = (hm.cy / H) * 100;
          var openLeft = hm.cx > W * 0.62, openDown = hm.cy < H * 0.34;
          var tf = 'translate(' + (openLeft ? 'calc(-100% - 12px)' : '12px') + ',' + (openDown ? '6px' : 'calc(-100% - 6px)') + ')';
          return (
            <div style={{ position: 'absolute', left: leftPct + '%', top: topPct + '%', transform: tf, width: 226, pointerEvents: 'none', zIndex: 5,
              background: 'var(--bg-elevated)', border: '1px solid var(--border-strong)', borderRadius: 8, padding: '9px 11px', boxShadow: '0 6px 20px rgba(0,0,0,0.5)' }}>
              <div style={{ fontSize: 12, fontFamily: 'var(--mono)', fontWeight: 600, color: 'var(--text-primary)' }}>@{hm.m.handle}</div>
              {hm.m.name && hm.m.name !== hm.m.handle && <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 1 }}>{hm.m.name}</div>}
              <div style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-secondary)', marginTop: 5, fontFeatureSettings: "'tnum' 1" }}>
                {(hm.m.following || 0).toLocaleString()} following · {(hm.m.followers || 0).toLocaleString()} followers
              </div>
              <div style={{ fontSize: 11, color: hm.m.bio ? 'var(--text-secondary)' : 'var(--text-disabled)', marginTop: 6, lineHeight: 1.45 }}>{bioSummary(hm.m)}</div>
              <div style={{ fontSize: 10, color: 'var(--accent)', marginTop: 6 }}>Click to open profile →</div>
            </div>);
        })()}
      </div>

      {/* cluster percentage cards — ordered most → least common */}
      <div style={{ display: 'flex', gap: 10, marginTop: 16, flexWrap: 'wrap' }}>
        {['silent', 'gatherer', 'operator', 'broadcaster'].map(function (k) {
          return (
            <div key={k} style={{ flex: '1 1 0', minWidth: 150, background: 'var(--bg-elevated)', border: '1px solid var(--border-subtle)', borderRadius: 10, padding: '12px 14px' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 7, marginBottom: 6 }}>
                <span style={{ width: 9, height: 9, borderRadius: '50%', background: CLUSTERS[k].color, flexShrink: 0 }}></span>
                <span style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-primary)' }}>{CLUSTERS[k].label}</span>
              </div>
              <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
                <span style={{ fontSize: 22, fontWeight: 600, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontFeatureSettings: "'tnum' 1" }}>{pct(counts[k])}%</span>
                <span style={{ fontSize: 11, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)' }}>{counts[k]}</span>
              </div>
              <div style={{ fontSize: 10.5, color: 'var(--text-disabled)', marginTop: 4 }}>{CLUSTERS[k].desc}</div>
            </div>);
        })}
      </div>

      {selPerson && <PersonDrawer person={selPerson} onClose={function () { setSelected(null); }} />}
    </Card>
  );
}

/* ══════════ MAIN SCREEN ══════════ */
function OverviewScreen({ onNavigate }) {
  var members = window.COHORT.members;
  var personal = members.filter(function (m) { return !m.isOfficial && m.status === 'ok'; });
  var total = personal.length;

  /* Bio stats */
  var bioStats = useMemo(function () {
    var empty = 0, short = 0, medium = 0, rich = 0;
    personal.forEach(function (m) {
      if (m.bioLen === 'empty') empty++;
      else if (m.bioLen === '<50') short++;
      else if (m.bioLen === '50-150') medium++;
      else rich++;
    });
    return { empty: empty, short: short, medium: medium, rich: rich };
  }, []);
  var minimalPct = Math.round((bioStats.empty + bioStats.short) / total * 100);

  /* Following stats */
  var followingStats = useMemo(function () {
    var vals = personal.map(function (m) { return m.following; }).sort(function (a, b) { return a - b; });
    return {
      median: vals[Math.floor(vals.length / 2)],
      p75: vals[Math.floor(vals.length * 0.75)],
      p90: vals[Math.floor(vals.length * 0.9)],
      under50: vals.filter(function (v) { return v < 50; }).length,
      under100: vals.filter(function (v) { return v < 100; }).length,
    };
  }, []);

  /* Surface area tiers */
  var surface = useMemo(function () {
    var low = 0, mid = 0, high = 0;
    personal.forEach(function (m) {
      if (m.surfaceTier === 'low') low++;
      else if (m.surfaceTier === 'high') high++;
      else mid++;
    });
    return { low: low, mid: mid, high: high };
  }, []);

  /* Activity personas */
  var activity = useMemo(function () {
    var d = { dormant: 0, lurker: 0, light: 0, medium: 0, heavy: 0 };
    personal.forEach(function (m) { d[m.activityPersona] = (d[m.activityPersona] || 0) + 1; });
    return d;
  }, []);

  /* Follower buckets */
  var followerBuckets = useMemo(function () {
    var b = [{ label: '< 100', count: 0 }, { label: '100–1K', count: 0 }, { label: '1K–10K', count: 0 }, { label: '10K–100K', count: 0 }, { label: '100K+', count: 0 }];
    personal.forEach(function (m) {
      if (m.followers < 100) b[0].count++;
      else if (m.followers < 1000) b[1].count++;
      else if (m.followers < 10000) b[2].count++;
      else if (m.followers < 100000) b[3].count++;
      else b[4].count++;
    });
    return b;
  }, []);
  var maxFB = Math.max.apply(null, followerBuckets.map(function (d) { return d.count; }));

  /* Following buckets */
  var followingBuckets = useMemo(function () {
    var b = [{ label: '< 50', count: 0 }, { label: '50–200', count: 0 }, { label: '200–500', count: 0 }, { label: '500–1K', count: 0 }, { label: '1K+', count: 0 }];
    personal.forEach(function (m) {
      if (m.following < 50) b[0].count++;
      else if (m.following < 200) b[1].count++;
      else if (m.following < 500) b[2].count++;
      else if (m.following < 1000) b[3].count++;
      else b[4].count++;
    });
    return b;
  }, []);
  var maxFlB = Math.max.apply(null, followingBuckets.map(function (d) { return d.count; }));

  /* Shared Attention (following lists) — computed client-side from per-member attention attached at export time */
  var attentionSummary = useMemo(function () {
    var withAtt = personal.filter(function (m) { return m.attention && m.attention.topFollowed && m.attention.topFollowed.length > 0; });
    if (withAtt.length === 0) return null;
    var totalInternal = 0, totalFollowed = 0, overlapSum = 0;
    var catCounts = { 'in-cohort': 0, 'ai-lab': 0, 'researcher': 0, 'tool': 0, 'media': 0, 'vc': 0, 'other': 0 };
    var dstCount = {};
    withAtt.forEach(function (m) {
      var a = m.attention;
      totalInternal += a.internalFollowCount || 0;
      totalFollowed += (a.topFollowed || []).length;
      overlapSum += a.cohortOverlapScore || 0;
      (a.topFollowed || []).forEach(function (t) {
        var k = t.handle;
        dstCount[k] = (dstCount[k] || 0) + 1;
        if (catCounts[t.category] != null) catCounts[t.category] += 1;
      });
    });
    var ranked = Object.entries(dstCount).sort(function (a, b) { return b[1] - a[1]; }).slice(0, 18).map(function (e) { return { handle: e[0], count: e[1] }; });
    var avgOverlap = withAtt.length ? Math.round(overlapSum / withAtt.length * 10) / 10 : 0;
    var internalRatio = totalFollowed > 0 ? Math.round((totalInternal / totalFollowed) * 100) : 0;
    return {
      membersWithData: withAtt.length,
      top: ranked,
      catCounts: catCounts,
      avgOverlap: avgOverlap,
      internalRatio: internalRatio,
      totalFollowed: totalFollowed,
    };
  }, [personal]);

  /* Top mentions */
  var topMentions = useMemo(function () {
    var c = {};
    personal.forEach(function (m) {
      (m.mentions || []).forEach(function (x) {
        var key = x.toLowerCase();
        if (key !== 'xai' && key !== 'grok') c[key] = (c[key] || 0) + 1;
      });
    });
    return Object.entries(c).sort(function (a, b) { return b[1] - a[1]; }).slice(0, 20).map(function (e) { return { mention: e[0], count: e[1] }; });
  }, []);
  var maxMC = topMentions.length > 0 ? topMentions[0].count : 1;

  /* Pedigree summary */
  var pedigree = useMemo(function () {
    var emp = {}, sch = {};
    personal.forEach(function (m) {
      if (!m.pedigree) return;
      (m.pedigree.previousEmployers || []).forEach(function (e) { emp[e] = (emp[e] || 0) + 1; });
      (m.pedigree.schools || []).forEach(function (s) { sch[s] = (sch[s] || 0) + 1; });
    });
    return {
      employers: Object.entries(emp).sort(function (a, b) { return b[1] - a[1]; }),
      schools: Object.entries(sch).sort(function (a, b) { return b[1] - a[1]; }).slice(0, 10),
      withPedigree: personal.filter(function (m) { return m.pedigree; }).length,
    };
  }, []);

  var extCount = members.filter(function (m) { return m.external; }).length;
  var verified = personal.filter(function (m) { return m.verified; }).length;
  var hasUrl = personal.filter(function (m) { return m.url; }).length;

  /* Name-origin proxy stats — see docs/analysis-ideas.md §2.8 for caveats.
     This is surname-based, aggregate-only; never label individuals from it. */
  var nameOriginStats = useMemo(function () {
    var groups = { chinese_han: [], south_asian: [], western_or_other: [], unknown: [] };
    personal.forEach(function (m) { (groups[m.nameOriginProxy || 'unknown'] = groups[m.nameOriginProxy || 'unknown'] || []).push(m); });
    function med(arr) { var s = arr.slice().sort(function (a, b) { return a - b; }); return s.length ? s[Math.floor(s.length / 2)] : 0; }
    function emptyBioRate(arr) {
      if (!arr.length) return 0;
      var n = arr.filter(function (m) { return m.bioLen === 'empty'; }).length;
      return Math.round(n / arr.length * 100);
    }
    var asianCount = groups.chinese_han.length + groups.south_asian.length;
    return {
      counts: {
        chinese: groups.chinese_han.length,
        southAsian: groups.south_asian.length,
        westernOther: groups.western_or_other.length,
        unknown: groups.unknown.length,
        asian: asianCount,
        nonAsian: groups.western_or_other.length,
      },
      asianPct: Math.round(asianCount / total * 100),
      medianFollowers: {
        chinese:      med(groups.chinese_han.map(function (m) { return m.followers; })),
        southAsian:   med(groups.south_asian.map(function (m) { return m.followers; })),
        westernOther: med(groups.western_or_other.map(function (m) { return m.followers; })),
      },
      emptyBioRate: {
        chinese:      emptyBioRate(groups.chinese_han),
        southAsian:   emptyBioRate(groups.south_asian),
        westernOther: emptyBioRate(groups.western_or_other),
      },
    };
  }, []);

  return (
    <div style={{ padding: '28px 32px', maxWidth: 1280, overflowY: 'auto' }}>

      {/* ── Hero Stats ── */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 28 }}>
        <StatCard label="Personal Accounts" value={total} sub="excluding 4 official" large />
        <StatCard label="Empty Bio" value={bioStats.empty} accent="var(--text-primary)" sub={Math.round(bioStats.empty / total * 100) + '% completely blank'} large />
        <StatCard label="Minimal Profile" value={minimalPct + '%'} accent="var(--accent)" sub={'bio < 50 chars or empty (' + (bioStats.empty + bioStats.short) + ' people)'} large />
        <StatCard label="Median Following" value={followingStats.median} accent="var(--text-secondary)" sub={'p75: ' + followingStats.p75 + ' · p90: ' + followingStats.p90} large />
        <StatCard label="External Targets" value={extCount} accent="var(--accent)" sub="Imagine team overlap" onClick={function () { onNavigate('directory', { filter: 'external' }); }} large />
      </div>

      {/* ── Surface Area + Activity ── */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 28 }}>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Surface Area Tier" sub="Low = bio <40 + following <80 + followers <400" />
          <SegmentBar total={total} segments={[
            { label: 'Low', count: surface.low, color: 'var(--text-disabled)' },
            { label: 'Mid', count: surface.mid, color: 'rgba(255,255,255,0.35)' },
            { label: 'High', count: surface.high, color: 'var(--accent)' },
          ]} />
        </Card>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Activity Persona" sub="Based on 30-day posting behavior" />
          <SegmentBar total={total} segments={[
            { label: 'Dormant', count: activity.dormant, color: 'var(--text-disabled)' },
            { label: 'Lurker', count: activity.lurker, color: 'rgba(255,255,255,0.20)' },
            { label: 'Light', count: activity.light, color: 'rgba(255,255,255,0.40)' },
            { label: 'Medium', count: activity.medium, color: 'rgba(255,255,255,0.60)' },
            { label: 'Heavy', count: activity.heavy, color: 'var(--accent)' },
          ]} />
        </Card>
      </div>

      {/* ── Bio + Follower Distribution ── */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 28 }}>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Bio Length Distribution" sub={bioStats.empty + ' empty · ' + bioStats.short + ' under 50 chars'} />
          <HBar label="Empty" value={bioStats.empty} max={total} count={bioStats.empty} total={total} />
          <HBar label="< 50" value={bioStats.short} max={total} count={bioStats.short} total={total} />
          <HBar label="50–150" value={bioStats.medium} max={total} count={bioStats.medium} total={total} />
          <HBar label="150+" value={bioStats.rich} max={total} count={bioStats.rich} total={total} />
        </Card>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Follower Distribution" />
          {followerBuckets.map(function (b) {
            return <HBar key={b.label} label={b.label} value={b.count} max={maxFB} count={b.count} total={total} />;
          })}
        </Card>
      </div>

      {/* ── Following Distribution ── */}
      <Card style={{ marginBottom: 28 }}>
        <SectionHead title="Following Distribution — Information Diet" sub={'Median: ' + followingStats.median + ' · ' + Math.round(followingStats.under100 / total * 100) + '% follow fewer than 100 accounts'} />
        {followingBuckets.map(function (b) {
          return <HBar key={b.label} label={b.label} value={b.count} max={maxFlB} count={b.count} total={total} />;
        })}
      </Card>

      {/* ── Shared Attention (new in Phase 2.5) — complements pedigree with current information diet overlap */}
      {attentionSummary && (
        <Card style={{ marginBottom: 28 }}>
          <SectionHead
            title="Shared Attention — Who the cohort follows"
            sub={attentionSummary.membersWithData + ' members have following data · ' + attentionSummary.internalRatio + '% of top follows are internal · avg ' + attentionSummary.avgOverlap + ' high-signal overlaps per person'} />
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6, marginBottom: 10 }}>
            {attentionSummary.top.slice(0, 12).map(function (t, i) {
              return (
                <span key={i} style={{ padding: '4px 10px', borderRadius: 6, background: 'rgba(255,255,255,0.06)', fontSize: 12, fontFamily: 'var(--mono)' }}>
                  @{t.handle} <span style={{ opacity: .55 }}>{t.count}</span>
                </span>
              );
            })}
          </div>
          <div style={{ fontSize: 11, color: 'var(--text-tertiary)' }}>
            High concentration on a small set of external researchers + labs is exactly the cohesion signal the attention layer was built to surface.
          </div>
        </Card>
      )}

      {/* ── Selectivity Map — 2D quadrant upgrade of the histogram above ── */}
      <SelectivityMap personal={personal} total={total} />

      {/* ── Pedigree + Composition ── */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 28 }}>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Previous Employers" sub={pedigree.withPedigree + ' of ' + total + ' have known pedigree (' + Math.round(pedigree.withPedigree / total * 100) + '%)'} />
          {pedigree.employers.map(function (e) {
            var lab = (window.ORG_LABELS || {})[e[0]] || e[0].replace('@', '');
            return <HBar key={e[0]} label={lab} value={e[1]} max={pedigree.employers[0] ? pedigree.employers[0][1] : 1} count={e[1]} total={total} color="var(--accent)" />;
          })}
        </Card>
        <Card style={{ flex: 1 }}>
          <SectionHead title="Schools & Universities" />
          {pedigree.schools.map(function (s) {
            return <HBar key={s[0]} label={s[0]} value={s[1]} max={pedigree.schools[0] ? pedigree.schools[0][1] : 1} count={s[1]} total={total} />;
          })}
        </Card>
      </div>

      {/* ── Composition Counters ── */}
      <div style={{ display: 'flex', gap: 12, marginBottom: 28 }}>
        <Card style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-elevated)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, color: 'var(--text-tertiary)', flexShrink: 0, fontFamily: 'var(--mono)', fontWeight: 600 }}>✓</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <span style={{ fontSize: 20, fontWeight: 600, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontFeatureSettings: "'tnum' 1" }}>{verified}</span>
              <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>/ {total}</span>
              <span style={{ fontSize: 12, color: 'var(--text-secondary)', fontFamily: 'var(--mono)' }}>{Math.round(verified / total * 100)}%</span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-secondary)' }}>Blue Verified</div>
          </div>
        </Card>
        <Card style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-elevated)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, color: 'var(--text-tertiary)', flexShrink: 0, fontFamily: 'var(--mono)', fontWeight: 600 }}>⌁</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <span style={{ fontSize: 20, fontWeight: 600, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontFeatureSettings: "'tnum' 1" }}>{hasUrl}</span>
              <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>/ {total}</span>
              <span style={{ fontSize: 12, color: 'var(--text-secondary)', fontFamily: 'var(--mono)' }}>{Math.round(hasUrl / total * 100)}%</span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-secondary)' }}>Has Personal URL</div>
          </div>
        </Card>
        <Card style={{ flex: 1, display: 'flex', alignItems: 'center', gap: 14 }}>
          <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-elevated)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 14, color: 'var(--text-tertiary)', flexShrink: 0, fontFamily: 'var(--mono)', fontWeight: 600 }}>29</div>
          <div>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <span style={{ fontSize: 20, fontWeight: 600, fontFamily: 'var(--mono)', color: 'var(--text-primary)', fontFeatureSettings: "'tnum' 1" }}>{window.COHORT.failed}</span>
              <span style={{ fontSize: 12, color: 'var(--text-tertiary)' }}>/ {window.COHORT.total}</span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--text-secondary)' }}>Not Found / Errored</div>
          </div>
        </Card>
      </div>

      {/* ── Top Mentions ── */}
      <Card style={{ marginBottom: 28 }}>
        <SectionHead title="Top @-mentions in Bios" sub="excluding @xai and @grok — organizations & schools most referenced" />
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {topMentions.map(function (t) { return <MentionTag key={t.mention} mention={t.mention} count={t.count} maxCount={maxMC} />; })}
        </div>
      </Card>

      {/* ── Cohort Composition (surname proxy) — public.
           The aggregate breakdown stands on its own as data; the caveat panel
           below makes the proxy nature explicit. The hypothesis-led commentary
           that interprets it lives in the editor-only block further down. */}
      <Card style={{ marginBottom: 28 }}>
        <SectionHead
          title="Inferred Name Origin"
          sub={'Asian (CN + South-Asian surname): ' + nameOriginStats.asianPct + '% · proxy only, aggregate use'} />
        <div style={{ display: 'flex', gap: 32, alignItems: 'flex-start', marginTop: 4 }}>
          <PieChart size={170} segments={[
            { label: 'Asian (surname proxy)',  value: nameOriginStats.counts.asian,        color: 'var(--accent)' },
            { label: 'Non-Asian',              value: nameOriginStats.counts.nonAsian,     color: 'rgba(255,255,255,0.35)' },
            { label: 'Unknown',                value: nameOriginStats.counts.unknown,      color: 'var(--text-disabled)' },
          ]} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ marginBottom: 14 }}>
              <HBar label="Chinese" value={nameOriginStats.counts.chinese} max={total} count={nameOriginStats.counts.chinese} total={total} color="var(--accent)" />
              <HBar label="S. Asian" value={nameOriginStats.counts.southAsian} max={total} count={nameOriginStats.counts.southAsian} total={total} color="rgba(249, 115, 22,0.55)" />
              <HBar label="Western+" value={nameOriginStats.counts.westernOther} max={total} count={nameOriginStats.counts.westernOther} total={total} />
              <HBar label="Unknown" value={nameOriginStats.counts.unknown} max={total} count={nameOriginStats.counts.unknown} total={total} color="var(--text-disabled)" />
            </div>
            <div style={{ fontSize: 11, color: 'var(--text-tertiary)', lineHeight: 1.6, paddingTop: 10, borderTop: '1px solid var(--border-subtle)' }}>
              <span style={{ color: 'var(--text-secondary)', fontWeight: 600 }}>Caveat:</span> surname-based heuristic only.
              Western-named people of Asian descent (married names, ABC, mixed) are mis-bucketed; same for the inverse.
              Use the aggregate, never the individual label.
            </div>
          </div>
        </div>
      </Card>

      {/* Editor's Notes moved to a dedicated hidden screen — see
         public/design/editor-notes.jsx, reachable via the "Notes" nav item
         that only appears when window.IS_EDITOR_MODE is true. Overview stays
         neutral / public-friendly. */}
    </div>
  );
}

window.OverviewScreen = OverviewScreen;
