#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PCR 检测体系灵敏度：1 页证据地图 + 报告目录（对外技术资料版）。"""
import base64
from pathlib import Path

BASE = Path('/Users/liuxinyuan/Desktop/Hermes输出-工作类')
OUT_HTML = BASE / ' Knowledge沉淀' if False else BASE / '知识沉淀' / 'PCR体系灵敏度_证据地图与目录_20261102_V01.html'
LOGO = Path('/Users/liuxinyuan/work/公司资料/logo_transparent.png')


def uri(p):
    return 'data:image/png;base64,' + base64.b64encode(p.read_bytes()).decode('ascii')


LOGO_URI = uri(LOGO)

# 六段因果链
chain = [
    ('01', '取样与模板回收', '每反应有效拷贝数、提取回收率、基质抑制', 'LOD 的统计下限', '[3]'),
    ('02', '变性 / 模板可及', 'GC 含量、二级结构、片段完整性', '引物能否找到靶点', '[6]'),
    ('03', '引物 / 探针退火', 'Tm、ΔG、二级结构、引物二聚体', '退火占据率与特异性', '[6]'),
    ('04', '聚合酶结合 / 延伸', 'kcat/Km(dNTP)、processivity、延伸速率、活性酶比例', '扩增效率 E 的核心', '[4][5]'),
    ('05', '探针切割', '5′核酸酶切割效率、探针可及性、链置换', '每扩增子的信号产出', '[5]'),
    ('06', '信号 / 阈值', '背景荧光、淬灭效率、仪器增益、阈值算法', 'Ct 与 LOD95 的判定', '[1][3]'),
]

clusters = [
    ('A', '口径与统计', 'LOD95、E、Ct、临床灵敏度分别回答什么？', 'MIQE；MIQE 2.0；LOD/LOQ 方法（A）', '临床灵敏度不是 LOD 的同义词'),
    ('B', '酶动力学与结构', '哪些动力学量直接决定延伸与切割？', 'DNA 聚合酶动力学综述；TaqMan 机制研究（B*，厂商主导）；PDB 1TAU/1TAQ（A）', '同一 qPCR 条件下的突变体动力学数据少'),
    ('C', '配方与辅因子', '游离 Mg²⁺、dNTP/Mg、离子强度如何改变有效活性？', 'PCR 优化方法学（C）；MIQE 报告框架（A）', '配方多为经验矩阵，缺普适最优值'),
    ('D', '引探热力学', 'Tm/ΔG、二级结构、扩增子长度如何影响退火与切割？', 'qPCR 引探设计综述（B）；TaqMan 机制（B*）', '过度稳定探针会降低区分度'),
    ('E', '体系边界', '热启动、RT、样本基质与抑制剂如何改写结论？', 'PCR 抑制机制综述（A）；耐热 RT 工程（B）；热启动 Taq（B）', '不同样本基质需独立验证'),
    ('F', '临床灵敏度', '患者阳性检出比例由什么决定？', '诊断准确性基本定义（A）', '需临床样本与目标人群，不能由酶学推算'),
]

toc = [
    ('00', '摘要：一张图看懂灵敏度'),
    ('01', '四个口径：LOD95、E、Ct、临床灵敏度'),
    ('02', '串联模型：从样本到阈值'),
    ('03', '酶学：kcat/Km、processivity、延伸速率、5′核酸酶'),
    ('04', '蛋白结构：A 家族结构域与结构–功能权衡'),
    ('05', '配方：游离 Mg²⁺、dNTP/Mg、离子强度、添加剂'),
    ('06', '引探：Tm/ΔG、二级结构、扩增子、探针切割'),
    ('07', '边界：热启动、RT-qPCR、样本基质与抑制剂'),
    ('08', '正向 / 负向调整矩阵：条件、收益、代价'),
    ('09', '实验验证：DoE 与 LOD95 确认'),
    ('10', '证据表、缺口清单、术语表'),
]

