/* AAU CRM — Executive Dashboard + Flow Map
   Rebuilt to fit the full system: Planning, Conversation Intel / Enablement
   and the QC Engine are now first-class pillars, not just the old
   Marketing→Inbox→Sales→Delivery→Finance line. */

// ---------- shared computed signals (single source for both screens) ----------
function useSystemPulse() {
  const A = AAU, PA = A.planning.periodActual, T = A.totals, P = A.pnl;
  // money / pace (live month-to-date vs target)
  const target = T.revenueTarget;                 // 600tr
  const actual = PA.revenue;                       // 318tr MTD
  const dE = PA.daysElapsed, dT = PA.daysTotal;    // 18 / 30
  const onPace = target * dE / dT;                 // nhịp cần đạt hôm nay
  const projected = actual / dE * dT;              // dự phóng cuối kỳ
  const pace = {
    target, actual, dE, dT, onPace, projected,
    pacePct: Math.round(actual / onPace * 100),
    projPct: Math.round(projected / target * 100),
    remaining: Math.max(0, target - actual),
    daysLeft: dT - dE,
    perDay: Math.max(0, target - actual) / Math.max(1, dT - dE),
    vsLast: Math.round((projected / A.planning.lastMonth - 1) * 100),
    behind: actual < onPace,
  };
  // finance
  const cogs = P.cogs.reduce((s, c) => s + c.amount, 0);
  const opex = P.opex.reduce((s, c) => s + c.amount, 0);
  const gross = P.revenue - cogs, ebit = gross - opex, net = ebit * (1 - P.taxRate);
  const margin = Math.round(net / P.revenue * 100);
  // delivery / fill
  const enrolling = A.classes.filter(c => c.status === 'enrolling');
  const fillRate = enrolling.length
    ? Math.round(enrolling.reduce((s, c) => s + c.enrolled / c.cap, 0) / enrolling.length * 100) : 0;
  const atRisk = enrolling.filter(c => c.enrolled / c.cap < 0.55).length;
  // sales
  const winRate = Math.round(PA.won / PA.deals * 100);          // deals → won
  const cac = T.spend / PA.won;
  // QC (rulesets aggregate)
  const qc = A.qcRulesets.reduce((a, r) => {
    a.analyzed += r.analyzed; a.pass += r.pass; a.fail += r.fail; a.w += r.avg * r.analyzed; return a;
  }, { analyzed: 0, pass: 0, fail: 0, w: 0 });
  qc.avg = qc.w / qc.analyzed; qc.passRate = Math.round(qc.pass / qc.analyzed * 100); qc.pending = 6;
  // intel / enablement
  const intel = {
    coverage: 83, patterns: 27, gaps: (window.INTEL ? INTEL.patterns.filter(p => p.coverage === 'gap').length : 2),
    autoLinked: '19/27',
  };
  return { A, PA, T, P, pace, net, margin, fillRate, atRisk, winRate, cac, qc, intel };
}

