/* Frequency View (Screen H) — Posting frequency time series */

var FREQ_TYPE_COLORS = {
  originals: 'rgba(255,255,255,0.75)',
  replies: '#52525B',
  quotes: 'var(--accent)',
  rts: '#71717A',
};

/* ═══════ VOLUME BAR CHART ═══════ */
function VolumeChart({ daily, hoveredDay, onHoverDay, scaleMode }) {
  /* Bars grow up from the baseline on first paint — the "圖表走勢" entrance.
     Static immediately when reduced-motion is requested. */
  var [grown, setGrown] = React.useState(!!window.PREFERS_REDUCED_MOTION);
  React.useEffect(function () {
    if (window.PREFERS_REDUCED_MOTION) return;
    var id = requestAnimationFrame(function () { setGrown(true); });
    return function () { cancelAnimationFrame(id); };
  }, []);

  var maxTotal = Math.max.apply(null, daily.map(function (d) { return d.total; }));
  if (maxTotal === 0) maxTotal = 1;
  var barH = 220;
  var isLog = scaleMode === 'log';

  function scaleH(v) {
    if (v <= 0) return 0;
    if (isLog) return (Math.log(v + 1) / Math.log(maxTotal + 1)) * barH;
    return (v / maxTotal) * barH;
  }

  /* Y-axis ticks */
  var yTicks = [];
  if (isLog) {
    [1, 2, 5, 10, 20, 50, 100, 200, 500].forEach(function (t) { if (t <= maxTotal) yTicks.push(t); });
    if (yTicks.indexOf(maxTotal) < 0) yTicks.push(maxTotal);
  } else {
    var step = maxTotal > 40 ? 10 : maxTotal > 15 ? 5 : 2;
    for (var y = 0; y <= maxTotal; y += step) yTicks.push(y);
  }

  return (
    <div style={{ display: 'flex', gap: 0, userSelect: 'none' }}>
      {/* Y axis */}
      <div style={{ width: 36, flexShrink: 0, position: 'relative', height: barH + 30, marginRight: 4 }}>
        {yTicks.map(function (t) {
          var bot = scaleH(t);
          return <div key={t} style={{ position: 'absolute', bottom: bot + 28, right: 4, fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-disabled)', fontFeatureSettings: "'tnum' 1" }}>{t}</div>;
        })}
      </div>

      {/* Bars */}
      <div style={{ flex: 1, display: 'flex', alignItems: 'flex-end', gap: 2 }}>
        {daily.map(function (d, i) {
          var isHov = hoveredDay === d.day;
          var totalH = scaleH(d.total);
          var oh = d.total > 0 ? totalH * (d.originals / d.total) : 0;
          var rh = d.total > 0 ? totalH * (d.replies / d.total) : 0;
          var qh = d.total > 0 ? totalH * (d.quotes / d.total) : 0;
          var rth = d.total > 0 ? totalH * (d.rts / d.total) : 0;
          var dayNum = d.day.slice(8);
          var showLabel = i === 0 || i === daily.length - 1 || i % 5 === 0;

          return (
            <div key={d.day} style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'stretch', cursor: 'default', position: 'relative' }}
              onMouseEnter={function () { onHoverDay(d.day); }}
              onMouseLeave={function () { onHoverDay(null); }}>

              {/* Tooltip */}
              {isHov && (
                <div style={{
                  position: 'absolute', bottom: totalH + 8, left: '50%', transform: 'translateX(-50%)',
                  background: 'var(--bg-elevated)', border: '1px solid var(--border-strong)', borderRadius: 6,
                  padding: '6px 10px', fontSize: 11, color: 'var(--text-primary)', whiteSpace: 'nowrap', zIndex: 10,
                  fontFamily: 'var(--mono)', fontFeatureSettings: "'tnum' 1", pointerEvents: 'none',
                  boxShadow: '0 4px 12px rgba(0,0,0,0.3)',
                }}>
                  <div style={{ fontWeight: 600, marginBottom: 3 }}>{d.day}</div>
                  <div style={{ color: 'rgba(255,255,255,0.75)' }}>Original: {d.originals}</div>
                  <div style={{ color: '#52525B' }}>Replies: {d.replies}</div>
                  <div style={{ color: 'var(--accent)' }}>Quotes: {d.quotes}</div>
                  <div style={{ color: '#71717A' }}>RTs: {d.rts}</div>
                  <div style={{ borderTop: '1px solid var(--border-default)', marginTop: 3, paddingTop: 3, color: 'var(--text-primary)', fontWeight: 600 }}>Total: {d.total}</div>
                </div>
              )}

              {/* Stacked segments */}
              <div style={{
                display: 'flex', flexDirection: 'column-reverse', borderRadius: '2px 2px 0 0', overflow: 'hidden',
                opacity: isHov ? 1 : 0.8,
                transform: grown ? 'scaleY(1)' : 'scaleY(0)',
                transformOrigin: 'bottom',
                transition: window.PREFERS_REDUCED_MOTION
                  ? 'opacity .1s'
                  : 'opacity .1s, transform .5s cubic-bezier(.22,1,.36,1)',
                transitionDelay: window.PREFERS_REDUCED_MOTION ? '0ms' : (i * 14) + 'ms',
              }}>
                <div style={{ height: Math.max(0, oh), background: 'rgba(255,255,255,0.75)' }}></div>
                <div style={{ height: Math.max(0, rh), background: '#52525B' }}></div>
                <div style={{ height: Math.max(0, qh), background: 'var(--accent)' }}></div>
                <div style={{ height: Math.max(0, rth), background: '#71717A' }}></div>
              </div>

              {/* X label */}
              <div style={{ textAlign: 'center', marginTop: 4, fontSize: 9, fontFamily: 'var(--mono)', color: showLabel ? 'var(--text-tertiary)' : 'transparent', fontFeatureSettings: "'tnum' 1" }}>{dayNum}</div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ═══════ HEATMAP ═══════ */
function HeatmapChart({ handleActivity, daily, onJumpToHandle, selectedHandle }) {
  var allDays = daily.map(function (d) { return d.day; });
  var maxVal = 1;
  handleActivity.forEach(function (h) {
    Object.values(h.byDay).forEach(function (v) { if (v > maxVal) maxVal = v; });
  });
  var [hovCell, setHovCell] = React.useState(null);
  var CELL_H = 18;

  return (
    <div style={{ overflowX: 'auto' }}>
      <div style={{ display: 'grid', gridTemplateColumns: '110px repeat(' + allDays.length + ', 1fr)', gap: 1, minWidth: 600 }}>
        {/* Header row */}
        <div style={{ fontSize: 10, color: 'var(--text-tertiary)', fontWeight: 600, padding: '4px 0' }}></div>
        {allDays.map(function (d, i) {
          var show = i === 0 || i === allDays.length - 1 || i % 5 === 0;
          return <div key={d} style={{ fontSize: 8, fontFamily: 'var(--mono)', color: show ? 'var(--text-disabled)' : 'transparent', textAlign: 'center', fontFeatureSettings: "'tnum' 1" }}>{d.slice(5)}</div>;
        })}

        {/* Handle rows — both the label and each daily cell route the user
            back to the Timeline filtered by that handle. */}
        {handleActivity.slice(0, 40).map(function (h) {
          var jump = function () { onJumpToHandle && onJumpToHandle(h.handle); };
          return (
            <React.Fragment key={h.handle}>
              <button onClick={jump}
                title={'Show @' + h.handle + '\'s mini-timeline'}
                style={{
                  fontSize: 11, fontFamily: 'var(--mono)',
                  color: selectedHandle === h.handle ? 'var(--accent)' : 'var(--text-secondary)',
                  padding: '0 4px', height: CELL_H, display: 'flex', alignItems: 'center',
                  overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
                  border: 'none',
                  background: selectedHandle === h.handle ? 'var(--accent-muted)' : 'transparent',
                  cursor: 'pointer', textAlign: 'left', borderRadius: 4,
                  fontWeight: selectedHandle === h.handle ? 600 : 400,
                }}
                onMouseEnter={function (e) { if (selectedHandle !== h.handle) { e.currentTarget.style.background = 'var(--bg-hover)'; e.currentTarget.style.color = 'var(--text-primary)'; } }}
                onMouseLeave={function (e) { if (selectedHandle !== h.handle) { e.currentTarget.style.background = 'transparent'; e.currentTarget.style.color = 'var(--text-secondary)'; } }}>
                @{h.handle.length > 14 ? h.handle.slice(0, 13) + '…' : h.handle}
                <span style={{ marginLeft: 'auto', fontSize: 9, color: 'var(--text-disabled)', fontFeatureSettings: "'tnum' 1", paddingLeft: 4 }}>{h.total}</span>
              </button>
              {allDays.map(function (d) {
                var v = h.byDay[d] || 0;
                var intensity = v / maxVal;
                var isHov = hovCell && hovCell.handle === h.handle && hovCell.day === d;
                return (
                  <div key={d}
                    onClick={v > 0 ? jump : undefined}
                    onMouseEnter={function () { setHovCell({ handle: h.handle, day: d, count: v }); }}
                    onMouseLeave={function () { setHovCell(null); }}
                    title={v > 0 ? '@' + h.handle + ' · ' + d + ' · ' + v + ' posts — click to filter Timeline' : ''}
                    style={{
                      height: CELL_H, borderRadius: 2,
                      background: v === 0 ? 'var(--bg-card)' : 'rgba(255,255,255,' + (0.08 + intensity * 0.45) + ')',
                      border: isHov ? '1px solid rgba(255,255,255,0.5)' : '1px solid transparent',
                      transition: 'border .1s',
                      cursor: v > 0 ? 'pointer' : 'default',
                    }}></div>
                );
              })}
            </React.Fragment>
          );
        })}
      </div>

      {/* Heatmap footer */}
      {handleActivity.length > 40 && (
        <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 8, fontStyle: 'italic' }}>
          Showing top 40 of {handleActivity.length} active handles
        </div>
      )}
    </div>
  );
}

/* ═══════ LEGEND ═══════ */
function FreqLegend() {
  return (
    <div style={{ display: 'flex', gap: 14, fontSize: 11, color: 'var(--text-tertiary)', flexWrap: 'wrap' }}>
      {[{ l: 'Original', c: 'rgba(255,255,255,0.75)' }, { l: 'Reply', c: '#52525B' }, { l: 'Quote', c: 'var(--accent)' }, { l: 'RT', c: '#71717A' }].map(function (x) {
        return (
          <span key={x.l} style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <span style={{ display: 'inline-block', width: 8, height: 8, borderRadius: 2, background: x.c }}></span>
            {x.l}
          </span>
        );
      })}
    </div>
  );
}

/* ═══════ MAIN FREQUENCY VIEW ═══════ */
/* ═══════ HEATMAP VIEW (own top-level Activity tab) ═══════ */
function HeatmapView({ onJumpToHandle }) {
  var data = window.TIMELINE_DATA;
  /* Selecting a handle in the heatmap opens an inline drawer on the right
     with that handle's mini-timeline — newest → oldest. Lets the user
     pivot from "who" to "what" without losing their place on the heatmap. */
  var [selected, setSelected] = React.useState(null);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden', position: 'relative' }}>
      <div style={{ padding: '10px 28px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0, background: 'var(--bg-surface)' }}>
        <FreqLegend />
        <div style={{ flex: 1 }}></div>
        <span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontFamily: 'var(--mono)', fontFeatureSettings: "'tnum' 1" }}>
          {data.handleActivity.length} active handles · {data.windowDays}d window
        </span>
      </div>
      <div style={{ flex: 1, overflowY: 'auto', padding: '20px 28px', paddingRight: selected ? 460 : 28, transition: 'padding-right .2s' }}>
        <div style={{ background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 8, padding: '20px' }}>
          <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 16 }}>
            Activity Heatmap — Handle × Day
          </div>
          <p style={{ fontSize: 11, color: 'var(--text-tertiary)', margin: '0 0 16px 0', lineHeight: 1.55, maxWidth: 600 }}>
            Each row is a handle, each column a day. Cell intensity = posts that day. Click any handle to peek at their mini-timeline on the right; the [→] button in the drawer opens the full filtered Timeline.
          </p>
          <HeatmapChart handleActivity={data.handleActivity} daily={data.daily}
            onJumpToHandle={function (h) { setSelected(h); }}
            selectedHandle={selected} />
        </div>
      </div>
      {selected && (
        <HandleMiniTimelineDrawer handle={selected}
          onClose={function () { setSelected(null); }}
          onOpenInTimeline={function () { onJumpToHandle && onJumpToHandle(selected); setSelected(null); }} />
      )}
    </div>
  );
}
window.HeatmapView = HeatmapView;