refs = [
    ('[1]', 'Bustin SA, et al. MIQE guidelines. Clin Chem. 2009. DOI 10.1373/clinchem.2008.112797'),
    ('[2]', 'Bustin SA, et al. MIQE 2.0. Clin Chem. 2025. DOI 10.1093/clinchem/hvaf043'),
    ('[3]', 'Methods to determine LOD/LOQ in qPCR. Biomol Detect Quantif. 2017. DOI 10.1016/j.bdq.2017.04.001'),
    ('[4]', 'Kuznetsova AA, et al. Structural and molecular kinetic features of DNA polymerases. IJMS. 2022. DOI 10.3390/ijms23126373'),
    ('[5]', 'Cao Q, et al. Mechanism and application of Taq DNA polymerase in TaqMan qPCR. Front Bioeng Biotechnol. 2026. DOI 10.3389/fbioe.2026.1773703（Vazyme 主导）'),
    ('[6]', 'qPCR primer design revisited. Biomol Detect Quantif. 2017. DOI 10.1016/j.bdq.2017.11.001'),
    ('[7]', 'PCR: basic protocol plus troubleshooting and optimization. J Vis Exp. 2012. DOI 10.3791/3998'),
    ('[8]', 'Sidstedt M, et al. PCR inhibition in qPCR, dPCR and MPS. Anal Bioanal Chem. 2020. DOI 10.1007/s00216-020-02490-2'),
    ('[9]', 'RCSB PDB: Taq polymerase–DNA complexes 1TAU / 1TAQ'),
    ('[10]', 'Šimundić AM. Measures of diagnostic accuracy: basic definitions. Biochem Med. 2009. PMC4975285'),
    ('[11]', 'Kuznetsova AA, et al. Thermostable reverse transcriptase for RT-PCR. Biomolecules. 2025. DOI 10.3390/biom15111507'),
    ('[12]', 'Lee SJ, et al. Direct and hot-start PCR with Taq. IJMS. 2023. DOI 10.3390/ijms241411405'),
]

chain_html = ''.join(f'''
<div class="node">
  <div class="n">{n}</div>
  <div class="nt"><b>{t}</b><span>{p}</span></div>
  <div class="ne">{e}<em>{ref}</em></div>
</div>''' for n, t, p, e, ref in chain)

cluster_html = ''.join(f'''
<tr>
  <td class="cl">{c}</td>
  <td class="cq"><b>{name}</b><br>{q}</td>
  <td class="ce">{src}</td>
  <td class="cg">{gap}</td>
</tr>''' for c, name, q, src, gap in clusters)

toc_html = ''.join(f'<div class="ti"><span>{n}</span>{t}</div>' for n, t in toc)
refs_html = ''.join(f'<div class="ref"><b>{n}</b> {r}</div>' for n, r in refs)