// ---------- pace-to-target band (Planning pillar, forward looking) ----------
function PaceBand({ s }) {
  const p = s.pace, f = AAU.fmtVNDm;
  const actualPct = Math.min(100, p.actual / p.target * 100);
  const paceMarkPct = Math.min(100, p.onPace / p.target * 100);
  const fill = p.behind ? '#b06f00' : '#0e7c4a';
  return (
    <Card pad className="mb16">
      <div className="row jcsb wrap g16">
        <div>
          <div className="row aic g8 t12 fw6" style={{ color: 'var(--p-text-secondary)' }}>
            <Icon name="target" size={14} /> Nhịp doanh thu · {s.PA.monthLabel}
          </div>
          <div className="row aife wrap g10 mt8">
            <span className="tnum fw7" style={{ fontSize: 36, lineHeight: 1, letterSpacing: '-0.02em' }}>{f(p.actual)}</span>
            <span className="t13 muted" style={{ paddingBottom: 3 }}>/ mục tiêu {f(p.target)}</span>
            <span style={{ paddingBottom: 2 }}><Badge tone={p.behind ? 'warning' : 'success'} dot>{p.behind ? 'Chậm nhịp ' + (100 - p.pacePct) + '%' : 'Vượt nhịp ' + (p.pacePct - 100) + '%'}</Badge></span>
          </div>
        </div>
        <div className="row g8" style={{ alignSelf: 'flex-start' }}>
          <Button size="sm" iconRight="arrowRight" onClick={() => navigate('/planning')}>Lập kế hoạch</Button>
          <Button variant="plain" size="sm" iconRight="arrowRight" onClick={() => navigate('/planning/tracking')}>Theo dõi KPI</Button>
        </div>
      </div>

      {/* full-width pace bar */}
      <div style={{ position: 'relative', height: 30, borderRadius: 9, background: '#f1f1f1', overflow: 'hidden', marginTop: 18 }}>
        <div style={{ position: 'absolute', inset: 0, width: actualPct + '%', background: fill, borderRadius: 9, display: 'flex', alignItems: 'center', justifyContent: 'flex-end', paddingRight: 10, color: '#fff', fontSize: 12, fontWeight: 700, transition: 'width .5s' }}>{Math.round(actualPct)}%</div>
        <div style={{ position: 'absolute', top: -3, bottom: -3, left: paceMarkPct + '%', width: 2, background: '#303030' }} />
      </div>
      <div className="row jcsb t11 muted mt4">
        <span>Đầu kỳ</span>
        <span>▕ Nhịp cần đạt hôm nay · {f(p.onPace)} ({Math.round(paceMarkPct)}%)</span>
        <span>{f(p.target)}</span>
      </div>

      {/* stats */}
      <div className="row g24 wrap mt16" style={{ borderTop: '1px solid var(--p-border-secondary)', paddingTop: 12 }}>
        <PaceStat k="Tiến độ kỳ" v={'Ngày ' + p.dE + '/' + p.dT} />
        <PaceStat k="Dự phóng cuối kỳ" v={f(p.projected) + ' · ' + p.projPct + '%'} tone={p.projPct >= 100 ? 'ok' : 'warn'} />
        <PaceStat k="Còn cần" v={f(p.remaining) + ' · ~' + f(p.perDay) + '/ngày'} />
        <PaceStat k="Dự phóng vs tháng trước" v={(p.vsLast >= 0 ? '+' : '') + p.vsLast + '%'} tone={p.vsLast >= 0 ? 'ok' : 'warn'} />
      </div>
    </Card>
  );
}
function PaceStat({ k, v, tone }) {
  const c = tone === 'ok' ? '#0e7c4a' : tone === 'warn' ? '#b06f00' : 'var(--p-text)';
  return <div><div className="t11 muted">{k}</div><div className="t13 fw7 tnum" style={{ color: c }}>{v}</div></div>;
}

// ---------- per-pillar health card ----------
function PillarCard({ icon, color, name, metric, sub, tone, path }) {
  return (
    <div onClick={() => navigate(path)} className="pillar-card"
      style={{ cursor: 'pointer', background: '#fff', border: '1px solid var(--p-border)', borderRadius: 12, padding: 14, boxShadow: 'var(--p-shadow-card)' }}>
      <div className="row aic jcsb mb10">
        <span className="row aic g8">
          <span className="center" style={{ width: 30, height: 30, borderRadius: 8, background: color + '18', color }}><Icon name={icon} size={17} /></span>
          <span className="t12 fw6">{name}</span>
        </span>
        {tone && <span className="status-dot" style={{ width: 8, height: 8, borderRadius: 99, background: tone === 'critical' ? '#c4320a' : tone === 'warning' ? '#d6a000' : '#0e9e6e' }} />}
      </div>
      <div className="t20 fw7 tnum" style={{ letterSpacing: '-0.01em' }}>{metric}</div>
      <div className="t12 muted mt4">{sub}</div>
    </div>
  );
}