/* ═══════ Mini-timeline drawer (right-side pull-out) ═══════ */
function HandleMiniTimelineDrawer({ handle, onClose, onOpenInTimeline }) {
  var tl = window.TIMELINE_DATA;
  var member = (window.COHORT.members || []).find(function (m) { return m.handle === handle; });

  var tweets = React.useMemo(function () {
    return tl.tweets
      .filter(function (t) { return t.handle === handle; })
      .sort(function (a, b) { return b.ts - a.ts; });   /* newest first */
  }, [handle]);

  /* Quick type breakdown — drives the header sub-line. */
  var byType = { original: 0, reply: 0, quote: 0, retweet: 0 };
  tweets.forEach(function (t) { if (byType[t.type] != null) byType[t.type]++; });

  function fmtAgo(ts) {
    var d = tl.windowEnd - ts;
    if (d < 60) return Math.floor(d) + 's';
    if (d < 3600) return Math.floor(d / 60) + 'm';
    if (d < 86400) return Math.floor(d / 3600) + 'h';
    return Math.floor(d / 86400) + 'd';
  }
  function fmtN(n) {
    if (!n) return '0';
    if (n >= 1e6) return (n / 1e6).toFixed(1) + 'M';
    if (n >= 1e3) return (n / 1e3).toFixed(1) + 'K';
    return String(n);
  }
  function openTweet(t) {
    var url = t.url || (t.handle && t.id ? 'https://x.com/' + t.handle + '/status/' + t.id : null);
    if (url) window.open(url, '_blank', 'noopener,noreferrer');
  }

  var typeColors = { original: 'var(--text-primary)', reply: 'var(--text-tertiary)', quote: 'var(--accent)', retweet: 'var(--text-secondary)' };
  var typeIcons  = { original: '●', reply: '↩', quote: '"', retweet: '↻' };

  return (
    <div style={{
      position: 'absolute', top: 0, right: 0, height: '100%', width: 440,
      background: 'var(--bg-surface)', borderLeft: '1px solid var(--border-default)',
      boxShadow: '-8px 0 24px rgba(0,0,0,0.4)',
      display: 'flex', flexDirection: 'column', zIndex: 5,
      animation: 'slideIn .15s ease-out',
    }}>
      {/* Header */}
      <div style={{ padding: '14px 18px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'flex-start', gap: 12, flexShrink: 0 }}>
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontSize: 13, fontFamily: 'var(--mono)', fontWeight: 600, color: 'var(--text-primary)' }}>
            @{handle}
          </div>
          {member && member.name && (
            <div style={{ fontSize: 11, color: 'var(--text-tertiary)', marginTop: 1 }}>
              {member.name}{member.followers ? ' · ' + fmtN(member.followers) + ' followers' : ''}
            </div>
          )}
          <div style={{ fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', marginTop: 6, fontFeatureSettings: "'tnum' 1" }}>
            {tweets.length} posts · {byType.original} orig · {byType.reply} reply · {byType.quote} quote · {byType.retweet} RT
          </div>
        </div>
        <button onClick={onOpenInTimeline}
          title="Open in full Timeline"
          style={{ background: 'var(--bg-elevated)', border: '1px solid var(--border-default)', color: 'var(--text-secondary)', borderRadius: 6, padding: '4px 10px', fontSize: 11, fontFamily: 'var(--mono)', cursor: 'pointer' }}>
          →
        </button>
        <button onClick={onClose}
          title="Close (Esc)"
          style={{ background: 'transparent', border: 'none', color: 'var(--text-tertiary)', fontSize: 18, cursor: 'pointer', padding: 0, lineHeight: 1, width: 22, height: 22 }}>
          ×
        </button>
      </div>

      {/* List */}
      <div style={{ flex: 1, overflowY: 'auto', padding: '8px' }}>
        {tweets.length === 0 ? (
          <div style={{ padding: '40px 16px', textAlign: 'center', color: 'var(--text-tertiary)', fontSize: 12 }}>
            No posts in the loaded window.
          </div>
        ) : tweets.map(function (t) {
          var typeColor = typeColors[t.type] || 'var(--text-tertiary)';
          var text = t.type === 'retweet' && t.retweetedText
            ? 'RT @' + (t.retweetedHandle || '') + ': ' + t.retweetedText
            : t.text;
          return (
            <div key={t.id} onClick={function () { openTweet(t); }}
              style={{
                padding: '10px 12px', marginBottom: 4, borderRadius: 8,
                borderLeft: '3px solid ' + typeColor,
                background: 'var(--bg-card)', cursor: 'pointer',
                transition: 'background .12s',
              }}
              onMouseEnter={function (e) { e.currentTarget.style.background = 'var(--bg-elevated)'; }}
              onMouseLeave={function (e) { e.currentTarget.style.background = 'var(--bg-card)'; }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 5, fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)' }}>
                <span style={{ color: typeColor }}>{typeIcons[t.type] || '·'}</span>
                <span style={{ textTransform: 'uppercase', letterSpacing: '0.04em' }}>{t.type}</span>
                {t.replyToHandle && <span>→ @{t.replyToHandle}</span>}
                {t.quotedHandle && <span>" @{t.quotedHandle}</span>}
                <span style={{ marginLeft: 'auto', fontFeatureSettings: "'tnum' 1" }}>{fmtAgo(t.ts)} ago</span>
              </div>
              <div style={{ fontSize: 12, color: 'var(--text-primary)', lineHeight: 1.5, overflow: 'hidden', display: '-webkit-box', WebkitLineClamp: 4, WebkitBoxOrient: 'vertical' }}>
                {text}
              </div>
              <div style={{ display: 'flex', gap: 12, marginTop: 6, fontSize: 10, fontFamily: 'var(--mono)', color: 'var(--text-tertiary)', fontFeatureSettings: "'tnum' 1" }}>
                <span>♥ {fmtN(t.likes)}</span>
                <span>⟳ {fmtN(t.retweets)}</span>
                <span>↩ {fmtN(t.replies)}</span>
                {t.views > 0 && (
                  <span style={{ marginLeft: 'auto', color: t.views >= 100000 ? 'var(--accent)' : 'var(--text-tertiary)', fontWeight: t.views >= 100000 ? 600 : 400 }}>
                    👁 {fmtN(t.views)}
                  </span>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

/* ═══════ FREQUENCY (Volume + stats; heatmap promoted out) ═══════ */
function FrequencyView({ onJumpToHandle }) {
  var [scaleMode, setScaleMode] = React.useState('log');
  var [hoveredDay, setHoveredDay] = React.useState(null);
  var data = window.TIMELINE_DATA;

  /* Summary stats */
  var totalTweets = data.count;
  var avgPerDay = Math.round(totalTweets / data.windowDays * 10) / 10;
  var peakDay = data.daily.reduce(function (max, d) { return d.total > max.total ? d : max; }, data.daily[0]);
  var quietDay = data.daily.reduce(function (min, d) { return d.total < min.total ? d : min; }, data.daily[0]);
  var topPoster = data.handleActivity.length > 0 ? data.handleActivity[0] : null;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
      {/* Toolbar */}
      <div style={{ padding: '10px 28px', borderBottom: '1px solid var(--border-subtle)', display: 'flex', alignItems: 'center', gap: 10, flexShrink: 0, background: 'var(--bg-surface)' }}>
        <FreqLegend />

        <div style={{ flex: 1 }}></div>
        <span style={{ fontSize: 12, color: 'var(--text-tertiary)', fontFamily: 'var(--mono)', fontFeatureSettings: "'tnum' 1" }}>
          {data.windowDays}d · {totalTweets} tweets
        </span>
      </div>

      {/* Content */}
      <div style={{ flex: 1, overflowY: 'auto', padding: '20px 28px' }}>
        {/* Summary stats */}
        <div style={{ display: 'flex', gap: 12, marginBottom: 20 }}>
          <FreqStatCard label="Total Tweets" value={totalTweets} />
          <FreqStatCard label="Avg / Day" value={avgPerDay} />
          <FreqStatCard label="Peak Day" value={peakDay ? peakDay.total : 0} sub={peakDay ? peakDay.day : ''} color="var(--text-primary)" />
          <FreqStatCard label="Quietest Day" value={quietDay ? quietDay.total : 0} sub={quietDay ? quietDay.day : ''} color="var(--text-tertiary)" />
          {topPoster && <FreqStatCard label="Most Active" value={topPoster.total + ' posts'} sub={'@' + topPoster.handle} color="var(--accent)" />}
        </div>

        {/* Chart — Heatmap was promoted to its own top-level Activity tab,
            so this view is just the Volume chart now (with log/linear toggle). */}
        <div style={{ background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 8, padding: '20px' }}>
          <div style={{ display: 'flex', alignItems: 'center', marginBottom: 16 }}>
            <div style={{ fontSize: 12, fontWeight: 600, color: 'var(--text-secondary)', textTransform: 'uppercase', letterSpacing: 0.5 }}>Daily Post Volume</div>
            <div style={{ flex: 1 }}></div>
            <div style={{ display: 'flex', background: 'var(--bg-elevated)', borderRadius: 6, border: '1px solid var(--border-default)', overflow: 'hidden' }}>
              {[{ v: 'log', l: 'Log' }, { v: 'linear', l: 'Linear' }].map(function (s) {
                var active = scaleMode === s.v;
                return <button key={s.v} onClick={function () { setScaleMode(s.v); }}
                  style={{ padding: '3px 12px', border: 'none', fontSize: 11, fontWeight: active ? 600 : 400, background: active ? 'var(--bg-hover)' : 'transparent', color: active ? 'var(--text-primary)' : 'var(--text-tertiary)', cursor: 'pointer', fontFamily: 'var(--sans)', transition: 'all .12s' }}>{s.l}</button>;
              })}
            </div>
          </div>
          <VolumeChart daily={data.daily} hoveredDay={hoveredDay} onHoverDay={setHoveredDay} scaleMode={scaleMode} />
          <div style={{ fontSize: 10, color: 'var(--text-disabled)', marginTop: 12, fontStyle: 'italic' }}>
            {scaleMode === 'log' ? 'Log scale (default) — compresses spike days so quiet days stay legible.' : 'Linear scale — true magnitude; quiet days flatten near the baseline.'}
          </div>
        </div>

        {/* Insights */}
        <div style={{ marginTop: 20, display: 'flex', gap: 12 }}>
          <InsightCard title="Distribution Skew" text={'Top 5 posters account for ~' + (data.handleActivity.length >= 5 ? Math.round(data.handleActivity.slice(0, 5).reduce(function (s, h) { return s + h.total; }, 0) / totalTweets * 100) : 0) + '% of all tweets. Classic long-tail distribution.'} />
          <InsightCard title="Weekend Pattern" text="Activity typically drops 30-50% on weekends. Monitor for anomalies — weekend spikes often signal product launches or incidents." />
          <InsightCard title="Silent Majority" text={(data.handleActivity.length < okCount() ? 'Only ' + data.handleActivity.length + ' of ' + okCount() + ' active profiles posted in this window.' : 'All tracked profiles posted at least once.')} />
        </div>
      </div>
    </div>
  );
}

function okCount() {
  return window.COHORT.members.filter(function (m) { return m.status === 'ok'; }).length;
}

/* ── Stat Card ── */
function FreqStatCard({ label, value, sub, color }) {
  return (
    <div style={{ background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: '14px 16px', flex: 1, minWidth: 100 }}>
      <div style={{ fontSize: 20, fontWeight: 600, fontFamily: 'var(--mono)', color: color || 'var(--text-primary)', fontFeatureSettings: "'tnum' 1", lineHeight: 1.1 }}><AnimatedNumber value={value} /></div>
      <div style={{ fontSize: 11, color: 'var(--text-secondary)', marginTop: 4 }}>{label}</div>
      {sub && <div style={{ fontSize: 10, color: 'var(--text-tertiary)', fontFamily: 'var(--mono)', marginTop: 2 }}>{sub}</div>}
    </div>
  );
}

/* ── Insight Card ── */
function InsightCard({ title, text }) {
  return (
    <div style={{ flex: 1, background: 'var(--bg-card)', border: '1px solid var(--border-subtle)', borderRadius: 12, padding: '14px 16px' }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: 'var(--text-secondary)', textTransform: 'uppercase', letterSpacing: 0.5, marginBottom: 6 }}>{title}</div>
      <div style={{ fontSize: 12, color: 'var(--text-tertiary)', lineHeight: 1.55 }}>{text}</div>
    </div>
  );
}

window.FrequencyView = FrequencyView;
