#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""2027 科研作战地图（生命科学 / 科研线）

输入：
  - 产品目录 数据/ls_product_catalog.json（102 个产品，真实货号与价格）
  - 客户分层 数据/2027战略_生命科学_成长型课题组.json
  - Q3 产品需求 数据/科研Q3产品需求汇总.json
  - 用户给定的：三层产品矩阵、300–400 万目标、5 条线索、PI 职业阶梯（图片）
输出：销售分析/2027科研作战地图_2026-10-17.html
"""
import io
import os
import sys

sys.path.insert(0, '/Users/liuxinyuan/Desktop/Hermes输出-工作类/脚本')
import brand_kit as BK  # noqa: E402

W = '/Users/liuxinyuan/Desktop/Hermes输出-工作类'
OUT = W + '/销售分析/2027科研作战地图_2026-10-17.html'

CSS = """
*{box-sizing:border-box}
body{margin:0;background:#f4f6fa;font-family:-apple-system,"PingFang SC","Microsoft YaHei",sans-serif;color:#1b2430;font-size:13px;line-height:1.62}
.wrap{max-width:1320px;margin:0 auto;padding:0 18px 44px}
h1{font-size:23px;margin:12px 0 4px}
.meta{color:#5b6675;font-size:12.5px;line-height:1.9;margin-bottom:12px}
.card{background:#fff;border:1px solid #e3e8f1;border-radius:10px;padding:14px 16px;margin-bottom:14px}
.card h2{font-size:15.5px;margin:0 0 10px;padding-left:9px;border-left:3px solid #1F4E79;display:flex;align-items:baseline;gap:8px}
.card h2 span{font-size:11px;color:#8a94a3;font-weight:600}
h3{font-size:13.3px;margin:14px 0 7px;color:#1F4E79}
table{width:100%;border-collapse:collapse;font-size:11.8px}
th{background:#1F4E79;color:#fff;padding:7px 8px;text-align:left;vertical-align:middle}
td{padding:6px 8px;border-bottom:1px solid #eef1f6;vertical-align:top}
td.n{text-align:right;white-space:nowrap;font-variant-numeric:tabular-nums}
.tag{display:inline-block;font-size:10.2px;font-weight:800;padding:1px 7px;border-radius:9px;white-space:nowrap}
.t1{background:#e8f0fb;color:#1F4E79}.t2{background:#fff4e0;color:#8a5a12}.t3{background:#e8f6ee;color:#1c7c54}
.p0{background:#fde8e6;color:#b3261e}.p1{background:#e8f0fb;color:#1F4E79}.p2{background:#eef2f8;color:#5b6675}
.kpis{display:grid;grid-template-columns:repeat(6,1fr);gap:9px;margin:12px 0 16px}
.kpi{background:#fff;border:1px solid #e3e8f1;border-top:3px solid #1F4E79;border-radius:9px;padding:9px 11px}
.kpi .l{font-size:10.5px;color:#66707d;font-weight:700}.kpi .v{font-size:18px;font-weight:900;line-height:1.3}.kpi .s{font-size:10px;color:#9aa3b2}
.grid2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.grid3{display:grid;grid-template-columns:repeat(3,1fr);gap:11px}
.box{background:#f7f9fc;border:1px solid #e3e8f1;border-radius:9px;padding:11px 13px}
.box.warn{background:#fffdf6;border-color:#efe0bb}
.box.ok{background:#f5fbf7;border-color:#cfe8d9}
.box h4{margin:0 0 6px;font-size:12.6px}
ul{margin:3px 0 0;padding-left:19px}li{margin-bottom:3px}
.mono{font-family:ui-monospace,Menlo,monospace;font-size:10.8px}
.fn{font-size:11px;color:#8a94a3;line-height:1.75}
.matrix td:first-child{font-weight:800;background:#f7f9fc;width:9%}
.planb td:nth-child(2){background:#f5fbf7}
.tl{display:grid;grid-template-columns:repeat(5,1fr);gap:9px}
.tl .p{background:#f7f9fc;border:1px solid #e3e8f1;border-top:3px solid #1F4E79;border-radius:9px;padding:9px 10px;font-size:11.3px}
.tl .p .h{font-weight:900;color:#1F4E79;font-size:12px;margin-bottom:3px}
.ladder td:first-child{width:11%;font-weight:800}
@media print{@page{size:A4;margin:9mm}body{background:#fff;font-size:10.2px}.card{break-inside:avoid}}
@media(max-width:980px){.kpis{grid-template-columns:repeat(3,1fr)}.grid2,.grid3,.tl{grid-template-columns:1fr}}
"""

PRODUCT_MATRIX = [
    ('分子', '一线<br><span class="fn">进门 / 现金牛</span>',
     'Taq（A101/A102）、dNTP（A801/A802）、DNA Marker（B202）、质粒小提（D101）、胶回收（E301）、逆转录（D101/D201）、qPCR 预混（A501/E102）、RT-qPCR（F101/F102）',
     '客户必买、单价透明、比价激烈', '用它进门，不指望它赚钱；毛利率低但能带来试用机会'),
    ('分子', '二线<br><span class="fn">替换 / 差异化</span>',
     '高保真（M121）、快速 PCR（A401）、一步法反转（D303）、探针 qPCR（E201/E202）、RT 探针（F201/F202）、无缝克隆（C101）、连接（C302）、植物直扩（A503）、RNA 柱提（B201/B202）',
     '性能或形态有明显差异，可对标诺唯赞/全式金', '主推替换，用“对比实验 + 价格梯度”切竞品'),
    ('分子', '领先<br><span class="fn">壁垒 / 绑定</span>',
     'Bst HS（H102）、LAMP Kit（H202/H302）、U+ 低残留（F104）、Tn5（BR3P201）、耐抑制高保真（BR3M121 改进）、冻干体系（服务）',
     '竞品做不到或我们独有；技术门槛高', '绑定 PI、做联合发表/标准，形成学术背书'),
    ('WB', '一线<br><span class="fn">进门 / 现金牛</span>',
     'RIPA（C101–C103）、蛋白酶/磷酸酶抑制剂（C121–C123）、BCA/Bradford（C201/C202）、上样缓冲液（C351）、电泳液（C361）、转膜液（D421）、TBST（D451）、PVDF/NC（D411–D414）、ECL（D602）',
     '高频消耗、品牌忠诚度低、看价格', '靠“整套配齐 + 打包价”进门'),
    ('WB', '二线<br><span class="fn">替换 / 差异化</span>',
     '一步法制胶（C331–C335）、快速封闭（D441）、180 kDa marker（C303）、DAB（D601）、抗体剥离液（D603）、15% 高比例胶',
     '省时间、少步骤；对标雅酶/爱博泰克', '用“省 1 小时/次”做卖点，替换制胶与封闭'),
    ('WB', '领先<br><span class="fn">壁垒 / 绑定</span>',
     'fg 级曝光液（新品）、梯度胶（整合）、低背景 ECL（改进）、冻干蛋白 marker（规划）',
     '灵敏度/背景/形态有代差', '绑定 imaging 大户与 CRO，做“低丰度蛋白”解决方案'),
]

PLAN_B = [
    ('高保真 P 不出来 / 非特异', 'M121 高保真', 'A401 快速 PCR（换体系）', 'M121 + 增强粗模板抗抑制版（Q3 需求）', '先排查模板/引物，再换酶；48h 给替代方案'),
    ('RT-qPCR 批间差、Ct 飘', 'F101/F102 RT-qPCR', 'D303 一步法 + E202 探针', 'F104 U+ 低残留（高要求场景）', '同批样本三点复测；不行直接换 F104'),
    ('qPCR ROX 不匹配仪器', 'E102（默认 ROX）', 'E103 / E201（低 ROX / 无 ROX）', '按仪器定制 ROX 版（Q3 需求 BR1E102）', '建“仪器-ROX”对照表，销售随身带'),
    ('RNA 提不出来 / 降解', 'B201/B202 柱提', 'B101 Brizol 沉淀法', '动物组织专用柱提（Q3 新品需求）', '先换方法学，再谈替换'),
    ('胶回收率低 / 长片段丢', 'E301 胶回收', 'C101 无缝克隆（免回收）', '高保真长片段体系', '>10kb 直接建议免回收路线'),
    ('制胶不稳定 / 隔夜才好用', 'C331–C335 一步法制胶', 'C303 预制胶（外购/代工）', '梯度胶（Q3 整合需求）', '先给“隔夜法”SOP，再推梯度胶'),
    ('ECL 背景高 / 弱条带', 'D602 ECL', 'D601 DAB（强信号）', 'fg 级曝光液（Q3 新品）', '按丰度分档推荐，不一把推 ECL'),
]

PI_LADDER = [
    ('博士毕业', '26–28 岁', '—', '刚进组，无采购权；但是未来的 PI', '只做关系，不投入'),
    ('青基（青年基金）', '男 ≤35 / 女 ≤40', '约 20–30 万/项', '起步期：建实验室、买第一批试剂，品牌未定', '★★★ 主攻：第一次采购窗口，替换成本最低'),
    ('优青 / 青年长江 / 青年拔尖', '男 ≤38 / 女 ≤40', '百万级', '扩张期：课题组扩编、开始上量', '★★★★ 主攻：上量最快的阶段'),
    ('杰青 / 长江特聘', '男 ≤45 / 女 ≤48', '数百万', '稳定期：大额采购，但已被诺唯赞等锁定', '★★ 只做单点替换，不打正面'),
    ('国家三大奖第一完成人', '获杰青/长江后 5–10 年', '—', '标杆期：采购看关系与背书', '★ 做背书合作（联合发表/顾问）'),
    ('两院院士', '当选平均 55–59 岁', '—', '顶层：极难攻，但背书价值最大', '★ 只做战略合作/名誉，不做销售指标'),
]

SCORE = [
    ('年龄窗口', '25', '距青基 35 岁 / 优青 38 岁还有几年；临界期（33–35、36–38）加分最高'),
    ('头衔与基金', '20', '已中青基 +15；优青/青年长江 +20；杰青 +5（已被锁定，反而低）'),
    ('经费规模', '20', '在研项目经费 ≥100 万 +20，50–100 万 +12，<50 万 +5'),
    ('课题组规模', '15', '博士/博后 ≥5 人 +15，3–4 人 +10，≤2 人 +5'),
    ('单位层级', '10', '省属/地方院校 +10（易攻），医院科研 +8，C9/985 +3（难攻）'),
    ('竞品渗透', '10', '诺唯赞/全式金占比 <30% +10；30–70% +5；>70% +0'),
]

LEADS = [
    ('① 青年基金 / 引进人才', '每年 3 月写本、4 月公告、9–10 月放榜；Q4 执行采购',
     '基金委公示、省科技厅、学校人事处“新进教师/引进人才”公示、学院新闻',
     '刚拿到青基/优青的新 PI（28–38 岁），第一年建实验室', '一线进门 + 二线替换', '4–5 月建名单 → 6–9 月拜访 → Q4 首单'),
    ('② 校转企技术', '教授创业公司，需要产业化原料与 OEM',
     '高校技术转移中心公示、大学科技园、工商信息（法人/股东为教授）',
     '有文章背书或负责人是大牛的校办企业', 'OEM + 领先产品', '每季度扫一次本地高校转化公示'),
    ('③ 大牛课题组出来的人', '博士/博后毕业去向，带走方法与习惯',
     '论文作者单位变动、课题组主页“毕业生去向”、学院新教师名单',
     '新入职的青椒/博后（原大牛组出身）', '一线 + 二线（沿用原组习惯）', '按“师门”建台账，毕业季 6–7 月集中触达'),
    ('④ 专利交易', '高校专利转让/许可给企业，企业要落地就需要原料',
     '国家知识产权局转让登记、智慧芽/incoPat、高校转化公示',
     '受让专利的企业（尤其诊断/生物药）', 'OEM + 领先产品', '季度扫描，先找“受让方”而非“转让方”'),
    ('⑤ 青椒（引进青年教师）', '人事处公示、人才引进公告',
     '学校人事处、学院官网“师资队伍”、人才招聘公告',
     '新入职 1–3 年的青年教师，正在建组', '一线进门', '每月更新，Q4 起纳入拜访计划'),
]

CAMPAIGNS = [
    ('战役一 · 青椒包围', '广东/浙江省属院校 + 非头部医院的新 PI（评分 ≥60）', '80 家', '一线进门（Taq/dNTP/marker/ECL）+ 二线替换（M121/D303/E202）', '2026Q4–2027Q2'),
    ('战役二 · 基金周期卡位', '3–4 月写本、9–10 月放榜的窗口', '按省/校建名单', '放榜后 2 周内触达，Q4 首单', '每年 3–4 月、9–10 月'),
    ('战役三 · 师门迁移', '大牛课题组毕业生去向（新单位/新 PI）', '待建（首批 50 人）', '沿用原组产品习惯，一线切入', '2027Q1–Q3'),
    ('战役四 · 校转企 / 专利', '教授创业公司、专利受让企业', '待建（首批 20 家）', 'OEM + 领先产品（LAMP/Tn5/冻干）', '2027Q2–Q4'),
    ('战役五 · OEM 选品', '科研 OEM 产品部门选品（10–15 个 SKU）', '10–15 SKU', '贴牌 + 稳定供货，锁定年度量', '2026Q4 定品，2027 放量'),
]

TARGET = [
    ('医院科研', 27, 12.8, '20', '60', '70', '80', '户均 2.2–3.0 万：抓 10 家重点医院课题组'),
    ('省属 / 地方院校', 13, 7.4, '6', '40', '45', '50', '户均 3 万：青椒包围主战场'),
    ('C9 / 985 / 211', 10, 19.0, '8', '40', '50', '60', '只做单点替换，不打正面'),
    ('企业 / 商贸 / 其他', 56, 9.8, '40', '40', '45', '50', '按单评估，选 20 家重点'),
    ('新客（青椒/新 PI）', 0, 0.0, '0', '80', '100', '120', '按 1 万/户，需 80–120 家新客'),
    ('OEM / 渠道', 0, 0.0, '0', '40', '40', '40', '选品 10–15 个 SKU'),
]

TIMELINE = [
    ('2026 Q4', '建三张表：青椒台账、师门台账、专利/校转企台账；OEM 定品 10–15 个；完成 PI 评分卡培训'),
    ('2027 Q1', '青椒包围第一波（80 家）；Q3 汇报的 P0 产品完成 1–2 个改版；联合测试基地签约（传染病院）'),
    ('2027 Q2', '基金放榜后 2 周集中触达；暨大博后进站；OEM 首批出货'),
    ('2027 Q3', '师门迁移战役；专利受让企业扫一轮；半年度复盘（客户数×客单价）'),
    ('2027 Q4', '冲量：锁定 Q4 采购；复盘 PI 评分卡准确率；定 2028 产品线'),
]

page = """<!DOCTYPE html><html lang="zh-CN"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>2027 科研作战地图</title>
<style>__CSS__</style></head><body><div class="wrap">
<h1>2027 科研作战地图（生命科学 · 科研线）</h1>
<div class="meta">
日期：2026-10-17 ｜ 内部资料，请勿外发 ｜ 目标：<b>2027 科研线 300–400 万</b>（2026 年 1–10 月实际 49.5 万，76 家有成交）<br>
三块内容：<b>产品矩阵（分子 / WB 三层 + Plan B）</b> · <b>农村包围城市的执行细化（5 条线索 + PI 潜力评分）</b> · <b>作战方向与市场洞察（钱在哪 / 谁拿钱 / 靠什么拿钱）</b>
</div>

<div class="kpis">
  <div class="kpi"><div class="l">2027 目标</div><div class="v">300–400 万</div><div class="s">2026 实际 49.5 万</div></div>
  <div class="kpi"><div class="l">增长倍数</div><div class="v">6–8×</div><div class="s">必须换打法，不是加人</div></div>
  <div class="kpi"><div class="l">产品矩阵</div><div class="v">3 层 × 2 线</div><div class="s">分子 65 / WB 30 个产品</div></div>
  <div class="kpi"><div class="l">线索来源</div><div class="v">5 条</div><div class="s">青基/校转企/师门/专利/青椒</div></div>
  <div class="kpi"><div class="l">作战战役</div><div class="v">5 个</div><div class="s">青椒/基金/师门/专利/OEM</div></div>
  <div class="kpi"><div class="l">主攻人群</div><div class="v">28–38 岁</div><div class="s">青基→优青阶段的 PI</div></div>
</div>

<div class="card"><h2>一、产品矩阵（分子 / WB）：三层 + Plan B <span>产品目录 102 个，真实货号</span></h2>
<table class="matrix"><thead><tr><th style="width:6%">线</th><th style="width:11%">层级</th><th style="width:40%">代表产品（货号）</th><th style="width:18%">客户认知</th><th>作战用法</th></tr></thead><tbody>
__MATRIX__
</tbody></table>
<div class="fn" style="margin-top:6px">三层不是按价格分，而是按<b>客户决策逻辑</b>分：一线决定“让不让我们进”，二线决定“能不能替换”，领先决定“能不能绑定”。</div>

<h3>1.1 Plan B：客户实验出问题时，48 小时内给替代方案</h3>
<table class="planb"><thead><tr><th style="width:17%">异常场景</th><th style="width:15%">主选（一线/二线）</th><th style="width:18%">备选（立即切换）</th><th style="width:20%">兜底（领先/在研）</th><th>动作</th></tr></thead><tbody>
__PLANB__
</tbody></table>
<div class="fn" style="margin-top:6px">意义：客户实验场景复杂，出问题时“有 Plan B”比“便宜 10%”更能留住客户。要求每个销售随身带这张表，异常 48h 内给方案，不允许“回去问研发”超过 2 天。</div></div>

<div class="card"><h2>二、PI 潜力评分卡：判断“这个教授有没有前途” <span>依据学术职业阶梯（年龄/头衔/经费）</span></h2>
<table class="ladder"><thead><tr><th>阶段</th><th>典型年龄 / 上限</th><th>经费量级</th><th>采购特征</th><th>我方策略</th></tr></thead><tbody>
__LADDER__
</tbody></table>
<h3>2.1 评分卡（满分 100，≥60 分进重点池）</h3>
<table><thead><tr><th style="width:16%">维度</th><th style="width:8%" class="n">分值</th><th>打分规则</th></tr></thead><tbody>
__SCORE__
</tbody></table>
<div class="box ok" style="margin-top:8px"><h4>为什么主攻 28–38 岁</h4>
<ul>
<li><b>青基（≤35）</b>是第一次独立采购窗口：实验室从零建，品牌未定，替换成本最低；但经费小（20–30 万），要靠“一线进门”。</li>
<li><b>优青/青年长江（≤38）</b>是上量最快的阶段：课题组扩编、经费上百万，开始形成固定供应商 —— 此时切入，性价比最高。</li>
<li><b>杰青（≤45）</b>已被诺唯赞/全式金锁定，只做单点替换；<b>院士</b>只做背书，不做销售指标。</li>
<li>反推时间窗：33–35 岁未中青基、36–38 岁冲优青的人，是最值得押注的“临界期 PI”。</li>
</ul></div></div>

<div class="card"><h2>三、农村包围城市：5 条线索怎么落地 <span>每条都有信号源、时间窗、产品和责任人</span></h2>
<table><thead><tr><th style="width:13%">线索</th><th style="width:20%">时间窗 / 触发点</th><th style="width:22%">信号源（去哪找）</th><th style="width:17%">目标画像</th><th style="width:14%">用什么产品</th><th>动作节奏</th></tr></thead><tbody>
__LEADS__
</tbody></table></div>

<div class="card"><h2>四、300–400 万怎么来：按客户层级拆 <span>不是“多跑”，是“换结构”</span></h2>
<table><thead><tr><th style="width:16%">客户层级</th><th class="n" style="width:7%">家数</th><th class="n" style="width:9%">2026 金额</th><th class="n" style="width:7%">有成交</th><th class="n" style="width:8%">2027 低</th><th class="n" style="width:8%">2027 中</th><th class="n" style="width:8%">2027 高</th><th>打法</th></tr></thead><tbody>
__TARGET__
</tbody></table>
<div class="fn" style="margin-top:6px">单位：万元。低/中/高三档分别对应 300 / 350 / 400 万。关键假设：新客按 1 万/户，需 80–120 家；现有客户户均从 0.65 万提到 1.5–2 万。</div>
<div class="grid2" style="margin-top:10px">
  <div class="box warn"><h4>目标能不能成，取决于三件事</h4>
  <ul>
    <li><b>新客数量</b>：80–120 家/年 = 每月 7–10 家，8 名销售人均 1 家/月 —— 必须靠青椒/师门/专利三条线供名单，不能靠陌拜。</li>
    <li><b>户均提升</b>：从 0.65 万到 1.5–2 万，靠“一线进门→二线替换”，单客品类从 1 个扩到 3 个。</li>
    <li><b>OEM 与渠道</b>：40 万是“确定性收入”，用来兜底，不靠它冲增长。</li>
  </ul></div>
  <div class="box"><h4>五个战役（谁负责、打哪里）</h4>
  <ul>
    <li><b>战役一 青椒包围</b>：广东/浙江省属 + 非头部医院，80 家，Q4 起。</li>
    <li><b>战役二 基金卡位</b>：3–4 月写本、9–10 月放榜，放榜 2 周内触达。</li>
    <li><b>战役三 师门迁移</b>：大牛组毕业生去向，首批 50 人。</li>
    <li><b>战役四 校转企/专利</b>：教授创业公司 + 专利受让企业，首批 20 家。</li>
    <li><b>战役五 OEM 选品</b>：10–15 个 SKU，Q4 定品。</li>
  </ul></div>
</div></div>

<div class="card"><h2>五、作战方向 × 市场洞察：钱在哪、谁拿钱、我们靠什么拿钱</h2>
<table><thead><tr><th style="width:14%">作战方向</th><th style="width:22%">钱在哪</th><th style="width:22%">谁拿钱</th><th style="width:22%">我们靠什么拿钱</th><th>2027 验证指标</th></tr></thead><tbody>
<tr><td><b>战役一 青椒包围</b></td><td>国家青基/省基金（20–30 万/项）+ 学校启动经费</td><td>28–35 岁新 PI（省属院校、医院科研岗）</td><td>一线（Taq/dNTP/marker/ECL）进门 + 二线（M121/D303）替换</td><td>新增 80 家，首单率 ≥40%</td></tr>
<tr><td><b>战役二 基金卡位</b></td><td>3–4 月写本、9–10 月放榜后的集中采购</td><td>中标 PI（青基/优青/面上）</td><td>放榜名单 + 2 周内上门，用“开题礼包”锁首单</td><td>名单覆盖率 ≥70%，Q4 首单 ≥30 家</td></tr>
<tr><td><b>战役三 师门迁移</b></td><td>新单位启动经费 + 原课题组延续采购</td><td>大牛组毕业的博士/博后（新 PI）</td><td>沿用原组产品习惯（同货号迁移），一线切入</td><td>首批 50 人，转化 ≥15 家</td></tr>
<tr><td><b>战役四 校转企/专利</b></td><td>教授创业融资 + 专利受让方产业化投入</td><td>校办企业、专利受让企业（诊断/生物药）</td><td>OEM + 领先产品（LAMP/Tn5/冻干）</td><td>首批 20 家，签约 ≥3 家</td></tr>
<tr><td><b>战役五 OEM 选品</b></td><td>科研 OEM 客户的稳定年度采购</td><td>科研 OEM 产品部门 / 贴牌客户</td><td>10–15 个 SKU 贴牌 + 稳定供货</td><td>定品 10–15 个，出货 ≥40 万</td></tr>
</tbody></table></div>

<div class="card"><h2>六、2027 时间轴（对齐基金节奏）</h2>
<div class="tl">
__TIMELINE__
</div></div>

<div class="card"><h2>七、数据与假设（必须写清）</h2>
<div class="fn">
① 2026 金额：生命科学 114 家客户、ERP 2026 年 1–10 月标准单/非赠品/已审核，合计 <b>49.5 万</b>，76 家有成交（户均 0.65 万）。<br>
② 产品货号与价格：<span class="mono">数据/ls_product_catalog.json</span>（102 个产品，2026 版目录）。<br>
③ Q3 产品需求：8 份生命科学汇报的「客户需求（优化方向）」，共 28 条（P0 11 条），见 <span class="mono">数据/科研Q3产品需求汇总.json</span>。<br>
④ PI 年龄/头衔：依据用户提供的学术职业阶梯表（青基 ≤35、优青/青年长江 ≤38、杰青 ≤45、院士 55–59），<b>年龄上限可能随政策调整，需年度复核</b>。<br>
⑤ 目标拆解为规划假设，非承诺；新客 1 万/户为 2026 年现有客户户均的 1.5 倍，需用“首单礼包 + 二线替换”支撑。<br>
⑥ 尚未取得的数据：各省基金中标名单（需采购或公开数据）、专利转让明细（需智慧芽/incoPat）、OEM 客户清单（需产品部提供）。
</div></div>
__FOOTER__
</div></body></html>"""


def rows(data, first_bold=False):
    out = []
    for r in data:
        cells = []
        for i, c in enumerate(r):
            cells.append('<td>%s</td>' % c)
        out.append('<tr>' + ''.join(cells) + '</tr>')
    return '\n'.join(out)


tm = []
for (name, n, amt, act, lo, mid, hi, how) in TARGET:
    tm.append('<tr><td><b>%s</b></td><td class="n">%d</td><td class="n">%.1f 万</td><td class="n">%s</td>'
              '<td class="n">%s</td><td class="n">%s</td><td class="n">%s</td><td class="fn">%s</td></tr>'
              % (name, n, amt, act, lo, mid, hi, how))

page = (page.replace('__CSS__', CSS)
        .replace('__MATRIX__', rows(PRODUCT_MATRIX))
        .replace('__PLANB__', rows(PLAN_B))
        .replace('__LADDER__', rows(PI_LADDER))
        .replace('__SCORE__', rows(SCORE))
        .replace('__LEADS__', rows(LEADS))
        .replace('__TARGET__', '\n'.join(tm))
        .replace('__TIMELINE__', '\n'.join(
            '<div class="p"><div class="h">%s</div>%s</div>' % (a, b) for a, b in TIMELINE)))
page = BK.inject(page, theme='dark', tag='2027 科研作战地图',
                 footer_extra='内部资料 · 请勿外发 ｜ 产品数据：生命科学目录 2026 ｜ 金额：ERP 2026 年 1–10 月')
v = BK.verify(page)
bad = [k for k, ok in v.items() if not ok]
assert not bad, bad
io.open(OUT, 'w', encoding='utf-8').write(page)
print('✅ %s（%.0f KB）' % (OUT, os.path.getsize(OUT) / 1024))