function ExecDashboard() {
  const per = usePeriod('month');
  const sc = per.scale, cmp = per.compareOn;
  const s = useSystemPulse();
  const T = s.T, P = s.P;
  const sv = v => Math.round(v * sc);
  const kind = per.cur.kind.toLowerCase();
  const cogs = P.cogs.reduce((a, c) => a + c.amount, 0);
  const opex = P.opex.reduce((a, c) => a + c.amount, 0);
  const gross = P.revenue - cogs, ebit = gross - opex, net = ebit * (1 - P.taxRate);

  const revTrend = [
    { l: 'T12', v: 410 }, { l: 'T1', v: 388 }, { l: 'T2', v: 432 }, { l: 'T3', v: 498 }, { l: 'T4', v: 558 }, { l: 'T5', v: 642 },
  ].map(m => ({ ...m, v: Math.round(m.v * sc) }));

  // alerts now span pillars: SLA (sales), QC (quality), delivery, intel (enablement), finance
  const alerts = [
    { tone: 'critical', icon: 'fire', t: '2 lead hot quá hạn SLA', d: 'Anh Khoa (Khoa BBQ) còn 3h ở Đàm phán · Anh Phong quá hạn TVCS', act: () => navigate('/leads/kanban') },
    { tone: 'critical', icon: 'shield', t: '1 hội thoại vi phạm nghiêm trọng', d: 'QC bắt cam kết sai chính sách "đảm bảo tăng x2 doanh thu" — cần manager duyệt', act: () => navigate('/qc/review') },
    { tone: 'warning', icon: 'alert', t: 'Lớp Nhượng quyền B04 nguy cơ ế', d: 'Mới 6/15 chỗ, khai giảng 22/06 — cần đẩy marketing', act: () => navigate('/classes') },
    { tone: 'warning', icon: 'sparkles', t: s.intel.gaps + ' pattern chưa có kịch bản', d: '"Chưa cần ngay" & "Đòi hoàn cọc" — win-rate thấp, Intel đề xuất tạo script', act: () => navigate('/enablement/intelligence') },
    { tone: 'warning', icon: 'dollar', t: 'Công nợ quá hạn 6tr', d: 'Mai Tú (Tú Tea) — đợt cuối quá hạn 30/05', act: () => navigate('/enrollments') },
  ];

  return (
    <div className="page wide">
      <PageHead title="Executive Dashboard" subtitle={'Sức khỏe toàn hệ thống · ' + per.cur.label}
        actions={<><PeriodNav p={per} compare /><Button icon="download">Xuất báo cáo</Button></>} />

      {/* ① Forward pace vs target (Planning) */}
      <PaceBand s={s} />

      {/* ② Money & throughput KPIs */}
      <div className="grid gc4 mb16">
        <KPI label="Lãi ròng" value={AAU.fmtVNDm(sv(net))} delta={cmp ? 12 : null} sub={'Biên ' + s.margin + '%'} icon="dollar" />
        <KPI label="Pipeline value" value={AAU.fmtVNDm(sv(T.pipelineValue))} delta={cmp ? 8 : null} sub={'Forecast ' + AAU.fmtVNDm(sv(T.forecast))} icon="kanban" />
        <KPI label={'Deal Won ' + kind} value={sv(s.PA.won)} delta={cmp ? 18 : null} sub={'Tỷ lệ chốt ' + s.winRate + '%'} icon="checkCircle" />
        <KPI label="CAC (chi phí/khách)" value={AAU.fmtVNDm(s.cac)} delta={cmp ? -6 : null} deltaDir="up" sub="LTV/CAC 4,2× · ngưỡng ≥3×" icon="target" />
      </div>

      {/* ③ Pillar health — one signal from every part of the system */}
      <Card title="Sức khỏe theo trụ" subtitle="Mỗi khối là một module — bấm để mở" className="mb16">
        <div className="pillar-grid">
          <PillarCard icon="megaphone" color="#0084ff" name="Marketing" metric={AAU.fmtVNDm(s.T.spend) + ' chi'} sub={AAU.fmtNum(s.PA.leads) + ' lead · CAC ' + AAU.fmtVNDm(s.cac)} tone="ok" path="/marketing/ads" />
          <PillarCard icon="kanban" color="#f59e0b" name="Sales CRM" metric={s.PA.won + ' won'} sub={s.PA.deals + ' deal · chốt ' + s.winRate + '%'} tone="ok" path="/sales/today" />
          <PillarCard icon="graduation" color="#0a9e6e" name="Delivery" metric={'Lấp đầy ' + s.fillRate + '%'} sub={'4 lớp tuyển · ' + s.atRisk + ' nguy cơ ế'} tone={s.atRisk ? 'warning' : 'ok'} path="/classes" />
          <PillarCard icon="dollar" color="#008060" name="Finance" metric={'Biên ' + s.margin + '%'} sub={'Lãi ' + AAU.fmtVNDm(s.net) + ' · công nợ 6tr'} tone="warning" path="/finance" />
          <PillarCard icon="sparkles" color="#573b8a" name="Enablement & AI" metric={'Phủ ' + s.intel.coverage + '%'} sub={s.intel.patterns + ' pattern · ' + s.intel.gaps + ' lỗ hổng'} tone={s.intel.gaps ? 'warning' : 'ok'} path="/enablement/intelligence" />
          <PillarCard icon="shield" color="#b45309" name="QC Engine" metric={'Điểm ' + s.qc.avg.toFixed(1).replace('.', ',')} sub={'Pass ' + s.qc.passRate + '% · ' + s.qc.pending + ' chờ duyệt'} tone="warning" path="/qc/review" />
        </div>
      </Card>

      {/* ④ Trend + cross-pillar alerts */}
      <div className="grid mb16" style={{ gridTemplateColumns: '1.7fr 1fr' }}>
        <Card title="Doanh thu 6 tháng" subtitle="Đơn vị: triệu ₫" actions={<Badge tone="success" dot>+15% MoM</Badge>}>
          <LineChart data={revTrend} color="#008060" fmt={v => Math.round(v)} height={240} />
        </Card>
        <Card title="Cảnh báo nóng" subtitle="Toàn hệ thống · cần xử lý">
          <div className="col g8">
            {alerts.map((a, i) => (
              <div key={i} className="row g10 aic alert-row" style={{ padding: 11, borderRadius: 10, background: 'var(--p-bg-surface-tertiary)', cursor: 'pointer' }} onClick={a.act}>
                <span className="center" style={{ width: 32, height: 32, borderRadius: 9, flexShrink: 0, background: '#fff', color: a.tone === 'critical' ? '#c4320a' : '#b06f00' }}><Icon name={a.icon} size={17} /></span>
                <div className="f1"><div className="t13 fw6">{a.t}</div><div className="t12 muted">{a.d}</div></div>
                <Icon name="chevronRight" size={16} />
              </div>
            ))}
          </div>
        </Card>
      </div>

      {/* ⑤ Funnel + P&L + sources */}
      <div className="grid gc3">
        <Card title="Phễu tăng trưởng" subtitle="Messages → Won">
          <Funnel steps={[
            { l: 'Messages', v: T.messages, color: '#0084ff' },
            { l: 'Lead', v: s.PA.leads, color: '#8b5cf6' },
            { l: 'Qualified', v: s.PA.qualified, color: '#f59e0b' },
            { l: 'Won', v: s.PA.won, color: '#10b981' },
          ]} />
        </Card>
        <Card title="P&L tóm tắt" subtitle={P.month}>
          <div className="col g10 t13">
            {[['Doanh thu', P.revenue, '#0e7c4a'], ['− COGS', -cogs, '#616161'], ['= Lãi gộp', gross, '#303030'], ['− Opex', -opex, '#616161'], ['− Thuế', -ebit * P.taxRate, '#616161'], ['= Lãi ròng', net, '#0e7c4a']].map((r, i) => (
              <div key={i} className="row jcsb aic" style={{ fontWeight: String(r[0]).startsWith('=') ? 700 : 500, paddingTop: String(r[0]).startsWith('=') ? 6 : 0, borderTop: String(r[0]).startsWith('=') ? '1px solid var(--p-border-secondary)' : 'none' }}>
                <span className="muted">{r[0]}</span><Money v={Math.abs(r[1])} />
              </div>
            ))}
            <Button variant="plain" size="sm" onClick={() => navigate('/finance')} iconRight="arrowRight" style={{ alignSelf: 'flex-start', marginTop: 4 }}>Xem chi tiết P&L</Button>
          </div>
        </Card>
        <Card title="Lead theo nguồn" subtitle="Tháng này">
          {(() => {
            const by = {}; AAU.leads.forEach(l => { const c = AAU.sourceMeta[l.source]; const k = c ? c.label : l.source; by[k] = (by[k] || 0) + 1; });
            const colors = ['#0084ff', '#111111', '#ea4335', '#0a9e6e', '#7c3aed', '#f59e0b'];
            const data = Object.entries(by).map(([l, v], i) => ({ l, v: v + 20, color: colors[i % colors.length] }));
            return <div className="row aic g16"><Donut data={data} center={{ v: AAU.fmtNum(s.PA.leads), l: 'lead' }} /><div className="col g6">{data.map((d, i) => <span key={i} className="row aic g6 t12"><span style={{ width: 9, height: 9, borderRadius: 2, background: d.color }} /><span className="muted">{d.l}</span></span>)}</div></div>;
          })()}
        </Card>
      </div>
    </div>
  );
}

