#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
适配体修饰 Tth（宝锐 Hyperstart®）vs 罗氏 Cobas / Z05 —— 自包含 HTML 精读页生成器
输出：知识沉淀/适配体修饰Tth_罗氏CobasZ05_热启动对比_20261010.html
铁律：零外链（无 link/script src/外链图片/超链接）、内联 CSS+SVG+Logo、brand_kit 注入页眉页脚
"""
import os, sys, base64, re

BASE = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(BASE, '脚本'))
import brand_kit as BK

OUT = os.path.join(BASE, '知识沉淀/适配体修饰Tth_罗氏CobasZ05_热启动对比_20261010.html')

# ══════════════════════════════════════════════════════════════════
# 图1：热启动机制与释放阈值（温度轴 + 动画游标）
# ══════════════════════════════════════════════════════════════════
def fig_mechanism():
    # 温度轴 40→100 ℃ 映射到 x: 70→1010
    def x(t):
        return 70 + (t - 40) * (940.0 / 60)
    lanes = [
        ('宝锐 Hyperstart®（适配体，可逆）', 55, 60, '#0043C1'),
        ('罗氏 Z05 + aptamer / AptaTaq', 55, 60, '#0F7B6C'),
    ]
    rows = []
    for i, (name, lo, hi, col) in enumerate(lanes):
        y = 118 + i * 96
        rows.append(f'''
  <g>
    <text x="70" y="{y-14}" class="lg">{name}</text>
    <rect x="{x(40):.0f}" y="{y}" width="{x(lo)-x(40):.0f}" height="40" rx="8" fill="#DCE3F0"/>
    <rect x="{x(lo):.0f}" y="{y}" width="{x(hi)-x(lo):.0f}" height="40" fill="#F5C86B"/>
    <rect x="{x(hi):.0f}" y="{y}" width="{x(100)-x(hi):.0f}" height="40" rx="8" fill="{col}" opacity=".92"/>
    <text x="{(x(40)+x(lo))/2:.0f}" y="{y+26}" class="sl" text-anchor="middle" fill="#5A6475">被适配体抑制</text>
    <text x="{(x(lo)+x(hi))/2:.0f}" y="{y+26}" class="sl" text-anchor="middle" fill="#8A5A00">过渡</text>
    <text x="{(x(hi)+x(100))/2:.0f}" y="{y+26}" class="sl" text-anchor="middle" fill="#fff">完全释放 · 有活性</text>
  </g>''')
    ticks = ''.join(
        f'<g><line x1="{x(t):.0f}" y1="300" x2="{x(t):.0f}" y2="308" stroke="#B9C4D6"/>'
        f'<text x="{x(t):.0f}" y="328" class="tk" text-anchor="middle">{t}</text></g>'
        for t in (40, 50, 55, 60, 70, 80, 90, 100))
    return f'''<svg viewBox="0 0 1080 360" class="fig" role="img" aria-label="适配体热启动释放阈值">
  <style>
    .lg{{font-size:15px;font-weight:700;fill:#12203A}}
    .sl{{font-size:13px}}
    .tk{{font-size:13px;fill:#7A8598}}
    .cursor{{animation:sweep 7s ease-in-out infinite}}
    @keyframes sweep{{0%,8%{{transform:translateX(0)}}50%{{transform:translateX({x(95)-x(40):.0f}px)}}
      58%,100%{{transform:translateX(0)}}}}
  </style>
  <text x="70" y="34" class="lg" style="font-size:17px">温度开关：适配体 <tspan fill="#B45309">释放阈值</tspan> 两侧几乎一致</text>
  <text x="70" y="58" style="font-size:13px;fill:#5A6475">宝锐口径「60 ℃ 以上、可逆热启动」；罗氏口径「&lt;55 ℃ 抑制、&gt;60 ℃ 完全释放」</text>
  {''.join(rows)}
  {ticks}
  <text x="540" y="352" class="tk" text-anchor="middle">温度（℃）</text>
  <g class="cursor">
    <line x1="{x(40):.0f}" y1="100" x2="{x(40):.0f}" y2="310" stroke="#E8443C" stroke-width="2" stroke-dasharray="5 4"/>
    <circle cx="{x(40):.0f}" cy="100" r="5" fill="#E8443C"/>
  </g>
  <rect x="820" y="330" width="230" height="0" fill="none"/>
</svg>'''

# ══════════════════════════════════════════════════════════════════
# 图2：三套程序时序对照（各段合计口径，0–60 min 轴）
# ══════════════════════════════════════════════════════════════════
def fig_timeline():
    X0, W, AXIS = 210, 780.0, 60.0        # 0–60 min 映射
    def px(m):
        return X0 + m / AXIS * W
    # (标签, 标称, [(分钟, 名称, 色, 是否激活点)])
    progs = [
        ('宝锐 Hyperstart Tth', '常规程序（标称 1 h 20 min）', [
            (2, '', '#DCE3F0', 0), (0.5, '90℃30s', '#E8443C', 1),
            (20, '60℃20m', '#0F7B6C', 0), (0.5, '95℃30s', '#E8443C', 1),
            (30, '45×(95℃10s+56℃30s)', '#0043C1', 0)]),
        ('宝锐 Hyperstart Tth', '快速程序（标称 29 min）', [
            (2, '', '#DCE3F0', 0), (0.5, '90℃30s', '#E8443C', 1),
            (5, '60℃5m', '#0F7B6C', 0), (0.5, '95℃30s', '#E8443C', 1),
            (4.5, '45×(95℃1s+60℃5s)', '#0043C1', 0)]),
        ('罗氏 Cobas 6800/8800', '标准程序（≈1 h）', [
            (2, '', '#DCE3F0', 0), (0.08, '94℃5s', '#E8443C', 1),
            (2, '', '#DCE3F0', 0), (6, '60℃6m', '#0F7B6C', 0), (4, '65℃4m', '#0F7B6C', 0),
            (2.9, '5×(95℃5s+55℃30s)', '#0043C1', 0), (22.5, '45×(91℃5s+58℃25s)', '#0043C1', 0),
            (2, '', '#DCE3F0', 0)]),
    ]
    rows, y = [], 66
    for name, sub, segs in progs:
        tot = sum(s[0] for s in segs)
        rows.append(f'<text x="{X0-16}" y="{y+13}" class="tl" text-anchor="end">{name}</text>')
        if sub:
            rows.append(f'<text x="{X0-16}" y="{y+30}" class="tl3" text-anchor="end">{sub}</text>')
        cur = 0.0
        narrow = 0
        for dur, lab, col, act in segs:
            w = max(dur / AXIS * W, 2.0)
            stroke = ' stroke="#E8443C" stroke-width="2" class="pulse"' if act else ''
            rows.append(f'<rect x="{px(cur):.1f}" y="{y}" width="{w:.1f}" height="34" rx="3" fill="{col}"{stroke}/>')
            if dur / AXIS * W > 58 and len(lab) * 7.2 < dur / AXIS * W - 8:
                rows.append(f'<text x="{px(cur)+w/2:.1f}" y="{y+22}" class="tl2" text-anchor="middle">{lab}</text>')
            elif lab:
                cx = px(cur) + w / 2
                ty = y - 15 - (narrow % 2) * 15      # 窄块标签上移并错层，避免相邻碰撞
                narrow += 1
                col = {'#E8443C': '#D6336C', '#0F7B6C': '#0F7B6C', '#0043C1': '#002D80'}.get(col, '#5A6475')
                rows.append(f'<line x1="{cx:.1f}" y1="{y-2}" x2="{cx:.1f}" y2="{ty+3:.0f}" stroke="{col}" stroke-width="1.2" stroke-dasharray="2 2"/>')
                rows.append(f'<text x="{cx:.1f}" y="{ty:.0f}" class="tl4" text-anchor="middle" style="fill:{col}">{lab}</text>')
            cur += dur
        rows.append(f'<text x="{px(cur)+10:.1f}" y="{y+23}" class="tt" stroke="#fff" stroke-width="3" paint-order="stroke">{tot:g} min 合计</text>')
        y += 92
    axis = ''.join(
        f'<g><line x1="{px(m):.1f}" y1="46" x2="{px(m):.1f}" y2="{y-46}" stroke="#EDF1F7"/>'
        f'<text x="{px(m):.1f}" y="36" class="tk" text-anchor="middle">{int(m)}</text></g>'
        for m in range(0, 61, 10))
    return f'''<svg viewBox="0 0 1080 340" class="fig" role="img" aria-label="三套程序时序对照">
  <style>
    .tl{{font-size:13.5px;font-weight:700;fill:#12203A}}
    .tl3{{font-size:12px;fill:#7A8598}}
    .tl4{{font-size:11.5px;fill:#D6336C;font-weight:700}}
    .tl2{{font-size:12px;fill:#fff;font-weight:600}}
    .tt{{font-size:12px;fill:#7A8598}}
    .tk{{font-size:12px;fill:#94A3B8}}
    .pulse{{animation:pl 1.6s ease-in-out infinite}}
    @keyframes pl{{0%,100%{{opacity:1}}50%{{opacity:.45}}}}
  </style>
  <text x="{X0}" y="22" style="font-size:15px;font-weight:700;fill:#12203A">时间轴（min）· 红框 = 热启动释放步骤</text>
  {axis}
  {''.join(rows)}
  <g transform="translate(210,{y-24})">
    <rect width="14" height="14" rx="3" fill="#E8443C"/><text x="20" y="12" class="tk">激活/释放</text>
    <rect x="110" width="14" height="14" rx="3" fill="#0F7B6C"/><text x="130" y="12" class="tk">逆转录 RT</text>
    <rect x="230" width="14" height="14" rx="3" fill="#0043C1"/><text x="250" y="12" class="tk">循环扩增</text>
    <rect x="350" width="14" height="14" rx="3" fill="#DCE3F0"/><text x="370" y="12" class="tk">孵育/UNG/冷却</text>
  </g>
</svg>'''


def kpi(v, k, note=''):
    return f'<div class="kpi"><div class="kv">{v}</div><div class="kk">{k}</div><div class="kn">{note}</div></div>'


BODY = f'''<!DOCTYPE html>
<html lang="zh-CN"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>适配体修饰 Tth vs 罗氏 Cobas/Z05 · 热激活条件对比</title>
<style>
:root{{--blue:#0043C1;--deep:#002D80;--ink:#0F172A;--bg:#F5F7FA;--line:#E4E9F2;--tint:#F1F5FE;
--grey:#94A3B8;--sub:#5A6475;--red:#E8443C;--teal:#0F7B6C;--amber:#B45309;--purple:#6D28D9}}
*{{box-sizing:border-box}}
body{{margin:0;background:var(--bg);color:var(--ink);
font:15px/1.7 -apple-system,"PingFang SC","Microsoft YaHei",sans-serif}}
.wrap{{max-width:1180px;margin:0 auto;padding:26px 22px 60px}}
h1{{font-size:30px;line-height:1.35;margin:6px 0 8px;letter-spacing:-.4px}}
h2{{font-size:21px;margin:38px 0 14px;padding-left:13px;border-left:5px solid var(--blue)}}
h3{{font-size:16.5px;margin:24px 0 10px;color:var(--deep)}}
.lead{{color:var(--sub);font-size:14.5px;margin-bottom:6px}}
.card{{background:#fff;border:1px solid var(--line);border-radius:14px;padding:20px 22px;
box-shadow:0 2px 10px rgba(16,40,90,.05);margin:14px 0}}
.kpis{{display:grid;grid-template-columns:repeat(auto-fit,minmax(212px,1fr));gap:14px;margin:18px 0}}
.kpi{{background:#fff;border:1px solid var(--line);border-left:5px solid var(--blue);border-radius:12px;padding:16px 18px}}
.kpi:nth-child(2){{border-left-color:var(--red)}} .kpi:nth-child(3){{border-left-color:var(--teal)}}
.kpi:nth-child(4){{border-left-color:var(--purple)}}
.kv{{font-size:25px;font-weight:800;color:var(--deep);letter-spacing:-.3px}}
.kk{{font-size:13px;font-weight:700;margin-top:4px}}
.kn{{font-size:12.5px;color:var(--sub);margin-top:5px;line-height:1.55}}
.fig{{width:100%;height:auto;display:block;background:#fff;border:1px solid var(--line);border-radius:14px;margin:14px 0}}
table{{width:100%;border-collapse:collapse;font-size:13.5px;background:#fff}}
th,td{{border:1px solid var(--line);padding:9px 11px;text-align:left;vertical-align:top}}
th{{background:var(--tint);font-weight:700;color:var(--deep);font-size:13px}}
tr:nth-child(even) td{{background:#FBFCFE}}
code{{background:#EEF2F9;padding:1px 5px;border-radius:4px;font-size:12.5px;font-family:ui-monospace,Menlo,monospace}}
.pill{{display:inline-block;padding:1px 8px;border-radius:20px;font-size:12px;font-weight:700}}
.ok{{background:#E4F6EC;color:#0d904f}} .warn{{background:#FEF3E2;color:var(--amber)}}
.gray{{background:#EEF1F6;color:var(--sub)}} .pri{{background:#FDE8E7;color:#C0271D}}
.detail{{background:#F8FAFF;border:1px solid #DCE7FB;border-left:4px solid var(--blue);border-radius:10px;padding:12px 15px;margin:10px 0;font-size:13.5px}}
.q{{background:#FFFBF3;border:1px solid #FBE6C2;border-left:4px solid var(--amber);border-radius:10px;padding:12px 15px;margin:10px 0;font-size:13.5px}}
.act{{background:#fff;border:1px solid var(--line);border-radius:12px;padding:15px 18px;margin:11px 0}}
.owner{{font-size:12.5px;color:var(--sub);margin-top:6px}}
.two{{display:grid;grid-template-columns:1fr 1fr;gap:16px}}
@media(max-width:820px){{.two{{grid-template-columns:1fr}}}}
ul{{margin:8px 0 8px 20px;padding:0}} li{{margin:5px 0}}
.src{{font-size:12.5px;color:var(--sub);line-height:1.85}}
.note{{font-size:12.5px;color:var(--grey);margin-top:6px}}
</style></head><body>
<div class="wrap">

<h1>适配体修饰 Tth 酶的热激活条件<br>—— 与罗氏 Cobas / Z05 体系的差异对照</h1>
<p class="lead">证据口径：宝锐侧 = 官方产品 PPT 转写 + ERP/货号主数据 + 客户活动记录（一手，本地留档）；
罗氏侧 = Roche Custom Biotech 官方产品册与 Data Sheet + Cobas 标准程序文献复现（一手）。
凡标注 <span class="pill gray">待确认</span> 者为本机无直接文字证据、须向产品部核实的项。</p>

<h2>一、决策总览</h2>
<div class="kpis">
  {kpi('适配体（可逆）', '热启动机制：两侧同源', '宝锐 Hyperstart® 与罗氏 Z05/AptaTaq 均为 aptamer 分子开关')}
  {kpi('60 ℃ 以上释放', '释放阈值：几乎一致', '宝锐写「60 ℃ 以上可逆」；罗氏写「&lt;55 ℃ 抑制 / &gt;60 ℃ 完全释放」')}
  {kpi('30 s<span style="font-size:14px"> vs </span>5 s', '程序中的激活步骤', '宝锐留 90–95 ℃ 30 s；Cobas 仅 94–95 ℃ 5 s（化学法需 5–15 min）')}
  {kpi('原料 vs 平台', '不可直接比的部分', '宝锐交付裸酶/预混液由客户自建体系；Cobas 是仪器+试剂+内标封闭平台')}
</div>

<h2>二、热启动机制与释放阈值</h2>
<div class="card">
<p>适配体是一段单链寡核苷酸，靠三级结构结合并封闭聚合酶活性位点。<b>它的结合是温度依赖且可逆的</b>——降温重新结合、升温再次释放，因此不需要化学修饰酶那种不可逆的长时间高温激活。</p>
{fig_mechanism()}
<div class="detail"><b>结论：</b>宝锐「60 ℃ 以上，可逆热启动」与罗氏「&lt;55 ℃ 抑制、&gt;60 ℃ 完全释放」描述的是<b>同一物理机制</b>。差异来自各家适配体序列的 Tm 不同，实际释放温度应以自家适配体的实测曲线为准。</div>
</div>

<h2>三、程序时序对照</h2>
<div class="card">
<p>三套程序都以升温过 60 ℃ 完成适配体释放。<b>宝锐在释放后保留 90–95 ℃ 30 s</b>（兼顾 RNA 二级结构解链与释放），
<b>Cobas 把该步骤压到 94–95 ℃ 仅 5 s</b>——因为适配体法不需要长激活，这也是其官方口径「PCR 热启动激活时间 0 min」的由来。</p>
{fig_timeline()}
<p class="note">柱长按「各段时长合计」绘制；标称总时长更长，差值为升降温与荧光采集开销。</p>
</div>

<h2>四、宝锐侧：Hyperstart® Tth</h2>
<div class="card">
<h3>4.1 机制与产品</h3>
<p>宝锐官方产品表原文：<code>2×Hyperstart® Direct Premix-UNG (Probe qPCR)（MD2021）：①适配体修饰的抗抑制 DNA 聚合酶，60 ℃ 以上，可逆热启动</code>
→ <b>Hyperstart® 品牌 = 适配体修饰的可逆热启动</b>，Tth 线即 <code>Hyperstart Tth</code>（E10 系列）。</p>
<table><thead><tr><th>形态</th><th>货号</th><th>说明</th></tr></thead><tbody>
<tr><td>裸酶</td><td><code>E10</code> · <code>E10-000725</code> · <code>E10-019505</code> · <code>E10-019510</code> · <code>E10-AT1</code> · <code>E10-AT5</code> · <code>E10-NA</code></td><td>6 位尾缀为配方版本号；<code>-NA</code> 为控核酸版</td></tr>
<tr><td>冻干定制</td><td><code>FE10</code> 系列（DG）</td><td>原位冻干形态</td></tr>
<tr><td>预混液</td><td><code>FM510</code> · <code>FM5101</code> · <code>M5101</code> · <code>M2101-DB</code> · <code>M510-DB</code> · <code>M510-TP</code> · <code>2FM101-1</code></td><td>含 UNG 版本齐备</td></tr>
</tbody></table>

<h3>4.2 官方推荐程序（E10-000725 · qRT 4-2 体系 · 仪器 48S）</h3>
<table><thead><tr><th>程序</th><th>步骤</th><th>全程</th></tr></thead><tbody>
<tr><td>常规</td><td>50 ℃ 2 min → <b>90 ℃ 30 s</b> → 60 ℃ 20 min → <b>95 ℃ 30 s</b> → 45×(95 ℃ 10 s, 56 ℃ 30 s)</td><td>1 h 20 min</td></tr>
<tr><td>快速</td><td>50 ℃ 2 min → <b>90 ℃ 30 s</b> → 60 ℃ 5 min → <b>95 ℃ 30 s</b> → 45×(95 ℃ 1 s, 60 ℃ 5 s)</td><td><b>29 min</b></td></tr>
<tr><td>DNA 体系</td><td>50 ℃ 2 min → <b>95 ℃ 30 s</b> → 50×(95 ℃ 5 s, 55 ℃ 30 s)</td><td>（仪器 SLAN-96P）</td></tr>
</tbody></table>
<div class="detail"><b>直接回答「热激活条件」：</b>适配体在 <b>60 ℃ 以上自动释放</b>，程序里对应 <b>90 ℃ 或 95 ℃ 30 s</b> 这一步，<b>不需要</b>化学修饰酶那样的 95 ℃ 5–15 min 长激活。</div>

<h3>4.3 客户侧实测（活动记录）</h3>
<ul>
<li>Tth 以 <b>裸酶</b>交付、<b>适配体修饰由客户自行完成</b>；镁离子型 3–4 U/反应、锰离子型 10 U/反应</li>
<li>POCT 客户仪器为 <b>90 ℃ 10 min</b> 特性，只能用 Tth 酶；现版镁离子型 Ct 表现可接受，但<b>逆转录需 30 min</b>，客户要求压到 <b>≤15 min</b></li>
<li>抗抑制实测：<code>E10-000725</code> 在尿素/胆酸盐/肝素钠/腐殖酸/异硫氰酸胍环境中优于 <code>Robustart Tth</code></li>
</ul>
</div>

<h2>五、罗氏侧：Cobas / Z05</h2>
<div class="card">
<h3>5.1 官方酶学参数（Z05 · HawkZ05 · AptaTaq）</h3>
<table><thead><tr><th>项目</th><th>数值</th></tr></thead><tbody>
<tr><td>热启动机制</td><td>适配体（Z05 聚合酶 + 特异寡核苷酸）</td></tr>
<tr><td>抑制 / 释放</td><td><b>&lt;55 ℃ 被抑制</b>；<b>&gt;60 ℃ 适配体完全释放</b></td></tr>
<tr><td>激活温度</td><td>≥ +60 ℃ 即有活性</td></tr>
<tr><td>最适温度 / 95 ℃ 半衰期</td><td>≈ +75 ℃ / ≈ 40 min</td></tr>
<tr><td>PCR 热启动激活时间</td><td><b>0 min</b>（化学修饰法对照需 15 min）</td></tr>
<tr><td>外切活性</td><td>无 3'→5' 外切；有双链特异 5'→3' 外切</td></tr>
</tbody></table>

<h3>5.2 Cobas 6800/8800 标准循环程序</h3>
<pre style="background:#F8FAFF;border:1px solid #DCE7FB;border-radius:10px;padding:13px 15px;font-size:12.8px;overflow-x:auto">Pre-PCR  : 50℃ 2:00 → 94℃ 0:05 → 55℃ 2:00 → 60℃ 6:00 → 65℃ 4:00
第1测量  : 5×(95℃ 0:05, 55℃ 0:30)
第2测量  : 45×(91℃ 0:05, 58℃ 0:25)
冷却     : 40℃ 2:00</pre>
<p class="note">无 95 ℃ 长预变性；逆转录采用 55/60/65 ℃ 分段共约 12 min。</p>
</div>

<h2>六、逐项差异</h2>
<div class="card" style="padding:0;overflow-x:auto">
<table><thead><tr><th>维度</th><th>宝锐 Hyperstart Tth</th><th>罗氏 Z05（Cobas）</th><th>差异性质</th></tr></thead><tbody>
<tr><td>热启动机制</td><td>适配体（可逆）</td><td>适配体（可逆）</td><td><b>同源</b></td></tr>
<tr><td>释放阈值</td><td>60 ℃ 以上</td><td>&gt;60 ℃ 释放 / &lt;55 ℃ 抑制</td><td><b>几乎一致</b></td></tr>
<tr><td>程序中激活步骤</td><td>90–95 ℃ <b>30 s</b></td><td>94–95 ℃ <b>5 s</b></td><td>宝锐留余量，罗氏压到最短</td></tr>
<tr><td>酶本体</td><td><b>Tth</b>（Thermus thermophilus）</td><td><b>Z05</b>（Thermus sp. Z05）</td><td><b>实质差异</b></td></tr>
<tr><td>RT 活性</td><td>有；Mn²⁺ 型天然依赖 Mn²⁺（宝锐另供 Mg²⁺ 型规避）</td><td>有；最适 ≈75 ℃</td><td>Tth 需 60 ℃ 长时 RT</td></tr>
<tr><td>RT 时长</td><td>常规 60 ℃ <b>20 min</b>（快速 5 min）</td><td>55/60/65 ℃ 分段共 ≈12 min</td><td><b>宝锐此处为客户痛点</b></td></tr>
<tr><td>抗抑制</td><td>E10-000725 优于 Robustart Tth</td><td>Z05 以高抗抑制著称</td><td>罗氏偏强（无同条件横比数据）</td></tr>
<tr><td>耐热</td><td>—</td><td>95 ℃ 半衰期 ≈40 min</td><td>罗氏有公开硬数据</td></tr>
<tr><td>交付形态</td><td><b>原料</b>（裸酶/预混/可冻干），客户自建体系</td><td><b>封闭平台</b>（仪器+试剂+内标+软件）</td><td><b>不可直接比</b></td></tr>
<tr><td>定位</td><td>POCT、呼吸道多联检、中低通量</td><td>高通量全自动（6800/8800）</td><td>—</td></tr>
</tbody></table>
</div>

<h2>七、结论与可执行动作</h2>
<div class="act"><b>① 客户答疑话术（可直接用）</b><br>
「适配体法的激活是温度开关：升温过 60 ℃ 即释放，程序里 90–95 ℃ 30 s 足够；<u>不需要</u>化学修饰酶的 95 ℃ 5–15 min 长激活——这正是适配体法能做快速 PCR / POCT 的原因。」
<div class="owner">主责：技术支持；协同：销售（客户答疑）｜验收：客户复述机制无误</div></div>

<div class="act"><b>② 打客户 RT 时间痛点</b><br>
客户要求「Tth 逆转录 ≤15 min」——现成答案是<b>快速程序 60 ℃ 5 min、全程 29 min</b>（官方数据）。先按 <code>E10-000725</code> 口径对齐，再谈版本。
<div class="owner">主责：产品销售（出对比数据包）；协同：技术支持（实测复核）｜验收：客户按快速程序跑通并回签</div></div>

<div class="act"><b>③ 适配体修饰的对外措辞先锁死</b><br>
对外统一说「<b>Hyperstart® 平台 = 适配体修饰可逆热启动</b>」，并引用 MD2021 产品行原文；涉 E10 需附产品部确认。
<div class="owner">主责：产品部（出 E10 说明书措辞）；协同：营销中心（宣讲物料）｜验收：说明书原文回函存档</div></div>

<div class="act"><b>④ 竞品对照口径</b><br>
与 Cobas/Z05 对比时，强调<b>机制同源、阈值一致</b>，差异落在酶本体与交付形态——不要把「原料」与「封闭平台」放在同一性能维度上比。
<div class="owner">主责：营销中心（宣讲物料）；协同：市场（竞品情报）｜验收：物料合规自检通过</div></div>

<h2>八、缺口与待确认</h2>
<div class="q"><b>① E10 系列说明书的「适配体」措辞</b> <span class="pill gray">待确认</span><br>
本机证据：同品牌 MD2021 行明确写「适配体修饰」；<b>E10 自家产品行未逐字写适配体</b>。
→ 影响：客户追问「哪个版本才是适配体封闭」时无官方原文可引。<b>请产品部出具 E10 现行说明书。</b></div>
<div class="q"><b>② 罗氏与宝锐的同条件横比数据</b> <span class="pill gray">缺失</span><br>
抗抑制、灵敏度、Ct 表现两侧口径不同源，<b>本页不做数值横比</b>。如需硬对比，须做同引探同仪器的头对头实验。</div>
<div class="q"><b>③ Cobas 程序为文献复现</b> <span class="pill gray">口径提醒</span><br>
标准循环程序取自公开文献对 Cobas 6800/8800 的复现，非罗氏官方 IFU 原文；正式引用请以对应试剂 IFU 为准。</div>

<h2>九、来源</h2>
<div class="src">
宝锐侧（本地留档一手）：<br>
· 官方产品 PPT 转写：<code>资料/PPT转写/PPT2_产品分子技术版_20260826-27.md</code>（第 39/40/45 张 + 适配体产品行）<br>
· 货号主数据：<code>培训与上手/刘子研上手包/数据/核酸扩增原料货号清单.json</code>；产品总表：<code>数据/product_master.json</code><br>
· 客户实证：<code>数据/_sr_extracted.json</code>（镁激活 TTH 裸酶 3–4 U/反应、客户自做适配体修饰）、<code>数据/activities_feishu.json</code>（POCT 90 ℃ 10 min 平台、RT ≤15 min 要求）<br><br>
罗氏侧：<br>
· Roche Custom Biotech《Molecular Diagnostics – Amplification》DNA Polymerases / Hot Start 产品册（Z05 参数、HawkZ05 = Z05 + aptamer）<br>
· HawkZ05 Fast DNA Polymerase Data Sheet（&lt;55 ℃ 抑制 / &gt;60 ℃ 完全释放）<br>
· AptaTaq 产品页与家族手册（可逆分子开关、激活时间 0 min、省 15 min）<br>
· Cobas 6800/8800 标准循环程序（公开文献复现）<br><br>
学术文献：<br>
· <code>10.1006/jmbi.1997.1165</code> J Mol Biol — 适配体同时抑制 Taq 与 <b>Tth</b> 聚合酶（异二聚体适配体）<br>
· <code>10.2174/0929866530666230216113348</code> Protein Pept Lett 2023 — Tth 逆转录活性依赖 Mn²⁺，突变可解除依赖<br>
· <code>10.1371/journal.pone.0345402</code> PLoS One 2026 — 化学修饰/适配体/抗体三类热启动对比（激活时长差异）<br>
· <code>10.1039/c6cc00454g</code> Chem Commun 2016 — 金属离子触发聚合酶可逆开关
</div>
<p class="src" style="margin-top:22px">宝锐生物 · 营销中心 ｜ 本页为内部技术精读资料，含客户项目信息，不得对外发送。</p>
</div>
<!--BRAND_INJECT-->
</body></html>'''

html_out = BK.inject(BODY, theme='dark', tag='营销中心 · 技术精读',
                     footer_extra='适配体修饰 Tth vs 罗氏 Cobas/Z05 · 2026-10-10')
os.makedirs(os.path.dirname(OUT), exist_ok=True)
open(OUT, 'w', encoding='utf-8').write(html_out)
print('✅ 已生成：%s' % OUT)

# ── 自检 ──
t = html_out
ext = re.findall(r'(?:src|href)\s*=\s*["\'](https?:)?//[^"\']+', t)
print('   零外链自检：外链资源 %d 处 %s' % (len(ext), ext[:3] if ext else '✅'))
print('   品牌套件：Logo %s ｜ slogan %s' %
      ('✅' if 'data:image/png;base64' in t else '❌',
       '✅' if BK.SLOGAN in t else '❌'))
print('   体量：%.1f KB ｜ <style> %d 个 ｜ 内联 SVG 图 %d 张' %
      (len(t.encode()) / 1024, t.count('<style'), t.count('<svg')))
# SVG 内容守卫：<title> 是 HTML rawtext 元素、<br> 在 SVG 无意义 —— 二者会吞掉后续图形
svgs = re.findall(r'<svg[^>]*class="fig".*?</svg>', t, re.S)
nt, nbr, nrect = sum(s.count('<title') for s in svgs), sum(s.count('<br') for s in svgs), sum(s.count('<rect') for s in svgs)
print('   SVG 守卫：<title> %d ｜ <br> %d ｜ rect %d  %s' %
      (nt, nbr, nrect, '✅' if (nt == 0 and nbr == 0 and nrect > 5) else '❌ 会破坏 SVG 渲染'))