HTML = f'''<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title>PCR 检测体系灵敏度 · 证据地图与报告目录</title>
<style>
@page {{ size: A4; margin: 0; }}
* {{ box-sizing: border-box; margin: 0; padding: 0; }}
html, body {{ width: 210mm; background: #fff; color: #17324A; font-family: "PingFang SC","Hiragino Sans GB","Microsoft YaHei",Arial,sans-serif; -webkit-print-color-adjust: exact; print-color-adjust: exact; }}
.page {{ width: 210mm; height: 297mm; padding: 8mm 10mm 6mm; background: #fff; position: relative; overflow: hidden; display: flex; flex-direction: column; }}
.head {{ height: 11mm; flex: 0 0 11mm; display: flex; align-items: center; gap: 4mm; border-bottom: .5mm solid #CFE0EC; }}
.head img {{ height: 8.5mm; width: auto; }}
.head .tag {{ font-size: 5.8pt; color: #5C7C90; letter-spacing: .05em; }}
.head .pg {{ margin-left: auto; font-family: Georgia,serif; font-size: 8pt; color: #1F4E79; }}
.title {{ flex: 0 0 24mm; padding-top: 3mm; }}
.kicker {{ font-size: 6pt; letter-spacing: .18em; color: #4E8AA8; font-weight: 600; }}
h1 {{ font-size: 20pt; line-height: 1.08; color: #123B5C; letter-spacing: -.02em; margin-top: 1.3mm; }}
h1 span {{ font-size: 10.5pt; color: #1F4E79; font-weight: 500; margin-left: 2mm; }}
.sub {{ font-size: 6.9pt; line-height: 1.5; color: #4F6D80; margin-top: 1.6mm; }}
.thesis {{ flex: 0 0 15mm; background: #F1F7FB; border-left: 2mm solid #1F4E79; padding: 2.4mm 4mm; display: flex; align-items: center; gap: 5mm; }}
.thesis .big {{ font-size: 9.2pt; line-height: 1.4; color: #123B5C; font-weight: 700; width: 66mm; flex: 0 0 66mm; }}
.thesis .sm {{ font-size: 6.2pt; line-height: 1.5; color: #4C6A7C; }}
.thesis .sm b {{ color: #1F4E79; }}
.main {{ flex: 1 1 auto; display: grid; grid-template-columns: 63mm 1fr; gap: 4.5mm; margin-top: 3mm; min-height: 0; }}
.left {{ min-width: 0; height: 100%; }}
.lab {{ font-size: 6.3pt; color: #1F4E79; font-weight: 700; letter-spacing: .06em; margin-bottom: 1.3mm; }}
.chain {{ display: flex; flex-direction: column; gap: 1.2mm; height: calc(100% - 5mm); }}
.node {{ flex: 1 1 0; }}
.node {{ display: grid; grid-template-columns: 7mm 1fr; gap: 1.6mm; border: .35mm solid #D6E5EF; border-radius: 1.2mm; padding: 1.8mm 2mm; background: #FCFEFF; min-height: 16.2mm; }}
.node:nth-child(even) {{ background: #F8FCFE; }}
.n {{ width: 6mm; height: 6mm; border-radius: 50%; background: #1F4E79; color: #fff; font-family: Georgia,serif; font-size: 6.3pt; display: flex; align-items: center; justify-content: center; }}
.nt b {{ display: block; font-size: 7.1pt; color: #123B5C; line-height: 1.25; }}
.nt span {{ display: block; font-size: 5.7pt; color: #587487; line-height: 1.35; margin-top: .5mm; }}
.ne {{ grid-column: 2; font-size: 5.5pt; color: #1F4E79; line-height: 1.3; border-top: .25mm dashed #D4E4EE; padding-top: .7mm; }}
.ne em {{ font-style: normal; color: #8AA3B2; margin-left: 1mm; font-size: 4.9pt; }}
.right {{ min-width: 0; height: 100%; display: flex; flex-direction: column; }}
table {{ height: 100%; }}
table {{ width: 100%; border-collapse: collapse; table-layout: fixed; font-size: 5.65pt; line-height: 1.35; }}
th {{ background: #1F4E79; color: #fff; font-weight: 600; text-align: left; padding: 1.6mm 1.5mm; font-size: 5.7pt; }}
td {{ border-bottom: .3mm solid #D8E6EF; padding: 1.7mm 1.5mm; vertical-align: top; color: #3C5D70; }}
tr:nth-child(even) td {{ background: #FAFDFE; }}
td.cl {{ font-family: Georgia,serif; color: #1F4E79; font-size: 8pt; font-weight: 700; text-align: center; }}
td.cq b {{ color: #123B5C; font-size: 6pt; }}
td.ce {{ color: #426176; }}
td.cg {{ color: #8A5A2B; }}
.grade {{ flex: 0 0 auto; margin-top: 1.8mm; font-size: 5.2pt; color: #6C8798; line-height: 1.45; }}
.grade b {{ color: #1F4E79; }}
.direction {{ flex: 0 0 12mm; margin-top: 2.2mm; display: grid; grid-template-columns: 1fr 1fr; gap: 2.5mm; }}
.dir {{ border: .35mm solid #D8E6EF; border-radius: 1mm; padding: 1.8mm 2.4mm; font-size: 5.5pt; line-height: 1.45; }}
.dir b {{ display: block; font-size: 5.8pt; margin-bottom: .5mm; }}
.dir.up {{ background: #F4FAF5; border-left: 1.2mm solid #6AAE72; }}
.dir.down {{ background: #FDF7F2; border-left: 1.2mm solid #D78B3A; }}
.dir b.up {{ color: #397342; }}
.dir b.down {{ color: #9A5A22; }}
.toc {{ flex: 0 0 45mm; margin-top: 2.4mm; border-top: .5mm solid #CFE0EC; padding-top: 2mm; }}
.toc .th {{ display: flex; align-items: baseline; gap: 3mm; margin-bottom: 1.4mm; }}
.toc .th b {{ font-size: 7.2pt; color: #1F4E79; }}
.toc .th span {{ font-size: 5.3pt; color: #6A8798; }}
.toc-grid {{ display: grid; grid-template-columns: 1fr 1fr; gap: .5mm 5mm; }}
.ti {{ font-size: 6pt; line-height: 1.55; color: #34566B; border-bottom: .2mm dotted #DCE8EF; padding-bottom: .35mm; }}
.ti span {{ display: inline-block; width: 6mm; color: #1F4E79; font-family: Georgia,serif; font-size: 5.6pt; }}
.refs {{ flex: 0 0 auto; margin-top: 1.6mm; border-top: .3mm solid #DCE8EF; padding-top: 1.3mm; display: grid; grid-template-columns: 1fr 1fr 1fr; gap: .4mm 4mm; }}
.ref {{ font-size: 4.55pt; line-height: 1.35; color: #6D8798; }}
.ref b {{ color: #1F4E79; }}
.foot {{ flex: 0 0 7mm; margin-top: auto; border-top: .4mm solid #CFE0EC; display: flex; align-items: center; gap: 3mm; font-size: 5.2pt; color: #6C8798; }}
.foot b {{ color: #1F4E79; }}
.foot .slogan {{ margin-left: auto; letter-spacing: .04em; color: #4D7C96; }}
</style>
</head>
<body>
<div class="page bior-page">
  <div class="head bior-header">
    <img src="{LOGO_URI}" alt="宝锐生物 BIORI BIOTECH">
    <div class="tag">PCR 检测体系 · 技术证据地图</div>
    <div class="pg">2026-11-02 / 01</div>
  </div>

  <div class="title">
    <div class="kicker">PCR SENSITIVITY · EVIDENCE MAP</div>
    <h1>PCR 检测体系灵敏度 <span>从样本到阈值的证据地图</span></h1>
    <div class="sub">TaqMan qPCR 为主；RT-qPCR 单列一章；同时看 LOD95、扩增效率 E、Ct 与临床灵敏度。本页用于确认报告结构，不作为最终技术结论。</div>
  </div>

  <div class="thesis">
    <div class="big">灵敏度是串联系统的总结果，<br>不是单一酶活指标。</div>
    <div class="sm">低拷贝时，取样体积与 Poisson 分布先设下限；酶学参数决定“能否高效延伸”，配方决定“酶与底物的有效状态”，引探决定“能否特异退火并被切割”。<b>任何一个环节的损失，都会抵消另一环节的增益。</b></div>
  </div>

  <div class="main">
    <div class="left">
      <div class="lab">因果链 / CAUSAL CHAIN</div>
      <div class="chain">{chain_html}</div>
    </div>

    <div class="right">
      <div class="lab">证据簇 / EVIDENCE CLUSTERS</div>
      <table>
        <thead><tr><th style="width:7%">簇</th><th style="width:31%">核心问题</th><th style="width:37%">代表证据（等级）</th><th style="width:25%">主要缺口</th></tr></thead>
        <tbody>{cluster_html}</tbody>
      </table>
      <div class="grade"><b>等级：</b>A 同行评审且直接相关｜B 同行评审但间接/体系特异｜B* 厂商主导研究，需独立互证｜C 方法学/协议｜G 缺口。临床灵敏度不进入酶学因果链，单独作为诊断准确性指标处理。</div>
    </div>
  </div>

  <div class="direction">
    <div class="dir up"><b class="up">正向调整 / 需有条件</b>processivity↑ · kcat/Km(dNTP)↑ · 游离 Mg²⁺ 滴定 · Tm/ΔG 匹配 · 短扩增子 · 热启动 · 基质前处理</div>
    <div class="dir down"><b class="down">负向作用 / 常见反向</b>Mg²⁺/dNTP 过量 · 高盐/甘油 · 探针过度稳定 · 引物二聚体 · 长扩增子/高 GC · 反复冻融 · 基质抑制剂</div>
  </div>

  <div class="toc">
    <div class="th"><b>报告目录 / CONTENTS</b><span>对外技术资料版 · 以客户能理解的因果链组织，不按论文罗列</span></div>
    <div class="toc-grid">{toc_html}</div>
  </div>

  <div class="refs">{refs_html}</div>

  <div class="foot bior-footer">
    <b>BIORI BIOTECH</b><span>珠海宝锐生物科技有限公司 · 0756-8699969 · marketing@biori.com</span>
    <span class="slogan">守护生命健康，缔造美好生活</span>
  </div>
</div>
</body>
</html>'''

OUT_HTML.parent.mkdir(parents=True, exist_ok=True)
OUT_HTML.write_text(HTML, encoding='utf-8')
print('written', OUT_HTML, OUT_HTML.stat().st_size)