// ===================== FLOW MAP — layered operating-system map =====================
function StepLabel({ n, title, sub }) {
  return (
    <div className="row aic g10" style={{ margin: '4px 0 12px' }}>
      <span className="center tnum fw7" style={{ width: 24, height: 24, borderRadius: 99, background: 'var(--p-text)', color: '#fff', fontSize: 13, flexShrink: 0 }}>{n}</span>
      <div><div className="t14 fw7">{title}</div>{sub && <div className="t12 muted">{sub}</div>}</div>
    </div>
  );
}

function FlowNode({ n }) {
  return (
    <div onClick={() => navigate(n.path)} className="flow-node" style={{ flex: 1, minWidth: 168, cursor: 'pointer', background: '#fff', border: '1px solid var(--p-border)', borderRadius: 14, padding: 16, boxShadow: 'var(--p-shadow-card)' }}>
      <div className="row aic g10 mb10"><span className="center" style={{ width: 38, height: 38, borderRadius: 11, background: n.color + '18', color: n.color }}><Icon name={n.icon} size={20} /></span><div className="t14 fw7">{n.label}</div></div>
      <div className="t22 fw7 tnum" style={{ letterSpacing: '-0.02em' }}>{n.metric}</div>
      <div className="t12 muted mt4">{n.sub}</div>
      <div className="t12 linkish mt10 row aic g4">Mở module <Icon name="arrowRight" size={13} /></div>
    </div>
  );
}

