/* ============================================================
   Beacon CS — ANALYZE (service performance · quality · outcome)
   ============================================================ */
function AnalyzeView({ intent = {} }) {
  const {
    KPIS, SCENES, REVIEW_QUEUE, OUTCOMES, KNOWLEDGE_HEALTH, KNOWLEDGE_COUNTS,
    AGENT_OUTCOME_CARDS, AGENT_OUTCOME_MONTHS, OUTCOME_DEFINITIONS, OUTCOME_DIAGNOSTICS, CLOSURE_ACTIONS,
    OUTCOME_MEASUREMENT, ANNA_IMPACT, ANNA_INTENTS, ANNA_DIAGNOSTICS,
    KNOWLEDGE_REVIEW_TODOS, MCP_SERVERS, REDLINE_RULES, R9_AUDIT,
  } = window.DATA;
  const { PageHead, Stat, Badge, Meter, Spark, Redline, Status } = window;
  const Icons = window.Icons;
  const [tab, setTab] = useState("anna");
  const [rq, setRq] = useState(null);
  useEffect(() => {
    const t = intent.tab || window.BeaconNav?.intent("analyze")?.tab;
    if (t) setTab(t);
  }, [intent.tab]);
  const openTarget = (section, nextTab) => window.BeaconNav?.go(section, nextTab ? { tab: nextTab } : {});
  const sceneNext = (s) => {
    if (s.uc === "UC-08") return { tone: "gray", label: "保持转人工", next: "安全敏感场景", badge: "边界", section: "test", tab: "safety" };
    if (s.resolve < 55) return { tone: "amber", label: "检查回答路径", next: "先核对依据、范围和负向信号", badge: "待判断", section: "train", tab: "review" };
    if (s.hand > 40) return { tone: "amber", label: "检查回答缺口", next: "系统再判断是否需要问答", badge: "待判断", section: "train", tab: "review" };
    return { tone: "green", label: "持续观察", next: "自助处理有效", badge: "正常", section: "analyze", tab: "outcome" };
  };
  const qualityCounts = {
    needsFix: REVIEW_QUEUE.filter(r => r.state === "needs-fix").length,
    redline: REVIEW_QUEUE.filter(r => r.redline).length,
    passed: REVIEW_QUEUE.filter(r => r.state === "passed").length,
  };
  const connectionList = MCP_SERVERS.filter(s => s.health !== "ok" || ["usm-mcp", "kyc-mcp", "risk-mcp", "ticket-mcp"].includes(s.id));
  const degradedConnections = connectionList.filter(s => s.health !== "ok");
  const ruleHits = REDLINE_RULES.reduce((sum, r) => sum + r.hits, 0);
  const activeRuleHits = REDLINE_RULES.filter(r => r.hits > 0).sort((a, b) => b.hits - a.hits);

  return (
    <div className="content-pad fadein">
      <PageHead title="分析" sub="查看处理结果、知识缺口和发布阻断。"
        right={<><button className="btn sm"><Icons.refresh s={14} /> 最近 7 天</button><button className="btn sm"><Icons.doc s={14} /> 导出当前视图</button></>} />

      <window.Tabs active={tab} onChange={setTab} tabs={[
        { id: "anna", label: "Anna 帮助效果" },
        { id: "overview", label: "总览" },
        { id: "scenes", label: "高频问题" },
        { id: "knowledge", label: "知识资产" },
        { id: "health", label: "运行健康", count: degradedConnections.length },
        { id: "quality", label: "质检", count: REVIEW_QUEUE.filter(r => r.state === "needs-fix").length },
        { id: "outcome", label: "处理结果" },
      ]} />

      {tab === "overview" && (
        <div>
          <div className="sec-grid-4" style={{ marginBottom: 16 }}>
            {KPIS.map((k, i) => <Stat key={i} {...k} />)}
          </div>
          <div className="overview-focus">
            <div className="card">
              <div className="card-head">
                <Icons.bot s={15} />
                <span className="card-title">处理结果分布</span>
                <span className="card-sub">最近 7 天</span>
                <button className="btn sm ghost" onClick={() => setTab("outcome")}>查看规则</button>
              </div>
              <div className="card-pad">
                <div className="outcome-compact-grid">
                  {AGENT_OUTCOME_CARDS.map(o => (
                    <button key={o.k} className="outcome-compact-card" onClick={() => setTab("outcome")}>
                      <span className="agent-outcome-title"><span className="dot-sq" style={{ background: o.color }}></span>{o.k}</span>
                      <span className="outcome-compact-num">{o.pct}<small>%</small></span>
                      <span className="outcome-compact-meta"><b>{o.n.toLocaleString()}</b> 个会话 · {o.delta}</span>
                    </button>
                  ))}
                </div>
                <div className="agent-outcome-trend">
                  <div className="spread" style={{ marginBottom: 12 }}>
                    <div>
                      <div style={{ fontWeight: 600, fontSize: 13.5 }}>月度结果分布</div>
                      <div className="muted" style={{ fontSize: 12, marginTop: 3 }}>只有 Anna 直接解决计入已解决。</div>
                    </div>
                    <div className="outcome-legend">
                      <span><i style={{ background: "var(--green)" }}></i> 直接解决</span>
                      <span><i style={{ background: "var(--blue)" }}></i> 转人工</span>
                      <span><i style={{ background: "var(--amber)" }}></i> 静默离开</span>
                      <span><i style={{ background: "var(--red)" }}></i> 无法安全解决</span>
                    </div>
                  </div>
                  <OutcomeStackedBars rows={AGENT_OUTCOME_MONTHS} />
                </div>
              </div>
            </div>
            <div className="card">
              <div className="card-head"><Icons.target s={15} /><span className="card-title">需要处理</span><span className="card-sub">只展示可行动项</span></div>
              <div className="card-pad">
                <div className="attention-list">
                  {CLOSURE_ACTIONS.slice(0, 4).map(a => (
                    <button key={a.label} className="attention-row" onClick={() => openTarget(a.section, a.tab)}>
                      <span className="attention-main">
                        <b>{a.label}</b>
                        <small>{a.next}</small>
                      </span>
                      <Badge tone={a.tone}>{a.value}</Badge>
                      <span className="action-cta">{a.action}<Icons.chevR s={14} /></span>
                    </button>
                  ))}
                </div>
                <div className="note" style={{ marginTop: 12 }}><Icons.bot s={14} style={{ flexShrink: 0 }} /> 衡量 Anna 在进入 Zendesk 前完成的工作：直接回答、转人工准备和未解决退出。</div>
              </div>
            </div>
          </div>
        </div>
      )}

      {tab === "scenes" && (
        <div className="card">
          <div className="card-head"><Icons.search s={15} /><span className="card-title">高频问题</span><span className="card-sub">选择下一批训练目标</span></div>
          <table className="tbl">
            <thead><tr><th>问题</th><th>会话数</th><th>Anna 直接解决</th><th>总转人工</th><th>趋势</th><th>下一步</th></tr></thead>
            <tbody>
              {SCENES.map(s => {
                const next = sceneNext(s);
                return (
                  <tr key={s.uc}>
                    <td>
                      <div style={{ fontWeight: 600 }}>{s.name}</div>
                      <div className="muted mono" style={{ fontSize: 11 }}>{s.uc}</div>
                    </td>
                    <td style={{ fontWeight: 600 }}>{s.vol}</td>
                    <td>
                      <div className="metric-cell">
                        <b>{s.resolve}%</b>
                        <Meter pct={s.resolve} color={s.resolve >= 60 ? "var(--green)" : s.resolve >= 40 ? "var(--blue)" : "var(--orange)"} />
                      </div>
                    </td>
                    <td>
                      {s.hand > 60
                        ? <Status tone="var(--amber)">{s.hand}% 转人工</Status>
                        : <span className="muted">{s.hand}%</span>}
                    </td>
                    <td>
                      <Spark data={s.trend} color={s.resolve >= 60 ? "var(--green)" : "var(--blue)"} />
                    </td>
                    <td>
                      <button className="next-row compact" onClick={() => openTarget(next.section, next.tab)}>
                        <span><b>{next.label}</b><small>{next.next}</small></span>
                        <Badge tone={next.tone}>{next.badge}</Badge>
                      </button>
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        </div>
      )}

      {tab === "anna" && (
        <div className="col" style={{ gap: 16 }}>
          <div className="sec-grid-4">
            {ANNA_IMPACT.map((k, i) => <Stat key={i} {...k} />)}
          </div>
          <div className="card">
            <div className="card-head">
              <Icons.bot s={15} />
              <span className="card-title">按问题查看帮助效果</span>
              <span className="card-sub">直接解决、转人工准备和无法解决</span>
            </div>
            <table className="tbl">
              <thead><tr><th>问题</th><th>会话数</th><th>直接解决</th><th>转人工准备完整</th><th>用户主动转人工</th><th>无法安全解决</th><th>下一步</th></tr></thead>
              <tbody>
                {ANNA_INTENTS.map(r => (
                  <tr key={r.uc}>
                    <td>
                      <div style={{ fontWeight: 600 }}>{r.question}</div>
                      <div className="muted mono" style={{ fontSize: 11 }}>{r.uc} · {r.note}</div>
                    </td>
                    <td style={{ fontWeight: 600 }}>{r.sessions}</td>
                    <td><AnnaMetric value={r.resolved} good={60} warn={40} /></td>
                    <td><AnnaMetric value={r.prepared} good={95} warn={85} /></td>
                    <td>{r.userHandoff >= 30 ? <Status tone="var(--amber)">{r.userHandoff}%</Status> : <span className="muted">{r.userHandoff}%</span>}</td>
                    <td>{r.fallback >= 20 ? <Status tone="var(--red)">{r.fallback}%</Status> : <span className="muted">{r.fallback}%</span>}</td>
                    <td><Badge tone={r.tone}>{r.next}</Badge></td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="sec-2col">
            <div className="card">
              <div className="card-head"><Icons.target s={15} /><span className="card-title">未完成原因</span></div>
              <div className="card-pad anna-health-grid">
                {ANNA_DIAGNOSTICS.map(s => (
                  <div key={s.k} className="dh-tile">
                    <div className="muted" style={{ fontSize: 12 }}>{s.k}</div>
                    <div className="row" style={{ gap: 7, marginTop: 7 }}><Badge tone={s.tone}>{s.v}</Badge></div>
                    <div className="muted" style={{ fontSize: 11.5, marginTop: 7 }}>{s.sub}</div>
                  </div>
                ))}
              </div>
            </div>
            <div className="card card-pad">
              <div className="card-title" style={{ marginBottom: 10 }}>计入帮助的条件</div>
              <div className="formula-card anna-formula">
                <span>直接解决或完成转人工准备</span>
                <b>+</b>
                <span>观察期内没有负向信号</span>
                <strong>计入帮助效果</strong>
              </div>
              <div className="note" style={{ marginTop: 12 }}>
                <Icons.lock s={14} style={{ flexShrink: 0 }} />
                本页统计 Anna 的处理结果；文章、问答和流程覆盖在“知识资产”查看。
              </div>
            </div>
          </div>
          <div className="card">
            <div className="card-head">
              <Icons.doc s={15} />
              <span className="card-title">统计规则</span>
              <span className="card-sub">问题分组和各列的计算方式。</span>
            </div>
            <div className="card-pad anna-counting-grid">
              <div className="anna-counting-block">
                <div className="anna-counting-title">问题分组</div>
                <p>每个 Beacon 会话按最终问题类型分组。结合用户最初问题、Anna 分类、转人工原因和同类问题重新发起，把不同表达合并到同一问题。</p>
                <p>一个会话只在一个问题行中计数一次。内部测试、垃圾会话、重复事件回放和缺少会话 ID 的记录不计入，并在“数据健康”中显示。</p>
              </div>
              <div className="anna-counting-block">
                <div className="anna-counting-title">各列计算</div>
                <ul>
                  <li><b>会话数</b> = Anna 参与处理该问题的会话。</li>
                  <li><b>直接解决</b> = 负向信号窗口结束后的已解决会话 / 会话数。</li>
                  <li><b>转人工准备完整</b> = 摘要包含用户、问题、已采集信息和排查结论的会话 / 转人工会话。</li>
                  <li><b>用户主动转人工</b> = 用户明确要求转人工的会话 / 会话数。</li>
                  <li><b>无法安全解决</b> = 因来源、安全、数据或能力不足而不能继续处理的会话 / 会话数。</li>
                </ul>
              </div>
              <div className="anna-counting-block">
                <div className="anna-counting-title">判定顺序</div>
                <p>信号冲突时按以下顺序归类：无法安全解决 → 用户主动转人工 → 直接解决 → 用户未继续回复。只有直接解决计入已解决。</p>
                <p>下一步提示根据风险、问题量、解决率、重复追问、来源缺口和转人工准备质量给出；它只指向先检查哪一处，不直接决定创建问答。</p>
              </div>
            </div>
          </div>
          <div className="card" style={{ marginTop: 16 }}>
            <div className="card-head"><Icons.doc s={15} /><span className="card-title">高风险回答记录</span><span className="card-sub">需求编号 R9 · 问答或处理流程版本、工具结果类别和最终出口</span></div>
            <table className="tbl">
              <thead><tr><th>会话</th><th>问答 / 处理流程</th><th>工具</th><th>结果类别</th><th>最终出口</th></tr></thead>
              <tbody>
                {R9_AUDIT.map(item => (
                  <tr key={item.id}>
                    <td className="mono">{item.id}</td>
                    <td>{item.asset}</td>
                    <td>{item.tool}</td>
                    <td><Badge tone={item.tone}>{item.result}</Badge></td>
                    <td>{item.exit}</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {tab === "knowledge" && (
        <div>
          <div className="sec-grid-4" style={{ marginBottom: 16 }}>
            {KNOWLEDGE_HEALTH.map((k, i) => <Stat key={i} {...k} />)}
          </div>
          <div className="sec-2col">
            <div className="card">
              <div className="card-head"><Icons.layers s={15} /><span className="card-title">当前内容</span><span className="card-sub">文章、问答和处理流程分别管理</span></div>
              <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 2 }}>
                {KNOWLEDGE_COUNTS.map(item => (
                  <div key={item.label} className="spread rc-row">
                    <div><b style={{ fontSize: 13 }}>{item.label}</b><div className="muted" style={{ fontSize: 11.5, marginTop: 3 }}>{item.note}</div></div>
                    <Badge tone={item.tone}>{item.n.toLocaleString()}</Badge>
                  </div>
                ))}
              </div>
            </div>
            <div className="card">
              <div className="card-head"><Icons.target s={15} /><span className="card-title">待判断问题</span><span className="card-sub">先核对答案依据和风险</span></div>
              <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                {[
                  ["未允许文章或待审核问答用于回答", "已阻断"],
                  ["重复追问", "9.4%"],
                  ["待判断的问题组", "42 个"],
                  ["缺少改动后重新测试", "后续发布条件"],
                ].map((r, i) => (
                  <div key={i} className="spread rc-row" style={{ alignItems: "flex-start" }}>
                    <div style={{ fontWeight: 600, fontSize: 13 }}>{r[0]}</div>
                    <Badge tone={i === 0 || i === 3 ? "green" : "amber"}>{r[1]}</Badge>
                  </div>
                ))}
                <button className="btn primary sm" style={{ alignSelf: "flex-start", marginTop: 2 }} onClick={() => openTarget("train", "review")}><Icons.train s={14} /> 打开常见问答</button>
              </div>
            </div>
          </div>
          <div className="card" style={{ marginTop: 16 }}>
            <div className="card-head">
              <Icons.flag s={15} />
              <span className="card-title">审核待办</span>
              <span className="card-sub">已停用问答、新版本待审稿和回答缺口</span>
              <button className="btn sm ghost" style={{ marginLeft: "auto" }} onClick={() => openTarget("train", "review")}>打开常见问答</button>
            </div>
            <div className="card-pad">
              <div className="attention-list">
                {KNOWLEDGE_REVIEW_TODOS.map(item => (
                  <button key={item.id} className="attention-row" onClick={() => openTarget("train", "review")}>
                    <span className="attention-main">
                      <b>{item.kind} · {item.id}</b>
                      <small>{item.issue} · 已等待 {item.age} · {item.detail}</small>
                    </span>
                    <Badge tone={item.tone}>{item.status}</Badge>
                    <span className="action-cta">{item.action}<Icons.chevR s={14} /></span>
                  </button>
                ))}
              </div>
              <div className="gate red" style={{ marginTop: 12 }}>
                <div className="gate-ico"><Icons.alert s={16} sw={2} /></div>
                <div style={{ flex: 1 }}><b>发布条件即时检查：</b>低风险覆盖下降超过 2 个百分点、任一高频问题覆盖下降超过 5 个百分点，或无法解决上升超过 2 个百分点时，立即进入共享待办并阻止发布，不等待 24 小时。</div>
              </div>
            </div>
          </div>
        </div>
      )}

      {tab === "health" && (
        <div className="col" style={{ gap: 16 }}>
          <div className="sec-grid-3">
            <Stat label="关键连接" val={connectionList.length} unit=" 个" delta="前置自助运行中" up ico="database" />
            <Stat label="异常连接" val={degradedConnections.length} unit=" 个" delta={degradedConnections.length ? "需要处理" : "全部正常"} up={degradedConnections.length === 0} ico="alert" />
            <Stat label="安全规则命中" val={ruleHits} unit=" 次" delta="最近 7 天已拦截" up={false} ico="shield" />
          </div>
          <div className="sec-2col">
            <div className="card">
              <div className="card-head">
                <Icons.database s={15} />
                <span className="card-title">连接运行状态</span>
                <span className="card-sub">健康、调用量和不可用情况</span>
                <button className="btn sm ghost" style={{ marginLeft: "auto" }} onClick={() => openTarget("settings", "integrations")}>管理配置</button>
              </div>
              <table className="tbl">
                <thead><tr><th>连接</th><th>用途</th><th>模式</th><th>调用量</th><th>状态</th></tr></thead>
                <tbody>
                  {connectionList.map(s => (
                    <tr key={s.id}>
                      <td>
                        <div style={{ fontWeight: 600 }}>{s.displayLabel}</div>
                      </td>
                      <td>{s.note}</td>
                      <td className="muted">{s.mode}</td>
                      <td className="mono muted" style={{ fontSize: 11.5 }}>{s.calls}</td>
                      <td><Badge tone={s.health === "ok" ? "green" : "amber"} dot={s.health === "ok" ? "var(--green)" : "var(--amber)"}>{s.health === "ok" ? "正常" : "不可用"}</Badge></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
            <div className="card">
              <div className="card-head"><Icons.shield s={15} /><span className="card-title">安全规则命中</span><span className="card-sub">最近 7 天</span></div>
              <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 9 }}>
                {activeRuleHits.slice(0, 5).map(r => (
                  <div key={r.id} className="spread rc-row">
                    <span>
                      <b className="mono" style={{ fontSize: 11.5 }}>{r.id}</b>
                      <span style={{ marginLeft: 8 }}>{r.name}</span>
                    </span>
                    <Badge tone={r.sev === "critical" ? "red" : "amber"}>{r.hits} 次已拦截</Badge>
                  </div>
                ))}
                <div className="note"><Icons.shield s={13} style={{ flexShrink: 0 }} /> 本页看命中量；规则验证和发布阻断在“测试”处理。</div>
                <button className="btn primary sm" style={{ alignSelf: "flex-start" }} onClick={() => openTarget("test", "safety")}><Icons.flask s={13} /> 打开安全规则测试</button>
              </div>
            </div>
          </div>
        </div>
      )}

      {tab === "quality" && (
        rq ? <ReviewDetail item={rq} onBack={() => setRq(null)} />
        : (
          <div className="col" style={{ gap: 16 }}>
            <div className="sec-grid-3">
              <Stat label="需要修复" val={qualityCounts.needsFix} delta="送往训练" up={false} ico="flag" />
              <Stat label="红线检查" val={qualityCounts.redline} delta="一票否决" up={false} ico="shield" />
              <Stat label="已通过" val={qualityCounts.passed} delta="安全样例" up ico="checkCircle" />
            </div>
            <div className="card">
              <div className="card-head"><Icons.flag s={15} /><span className="card-title">质检队列</span><span className="card-sub">红线失败即阻断</span></div>
              <table className="tbl">
                <thead><tr><th>样本</th><th>原因</th><th>红线</th><th>结果</th><th>状态</th><th></th></tr></thead>
                <tbody>
                  {REVIEW_QUEUE.map(r => (
                    <tr key={r.id} style={{ cursor: "pointer" }} onClick={() => setRq(r)}>
                      <td><div className="mono" style={{ fontSize: 12 }}>{r.id}</div><div className="muted mono" style={{ fontSize: 11 }}>{r.uc}</div></td>
                      <td>{r.reason}</td>
                      <td>{r.redline ? <Redline>{r.redline}</Redline> : <span className="muted">—</span>}</td>
                      <td>{r.score === "—" ? <span className="muted">待质检</span> : <b style={{ color: r.score === "0" ? "var(--red)" : r.score === "2" ? "var(--green)" : "var(--ink)" }}>{r.score} / 2</b>}</td>
                      <td>{
                        r.state === "needs-fix" ? <Badge tone="red" dot="var(--red)">需要修复</Badge>
                        : r.state === "reviewing" ? <Badge tone="amber" dot="var(--amber)">质检中</Badge>
                        : <Badge tone="green" dot="var(--green)">已通过</Badge>
                      }</td>
                      <td><Icons.chevR s={15} className="muted" /></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            </div>
          </div>
        )
      )}

      {tab === "outcome" && (
        <div className="col" style={{ gap: 16 }}>
          <div className="sec-2col">
            <div className="card">
              <div className="card-head"><span className="card-title">处理结果</span><span className="card-sub">只有 Anna 直接解决计入已解决。</span></div>
              <div className="card-pad">
                {OUTCOMES.map((o, i) => (
                  <div key={i} style={{ marginBottom: 16 }}>
                    <div className="spread" style={{ marginBottom: 6 }}>
                      <span style={{ fontWeight: 500, fontSize: 13 }}><span className="dot-sq" style={{ background: o.color }}></span> {o.k}</span>
                      <span className="muted" style={{ fontSize: 12.5 }}><b style={{ color: "var(--ink)" }}>{o.n.toLocaleString()}</b> · {o.pct}%</span>
                    </div>
                    <Meter pct={o.pct} color={o.color} />
                  </div>
                ))}
              </div>
            </div>
            <div className="col" style={{ gap: 16 }}>
              <div className="card card-pad">
                <div className="card-title" style={{ marginBottom: 10 }}>解决率公式</div>
                <div className="formula-card">
                  <span>Anna 直接解决会话</span>
                  <b>÷</b>
                  <span>Anna 已参与的 Beacon 会话</span>
                  <strong>= Anna 直接解决率</strong>
                </div>
                <div className="note" style={{ marginTop: 12 }}><Icons.lock s={14} style={{ flexShrink: 0 }} /> 转人工、用户未继续回复和无法安全解决均不计为已解决。</div>
              </div>
              <div className="outcome-mini-grid">
              <div className="card card-pad">
                <div className="muted" style={{ fontSize: 12.5 }}>预计节省人工时间</div>
                <div className="stat-val" style={{ marginTop: 6 }}>3,180<span className="unit"> 分钟/周</span></div>
                <div className="muted" style={{ marginTop: 6, fontSize: 11.5 }}>改动前参考：人工平均处理 13 分钟。</div>
              </div>
              <div className="card card-pad">
                  <div className="muted" style={{ fontSize: 12.5 }}>可用回答依据覆盖率</div>
                  <div className="spread" style={{ marginTop: 10 }}>
                    <span style={{ fontSize: 13 }}>高频问题</span><b>71%</b>
                  </div>
                  <Meter pct={71} color="var(--blue)" />
                </div>
              </div>
            </div>
          </div>
          <div className="sec-2col">
            <div className="card">
              <div className="card-head"><Icons.target s={15} /><span className="card-title">未解决诊断</span><span className="card-sub">回流训练与测试</span></div>
              <div className="card-pad" style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                {OUTCOME_DIAGNOSTICS.map(d => (
                  <button key={d.label} className="next-row" onClick={() => openTarget(d.section, d.tab)}>
                    <span>
                      <b>{d.label}</b>
                      <small>{d.next}</small>
                    </span>
                    <Badge tone={d.tone}>{d.value}</Badge>
                  </button>
                ))}
              </div>
            </div>
            <div className="card">
              <div className="card-head"><span className="card-title">客户旅程</span><span className="card-sub">仅统计 Beacon 前置入口</span></div>
              <div className="card-pad">
                <Funnel rows={[
                  { label: "进入聊天窗口", n: 8420, pct: 100 },
                  { label: "Anna 已参与", n: 8100, pct: 96 },
                  { label: "Anna 直接解决", n: 4243, pct: 50 },
                  { label: "总转人工", n: 2680, pct: 32 },
                  { label: "静默离开", n: 1177, pct: 14 },
                ]} />
              </div>
            </div>
          </div>
          <details className="card metric-details">
            <summary><span><Icons.target s={15} /> 统计规则</span><small>与总览图表一致</small></summary>
            <div className="measurement-grid">
              {OUTCOME_MEASUREMENT.map(m => (
                <div key={m.k} className="measurement-tile">
                  <div className="measurement-key">{m.k}</div>
                  <div className="measurement-val">{m.v}</div>
                  <div className="measurement-desc">{m.d}</div>
                </div>
              ))}
            </div>
          </details>
          <div className="card">
            <div className="card-head"><Icons.layers s={15} /><span className="card-title">结果规则</span><span className="card-sub">数字的计入与排除条件</span></div>
            <table className="tbl">
              <thead><tr><th>结果分类</th><th>计入条件</th><th>排除条件</th><th>修复路径</th></tr></thead>
              <tbody>
                {OUTCOME_DEFINITIONS.map(d => (
                  <tr key={d.k}>
                    <td style={{ fontWeight: 600 }}>{d.k}</td>
                    <td>{d.includes}</td>
                    <td>{d.excludes}</td>
                    <td>
                      <button className="next-row compact" onClick={() => openTarget(d.section, d.tab)}>
                        <span><b>{d.action}</b><small>{d.fix}</small></span>
                        <Icons.chevR s={14} />
                      </button>
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          </div>
          <div className="card">
            <div className="card-head"><span className="card-title">数据健康</span><span className="card-sub">这些数字使用的输入数据</span></div>
            <div className="card-pad sec-grid-4" style={{ gap: 14 }}>
              {[
                { k: "事件接入", v: "正常", tone: "green" },
                { k: "转人工摘要数据", v: "完整率 98.7%", tone: "green" },
                { k: "风险信号", v: "不可用", tone: "amber", sub: "研发标识：risk-mcp" },
                { k: "旅程匹配", v: "次日已同步", tone: "green" },
              ].map((d, i) => (
                <div key={i} className="dh-tile">
                  <div className="muted" style={{ fontSize: 12 }}>{d.k}</div>
                  <div className="row" style={{ gap: 7, marginTop: 6 }}><Badge tone={d.tone} dot={d.tone === "green" ? "var(--green)" : "var(--amber)"}>{d.v}</Badge></div>
                  {d.sub ? <div className="muted mono" style={{ fontSize: 11, marginTop: 6 }}>{d.sub}</div> : null}
                </div>
              ))}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

/* ---- Review detail (scorecard + evidence) ---- */
function ReviewDetail({ item, onBack }) {
  const { Badge, Redline } = window;
  const Icons = window.Icons;
  const openTarget = (section, nextTab) => window.BeaconNav?.go(section, nextTab ? { tab: nextTab } : {});
  return (
    <div className="fadein">
      <button className="btn sm ghost" onClick={onBack} style={{ marginBottom: 14 }}><Icons.chevR s={14} style={{ transform: "rotate(180deg)" }} /> 返回质检队列</button>
      <div className="sec-2col">
        <div className="card">
          <div className="card-head"><span className="card-title">质检评分 · {item.id}</span>{item.critical ? <Redline>一票否决</Redline> : null}</div>
          <div className="card-pad">
            {[
              { c: "回答有可靠依据", h: "陈述与当前文章、已发布问答、处理流程或工具事实一致。", v: item.redline === "忠实性" ? 0 : 2 },
              { c: "遵守红线（禁止披露 / 链上不可逆）", v: item.redline === "禁止披露" ? 0 : 2 },
              { c: "正确转人工并提供完整摘要", v: 2 },
              { c: "语气和语言匹配", v: 2 },
            ].map((s, i) => (
              <div key={i} className="spread sc-row">
                <span style={{ fontSize: 13 }}>{s.c}{s.h ? <small>{s.h}</small> : null}</span>
                <Badge tone={s.v === 0 ? "red" : s.v === 1 ? "amber" : "green"}>{s.v} / 2</Badge>
              </div>
            ))}
            {item.critical && (
              <div className="gate red" style={{ marginTop: 14 }}>
                <div className="gate-ico"><Icons.alert s={17} sw={2} /></div>
                <div style={{ flex: 1, fontWeight: 500 }}>任一红线项得 0 分都会阻断会话。必须先送往训练修复，才能通过。</div>
              </div>
            )}
          </div>
        </div>
        <div className="card">
          <div className="card-head"><span className="card-title">证据</span></div>
          <div className="card-pad">
            <div className="ev-msg ai">“……延迟是因为我们内部正在调整热钱包流动性。”</div>
            <div className="note" style={{ margin: "10px 0" }}><Icons.x s={14} style={{ color: "var(--red)", flexShrink: 0 }} /> 泄露了隐藏原因。面向客户只能说明“处理中”或“正在复核”。</div>
            <hr className="hr" />
            <dl className="kv">
              <dt>状态流转</dt><dd>待处理 → 质检中 → <b style={{ color: "var(--red)" }}>需要修复</b></dd>
              <dt>质检人</dt><dd>{item.reviewer}</dd>
              <dt>关联处理流程</dt><dd className="mono">kyc-under-review v5</dd>
            </dl>
            <button className="btn primary sm" style={{ marginTop: 14 }} onClick={() => openTarget("train", "skills")}><Icons.train s={14} /> 前往训练修复</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function AnnaMetric({ value, good, warn }) {
  const color = value >= good ? "var(--green)" : value >= warn ? "var(--amber)" : "var(--red)";
  return (
    <div className="metric-cell anna-metric">
      <b>{value}%</b>
      <window.Meter pct={value} color={color} />
    </div>
  );
}

/* ---- small charts ---- */
function TrendChart({ series, target }) {
  const W = 380, H = 188, mL = 34, mR = 12, mT = 12, mB = 26;
  const pw = W - mL - mR, ph = H - mT - mB;
  const max = 60, min = 30;                       // fixed band for the 50–55% target zone
  const xLabels = ["5月26日","27日","28日","29日","30日","31日","6月1日"];
  const x = i => mL + (i / (series.length - 1)) * pw;
  const y = v => mT + ph - ((v - min) / (max - min)) * ph;
  const pts = series.map((v, i) => [x(i), y(v)]);
  const line = pts.map((p, i) => (i ? "L" : "M") + p[0].toFixed(1) + " " + p[1].toFixed(1)).join(" ");
  const area = line + ` L ${x(series.length-1)} ${mT+ph} L ${mL} ${mT+ph} Z`;
  const grid = [30,40,50,60];
  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{ width: "100%", height: "auto", display: "block" }}>
      <defs><linearGradient id="tg" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stopColor="#03B2BD" stopOpacity=".18" /><stop offset="1" stopColor="#03B2BD" stopOpacity="0" /></linearGradient></defs>
      {/* target band 50–55 */}
      <rect x={mL} y={y(55)} width={pw} height={y(50)-y(55)} fill="#13C287" opacity="0.07" />
      {grid.map(g => (
        <g key={g}>
          <line x1={mL} y1={y(g)} x2={W-mR} y2={y(g)} stroke="#E8E8E9" strokeWidth="1" />
          <text x={mL-7} y={y(g)+3} textAnchor="end" fontSize="9.5" fill="#B0B0B0" fontFamily="Alexandria">{g}%</text>
        </g>
      ))}
      <line x1={mL} y1={y(50)} x2={W-mR} y2={y(50)} stroke="#13C287" strokeWidth="1" strokeDasharray="3 3" opacity="0.6" />
      <text x={W-mR} y={y(50)-5} textAnchor="end" fontSize="9.5" fill="#13C287" fontFamily="Alexandria" fontWeight="600">目标 50%</text>
      <path d={area} fill="url(#tg)" />
      <path d={line} fill="none" stroke="#03B2BD" strokeWidth="2" strokeLinejoin="round" strokeLinecap="round" />
      {pts.map((p, i) => <circle key={i} cx={p[0]} cy={p[1]} r={i===pts.length-1?3.5:2.2} fill="#fff" stroke="#03B2BD" strokeWidth={i===pts.length-1?2.5:1.5} />)}
      {xLabels.map((l, i) => <text key={i} x={x(i)} y={H-8} textAnchor="middle" fontSize="9" fill="#B0B0B0" fontFamily="Alexandria">{l}</text>)}
    </svg>
  );
}

function Funnel({ rows }) {
  return (
    <div>
      {rows.map((r, i) => (
        <div key={i} style={{ marginBottom: 11 }}>
          <div className="spread" style={{ marginBottom: 4 }}>
            <span style={{ fontSize: 12.5, fontWeight: 500 }}>{r.label}</span>
            <span className="muted" style={{ fontSize: 12 }}>{r.n.toLocaleString()} · {r.pct}%</span>
          </div>
          <div className="funnel-bar"><i style={{ width: r.pct + "%", background: i === rows.length - 1 ? "var(--orange)" : "var(--blue)" }}></i></div>
        </div>
      ))}
    </div>
  );
}

function OutcomeStackedBars({ rows }) {
  const segments = [
    ["resolved", "var(--green)", "直接解决"],
    ["handoff", "var(--blue)", "转人工"],
    ["dropoff", "var(--amber)", "静默离开"],
    ["fallback", "var(--red)", "无法安全解决"],
  ];
  return (
    <div className="outcome-stack">
      {rows.map(r => (
        <div className="outcome-stack-row" key={r.m}>
          <div className="outcome-stack-label">{r.m}</div>
          <div className="outcome-stack-bar" aria-label={`${r.m}处理结果分布`}>
            {segments.map(([key, color, label]) => (
              <i key={key} style={{ width: r[key] + "%", background: color }} title={`${label}：${r[key]}%`}></i>
            ))}
          </div>
          <div className="outcome-stack-value">{r.resolved}%</div>
        </div>
      ))}
    </div>
  );
}

window.AnalyzeView = AnalyzeView;
