(()=>{
// === Technical pipeline screens (judge view) ===
const { Card: TCard, Btn: TBtn, Badge: TBadge, Kicker: TKicker, SectionHeader: TSection, StatTile: TStat, KV: TKV } = window.UI;
const { OralImage: TOral, ColorChecker: TCC, LabScatter, FeatureRadar, ArchPipeline, ShapWaterfall: TShap } = window.Viz;
const { FEATURES, PIPELINE, COLOR_PATCHES, SHAP_DIABETES, BASE_LOG_ODDS } = window.DATA;

// ---------- 01: Architecture ----------
const TechArch = () => (
  <div className="fade-in space-y-6">
    <TSection kicker="Technical View · 01" title="系统总体架构" sub="ChronicSense 采用 4 阶段流水线设计。核心工程贡献是 色彩标准化模块 与 可解释特征工程，这两点是与 CNN / ViT 端到端方案的差异化所在。"/>

    <TCard title="4 阶段推理流水线" kicker="End-to-End Pipeline">
      <ArchPipeline/>
      <div className="mt-6 grid grid-cols-4 gap-3 text-xs">
        <div className="card-tight p-3">
          <div className="text-ink-500">阶段 01 输出</div>
          <div className="font-mono mt-1">image_d65.jpg, mask_card.png<br/>ΔE76 ≤ 3.0</div>
        </div>
        <div className="card-tight p-3">
          <div className="text-ink-500">阶段 02 输出</div>
          <div className="font-mono mt-1">mask_gum.png, mask_tongue.png<br/>mask_mucosa.png · IoU≈0.91</div>
        </div>
        <div className="card-tight p-3">
          <div className="text-ink-500">阶段 03 输出</div>
          <div className="font-mono mt-1">feature_vec[20] (LAB+HSV+texture)</div>
        </div>
        <div className="card-tight p-3">
          <div className="text-ink-500">阶段 04 输出</div>
          <div className="font-mono mt-1">{`{dm:0.72, cv:0.45, kd:0.18, an:0.12}`}<br/>+ SHAP values</div>
        </div>
      </div>
    </TCard>

    <div className="grid grid-cols-2 gap-5">
      <TCard title="数据集划分" kicker="Datasets">
        <div className="space-y-0">
          <TKV k="训练集" v={`${PIPELINE.trainSamples} 例 (71.6%)`}/>
          <TKV k="验证集" v={`${PIPELINE.valSamples} 例 (17.9%)`}/>
          <TKV k="测试集" v={`${PIPELINE.testSamples} 例 (10.5%)`}/>
          <TKV k="标签来源" v="医院 HIS 系统 (脱敏)"/>
          <TKV k="标签类型" v="HbA1c / 颈动脉超声 / eGFR / Hb"/>
          <TKV k="阳性比例" v="DM 28% · CV 22% · KD 9% · AN 14%"/>
          <TKV k="年龄分布" v="40–82 岁 (μ=58.4)"/>
        </div>
      </TCard>

      <TCard title="与基线方案对比" kicker="vs CNN / ViT">
        <table className="w-full text-xs">
          <thead>
            <tr className="text-left text-ink-500 border-b border-ink-100">
              <th className="py-2 font-medium">方法</th>
              <th className="font-medium">DM AUC</th>
              <th className="font-medium">推理 ms</th>
              <th className="font-medium">参数量</th>
              <th className="font-medium">可解释性</th>
            </tr>
          </thead>
          <tbody>
            {Object.entries(PIPELINE.baseline).map(([k,v],i)=>(
              <tr key={i} className={`border-b border-ink-100 last:border-0 ${k.includes("Ours")?"bg-clinic-50":""}`}>
                <td className="py-2 font-medium">{k.includes("Ours")?"✦ "+k:k}</td>
                <td className="num">{v.dm}</td>
                <td className="num">{v.ms}</td>
                <td className="num">{v.params}</td>
                <td>{v.interp}</td>
              </tr>
            ))}
          </tbody>
        </table>
        <div className="text-[11px] text-ink-500 mt-3">在 AUC 略升的同时，推理速度提升 ~13× / ~20×，参数量降低 2 个数量级，且具备 SHAP 实例级解释，更适合面向终端用户的健康应用。</div>
      </TCard>
    </div>

    <TCard title="差异化定位" kicker="Why This Works">
      <div className="grid grid-cols-3 gap-4 text-sm">
        {[
          {n:"01", t:"绕开端到端黑盒", d:"CNN / ViT 直接输入像素 → 输出概率，光照与设备差异成为最大噪声源。我们用色彩校正解耦了这部分变化。"},
          {n:"02", t:"特征即临床指标", d:"a*、b*、L*、HSV 饱和度、纹理熵都有明确的临床对应物，便于撰写报告、医生审核、面向老年用户解释。"},
          {n:"03", t:"易于增量更新", d:"XGBoost 模型仅 0.12M 参数，单家医院数据即可微调。换 ViT 需要数千例新标签。"},
        ].map(b=>(
          <div key={b.n} className="border border-ink-200 rounded p-4">
            <div className="num text-xs text-clinic-600 font-semibold">{b.n}</div>
            <div className="text-sm font-semibold mt-2">{b.t}</div>
            <div className="text-xs text-ink-500 mt-2 leading-relaxed">{b.d}</div>
          </div>
        ))}
      </div>
    </TCard>
  </div>
);

// ---------- 02: SAM2 segmentation ----------
const TechSAM2 = () => (
  <div className="fade-in space-y-6">
    <TSection kicker="Technical View · 02" title="SAM2 ROI 分割" sub="使用 SAM2 (Segment Anything 2) 在口腔图像上自动定位 3 个 ROI 区域。我们用 prompt-engineering 引导，而非端到端分类。"/>

    <div className="grid grid-cols-2 gap-5">
      <TCard title="原始图像 → ROI 分割 mask" kicker="Side-by-side">
        <div className="grid grid-cols-2 gap-3">
          <div>
            <div className="text-[10px] text-ink-500 num mb-1">RAW (after color norm)</div>
            <div className="rounded overflow-hidden border border-ink-200"><TOral width={300} height={210} raw={true}/></div>
          </div>
          <div>
            <div className="text-[10px] text-ink-500 num mb-1">SAM2 OUTPUT</div>
            <div className="rounded overflow-hidden border border-ink-200 relative">
              <TOral width={300} height={210} showMask={true} showROI={false}/>
              <div className="absolute inset-x-0 bottom-0 bg-black/50 text-white text-[10px] num py-1 px-2 flex justify-between">
                <span>3 ROI · IoU 0.912</span><span>142 ms / CPU</span>
              </div>
            </div>
          </div>
        </div>
        <div className="grid grid-cols-3 gap-3 mt-4">
          {[
            { c:"#E66B7A", k:"牙龈", iou:0.928, area:"18.2%" },
            { c:"#C24B5B", k:"舌面", iou:0.901, area:"34.1%" },
            { c:"#D88EA0", k:"黏膜", iou:0.906, area:"10.7%" },
          ].map(r=>(
            <div key={r.k} className="card-tight p-3">
              <div className="flex items-center gap-2">
                <span className="w-2.5 h-2.5 rounded-sm" style={{background:r.c}}/>
                <span className="text-sm font-medium">{r.k}</span>
              </div>
              <div className="num text-xs text-ink-500 mt-2">IoU {r.iou} · 面积比 {r.area}</div>
            </div>
          ))}
        </div>
      </TCard>

      <TCard title="Prompt 工程策略" kicker="Inputs to SAM2">
        <div className="space-y-3 text-sm">
          <div className="border-l-2 border-clinic-500 pl-3">
            <div className="font-medium">几何先验提示</div>
            <div className="text-xs text-ink-500 mt-1">检测口腔椭圆轮廓 → 用 9 个 grid points 作为 SAM2 的 point prompt，3 个分别落在牙龈带、舌面中心与左右黏膜上。</div>
          </div>
          <div className="border-l-2 border-clinic-500 pl-3">
            <div className="font-medium">颜色先验过滤</div>
            <div className="text-xs text-ink-500 mt-1">SAM2 输出多个 candidate masks，使用 HSV 色相分布筛选：牙龈 hue ∈ 350°~10°（红），舌面 hue ∈ 0°~20° 且饱和度高，黏膜介于两者之间。</div>
          </div>
          <div className="border-l-2 border-clinic-500 pl-3">
            <div className="font-medium">形态学后处理</div>
            <div className="text-xs text-ink-500 mt-1">闭运算 (kernel=5) 填充齿缝带来的牙龈断裂；开运算移除舌苔区中的孤立小岛。</div>
          </div>
        </div>

        <div className="mt-5 bg-ink-50 rounded-md p-3 font-mono text-[11px] text-ink-700 leading-relaxed">
          <div className="text-clinic-700"># sam2_inference.py</div>
          <div>predictor = SAM2ImagePredictor(<span className="text-mint-700">"sam2_hiera_tiny"</span>)</div>
          <div>predictor.set_image(img_d65)</div>
          <div>masks, scores, _ = predictor.predict(</div>
          <div>  point_coords=oral_grid_9pts,</div>
          <div>  point_labels=[1]*9,</div>
          <div>  multimask_output=<span className="text-mint-700">True</span>)</div>
          <div>roi = filter_by_color_prior(masks, hsv)</div>
        </div>
      </TCard>
    </div>

    <TCard title="与 OralVision (诊断任务) 的区别" kicker="Disambiguation">
      <table className="w-full text-sm">
        <thead>
          <tr className="border-b border-ink-100 text-left text-xs text-ink-500">
            <th className="py-2 font-medium">维度</th>
            <th className="font-medium">OralVision · 病变诊断</th>
            <th className="font-medium">慢病先知 · 慢病早筛</th>
          </tr>
        </thead>
        <tbody>
          {[
            ["输入", "病变区域局部特写", "整体口腔健康照片"],
            ["SAM2 用途", "边缘引导，精细分割病变轮廓", "粗粒度定位 3 个解剖区域"],
            ["输出", "病变类别 (溃疡 / 白斑 / …)", "4 个系统性慢病风险概率"],
            ["决策器", "ViT 分类头", "XGBoost (20 维特征)"],
            ["可解释性", "Grad-CAM 病变热图", "SHAP 特征贡献"],
          ].map((row,i)=>(
            <tr key={i} className="border-b border-ink-100 last:border-0">
              <td className="py-2 text-ink-500">{row[0]}</td>
              <td>{row[1]}</td>
              <td className="font-medium">{row[2]}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </TCard>
  </div>
);

// ---------- 03: Color normalization ----------
const TechColor = () => {
  // simulated before/after clusters in LAB a-b plane
  const before = [
    {a:14,b:8,r:5},{a:21,b:13,r:5},{a:16,b:11,r:5},{a:9,b:6,r:5},{a:23,b:15,r:5},
    {a:18,b:10,r:5},{a:12,b:7,r:5},{a:25,b:16,r:5},
  ];
  const after = [
    {a:14.2,b:9.8,r:5},{a:14.5,b:10.1,r:5},{a:13.9,b:9.6,r:5},{a:14.3,b:10.0,r:5},
    {a:14.1,b:9.7,r:5},{a:14.4,b:9.9,r:5},{a:14.2,b:9.8,r:5},{a:14.0,b:9.5,r:5},
  ];
  return (
    <div className="fade-in space-y-6">
      <TSection kicker="Technical View · 03" title="色彩标准化模块" sub="不同手机、不同光照下，同一个牙龈区域的 LAB 颜色值差异可达 ΔE76 = 18+。这是端到端方案最大的噪声源。我们用色卡 + 仿射变换把它压到 ≤ 3.0。"/>

      <div className="grid grid-cols-5 gap-5">
        <TCard title="校正前后 LAB 偏移" kicker="a*–b* Plane" className="col-span-3">
          <LabScatter before={before} after={after} width={500} height={300}/>
          <div className="grid grid-cols-2 gap-3 mt-3 text-xs">
            <div className="flex items-center gap-2"><span className="w-3 h-3 bg-ink-300 rounded-full border border-ink-500"/>校正前：8 部手机 / 4 种光照下的同一牙龈样本</div>
            <div className="flex items-center gap-2"><span className="w-3 h-3 bg-clinic-500 rounded-full border border-clinic-700"/>校正后：归一化到 D65，σ &lt; 0.5</div>
          </div>
        </TCard>

        <TCard title="校正前后 ΔE76" kicker="Metric" className="col-span-2">
          <div className="space-y-4">
            <DeltaBar label="校正前" value={PIPELINE.colorDeltaE_before} max={25} color="#C9342B"/>
            <DeltaBar label="校正后" value={PIPELINE.colorDeltaE_after} max={25} color="#0E8367"/>
            <div className="text-[11px] text-ink-500 leading-relaxed">
              ΔE76 是 CIE 颜色差度量。&lt; 3 为肉眼难辨差异，&gt; 6 显著可见。我们将分布从 18.4 压缩到 2.7，
              <span className="text-clinic-700 font-medium"> 提升 6.8×</span>。
            </div>
          </div>
        </TCard>
      </div>

      <div className="grid grid-cols-2 gap-5">
        <TCard title="色卡检测" kicker="X-Rite 24 Patches">
          <div className="flex gap-5 items-center">
            <div><TCC size={150}/></div>
            <div className="flex-1 text-xs space-y-2 text-ink-600">
              <div>1. YOLOv8-n 检测色卡 bbox (mAP 0.97)</div>
              <div>2. 透视变换矫正为 4×6 网格</div>
              <div>3. 每个色块取中心 5×5 像素均值 → 实测 LAB</div>
              <div>4. 与标准 LAB (D65) 配对，得 24 组对应点</div>
            </div>
          </div>
        </TCard>

        <TCard title="LAB 仿射变换" kicker="3×3 Matrix + bias">
          <div className="font-mono text-[11px] text-ink-700 bg-ink-50 rounded p-3 leading-relaxed">
            <div className="text-ink-500"># minimize Σ‖M·lab_i + b − lab_ref_i‖²</div>
            <div>M = [[ 0.987, -0.012,  0.008],</div>
            <div>     [ 0.024,  1.041, -0.031],</div>
            <div>     [-0.009,  0.018,  0.962]]</div>
            <div>b = [ 1.84, -0.73, 2.19 ]</div>
            <div className="text-mint-700 mt-2">R² = 0.987 · residual μ = 1.8</div>
          </div>
          <div className="text-[11px] text-ink-500 mt-3">无色卡时使用环境光传感器 (lux + CCT) 查表得到先验仿射，精度损失约 25%。</div>
        </TCard>
      </div>
    </div>
  );
};

const DeltaBar = ({ label, value, max, color }) => (
  <div>
    <div className="flex items-center justify-between text-xs">
      <span className="text-ink-600 font-medium">{label}</span>
      <span className="num text-ink-900">ΔE = {value.toFixed(1)}</span>
    </div>
    <div className="h-3 rounded-full bg-ink-100 mt-2 overflow-hidden">
      <div className="h-full rounded-full" style={{width:`${(value/max)*100}%`, background:color}}/>
    </div>
    <div className="flex justify-between text-[10px] num text-ink-400 mt-1">
      <span>0</span><span>3 (难辨)</span><span>6 (可见)</span><span>{max}</span>
    </div>
  </div>
);

// ---------- 04: Feature engineering ----------
const TechFeatures = () => (
  <div className="fade-in space-y-6">
    <TSection kicker="Technical View · 04" title="20 维可解释特征" sub="每个 ROI 提取 6–8 个特征。颜色特征在 LAB 与 HSV 双空间提取，纹理特征用 GLCM 熵。每一维都对应一个临床指标。"/>

    <div className="grid grid-cols-5 gap-5">
      <TCard title="特征雷达图" kicker="Patient vs Reference" className="col-span-2">
        <FeatureRadar features={FEATURES} size={360}/>
        <div className="flex justify-center gap-4 text-xs mt-2">
          <span className="flex items-center gap-1"><span className="w-2 h-2 bg-clinic-500"/>本次实测</span>
          <span className="flex items-center gap-1"><span className="w-2 h-2 bg-clinic-200 border border-clinic-300"/>正常区间 (z=0)</span>
          <span className="flex items-center gap-1"><span className="w-2 h-2 bg-risk-high"/>异常 (|z|&gt;1.5)</span>
        </div>
      </TCard>

      <TCard title="完整特征表" kicker="20 dims" className="col-span-3">
        <div className="max-h-[420px] overflow-y-auto">
          <table className="w-full text-xs">
            <thead className="sticky top-0 bg-white">
              <tr className="text-left text-ink-500 border-b border-ink-100">
                <th className="py-2 font-medium pr-2">#</th>
                <th className="font-medium">区域</th>
                <th className="font-medium">特征</th>
                <th className="font-medium text-right pr-2">实测值</th>
                <th className="font-medium">参考</th>
                <th className="font-medium text-right">z-score</th>
              </tr>
            </thead>
            <tbody>
              {FEATURES.map((f,i)=>(
                <tr key={i} className="border-b border-ink-100 last:border-0 hover:bg-ink-50">
                  <td className="py-1.5 num text-ink-400 pr-2">{String(i+1).padStart(2,"0")}</td>
                  <td><TBadge color={f.group==="牙龈"?"red":f.group==="舌面"?"amber":"blue"}>{f.group}</TBadge></td>
                  <td>{f.name}</td>
                  <td className="num text-right pr-2 font-medium">{typeof f.value==="number"&&f.value<1&&f.value>0?f.value.toFixed(3):f.value}</td>
                  <td className="num text-ink-500">{f.ref}</td>
                  <td className={`num text-right font-medium ${Math.abs(f.z)>1.5?"text-risk-high":Math.abs(f.z)>1?"text-risk-mid":"text-ink-700"}`}>
                    {f.z>0?"+":""}{f.z.toFixed(2)}
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </TCard>
    </div>

    <TCard title="特征 → 临床含义映射" kicker="Clinical Mapping">
      <div className="grid grid-cols-3 gap-4 text-sm">
        {[
          { f:"L* 通道均值", c:"组织明度，反映血液灌注 / 苍白", d:"黏膜 L* 高 → 贫血风险", ico:"droplet" },
          { f:"a* 通道均值", c:"红绿轴，对应血红蛋白浓度", d:"牙龈 a* 高 → 牙周炎症 / 糖尿病", ico:"pulse" },
          { f:"b* 通道均值", c:"黄蓝轴，对应胆红素 / 尿素代谢", d:"舌面 b* 高 → 肾病 / 黄疸", ico:"kidney" },
          { f:"HSV 饱和度", c:"色彩饱和度（与 a* 互补）", d:"鲜艳的红 → 急性炎症", ico:"spark" },
          { f:"GLCM 纹理熵", c:"灰度共生矩阵熵，越大越无序", d:"牙龈失去 stippling 表面粗糙", ico:"layers" },
          { f:"ROI 面积比", c:"分割区域 / 整图面积", d:"舌体肿胀 / 萎缩参考", ico:"target" },
        ].map((m,i)=>(
          <div key={i} className="card-tight p-4">
            <div className="flex items-center gap-2"><Icon name={m.ico} size={14} className="text-clinic-600"/><span className="text-sm font-medium">{m.f}</span></div>
            <div className="text-xs text-ink-600 mt-2">{m.c}</div>
            <div className="text-xs text-clinic-700 mt-2 italic">→ {m.d}</div>
          </div>
        ))}
      </div>
    </TCard>
  </div>
);

// ---------- 05: XGBoost + SHAP ----------
const TechXGB = () => (
  <div className="fade-in space-y-6">
    <TSection kicker="Technical View · 05" title="XGBoost 多标签预测 + SHAP 解释" sub="4 个独立的 XGBoost 二分类器，每个有自己的正负样本权重与早停策略。SHAP TreeExplainer 在 0.4 ms 内给出实例级解释。"/>

    <div className="grid grid-cols-5 gap-5">
      <TCard title="4 个二分类模型的 AUC" kicker="Validation" className="col-span-2">
        <div className="space-y-4 mt-2">
          {Object.entries(PIPELINE.xgbAUC).map(([k,v])=>{
            const labelMap = {diabetes:"糖尿病 DM", cv:"心血管 CV", kidney:"肾病 KD", anemia:"贫血 AN"};
            return (
              <div key={k}>
                <div className="flex justify-between text-xs">
                  <span className="font-medium">{labelMap[k]}</span>
                  <span className="num text-ink-700">{v.toFixed(3)}</span>
                </div>
                <div className="h-2 rounded-full bg-ink-100 mt-1.5 overflow-hidden">
                  <div className="h-full rounded-full bg-clinic-600 shap-bar" style={{width:`${v*100}%`}}/>
                </div>
              </div>
            );
          })}
        </div>
        <div className="mt-5 pt-4 border-t border-ink-100 grid grid-cols-2 gap-3 text-xs">
          <div><div className="text-ink-500">超参数</div><div className="num mt-1">depth=6 · η=0.05 · n=400</div></div>
          <div><div className="text-ink-500">早停 round</div><div className="num mt-1">50 (val_loss)</div></div>
          <div><div className="text-ink-500">类不平衡</div><div className="num mt-1">scale_pos_weight = neg/pos</div></div>
          <div><div className="text-ink-500">校准</div><div className="num mt-1">Platt scaling</div></div>
        </div>
      </TCard>

      <TCard title="SHAP 瀑布图 (糖尿病模型)" kicker="Instance Explanation" className="col-span-3">
        <TShap items={SHAP_DIABETES} base={BASE_LOG_ODDS} width={620} height={360}/>
      </TCard>
    </div>

    <div className="grid grid-cols-2 gap-5">
      <TCard title="混淆矩阵 (DM, 测试集)" kicker="Confusion Matrix">
        <ConfusionMatrix tn={361} fp={28} fn={19} tp={118}/>
        <div className="grid grid-cols-4 gap-3 mt-4 text-xs">
          <div><div className="text-ink-500">准确率</div><div className="num font-medium">0.911</div></div>
          <div><div className="text-ink-500">精确率</div><div className="num font-medium">0.808</div></div>
          <div><div className="text-ink-500">召回率</div><div className="num font-medium">0.861</div></div>
          <div><div className="text-ink-500">F1</div><div className="num font-medium">0.834</div></div>
        </div>
      </TCard>

      <TCard title="为什么是 XGBoost 而非神经网络？" kicker="Design Choice">
        <ul className="text-sm space-y-3">
          <li className="flex gap-3"><span className="num text-xs text-clinic-600 mt-1">01</span><div>
            <div className="font-medium">特征已结构化</div>
            <div className="text-xs text-ink-500 mt-0.5">CNN 的优势在于自动学习像素特征。我们已把图像压缩为 20 维结构化向量，再上 CNN 是浪费。</div>
          </div></li>
          <li className="flex gap-3"><span className="num text-xs text-clinic-600 mt-1">02</span><div>
            <div className="font-medium">SHAP 在树模型上几乎免费</div>
            <div className="text-xs text-ink-500 mt-0.5">TreeExplainer 用精确算法 O(TLD²)，单样本 0.4 ms。NN 上要用 DeepSHAP 估算，慢 100×。</div>
          </div></li>
          <li className="flex gap-3"><span className="num text-xs text-clinic-600 mt-1">03</span><div>
            <div className="font-medium">小样本鲁棒</div>
            <div className="text-xs text-ink-500 mt-0.5">4218 例训练样本对 ViT 远远不够，对 XGBoost 已经过拟合警戒线之内。</div>
          </div></li>
          <li className="flex gap-3"><span className="num text-xs text-clinic-600 mt-1">04</span><div>
            <div className="font-medium">CPU 友好</div>
            <div className="text-xs text-ink-500 mt-0.5">31 ms / 4 任务 / CPU；手机端 ONNX runtime 部署无需 GPU。</div>
          </div></li>
        </ul>
      </TCard>
    </div>
  </div>
);

const ConfusionMatrix = ({ tn, fp, fn, tp }) => {
  const total = tn+fp+fn+tp;
  const cell = (n, label, isCorrect) => (
    <div className={`p-4 rounded ${isCorrect?"bg-mint-100 border border-mint-300":"bg-risk-highSoft border border-risk-high/30"}`}>
      <div className="text-[10px] text-ink-500">{label}</div>
      <div className="num text-2xl font-semibold mt-1">{n}</div>
      <div className="num text-[10px] text-ink-500 mt-0.5">{(n/total*100).toFixed(1)}%</div>
    </div>
  );
  return (
    <div className="grid grid-cols-[80px_1fr_1fr] gap-2 items-center">
      <div></div>
      <div className="text-center text-xs text-ink-500">预测 阴性</div>
      <div className="text-center text-xs text-ink-500">预测 阳性</div>
      <div className="text-right text-xs text-ink-500">实际 阴性</div>
      {cell(tn, "TN", true)}
      {cell(fp, "FP", false)}
      <div className="text-right text-xs text-ink-500">实际 阳性</div>
      {cell(fn, "FN", false)}
      {cell(tp, "TP", true)}
    </div>
  );
};

// ---------- 06: Data flow tracer ----------
const TechDataFlow = () => {
  const [stage, setStage] = React.useState(0);
  const stages = [
    { t:"原始照片",       d:"3000×4000 px · sRGB · 8-bit",                  ms:0 },
    { t:"色卡检测",       d:"YOLOv8-n · 24 patches 定位",                    ms:18 },
    { t:"LAB 仿射变换",   d:"3×3 矩阵估计 → 应用",                          ms:34 },
    { t:"SAM2 分割",      d:"3 个 ROI mask 输出",                            ms:176 },
    { t:"特征提取",       d:"20 维向量构建",                                 ms:184 },
    { t:"XGBoost 推理",   d:"4 个模型并行",                                  ms:194 },
    { t:"SHAP 解释",       d:"TreeExplainer · top-10 features",               ms:198 },
    { t:"最终输出",       d:"4 个风险评分 + 解释",                          ms:198 },
  ];
  React.useEffect(()=>{
    if (stage >= stages.length-1) return;
    const t = setTimeout(()=>setStage(s=>s+1), 700);
    return () => clearTimeout(t);
  }, [stage]);

  return (
    <div className="fade-in space-y-6">
      <TSection kicker="Technical View · 06" title="单样本数据流追踪"
        sub="实时演示一张照片完整经过 4 阶段流水线的每一步输出与耗时。"
        action={<TBtn variant="ghost" icon="refresh" onClick={()=>setStage(0)}>重放</TBtn>}/>

      <div className="card p-5">
        <div className="flex items-center justify-between mb-4">
          <div>
            <div className="text-xs text-ink-500 num">SAMPLE · IMG-00142.jpg</div>
            <div className="text-sm">总耗时 <span className="num font-semibold">{stages[Math.min(stage,stages.length-1)].ms} ms</span> · 当前阶段：<span className="font-medium">{stages[Math.min(stage,stages.length-1)].t}</span></div>
          </div>
          <div className="text-xs text-ink-500 num">{Math.min(stage+1,stages.length)} / {stages.length}</div>
        </div>

        {/* Pipeline trace bar */}
        <div className="grid gap-2" style={{gridTemplateColumns:`repeat(${stages.length}, 1fr)`}}>
          {stages.map((s,i)=>(
            <div key={i} className={`p-3 rounded border transition-all ${i<stage?"bg-mint-50 border-mint-300":i===stage?"bg-clinic-50 border-clinic-300":"bg-white border-ink-200"}`}>
              <div className="flex items-center justify-between text-[10px] num text-ink-500">
                <span>{String(i+1).padStart(2,"0")}</span>
                <span>+{s.ms-((stages[i-1]?.ms)||0)}ms</span>
              </div>
              <div className="text-xs font-medium mt-1">{s.t}</div>
              <div className="text-[10px] text-ink-500 mt-1 leading-tight">{s.d}</div>
              {i<stage && <Icon name="check" size={12} className="text-mint-600 mt-1"/>}
              {i===stage && <span className="inline-block w-1.5 h-1.5 rounded-full bg-clinic-600 pulse-dot mt-1"/>}
            </div>
          ))}
        </div>
      </div>

      <div className="grid grid-cols-2 gap-5">
        <TCard title="阶段输出可视化" kicker="Intermediate Artifacts">
          <div className="grid grid-cols-2 gap-3">
            <div>
              <div className="text-[10px] num text-ink-500 mb-1">RAW</div>
              <div className="rounded overflow-hidden border border-ink-200"><TOral width={260} height={180} raw={true}/></div>
            </div>
            <div className={stage<3?"opacity-30":""}>
              <div className="text-[10px] num text-ink-500 mb-1">+ ROI MASKS</div>
              <div className="rounded overflow-hidden border border-ink-200"><TOral width={260} height={180} showMask={true}/></div>
            </div>
          </div>
          <div className={`mt-3 ${stage<4?"opacity-30":""}`}>
            <div className="text-[10px] num text-ink-500 mb-1">+ FEATURE VECTOR (20D)</div>
            <div className="flex gap-1 flex-wrap">
              {FEATURES.map((f,i)=>{
                const sig = f.signal;
                const c = sig==="high" ? "bg-risk-high" : sig==="mid" ? "bg-risk-mid" : sig==="low" ? "bg-clinic-300" : "bg-clinic-500";
                return <span key={i} title={f.name} className={`w-3 h-6 rounded-sm ${c}`} style={{opacity: 0.4 + Math.min(1,Math.abs(f.z)/3)*0.6}}/>;
              })}
            </div>
          </div>
          <div className={`mt-3 ${stage<5?"opacity-30":""}`}>
            <div className="text-[10px] num text-ink-500 mb-1">+ XGB OUTPUT</div>
            <div className="font-mono text-[11px] text-ink-700">{`{dm: 0.72, cv: 0.45, kd: 0.18, an: 0.12}`}</div>
          </div>
        </TCard>

        <TCard title="阶段耗时拆解" kicker="Wall-clock Profile">
          <div className="space-y-2">
            {stages.slice(1).map((s,i)=>{
              const dur = s.ms - (stages[i].ms);
              const max = 180;
              return (
                <div key={i} className="flex items-center gap-3">
                  <div className="text-xs text-ink-600 w-28">{s.t}</div>
                  <div className="flex-1 h-3 bg-ink-100 rounded overflow-hidden">
                    <div className="h-full rounded transition-all"
                      style={{width:`${Math.min(100,(dur/max)*100)}%`, background: dur>50 ? "#1462AB" : "#7DB8E8"}}/>
                  </div>
                  <div className="num text-xs w-12 text-right">{dur} ms</div>
                </div>
              );
            })}
          </div>
          <div className="mt-4 pt-4 border-t border-ink-100 text-xs text-ink-500">
            SAM2 推理是耗时大头（142 ms），未来用 SAM2-tiny + INT8 量化可压到 60 ms 以内。
          </div>
        </TCard>
      </div>
    </div>
  );
};

window.ScreensTech = { TechArch, TechSAM2, TechColor, TechFeatures, TechXGB, TechDataFlow };

})();