function ConvArrow({ pct, label }) {
  return (
    <div className="center col g4" style={{ width: 70, flexShrink: 0 }}>
      <span className="t13 fw7 tnum" style={{ color: '#0e7c4a' }}>{pct}</span>
      <Icon name="arrowRight" size={20} color="#b5b5b5" />
      <span className="t11 muted center" style={{ lineHeight: 1.15, textAlign: 'center' }}>{label}</span>
    </div>
  );
}

function EngineCard({ icon, color, name, role, metric, serves, path }) {
  return (
    <div onClick={() => navigate(path)} className="f1" style={{ minWidth: 230, cursor: 'pointer', background: '#fff', border: '1px dashed var(--p-border-hover)', borderRadius: 12, padding: '14px 16px' }}>
      <div className="row aic g8 mb6"><span className="center" style={{ width: 28, height: 28, borderRadius: 8, background: color + '18', color }}><Icon name={icon} size={16} /></span><span className="t13 fw7">{name}</span></div>
      <div className="t12 muted" style={{ minHeight: 32 }}>{role}</div>
      <div className="row aic jcsb mt8">
        <span className="t12 fw7 tnum">{metric}</span>
        <span className="t11" style={{ color: color, background: color + '14', padding: '2px 8px', borderRadius: 99, fontWeight: 600 }}>↑ {serves}</span>
      </div>
    </div>
  );
}

function FlowMap() {
  const s = useSystemPulse();
  const T = s.T, PA = s.PA, f = AAU.fmtVNDm, fn = AAU.fmtNum;
  const msgToLead = (PA.leads / T.messages * 100).toFixed(1).replace('.', ',') + '%';
  const leadToQual = Math.round(PA.qualified / PA.leads * 100) + '%';
  const qualToWon = (PA.won / PA.qualified * 100).toFixed(1).replace('.', ',') + '%';

  const nodes = [
    { id: 'mkt', label: 'Marketing', icon: 'megaphone', color: '#0084ff', path: '/marketing/ads', metric: f(T.spend) + ' chi', sub: PA.posts + ' bài · ' + fn(PA.leads) + ' lead' },
    { id: 'inbox', label: 'Inbox', icon: 'inbox', color: '#7c3aed', path: '/inbox', metric: fn(T.messages), sub: 'hội thoại · 92% phản hồi' },
    { id: 'sales', label: 'Sales CRM', icon: 'kanban', color: '#f59e0b', path: '/leads/kanban', metric: PA.won + ' won', sub: PA.deals + ' deal · ' + fn(PA.qualified) + ' qualified' },
    { id: 'delivery', label: 'Delivery', icon: 'graduation', color: '#0a9e6e', path: '/classes', metric: PA.students + ' ghi danh', sub: PA.cohorts + ' khóa khai giảng' },
    { id: 'finance', label: 'Finance', icon: 'dollar', color: '#008060', path: '/finance', metric: f(PA.revenue), sub: 'biên ròng ' + s.margin + '%' },
  ];
  const convs = [
    { pct: msgToLead, label: 'msg → lead' },
    { pct: leadToQual, label: 'lead → qualified' },
    { pct: qualToWon, label: 'qualified → won' },
    { pct: f(PA.revenue / PA.students), label: 'doanh thu / HV' },
  ];

  return (
    <div className="page wide">
      <PageHead title="Flow Map — Bản đồ vận hành hệ thống"
        subtitle="Kế hoạch đặt mục tiêu → dòng chảy khách chạy qua 5 trụ → các engine hỗ trợ giám sát & tiếp nhiên liệu. Bấm khối bất kỳ để vào module." />

      {/* ① PLAN sets the targets */}
      <StepLabel n="1" title="Kế hoạch đặt mục tiêu" sub="Lập kế hoạch → KPI rải xuống từng mắt xích" />
      <Card pad className="mb8" style={{ borderLeft: '3px solid #1f5199' }}>
        <div className="row aic jcsb wrap g16" onClick={() => navigate('/planning')} style={{ cursor: 'pointer' }}>
          <div className="row aic g12">
            <span className="center" style={{ width: 38, height: 38, borderRadius: 11, background: '#1f519918', color: '#1f5199' }}><Icon name="target" size={20} /></span>
            <div>
              <div className="t14 fw7">Mục tiêu kỳ {PA.monthLabel}</div>
              <div className="t12 muted">Doanh thu {f(s.pace.target)} · {PA.cohorts}+ khóa khai giảng · quota {Math.round(s.pace.target / 11000000)} ghi danh</div>
            </div>
          </div>
          <div className="row aic g20">
            <div><div className="t11 muted">Đã đạt</div><div className="t14 fw7 tnum">{f(PA.revenue)} · {s.pace.pacePct}% nhịp</div></div>
            <Badge tone={s.pace.behind ? 'warning' : 'success'} dot>{s.pace.behind ? 'Chậm nhịp' : 'Đúng nhịp'}</Badge>
            <Icon name="chevronRight" size={18} />
          </div>
        </div>
      </Card>
      <div className="center" style={{ color: '#c5c5c5', margin: '2px 0' }}><Icon name="chevronDown" size={20} /></div>

      {/* ② CORE CONVEYOR */}
      <StepLabel n="2" title="Dòng chảy chính" sub="Hành trình khách & tỉ lệ chuyển đổi giữa các mắt xích" />
      <Card pad className="mb20">
        <div className="row aic" style={{ overflowX: 'auto', paddingBottom: 6 }}>
          {nodes.map((n, i) => (
            <React.Fragment key={n.id}>
              <FlowNode n={n} />
              {i < nodes.length - 1 && <ConvArrow pct={convs[i].pct} label={convs[i].label} />}
            </React.Fragment>
          ))}
        </div>
      </Card>

      {/* ③ SUPPORT ENGINES */}
      <StepLabel n="3" title="Hệ thống hỗ trợ vận hành" sub="Các engine đọc & nuôi dòng chảy chính — phần mới của hệ thống" />
      <div className="engine-grid mb16">
        <EngineCard icon="sparkles" color="#573b8a" name="Conversation Intel" path="/enablement/intelligence"
          role="Quét hội thoại → phát hiện pattern → khớp tri thức → gợi ý cho sale." metric={s.intel.patterns + ' pattern · phủ ' + s.intel.coverage + '%'} serves="Inbox · Sales" />
        <EngineCard icon="layers" color="#0084ff" name="Enablement & AI" path="/enablement/assets"
          role="Asset · Script Flow · Knowledge Base · AI Chat (RAG) tiếp nhiên liệu cho sale." metric="AI giữ nhiệt ngoài giờ" serves="Inbox · Sales" />
        <EngineCard icon="shield" color="#b45309" name="QC Engine" path="/qc/review"
          role="Chấm điểm chất lượng hội thoại & cuộc gọi theo ruleset, gắn cờ vi phạm." metric={'Điểm ' + s.qc.avg.toFixed(1).replace('.', ',') + ' · pass ' + s.qc.passRate + '%'} serves="Inbox · Sales" />
        <EngineCard icon="refresh" color="#0a9e6e" name="Vòng lặp upsell" path="/courses"
          role="Won → học viên → journey → khóa kế tiếp, quay lại nuôi Marketing." metric="Mở rộng LTV" serves="Delivery → Marketing" />
      </div>

      {/* ④ conversion scoreboard */}
      <div className="grid gc4">
        <KPI label="Messages → Lead" value={msgToLead} sub="Trung bình ngành ~18%" icon="message" />
        <KPI label="Lead → Won" value={(PA.won / PA.leads * 100).toFixed(1).replace('.', ',') + '%'} sub="Mục tiêu 9%" icon="target" />
        <KPI label="Phủ tri thức (Intel)" value={s.intel.coverage + '%'} sub={s.intel.gaps + ' pattern còn lỗ hổng'} icon="book" />
        <KPI label="QC pass rate" value={s.qc.passRate + '%'} sub={'Điểm TB ' + s.qc.avg.toFixed(1).replace('.', ',') + ' · ngưỡng ≥7'} icon="shield" />
      </div>
    </div>
  );
}

Object.assign(window, { ExecDashboard, FlowMap });
